/* ************************************************************************
 * *                                                                      *
 * *    Function to add the slabels array to the product_end structure    *
 * *            in a format like what was in effect at V6.11.             *
 * *                                                                      *
 * ************************************************************************
 * File: iris/output/AddLabels611.C
 *
 *                     COPYRIGHT (c) 1999, 2000  BY
 *          SIGMET INCORPORATED, WESTFORD MASSACHUSETTS, U.S.A.
 * 
 * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
 * ONLY  IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE
 * INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE  OR  ANY OTHER
 * COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
 * OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
 * TRANSFERED.
 */

#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sigtypes.h"
#include "headers.h"
#include "product.h"
#include "setup.h"
#include "dsp.h"
#include "user_lib.h"
#include "misc_lib.h"

/*
 * Old product_end structure.
 */

struct product_end611
{
  char sprod_sitename[16];             /* Name of product generator site, space padded */
  char sprod_version[8];               /* Product IRIS version, null terminated */
  char sing_version[8];                /* Ingest IRIS version, null terminated */
    
  struct ymds_time old_ing;            /* Oldest data in this file */
  char ipad44x46[46];

/* Information about the radar site.  Latitude and Longitude are stored as 
 * 32-bit binary angles, where 20000000 Hex is 45 degrees North Latitude or 
 * East Longitude.  All heights are in meters.  For products of many tasks,
 * these are taken from the first site.  For track product, these are taken
 * from the site making the track.
 */
  char  sing_sitename[16];             /* Name of ingest site, space padded */
  SINT2 igmt_min;                      /* # minutes ahead of GMT */
  BIN4  ilat_center;                   /* Latitude of center of product */
  BIN4  ilon_center;                   /* Longitude of center of product */
  SINT2 ignd_hgt;                      /* Ground height (m above sea level) */
  SINT2 irad_hgt;                      /* Radar height (m above ground) */

/*Signal processing related numbers.  These are mostly copied from the task
 * configuration structure.
 */
  SINT4 iprf;                           /* PRF in hertz */
  SINT4 ipw;                            /* Pulse width in 1/100 usec */
  UINT2 idsptype;
  UINT2 itrig;                          /* Trigger rate scheme */
  SINT2 isamp;                          /* # samples used */
  char  sfilter[12];                    /* Clutter filter file name */
  UINT2 idop_filter_first;              /* Doppler filter used on first bin */
  SINT4 ilambda;                        /* Wavelength in cm*100 */
  SINT4 itrunc;                         /* Truncation height in cm */
  SINT4 ibin_first;                     /* Range of first bin in cm */
  SINT4 ibin_last;                      /* Range of last bin in cm */
  SINT4 ibin_out_num;                   /* Number of output bins */

  UINT2 iflags;                         /* Flags */
#define PH_OVERLAY_P   (0x0001)     /*  Has an overlay \ For picture */
#define PH_RINGS_P     (0x0002)     /*  Has range rings/ products only */

  /*Number of ingest and product files processed to produce this product:
   * Only for accumulating products. */
  SINT2 input_cnt;                  

  char slabels[16][4];                 /* Labels on legend */

  UINT2 ilog_filter_first;             /* Log filter used on first bin */
  char ipad238x2[2];
  BIN4  ilat_ref;                      /* Latitude of projection reference point */
  BIN4  ilon_ref;                      /* Longitude of projection reference point */

  /*The following sequence number can be used whenever product files need to be
   * ordered or indexed in some way.  For example, when the Nth product is written
   *to a tape, the value is filled in with N.
   */
  SINT2 isequence_num;

  /* Only applicable to picture products, will be zeroed in data products */
  UINT2 istep_colors[16];               /*  Color #'s for above steps */
  UINT1 irej_color;                     /*  Color to represent thresholded data */

  char ipad283x3[3];

  /* The number of results elements at the end of the file.
   * Used for warning, shearline, and track only */
  SINT2 iresults_count;

#define PROD_END_PAD (20)
  char ipad_end[PROD_END_PAD];

};

struct private_scale_def
{
  UINT4 iflags;
  SINT2 icolcnt;
  UINT2 ilevel_seams[16];
};

/* Local function prototypes
 */
static void ProcessCommandLine
(int iArgc, 
 char *sArgv[],
 struct private_scale_def *pScaleDef_a );

static void Usage( void );

