/* ***********************************************************************
 * *                                                                     *
 * *  Function to convert an Picture file to an IRIS Image product       *
 * *                                                                     *
 * ***********************************************************************
 * File: utils/in-pipes/PictureToIris.C
 *
 *                         COPYRIGHT (c) 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 input Picture file (JPEG, GIF, TIFF,
 *  PBM(This is PBM, PGM and PPM (Ascii or Raw))
 * and converts it into an IRIS IMAGE product.
 * An IRIS IMAGE product is a iris product_hdr struct followed by a 
 * GIF picture.
 *
 * NOTE: Make sure in the setup utility under Input, that PictureToIris
 * Command line syntax is set to Pathnames.
 *
 *
 * 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 <ctype.h>
#include <unistd.h>

#include "sigtypes.h"
#include "headers.h"
#include "product.h"
#include "user_lib.h"
#include "misc_lib.h"
#include "fileformats_lib.h"

struct command_line
{
  char  sInFile[FILENAME_SIZE];
  char  sInPath[PATHNAME_SIZE];
  char  sOutPath[PATHNAME_SIZE];
};

struct convert_config
{
  UINT1  lLogToFile;
  UINT1  lLogToTerm;
  UINT1  lVerbose;              /* Log more details */
  FILE   *iLogFile;             /* Open file descriptor to log file */
  char   sIngSitename[16];      /* Ingest sitename to use, space padded */
};
struct convert_config CSetup_c;

/* Local function prototypes
 */
static void  ProcessCommandLine (int iArgc, char *sArgv[],
   struct command_line *pCommand_a );
static void  Usage( void );
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);
static void  ConvertPictureToGIF(struct command_line *cmd_a, PICINFO *pinfo_a);
static void  ConvertGIFToIris(struct command_line *cmd_a, PICINFO *pinfo_a);

/* ===============================================================
 * Main program starts here.
 */
int main(int iArgc, char *sArgv[])
{
  struct command_line cmd;
  PICINFO  pinfo;

  setlocale( LC_ALL, "" ) ;

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

  /* Process the setup file,if any.  ** We're using:
  **  /usr/sigmet/config/PictureToIris.conf */
  LoadSetup(&CSetup_c);

  /* Open the logging file, if any */
  if (CSetup_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, "PictureToIris.log" );
    CSetup_c.iLogFile = fopen( sLogPath, "w" );
    if (NULL == CSetup_c.iLogFile)
    {
      fprintf( stderr, "Can not open log file: '%s'\n", sLogPath );
      exit(EXIT_FAILURE);
    }
  }

  /* Starting here we can use the Lprintf function */
  if (CSetup_c.lVerbose)
    Lprintf( "Verbose Logging On.\n");

  /* Now check for missing data in the command line */
  if (cmd.sInPath[0]==0)
  {
    Lprintf("ERROR: missing -ip command line option\n" );
    exit(EXIT_FAILURE);
  }
  if (cmd.sOutPath[0]==0)
  {
    Lprintf("ERROR: missing -op command line option\n" );
    exit(EXIT_FAILURE);
  }

  ConvertPictureToGIF(&cmd, &pinfo);
  ConvertGIFToIris(&cmd, &pinfo);

  exit( EXIT_SUCCESS );
}

static void ConvertPictureToGIF(struct command_line *cmd_a, PICINFO *pinfo_a)
{
  int  ifiletype;
  FILE *fp;

  ifiletype = GetPictureType(cmd_a->sInPath);
  switch(ifiletype) 
  {
    case FILE_FORMAT_TYPE_GIF  :
      ReadGIFFilename(cmd_a->sInPath, pinfo_a);
      break;
#ifdef LINUX 
    case FILE_FORMAT_TYPE_JPEG :
      ReadJPEG(cmd_a->sInPath, pinfo_a);
      break;
    case FILE_FORMAT_TYPE_TIFF :
      ReadTIFF(cmd_a->sInPath, pinfo_a);
      break;
#endif
    case FILE_FORMAT_TYPE_PBM :
      ReadPBM(cmd_a->sInPath, pinfo_a);
      break;
    default:
      Lprintf("ERROR: Unknown picture type\n" );
      exit(EXIT_FAILURE);
  }

  switch(ifiletype) 
  {
#ifdef LINUX 
    case FILE_FORMAT_TYPE_JPEG :
    case FILE_FORMAT_TYPE_TIFF :
#endif
    case FILE_FORMAT_TYPE_PBM :
      /* Remove jpeg ,tiff or pbm file.
      ** Writing converted gif file to sInPath.
      */
      unlink(cmd_a->sInPath);
      fp = fopen(cmd_a->sInPath, "w");
      if (fp)
      {
        WriteGIF(fp, pinfo_a->pic, pinfo_a->w, pinfo_a->h, pinfo_a->Colormap, 256, 2, " ");
        fclose(fp);
      }
      else
      {
        Lprintf("ERROR: Can't open input file. Trying to write GIF from a JPEG/TIFF/PBM\n");
        exit(EXIT_FAILURE);
      }
      break;
  }
}

