/* ********************************************************
 * *                                                      *
 * *  Function to convert a KMA CAPPI to IRIS format      *
 * *                                                      *
 * ********************************************************
 * File: utils/pipes_in/KmaRadToIris.C
 *
 *               COPYRIGHT (c) 2000, 2001, 2003, 2006  BY
 *             VAISALA INC., 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.
 */

/* This program is a pipe which takes an IRIS product in the standard input
 * and writes a modified product out the standard output.
 *
 * Note if you are modifying this program, and wish to insert a diagnostic
 * printf, be sure to write it to the error output.
 */

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

#include "sigtypes.h"
#include "headers.h"
#include "sigversion.h"
#include "product.h"
#include "dsp.h"
#include "user_lib.h"

/* This holds information to customize the convertor */
#define KMA_MAX_SITES (5)
struct site_table
{
  char sSiteCode[20];
  char sSiteName[20];
  FLT4 fLatitude;
  FLT4 fLongitude;
};
struct convert_config
{
  UINT1 lLogToFile;
  UINT1 lLogToTerm;
  UINT1 lVerbose;             /* Log more details */
  UINT1 lAppendToLog;         /* Do not erase file each time */
  FILE *iLogFile;             /* Open file descriptor to log file */
  char  sFileName[FILENAME_SIZE];
  SINT4 iSiteCount;
  struct site_table Sites[KMA_MAX_SITES];
};

struct convert_config CConfig_c;

/* Local function prototypes
 */
static void ProcessCommandLine
(int iArgc, 
 char *sArgv[],
 char sFilename_a[FILENAME_SIZE] );

static void Usage( void );

static void FillProductHeader
(struct product_hdr *phdr_a,
 const char *sFileName_a,
 const struct site_table *pSite_a );

static void ConvertKmaToIris
( const char *sFileName_a );

static void LoadSetup
( struct convert_config *pCSetup_a );

static UINT2 ProcessConfigLine
(char *sline_a,
 struct convert_config *pCSetup_a );

static void Lprintf
( const char *sString_a );

/* ===============================================================
 * Main program starts here.
 */
int main(int iArgc, char *sArgv[])
{
  char sFileName[FILENAME_SIZE];

  setlocale( LC_ALL, "" ) ;

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

  /* Process the setup file, if any */
  LoadSetup( &CConfig_c );

  /* Open the logging file, if any */
  if (CConfig_c.lLogToFile)
    {
      char *sptr;
      char sLogPath[PATHNAME_SIZE];
      sptr = getenv( "IRIS_LOG" );
      if (sptr)
	{
	  strncpy( sLogPath, sptr, PATHNAME_SIZE-20 );
	  sLogPath[PATHNAME_SIZE-20] = 0;
	}
      else
	strcpy( sLogPath, "/tmp/" );
      strcat( sLogPath, "KmaRadToIris.log" );
      if (CConfig_c.lAppendToLog)
	CConfig_c.iLogFile = fopen( sLogPath, "a" );
      else
	CConfig_c.iLogFile = fopen( sLogPath, "w" );
      if (NULL == CConfig_c.iLogFile)
	{
	  fprintf( stderr, "Can not open log file: '%s'\n", sLogPath );
	  exit(EXIT_FAILURE);
	}
    }

  /* Starting here we can use the Lprintf function */

  ConvertKmaToIris( sFileName );

  exit( EXIT_SUCCESS );
}
/* ==========================================================
 *
 */