static MESSAGE ProcessProductHeader
(struct product_hdr *pheader_a,
 const struct private_scale_def *pScaleDef_a
 );

static void ComputeColormap
(UINT2 idtype_a,                 /* Data type */
 struct color_scale_def *colors_a,   /* Always modified */
 struct product_end611 *pend_a,
 union level_control *plevel_a,
 struct scale_text newscale_a[16],
 const struct private_scale_def *pPrivateScale_a );

static void local_colormap
(UINT2 iparam_a,
 struct color_scale_def *scaledef_a,
 struct scale_text newscale_a[16],
 const struct private_scale_def *pPrivateScale_a,
 union level_control *level_a,
 const struct data_convert *pconvert_a );

static void patchup_color_scale
(struct color_scale_def *scaledef_a,
 UINT2 icolscale_a[16],
 const struct private_scale_def *pPrivateScale_a );

int main(int iArgc, char *sArgv[])
{
  struct product_hdr ProdHeader;
  SINT4 iRes, iLine;
  UINT1 *pBuffer;
  MESSAGE istatus;
  struct private_scale_def ScaleDefinition;
  SINT4 iCount;

  setlocale( LC_ALL, "" ) ;

  /* Process the command line arguments */
  ProcessCommandLine( iArgc, sArgv, &ScaleDefinition );

  /* Read in the header */
  iCount =  fread( &ProdHeader, sizeof(ProdHeader), 1, stdin );
  if (iCount != 1) fprintf( stderr, "Bad read, got%d, wanted%d\n",
					     iCount, sizeof(ProdHeader));
  istatus = ProcessProductHeader( &ProdHeader, &ScaleDefinition );
  if (istatus != SS_NORMAL) exit(EXIT_FAILURE);

  /* Write out the header, color scale information may be changed. */
  iCount = fwrite( &ProdHeader, sizeof(ProdHeader), 1, stdout );
  if (iCount != 1) fprintf( stderr, "Bad write\n" );

  /* Malloc input and output buffers */
  iRes = idata_resolution( ProdHeader.pcf.idata_out );
  pBuffer  = (UINT1*)malloc( ProdHeader.pcf.ixsize*iRes/8 );

  /* Now copy the data, no changes made here */
  for (iLine=0; iLine<ProdHeader.pcf.iysize; iLine++)
    {
      iCount = fread(  pBuffer, iRes/8, ProdHeader.pcf.ixsize, stdin );
      if (iCount != ProdHeader.pcf.ixsize) fprintf( stderr, "Bad read\n" );
      iCount = fwrite( pBuffer, iRes/8, ProdHeader.pcf.ixsize, stdout );
      if (iCount != ProdHeader.pcf.ixsize) fprintf( stderr, "Bad write\n" );
    }
  exit( EXIT_SUCCESS );
}
/* ======================================================================
 * Function to process the command line arguments.
 */
static void ProcessCommandLine
(int iArgc_a, 
 char *sArgv_a[],
 struct private_scale_def *pScaleDef_a )
{

  int iArg, iIndex;

  /* Zero the scale, and fill in some default numbers */
  memset( pScaleDef_a, 0, sizeof(pScaleDef_a) );
  pScaleDef_a->icolcnt = 14;
  /* These number assume we have a 16-bit data type available */
  for (iIndex=0; iIndex<16; iIndex++)
    {
      pScaleDef_a->ilevel_seams[iIndex] = 1+ (16*256*iIndex);
    }
  pScaleDef_a->iflags = COLOR_SCALE_VARIABLE;
  /* Note that the top and bottom saturation flags are picked up from the file
   * pScaleDef_a->iflags = COLOR_SCALE_VARIABLE|COLOR_SCALE_TOP_SAT|COLOR_SCALE_BOT_SAT;
   */

