/* **************************************************************
 * *                                                            *
 * *  Function to convert a KMA Satellite image to IRIS format  *
 * *                                                            *
 * **************************************************************
 * File: utils/pipes_in/KmaSatToIris.C
 *
 *                  COPYRIGHT (c) 2000, 2001, 2002  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.
 */

/* This program is a pipe which takes an KMA satellite 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 <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

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

/* This holds information to customize the convertor */
struct sat_defs
{
  UINT1 lLogToFile;
  UINT1 lLogToTerm;
  UINT1 lVerbose;
  UINT1 lAppendToLog;
  FILE *iLogFile;
  SINT4 iWidth;          /* Size in pixels */
  SINT4 iHeight;
  FLT8  fWidthKm;        /* Size in km */
  FLT8  fHeightKm;
  struct latlon8 Center;
  char  sSitename[16];   /* space padded */
};

static struct sat_defs CConfig_c;
static char log_str[200];

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

static void Usage( void );

static void ConvertKmaSatToIris
( const char *sFileName_a,
  const struct sat_defs *pDef_a );

static UINT1 FillProductHeader
(struct product_hdr *pPhead_a, 
 const char *sFile_a,            /* Just filename */
 const struct sat_defs *pDefs_a );

static UINT1 GetTimeFromFilename
( struct ymds_time *pTime_a,
  const char *sFile_a );

static void ProcessConfigFile
( struct sat_defs *pDefs_a );