static void ConvertKmaToIris
( const char *sFileName_a )
{
  
  char log_str[200];
  
  SINT4 iSize;
  int    ii, site_index;
  unsigned char dat_block[512 * 512];
  unsigned short out_block[512 * 512];
  struct product_hdr phdr;


  /* Search for the site code in the first 3 characters of the filename */
  site_index = 10; 
  for(ii=0; ii<KMA_MAX_SITES; ii++)
    {
      if (strncmp(sFileName_a, CConfig_c.Sites[ii].sSiteCode, 3) == 0)
	{
	  site_index = ii;
	  break;
	}
    }

  if (site_index == 10)
    {
      sprintf(log_str, "File %s is an invalid site.\n", sFileName_a); 
      Lprintf(log_str);
      exit(EXIT_FAILURE);
    }

  sprintf(log_str, "Processing input file: %s\n", sFileName_a);
  Lprintf(log_str);

  /****
       The input radar data is 512 pixels by 512 pixels where each pixel
       is one KM by one KM.
  ****/
  
  iSize = fread(dat_block, sizeof(char), (512 * 512), stdin); 
  if (iSize != 512*512)
    {
      sprintf(log_str, "File read size wrong, got %d, expected %d\n", iSize,
	      512*512 );
      Lprintf(log_str);
      exit(EXIT_FAILURE);
    }
  
  /****
       If we have a good area file, then we must now convert it into an IRIS
       user product.  So we take the steps to do that.
  ****/
    
  FillProductHeader( &phdr, sFileName_a, &CConfig_c.Sites[site_index] );
  for (ii=0; ii<(512*512); ii++)
    {
      if (dat_block[ii] == 255) out_block[ii] = 65535;
      else
	{
	  UINT4  dat_val_i;
	  float  dat_val_f;

	  if (dat_block[ii] < 100)
	    dat_val_f = 0.10 * (float)dat_block[ii];
	  else
	    dat_val_f = (float)(dat_block[ii] - 90);
	  dat_val_i = (UINT4)(dat_val_f * 10000.0);
	  rain_long_to_file(&dat_val_i, 1, &out_block[ii]);
	}
    }
  
  /****
       Now we write the data to disk.
  ****/
  
  fwrite(&phdr, sizeof(struct product_hdr), 1, stdout );
  
  fwrite(out_block, 2, (512*512), stdout);  

}
/* ======================================
 */