  /* Parse command line options
   */
  for( iArg=1 ; iArg<iArgc_a ; iArg++ )
    {
      const char *sArg = sArgv_a[iArg];

      /* fprintf( stderr, "Processing %d: '%s'\n", iArg, sArg ); */
      if (0 == strncmp( sArg, "-seams", 6 ) )
	{
	  char sString[110], *sSubArg;
	  int iValue;

	  strncpy( sString, &sArg[6], 109); sString[109]=0;

	  for (iIndex=0; iIndex<16; iIndex++)
	    {
	      if (iIndex==0)
		sSubArg = strtok( sString, ":" );
	      else
		sSubArg = strtok( NULL, ":" );
	      if (sSubArg==NULL) Usage();
	      if( sscanf( sSubArg, "%d", &iValue ) != 1 )
		{
		  fprintf( stderr, "Could not parse '%s' after '%s'\n", sSubArg, sArg ) ;
		  Usage() ;
		}
	      pScaleDef_a->ilevel_seams[iIndex] = iValue;	      
	    }
	}

      else if (0 == strncmp( sArg, "-colors", 7) )
	{
	  char sString[10], *sSubArg;
	  int iValue;
	  strncpy( sString, &sArg[7], 9); sString[9]=0;
	  sSubArg = strtok( sString, ":" );
	  if (sSubArg==NULL) Usage();
	  if( sscanf( sSubArg, "%d", &iValue ) != 1 )
	    {
	      fprintf( stderr, "Could not parse '%s' after '%s'\n", sSubArg, sArg ) ;
	      Usage() ;
	    }
	  pScaleDef_a->icolcnt = MAX( 2, MIN( 14, iValue));	      
	}

      else if (0 == strncmp( sArg, "-h", 2))
	{
	  Usage();
	}
      
    }
  return;
}
/* ==================================================
 */
static void Usage( void )
{
  fprintf( stderr, "Options: -levels:N1:N2:N3:...:N16\n" );
  fprintf( stderr, "         -colors:N\n" );
  fprintf( stderr, "         -help\n" );
  fprintf( stderr, "         (all other options ignored)\n" );
  exit(EXIT_FAILURE) ;
}
/* =======================================================================
 * Check for some consistency.  The Product type must be valid, and the file
 * size must be large enough to hold the data expected.  Also generate the
 * colormap, and latch some output options.  
 */
static MESSAGE ProcessProductHeader
(struct product_hdr *pheader_a,
 const struct private_scale_def *pScaleDef_a
 )
{
  MESSAGE istatus;
  SINT4 isrc_size[3];
  struct scale_text scale[16];

  SINT4 iCartesianSize;       /* Size calculated based on header */
  union level_control Level;  /* Level control structure */

  memset( &scale, 0, sizeof(scale) );
  switch (pheader_a->pcf.iptype)
    {
    default:
      fprintf( stderr, "Product type not supported\n" );
      istatus = USER_ERROR_SIG;
      break;

    case PROD_PPI:
    case PROD_RHI:
    case PROD_CAPPI:
    case PROD_CROSS:
    case PROD_TOPS:
    case PROD_RAIN1:
    case PROD_RAINN:
    case PROD_VIL:
    case PROD_SHEAR:
    case PROD_MAX:
    case PROD_USER:
    case PROD_USERV:
    case PROD_BEAM:
      isrc_size[0] = pheader_a->pcf.ixsize;
      isrc_size[1] = pheader_a->pcf.iysize;
      isrc_size[2] = pheader_a->pcf.izsize;
      if( ( isrc_size[0] < MIN_PRODUCT_SIZE ) ||
	  ( isrc_size[0] > MAX_PRODUCT_SIZE ) ||
	  ( isrc_size[1] < MIN_PRODUCT_SIZE ) ||
	  ( isrc_size[1] > MAX_PRODUCT_SIZE ) )
	{
	  sig_signal_va( IRIS_PROD_XYSIZE, 2, isrc_size[0], isrc_size[1] ) ;
	  return( USER_ERROR_SIG ) ;
	}
      if (isrc_size[2]==0) isrc_size[2]=1;
      if( ( isrc_size[2] < 0 ) ||
	  ( isrc_size[2] > MAX_PRODUCT_SURFACES ) )
	{
	  sig_signal_va( IRIS_PROD_ZSIZE, 1, isrc_size[2] ) ;
	  return( USER_ERROR_SIG ) ;
	}
      
      {
	SINT4 ires;
	ires = idata_resolution( pheader_a->pcf.idata_out );
	iCartesianSize = isrc_size[0]*isrc_size[1]*(ires/8)*isrc_size[2];
	if ( (iCartesianSize+PRODUCT_HDR_SIZE) > pheader_a->hdr.ibytes )
	  {
	    fprintf( stderr, "File size %d bytes is too small to contain expected data %d bytes\n",
		     pheader_a->hdr.ibytes, iCartesianSize );
	    return USER_ERROR_SIG;
	  }
	
	/* Note that this computes the color mapping table and modifies the header
	 * to use the current color map.
	 */
	ComputeColormap( pheader_a->pcf.idata_out, &pheader_a->pcf.colors, 
			 /* Double cast required to supress warnings */
			 (struct product_end611 *)(void *)(&pheader_a->end), &Level, 
			 scale, pScaleDef_a );
      }
      istatus = SS_NORMAL;
      break;
    }

  return istatus;
}