static UINT1 ProcessConfigLine
(char *sLine_a,
 struct sat_defs *pDefs_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 */
  ProcessConfigFile( &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, "KmaSatToIris.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 */

  ConvertKmaSatToIris( sFileName, &CConfig_c );

  exit( EXIT_SUCCESS );
}

/* ======================================================================
 * 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) ;
}

/* ===========================================
 * 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 );
    }
}


/*
  Here are some limitation placed upon the input file:
  1) The file must be metcator projection
  2) The file can have some blank data on the bottom and on the right.
     It has been observed that this is an outcome of converting the
     normal satellite AREA file to a mercator projection.
  3) The data area (after the blanks are stripped) must not exceed
     1100 pixels in either dimention.
*/

/* =======================================================
 * Process the config file.
 */
static void ProcessConfigFile
( struct sat_defs *pDefs_a )
{
  char sPath[PATHNAME_SIZE];
  char sline[81], *sptr;
  FILE* stream;
  SINT4 iline;
  UINT2 lerror;

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

  pDefs_a->iWidth = 940;
  pDefs_a->iHeight = 940;
  pDefs_a->fWidthKm = 1100;
  pDefs_a->fHeightKm = 1100;
  pDefs_a->Center.fLon = (FPI/180.0) * 127.0000;
  pDefs_a->Center.fLat = (FPI/180.0) * 36.6667;

  /* 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, "KmaSatToIris.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, pDefs_a );
      if (lerror) fprintf( stderr, "Syntax error on KmaSatToIris.conf file line %d\n", iline );
      iline +=1;
      sptr = fgets( sline, 81, stream );
    }

  fclose( stream );


  /* Check for required configuration */
  if (!pDefs_a->sSitename[0])
    {
      fprintf( stderr, "Sorry, SITE line required in config file\n" );
      exit(EXIT_FAILURE);
    }
}
/* ====================================================================
 * Process one line of the config file.  Return true if there is a syntax
 * error.
 */
static UINT1 ProcessConfigLine
(char *sLine_a,
 struct sat_defs *pDefs_a )
{
  UINT4 icount, ioffset;
  FLT8 fTemp;
  char *stokens[5], *sptr;

  /* Process up to 5 tokens, stop when the line is exhausted */
  ioffset = 0;
  icount = 0;
  while( icount<5)
    {
      stokens[icount] = sigtok( sLine_a, &ioffset );
      if (NULL == stokens[icount])
	break;
      else
	icount++;
    }

  /* Blank lines are allowed */
  if (icount==0) return FALSE;

  /* Skip comment lines */
  if (stokens[0][0] == '#') return FALSE;
  
  if ( 0 == strcmp( "APPEND_TO_LOG", stokens[0] ) )
    {
      pDefs_a->lAppendToLog=TRUE;
      return FALSE;
    }

  if (0 == strcmp( "CENTER_LAT", stokens[0]) )
    {
      if (icount<2) return TRUE; 
      fTemp = strtod( stokens[1], &sptr );
      if (sptr == stokens[1]) return TRUE;
      if (fTemp>90.0) return TRUE;
      if (fTemp<-90.0) return TRUE;
      pDefs_a->Center.fLat = (FPI/180.0) * fTemp;
      return FALSE;
    }

  if (0 == strcmp( "CENTER_LON", stokens[0]) )
    {
      if (icount<2) return TRUE; 
      fTemp = strtod( stokens[1], &sptr );
      if (sptr == stokens[1]) return TRUE;
      if (fTemp> 180.0) return TRUE;
      if (fTemp<-180.0) return TRUE;
      pDefs_a->Center.fLon = (FPI/180.0) * fTemp;
      return FALSE;
    }

  /* Check for LOG command */
  if ( 0 == strcmp( "LOG", stokens[0] ) )
    {
      if ( icount < 2 ) return TRUE;
      
      if      ( 0 == strcmp( "BOTH", stokens[1] ) ) 
	{pDefs_a->lLogToFile=TRUE;  pDefs_a->lLogToTerm=TRUE;}
      else if ( 0 == strcmp( "FILE", stokens[1] ) ) 
	{pDefs_a->lLogToFile=TRUE;  pDefs_a->lLogToTerm=FALSE;}
      else if ( 0 == strcmp( "TERM", stokens[1] ) )
	{pDefs_a->lLogToFile=FALSE; pDefs_a->lLogToTerm=TRUE;}
      else if ( 0 == strcmp( "NONE", stokens[1] ) )
	{pDefs_a->lLogToFile=FALSE; pDefs_a->lLogToTerm=FALSE;}
      else
	return TRUE;
      return FALSE;
    }

  /* Check for SITE command */
  if (0 == strcmp( "SITE", stokens[0]) )
    {
      char sSitenameNull[20];
      if (icount<2) return TRUE;
      strncpy( sSitenameNull, stokens[1], 20-1 );
      sSitenameNull[20-1] = 0;
      spacify_ncpy( pDefs_a->sSitename, sSitenameNull, 16 );
      return FALSE;
    }

  /* Unrecognized lines will generate a syntax error */
  return TRUE;
}
/* ==================================
 * Process one input file.
 */
static void ConvertKmaSatToIris
(const char *sFile_a,            /* Just filename */
 const struct sat_defs *pDefs_a )
{
  struct product_hdr phdr;
  UINT1  lError;
  SINT4  iY, iDataSize;
  UINT1  *pData;
  char log_str[200];
 
  sprintf(log_str, "Processing input file: %s\n", sFile_a);
  Lprintf(log_str);
  
  lError = FillProductHeader( &phdr, sFile_a, pDefs_a );
  if (lError) return;  /* lError indicates that an error was already reported */

  iDataSize = phdr.pcf.ixsize * phdr.pcf.iysize;
  pData = (UINT1 *)malloc( iDataSize );
  if (!pData)
    {
      Lprintf("Unable to malloc the buffer\n" );
      return;
    }


  /* fopen succeeded */
  for (iY=0; iY<phdr.pcf.iysize; iY++)
    {
      /* SINT4 iX;
       *      for (iX=0; iX<phdr.pcf.ixsize; iX++)
       */
	{
	  int iOffset, iSize;
	  
	  iOffset = ((phdr.pcf.iysize - iY) - 1)*phdr.pcf.ixsize;
	  iSize = fread(&pData[iOffset], 1, phdr.pcf.ixsize, stdin );

	  if (iSize != phdr.pcf.ixsize)
	    {
	      sprintf(log_str, "File read size line %d wrong, got %d, expected %d\n",
		      iY, iSize, phdr.pcf.ixsize );
	      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.
  ****/
  
  sprintf(log_str, "Processing satellite file: %s\n", sFile_a);
  Lprintf(log_str);
  
  /****
       Now we write the data of the user file to disk.
  ****/
  
  fwrite(&phdr, sizeof(struct product_hdr), 1, stdout);
  
  for(iY=0; iY<phdr.pcf.iysize; iY++)
    {
      fwrite(&pData[iY*phdr.pcf.ixsize], 1, phdr.pcf.ixsize, stdout);  
    }
  
  free(pData);
  
}

/* ========================================================
 * Fill in the product header.  Returns non-zero on error.
 */
static UINT1 FillProductHeader
(struct product_hdr *pPhead_a, 
 const char *sFile_a,
 const struct sat_defs *pDefs_a )
{
  UINT1  lError;
  struct ymds_time DataTime;

  if (pDefs_a->iWidth > MAX_PRODUCT_SIZE || pDefs_a->iHeight > MAX_PRODUCT_SIZE)
    {
      sprintf(log_str, "Error - input dimensions too big. (max is %d) Width=%d  Height=%d\n",
	      MAX_PRODUCT_SIZE, pDefs_a->iWidth, pDefs_a->iHeight);
      Lprintf(log_str);
      return TRUE;
    }

  lError = GetTimeFromFilename( &DataTime, sFile_a );
  if (lError) return lError;

  memset( pPhead_a, 0, sizeof(struct product_hdr));
  pPhead_a->hdr.id = ST_PRODUCT_HDR;
  pPhead_a->hdr.ivers = SVER_PRODUCT_HDR_P;
  pPhead_a->hdr.ibytes = sizeof(struct product_hdr);  /* Full size filled in below */
  pPhead_a->hdr.iflags = HD_STRUCTURE_COMPLETE;
  pPhead_a->pcf.hdr.id = ST_PRODUCT_CONF;
  pPhead_a->pcf.hdr.ivers = SVER_PRODUCT_CONF_P;
  pPhead_a->pcf.hdr.ibytes = sizeof (struct product_configuration);
  pPhead_a->pcf.hdr.iflags = HD_STRUCTURE_COMPLETE;
  pPhead_a->pcf.iptype = PROD_USER;
  pPhead_a->pcf.isch = 0;
  pPhead_a->pcf.isch_skip = 0;
  pPhead_a->pcf.ing_time = DataTime;
  pPhead_a->pcf.epoch = DataTime;
  memcpy(pPhead_a->pcf.spname, "Satellite   ", 12); 
  memcpy(pPhead_a->pcf.stname, "Satellite   ", 12); 
  pPhead_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.
  ****/
  pPhead_a->pcf.ixscale = 
    NINT((pDefs_a->fWidthKm / pDefs_a->iWidth) * 1000 * 100);
  pPhead_a->pcf.iyscale = 
    NINT((pDefs_a->fHeightKm / pDefs_a->iHeight) * 1000 * 100);
  pPhead_a->pcf.izscale = 0;
  pPhead_a->pcf.ixsize = pDefs_a->iWidth;
  pPhead_a->pcf.iysize = pDefs_a->iHeight;
  pPhead_a->pcf.izsize = 1;
  pPhead_a->hdr.ibytes = sizeof (struct product_hdr) + (pPhead_a->pcf.ixsize * pPhead_a->pcf.iysize);
  pPhead_a->pcf.ixrad = 0;
  pPhead_a->pcf.iyrad = 0;
  pPhead_a->pcf.izrad = 0;
  pPhead_a->pcf.irange_last_v20 = 0;
  pPhead_a->pcf.idata_out = DB_USER;
  pPhead_a->pcf.idata_in  = DB_USER;
  pPhead_a->pcf.iprojection_type = MAPROJ_MERCATOR;
  pPhead_a->pcf.colors.iflags = (COLOR_SCALE_TOP_SAT | COLOR_SCALE_BOT_SAT);
  pPhead_a->pcf.colors.istart = 300;
  pPhead_a->pcf.colors.istep  = 200;
  pPhead_a->pcf.colors.icolcnt = 12;
  pPhead_a->pcf.colors.iset_and_scale = 0x0202;
  
  memcpy( pPhead_a->end.sprod_sitename, pDefs_a->sSitename, 16);
  strcpy( pPhead_a->end.sprod_version, IRIS_VERSION);
  strcpy( pPhead_a->end.sing_version,  IRIS_VERSION);
  pPhead_a->end.old_ing = DataTime;
  pPhead_a->end.iprf = 500;
  pPhead_a->end.ipw = 100;
  pPhead_a->end.ilambda = 500;
  pPhead_a->end.ipolar  = POL_HORIZ_FIX ;
  memcpy( pPhead_a->end.sing_sitename, pDefs_a->sSitename, 16);
  memcpy( pPhead_a->end.sIngHardwareName, pPhead_a->end.sing_sitename, 16);
  pPhead_a->end.iMinutesWest = 0;
  
  pPhead_a->end.ilon_center = iBin4FromRadian(pDefs_a->Center.fLon);
  pPhead_a->end.ilat_center = iBin4FromRadian(pDefs_a->Center.fLat);
  pPhead_a->end.ilon_ref = iBin4FromRadian(pDefs_a->Center.fLon);
  pPhead_a->end.ilat_ref = iBin4FromRadian(pDefs_a->Center.fLat);
  
  pPhead_a->end.ignd_hgt = 50;
  pPhead_a->end.irad_hgt = 10;

  return FALSE;
  
}

/* ====================================
 * Parses the filename to determine the date and time.
 */
static UINT1 GetTimeFromFilename
( struct ymds_time *pTime_a,
  const char *sFile_a )
{
  int iYear, iMonth, iDay, iHour, iMinute;
  char s1[10];
  struct tm tm_time, tm2_time;
  time_t in_time;
  /* Filename consists of g5.yyyymmdd.hhmm.dat */
  sscanf( sFile_a, "%3s%4d%2d%2d.%2d%2d", s1, &iYear, &iMonth, 
	  &iDay, &iHour, &iMinute);
  /* fprintf( stderr, "Time: %4d %2d %2d: %2d %2d\n", iYear, iMonth, iDay, iHour, iMinute ); */

  tm_time.tm_sec = 0;
  tm_time.tm_min = iMinute;
  tm_time.tm_hour = iHour;
  tm_time.tm_mday = iDay;
  tm_time.tm_mon = iMonth-1;
  tm_time.tm_year = iYear - 1900;
  tm_time.tm_wday = 0;
  tm_time.tm_yday = 0;
  tm_time.tm_isdst = 0;
  in_time = mktime(&tm_time);
  in_time += 18*60*60;  /* Add 18 hours? */
  gmtime_r(&in_time,&tm2_time);

  memset( pTime_a, 0, sizeof(*pTime_a) );
  pTime_a->iyear = tm2_time.tm_year + 1900;
  pTime_a->imon  = tm2_time.tm_mon + 1;
  pTime_a->iday  = tm2_time.tm_mday;
  pTime_a->isec  = iPackTime( tm2_time.tm_hour, tm2_time.tm_min, 0 );
  return FALSE;
}