static void FillProductHeader
(struct product_hdr *phdr_a,
 const char *sFileName_a,
 const struct site_table *pSite_a )
{
  char tmp_str[10];
  SINT4 ihour, iminu;

  memset( phdr_a, 0, sizeof(*phdr_a));
  phdr_a->hdr.id = ST_PRODUCT_HDR;
  phdr_a->hdr.ivers = SVER_PRODUCT_HDR_P;
  phdr_a->hdr.ibytes = sizeof (struct product_hdr) + (512 * 512 * 2);
  phdr_a->hdr.reserved = 0;
  phdr_a->hdr.iflags = HD_STRUCTURE_COMPLETE;
  phdr_a->pcf.hdr.id = ST_PRODUCT_CONF;
  phdr_a->pcf.hdr.ivers = SVER_PRODUCT_CONF_P;
  phdr_a->pcf.hdr.ibytes = sizeof (struct product_configuration);
  phdr_a->pcf.hdr.reserved = 0;
  phdr_a->pcf.hdr.iflags = HD_STRUCTURE_COMPLETE;
  phdr_a->pcf.iptype = PROD_CAPPI;
  phdr_a->pcf.isch = 0;
  phdr_a->pcf.isch_skip = 0;
  
  strncpy(tmp_str, &sFileName_a[11], 2);
  tmp_str[2] = 0;
  ihour = atoi(tmp_str);
  strncpy(tmp_str, &sFileName_a[13], 2);
  tmp_str[2] = 0;
  iminu = atoi(tmp_str);
  
  /* prod_time is the time the product was made */
  GetTimeYmds( &phdr_a->pcf.prod_time, TIME_FLG_UTC );

  memset( &phdr_a->pcf.ing_time, 0, sizeof(phdr_a->pcf.ing_time) );
  phdr_a->pcf.ing_time.isec = (ihour*3600)+(iminu*60);
  strncpy(tmp_str, &sFileName_a[3], 4); 
  tmp_str[4] = 0;
  phdr_a->pcf.ing_time.iyear = atoi(tmp_str);
  strncpy(tmp_str, &sFileName_a[7], 2); 
  tmp_str[2] = 0;
  phdr_a->pcf.ing_time.imon = atoi(tmp_str);
  strncpy(tmp_str, &sFileName_a[9], 2); 
  tmp_str[2] = 0;
  phdr_a->pcf.ing_time.iday = atoi(tmp_str);
  
  phdr_a->pcf.epoch = phdr_a->pcf.ing_time;
  
  phdr_a->end.old_ing = phdr_a->pcf.ing_time;
  
  memcpy(phdr_a->pcf.spname, "KMA_CAPPI   ", 12); 
  memcpy(phdr_a->pcf.stname, "KMA_CAPPI   ", 12); 
  phdr_a->pcf.iflags = 0;
  
  /****
       The pixel scale is determined by the row and column resolution in the
       dir block times the resolution in the nav block.
  ****/
  phdr_a->pcf.ixscale = 1000 * 100; /* 1km square pixels */
  phdr_a->pcf.iyscale = 1000 * 100; /* 1km square pixels */
  phdr_a->pcf.izscale = 0;
  phdr_a->pcf.ixsize = 512;
  phdr_a->pcf.iysize = 512;
  phdr_a->pcf.izsize = 1;  /* set to 0 for PPI */
  phdr_a->pcf.ixrad = 256000; /* radar in middle of screen */
  phdr_a->pcf.iyrad = 256000;
  phdr_a->pcf.izrad = 0;
  phdr_a->pcf.irange_last_v20 = 0;
  phdr_a->pcf.idata_out = DB_RAINRATE2;
  phdr_a->pcf.idata_in  = DB_RAINRATE2;
  phdr_a->pcf.iprojection_type = 1;

  /* Remove this line if not a CAPPI */
  phdr_a->pcf.psi.cappi.icappi_hgt = 100000;

  phdr_a->pcf.colors.iflags = (COLOR_SCALE_TOP_SAT | COLOR_SCALE_BOT_SAT);
  phdr_a->pcf.colors.istart = 200;
  phdr_a->pcf.colors.istep  = 100;
  phdr_a->pcf.colors.icolcnt = 16;
  phdr_a->pcf.colors.iset_and_scale = 0x0101;
  
  memcpy(&(phdr_a->end.sprod_sitename), "                ", 16);
  memcpy(&(phdr_a->end.sprod_sitename), pSite_a->sSiteName,
	 strlen(pSite_a->sSiteName) );
  strcpy((char *)&(phdr_a->end.sprod_version), IRIS_VERSION);
  strcpy((char *)&(phdr_a->end.sing_version),  IRIS_VERSION);
  
  phdr_a->end.iprf = 500;
  phdr_a->end.ipw = 100;
  phdr_a->end.ilambda = 500;
  phdr_a->end.ipolar  = POL_HORIZ_FIX ;
  memcpy(&(phdr_a->end.sing_sitename), "                ", 16);
  memcpy(&(phdr_a->end.sing_sitename), pSite_a->sSiteName,
	 strlen(pSite_a->sSiteName) );
  memcpy(&(phdr_a->end.sIngHardwareName), &(phdr_a->end.sing_sitename), 16);
  phdr_a->end.iMinutesWest = 0;
  
  /* now scale lon for IRIS */
  phdr_a->end.ilon_center = iBin4FromFDeg(pSite_a->fLongitude); 
  
  /* now scale lat for IRIS */
  phdr_a->end.ilat_center = iBin4FromFDeg(pSite_a->fLatitude);
  
  phdr_a->end.ignd_hgt = 50;
  phdr_a->end.irad_hgt = 10;
  
}


/* ======================================================================
 * Function to process the command line arguments.
 */