/* ============================================================================
 * This subroutine computes the color map and the color parameter scale
 * text from the product header.
 */
static void ComputeColormap
(UINT2 idtype_a,                    /* Data type */
 struct color_scale_def *colors_a,  /* Fill in color seam information */
 struct product_end611 *pend_a,
 union level_control *plevel_a,     /* Filled in so we can levelize */
 struct scale_text newscale_a[16],  /* Label text is here */
 const struct private_scale_def *pPrivateScale_a )
{
  struct data_convert convert;
  int iIndex;

  /* ----------------------------------------------------------------------- */
  /* Skip for invalid data types
   */
  if (idtype_a == 0) return;

  /* Note that the 6.11 product_end has slabels where polarization control is now.*/
  FillDataConvert( &convert, pend_a->iprf, pend_a->itrig, pend_a->ilambda, POL_HORIZ_FIX,
		   CONVERT_FLAGS_DEFAULT );

  local_colormap(idtype_a, colors_a, newscale_a, pPrivateScale_a, plevel_a, &convert );

  /* Fill in the text strings, use the middle values, truncate to 4 characters. */
  for (iIndex=0; iIndex<16; iIndex++)
    {
      spacify_ncpy( pend_a->slabels[iIndex], newscale_a[iIndex].sCenter, 4 );
      /*
      fprintf( stderr, "Label %2d: %6.6s %6.6s %6.6s %6.6s %6.6s\n",
	       iIndex, newscale_a[iIndex].left, newscale_a[iIndex].sLeftCenter,
	       newscale_a[iIndex].sCenter, newscale_a[iIndex].sRightCenter,
	       newscale_a[iIndex].right );
      */
    }
}

/* ============================================================================
 * This subroutine returns information about a parameter that will help display
 * it.  
 */
static void local_colormap
(UINT2 iparam_a,                        /* Data type */
 struct color_scale_def *scaledef_a,    /* Returns color seam info for header */
 struct scale_text newscale_a[16],      /* Returns Array of text for possible legend use */
 const struct private_scale_def *pPrivateScale_a,
 union level_control *level_a,          /* Returns level control inforamation */
 const struct data_convert *pconvert_a ) /* Information to help convert data */
{   
  UINT4 idtype, index;
  UINT2 iColorScale[COLOR_MAP_ZOOM][16];
  UINT1 iColorNoData, iColorThresh;
  UINT2 iOldColorScale[16];
  /* ----------------------------------------------------------------------- */

  idtype = iparam_a;

  patchup_color_scale( scaledef_a, iOldColorScale, pPrivateScale_a);

  /* Copy color scale to a zoomed version */
  for (index=0; index<16; index++)
    {
      iColorScale[0][index] = iOldColorScale[index];
      iColorScale[1][index] = COLOR_MAP_MAX+iOldColorScale[index];      
    }
  iColorNoData = 0;
  iColorThresh = 1;
  generic_map( idtype, scaledef_a, iColorScale,
	       iColorThresh, iColorNoData, level_a, pconvert_a, newscale_a );

}

/* ======================================================
 * Fill in color array, and optionally override the whole thing
 */
static void patchup_color_scale
(struct color_scale_def *scaledef_a,
 UINT2 icolscale_a[16],
 const struct private_scale_def *pPrivateScale_a )

{
  SINT4 icolor;
  /* ----------------------------------------------------------------------- */

  scaledef_a->iflags  = COLOR_SCALE_VARIABLE | pPrivateScale_a->iflags;
  scaledef_a->istart  = 0;
  scaledef_a->istep   = 0;
  scaledef_a->icolcnt = pPrivateScale_a->icolcnt;
  /* Leave set_and_scale unchanged */
  for (icolor=0; icolor<16; icolor++)
    scaledef_a->ilevel_seams[icolor] =  pPrivateScale_a->ilevel_seams[icolor];

}