static void ConvertGIFToIris(struct command_line *cmd_a, PICINFO *pinfo_a)
{
  int    istatus;
  FILE   *fp;
  char   *sptr;
  char   sname[16];
  SINT4  ifilesize = 0;
  char   *pbufr;
  SINT4  ichannel;
  struct product_hdr prod_hdr;
  struct full_time_spec Time;

  /* Setup the product header */
  
  strcpy(sname, "unknown");
  if ((sptr = strrchr(cmd_a->sInPath, '/')) != NULL)
    strncpy(sname, sptr+1, 16);
  else
    strncpy(sname, cmd_a->sInPath, 16);

  sname[15] = '\0';
  if ((sptr = strrchr(sname, '.')) != NULL)
    *sptr = '\0';

  STR_UPPER(sname, 16);
  
  GetTimeFull( &Time, TIME_FLG_GMT );
  HeaderFromScratch( &prod_hdr, &Time, CSetup_c.sIngSitename,
		     CSetup_c.sIngSitename, sname );

  /* Get the size of the gif picture image.  */  
  fp = fopen( cmd_a->sInPath, "r");
  if (fp)
  {
    fseek(fp, 0L, 2);          
    ifilesize = ftell(fp);
    fseek(fp, 0L, 0);
  }
  else
  {
    Lprintf("ERROR: Can't open input file. Trying to get size size\n");
    exit(EXIT_FAILURE);
  }

  istatus = imapopen(cmd_a->sInPath, FALSE, (void**)&pbufr, &ifilesize, &ichannel);
  if (istatus!=SS_NORMAL)
  {
    Lprintf("ERROR: Can't map file to a buffer \n");
    exit(EXIT_FAILURE);
  }

  prod_hdr.pcf.iptype  = PROD_IMAGE;
  prod_hdr.pcf.ixsize  = pinfo_a->w;
  prod_hdr.pcf.iysize  = pinfo_a->h;
  prod_hdr.pcf.izsize  = 1;

  prod_hdr.hdr.ibytes = PRODUCT_HDR_SIZE + ifilesize; 


  fp = fopen(cmd_a->sOutPath, "w");
  if (fp)
  {
    fwrite( &prod_hdr, sizeof(struct product_hdr), 1, fp );
    fwrite( pbufr, ifilesize, 1, fp );
    fclose(fp);
  }
  else
  {
    Lprintf("ERROR: Can't open output file\n");
    exit(EXIT_FAILURE);
  }

  if (CSetup_c.lVerbose)
  {
    char   sLog[200];
    sprintf( sLog, "Wrote %d bytes, \n", prod_hdr.hdr.ibytes);
    Lprintf( sLog);
  }

  istatus = imapclose( pbufr, ifilesize, ichannel );
}

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

  int iArg;
  memset( pCommand_a, 0, sizeof(*pCommand_a) );

  /* 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, "-h", 2 ))
	{
	  Usage();
	}
      else if (0 == strncmp( sArg, "-if:", 4 ))
        {
          strncpy( pCommand_a->sInFile, &sArg[4], FILENAME_SIZE-1 );
        }
      else if (0 == strncmp( sArg, "-ip:", 4 ))
        {
          strncpy( pCommand_a->sInPath, &sArg[4], PATHNAME_SIZE-1 );
        }
      else if (0 == strncmp( sArg, "-op:", 4 ))
        {
          strncpy( pCommand_a->sOutPath, &sArg[4], PATHNAME_SIZE-1 );
        }
    }
  return;
}
/* ==================================================
 */
static void Usage( void )
{
  fprintf( stderr, "Options: -help\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) );
  spacify_ncpy( pCSetup_a->sIngSitename, "UNKNOWN", 16 );

  /* 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, "PictureToIris.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 config 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>
 * SITENAME      <name>
 * 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;


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

  /* See if the line contains the SITENAME command */
  if ( 0 == strcmp( "SITENAME", stokens[0] ) )
    {
      if ( icount < 2 ) return TRUE;
      
      spacify_ncpy( pConfig_a->sIngSitename, stokens[1], 16 );
      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 (CSetup_c.lLogToTerm) fputs( sString_a, stderr );
  if (CSetup_c.lLogToFile)
    {
      fputs( sString_a, CSetup_c.iLogFile );
      fflush( CSetup_c.iLogFile );
    }
}