static void ProcessCommandLine
(int iArgc_a, 
 char *sArgv_a[],
 char sFilename_a[FILENAME_SIZE] )
{

  int iArg;

  /* 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 (sArg[0] == '-')
	{
	  if (0 == strncmp( sArg, "-h", 2 ))
	    {
	      Usage();
	    }
	}
      else
	strncpy( sFilename_a, sArg, FILENAME_SIZE-1 );
      
    }
  return;
}
/* ==================================================
 */
static void Usage( void )
{
  fprintf( stderr, "Options: -help\n" );
  fprintf( stderr, "         filename\n" );
  fprintf( stderr, "         (all other arguments ignored)\n" );
  exit(EXIT_FAILURE) ;
}

/* ============================================================
 * Function to load the convert setup from a configuration file.
 */
static void LoadSetup
( struct convert_config *pCSetup_a )
{
  char sPath[PATHNAME_SIZE];
  char sline[81], *sptr;
  FILE* stream;
  SINT4 iline;
  UINT2 lerror;

  /* Initialize the data to the default values */
  memset( pCSetup_a, 0, sizeof(*pCSetup_a) );

  /* Generate the file name and open the file */
  sptr = getenv( "IRIS_CONFIG" );
  if (NULL == sptr) 
    {
      sig_signal_va( USER_NO_ENV, 1, "IRIS_CONFIG" );
      exit(EXIT_FAILURE);
    }

  strncpy( sPath, sptr, 140 );
  strcat( sPath, "KmaRadToIris.conf" );
  stream = fopen( sPath, "r" );

  /* Don't worry about a missing config file */
  if (NULL == stream) return;

  /* now loop through the file reading and parsing lines */
  iline = 1;
  sptr = fgets( sline, 81, stream );
  while (NULL != sptr)
    {
      lerror = ProcessConfigLine( sptr, pCSetup_a );
      if (lerror) fprintf( stderr, "Syntax error on KmaRadToIris.conf file line %d\n", iline );
      iline +=1;
      sptr = fgets( sline, 81, stream );
    }

  fclose( stream );

  return;
}

/* ===============================================================
 * Process one line from the configuration file.  Returns nonzero if there
 * is a syntax error.
 *
 * The config can contain the following commands.  All blank lines and
 * lines beginning with "#" are ignored.  Commands can be in any order.
 * Commands take effect in the order received.  For example, syntax errors
 * before the LOG command will not be logged.
 *
 * LOG           <FILE TERM BOTH NONE>
 * SITE name16 name3 lat long
 * VERBOSE
 *
 *
 */
static UINT2 ProcessConfigLine
(char *sline_a,
 struct convert_config *pConfig_a )
{
  char *stokens[9];
  UINT4 icount, ioffset;
  
  ioffset = 0;
  icount  = 0;
  /* Process up to 9 tokens, stop when the line is exhausted. */
  while (icount<9) 
    {
      stokens[icount] = sigtok( sline_a, &ioffset );
      if (NULL == stokens[icount])
	break;
      else
	icount++;
    }
  
  /* Blank lines are allowed and skipped */
  if (icount == 0) return FALSE;
  
  /* Skip commented lines */
  if (stokens[0][0] == '#') return FALSE;
  
  if ( 0 == strcmp( "APPEND_TO_LOG", stokens[0] ) )
    {
      pConfig_a->lAppendToLog=TRUE;
      return FALSE;
    }
  
  /* See if the line contains the LOG file command */
  if ( 0 == strcmp( "LOG", stokens[0] ) )
    {
      if ( icount < 2 ) return TRUE;
      
      if      ( 0 == strcmp( "BOTH", stokens[1] ) ) 
	{pConfig_a->lLogToFile=TRUE;  pConfig_a->lLogToTerm=TRUE;}
      else if ( 0 == strcmp( "FILE", stokens[1] ) ) 
	{pConfig_a->lLogToFile=TRUE;  pConfig_a->lLogToTerm=FALSE;}
      else if ( 0 == strcmp( "TERM", stokens[1] ) )
	{pConfig_a->lLogToFile=FALSE; pConfig_a->lLogToTerm=TRUE;}
      else if ( 0 == strcmp( "NONE", stokens[1] ) )
	{pConfig_a->lLogToFile=FALSE; pConfig_a->lLogToTerm=FALSE;}
      else
	return TRUE;
      return FALSE;
    }

  if ( 0 == strcmp( "SITE", stokens[0] ) )
    {
      struct site_table *pSite;
      if (icount<5) return TRUE;
      if (pConfig_a->iSiteCount>=KMA_MAX_SITES) return TRUE;

      pSite = &pConfig_a->Sites[pConfig_a->iSiteCount];
      strncpy( pSite->sSiteName, stokens[1], 19 );
      strncpy( pSite->sSiteCode, stokens[2], 19 );
      pSite->fLatitude = atof(stokens[3]);
      pSite->fLongitude = atof(stokens[4]);
      pConfig_a->iSiteCount++;
      return FALSE;
    }
  
  if ( 0 == strcmp( "VERBOSE", stokens[0] ) )
    {
      pConfig_a->lVerbose = TRUE;
      return FALSE;
    }

  /* Unrecognized lines will generate a syntax error */
  return TRUE;
}

/* ===========================================
 * Print string to log and terminal, if desired.
 */
static void Lprintf
( const char *sString_a )
{
  if (CConfig_c.lLogToTerm) fputs( sString_a, stderr );
  if (CConfig_c.lLogToFile)
    {
      fputs( sString_a, CConfig_c.iLogFile );
      fflush( CConfig_c.iLogFile );
    }
}
