/* ******************************************************************
 * *                                                                *
 * *  Function to convert an INM file to an IRIS RAW product        *
 * *                                                                *
 * ******************************************************************
 * File: utils/pipes_in/InmToIris.C
 *
 *                        COPYRIGHT (c) 2005 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 input INM polar volume file
 * and converts it into an IRIS RAW product containing that data.
 *
 * 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 "sigtypes.h"
#include "dsp.h"
#include "headers.h"
#include "iris_task.h"
#include "ingest.h"
#include "sigversion.h"
#include "product.h"

#include "misc_lib.h"
#include "user_lib.h"

#define  TRACE_ON (0)

/* This holds information to customize the convertor */
struct command_line
{
  char  sInFile[FILENAME_SIZE];
  char  sInPath[PATHNAME_SIZE];
  char  sOutPath[PATHNAME_SIZE];
  SINT4 iDevice;
};

struct header_info
{
  float lon; 
  float lat;
  float data_slope;
  float data_offset;
  float radar_height;
  float range_size;
  float ele[20];
  int   ele_count;
  int   az_count;
  int   range_count;
  unsigned int isec;
  unsigned short imills;
  unsigned short iyear;
  unsigned short imon;
  unsigned short iday;
  unsigned short s_data[21];
};

struct convert_config
{
  UINT1 lLogToFile;
  UINT1 lLogToTerm;
  UINT1 lVerbose;
  UINT1 lVerbose2;
  UINT1 lAppendToLog;
  char  ipadx[3];
  FILE *iLogFile;
  FILE *iInFile;
};

static struct convert_config CSetup_c;

/* Local function prototypes
 */
static UINT1 BuildIngestHeader
(struct ingest_header *pIHeader_a,
 const struct header_info *pInfo_a );

static void BuildIngestConfig
(struct ingest_configuration *pIngCon_a,
 const struct header_info *pInfo_a );

static UINT1 BuildTaskConfig
(struct task_configuration *pTaskCon_a,
 const struct header_info *pInfo_a );

static UINT1 BuildGparm
(struct gparm *pGparm_a,
 const struct header_info *pInfo_a );

static void ScanAndWrite
( const char *sPathStart_a,        /* Start of pathnames for ingest files */
  const struct ingest_header *pIHeader_a,
  const struct header_info *pInfo_a );

static void OpenNewFiles
( struct ingest_file_state Files_a[NUM_DEFINED_DATA],
  const struct ingest_header *pIHeader_a,  /* Ingest header */
  SINT2  iSweepNumber_a,         /* New IRIS sweep number, origin 1 */
  const struct ymds_time *SweepTimeLocal_a,
  const char *sPathStart_a );    /* Start of pathnames */

static void CloseOldFiles
(struct ingest_file_state Files_a[NUM_DEFINED_DATA]);

static void RemoveIngestFiles
( const struct ingest_header *pIHeader_a,  /* Ingest header */
  const char *sPathStart_a );    /* Start of pathnames */

static void ProcessCommandLine
(int iArgc, 
 char *sArgv[],
 struct command_line *pCommand_a );

static void Usage( void );

static void LoadSetup
( struct convert_config *pCSetup_a,
  const struct command_line *pCommand_a );

static UINT2 ProcessConfigLine
(char *sline_a,
 struct convert_config *pCSetup_a,
 SINT4 iDevice_a );    /* Device number origin 0 of this pipe */

static void Lprintf
( const char *sString_a );

static MESSAGE SignalHandler
(MESSAGE iStatus_a,
 UINT4 iCount_a,
 const UINT4 iSigArgs_a[] );

void extract_radar_data
(int ele_index,
 int az_count,
 int range_count, 
 unsigned char *r_data);

void extrat_header_info
(struct header_info *header_info);

float make_float
(unsigned char *a,
 int index);

static void ConvertINM
(const char *sOutPath_a);

#define MAX_LINELENGTH (120)
/* ===============================================================
 * Main program starts here.
 */
int main(int iArgc, char *sArgv[])
{
  char *sptr;
  struct command_line Command;
  setlocale( LC_ALL, "" ) ;

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

  LoadSetup(&CSetup_c, &Command);

  /* Open the logging file, if any */
  if (CSetup_c.lLogToFile)
    {
      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, "InmToIris.log" );
      if (CSetup_c.lAppendToLog)
	CSetup_c.iLogFile = fopen( sLogPath, "a" );
      else
	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 */
  sig_establish( SignalHandler, "InmToIris" );

  if (CSetup_c.lVerbose) Lprintf( "Verbose Logging On.\n");

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

  /* Open the input file */
  CSetup_c.iInFile = fopen( Command.sInPath, "r" );
  if (NULL == CSetup_c.iInFile)
    {
      char sError[PATHNAME_SIZE+50];
      sprintf( sError, "Can not open input file: '%s'\n", Command.sInPath );
      Lprintf( sError );
      exit(EXIT_FAILURE);
    }

  if (CSetup_c.lVerbose)
    {
      char sString[FILENAME_SIZE+50];
      sprintf( sString, "Processing file: %s\n", Command.sInFile );
      Lprintf( sString );
    }
  ConvertINM(Command.sOutPath);

  fclose(CSetup_c.iInFile);
   
  exit( EXIT_SUCCESS );
}

float make_float(unsigned char *a, int index)
{
  int *b, c, d, e, f, g, exp;
  double exp_val, frac_val, fin_val;

  b = (int *)(a + index);
  c = (*b & 0xffff0000) >> 16;
  d = (*b & 0x00008000) >> 15;
  e = (*b & 0x00007f80) >> 7;
  f = (*b & 0x0000007f);
  g = (f << 16) + c;

  exp = e - 128;
  exp_val = pow (2.0, (double)exp);

  frac_val = (double)g / 0xffffff;
  frac_val += 0.5;
  fin_val = frac_val * exp_val;
  if (d == 1) fin_val *= -1.0;
  if ((d == 0) && (e == 0)) fin_val = 0.0;
  return(fin_val);
}

void extract_header_info(struct header_info *header_info)
{
  unsigned char a[512];
  int i, j, k, *b;
  int read_count;

 i= fread(a, 1, 512, CSetup_c.iInFile);

  header_info->iyear = 2000 + ((a[12] - 0x30) * 10) + (a[13] - 0x30);
  header_info->imon = ((a[14] - 0x30) * 10) + (a[15] - 0x30);
  header_info->iday = ((a[16] - 0x30) * 10) + (a[17] - 0x30);
  header_info->isec = ((a[18] - 0x30) * 36000) + ((a[19] - 0x30) * 3600) +
                      ((a[20] - 0x30) * 600) + ((a[21] - 0x30) * 60) +
                      ((a[22] - 0x30) * 10) + (a[23] - 0x30);
  header_info->imills = 0;
  b = (int *)(a+280);
  header_info->ele_count = *b; 
  b = (int *)(a+364);
  header_info->az_count = *b; 
  b = (int *)(a+368);
  header_info->range_count = *b; 
  header_info->lon = make_float(a, 98);  
  header_info->lat = make_float(a, 102);  
  header_info->data_slope = make_float(a, 151);  
  header_info->data_offset = make_float(a, 155);  
  header_info->radar_height = make_float(a, 188);  
  header_info->range_size = make_float(a, 384);  
  for (i=0;i<20;i++) header_info->ele[i] = make_float(a, (284+(i*4)));  

  for (i=0; i<header_info->ele_count; i++)
  {
    rewind(CSetup_c.iInFile);
    fread(a, 1, 512, CSetup_c.iInFile);
    for (j=0; j<i; j++)
    {
      read_count = (header_info->az_count + 1) * (header_info->range_count + 4);
      for (k=0;k<read_count;k++) fread(a, 1, 1, CSetup_c.iInFile);
      read_count = 512 - (read_count % 512);
      for (k=0;k<read_count;k++) fread(a, 1, 1, CSetup_c.iInFile);
    }
    fread(&(header_info->s_data[i]), 2, 1, CSetup_c.iInFile);
  }
  header_info->s_data[20] = header_info->s_data[19] + 
            (header_info->s_data[19] - header_info->s_data[18]);
}

void extract_radar_data(int ele_index, int az_count, int range_count, 
       unsigned char *r_data)
{
  int i, j, read_count;
  unsigned char a[1];
  
  rewind(CSetup_c.iInFile);
  /* read in and discard header and all elevations of data up to ours */
  for (j=0; j<512; j++) fread(a, 1, 1, CSetup_c.iInFile);
  for (i=0; i<ele_index; i++)
  {
    read_count = (az_count + 1) * (range_count + 4);
    for (j=0;j<read_count;j++) fread(a, 1, 1, CSetup_c.iInFile);
    read_count = 512 - (read_count % 512);
    for (j=0;j<read_count;j++) fread(a, 1, 1, CSetup_c.iInFile);
  }

  /* now read in our data az by az */
  for (i=0; i<az_count+1; i++)
  {
    for (j=0; j<4; j++) fread(a, 1, 1, CSetup_c.iInFile);
    fread((unsigned char  *)(r_data+(range_count * i)), 1, range_count, CSetup_c.iInFile);
  }
}

/* =============================================================
 * Convert the INM data to IRIS.  Exit if there is an error.
 */
static void ConvertINM
(const char *sOutPath_a)
{
  MESSAGE istatus;
  UINT1 lOk;
  struct header_info Info;
  struct ingest_header IHeader;
  UINT1 lSwpMask[MAX_SWEEPS];
  char sStartPath[PATHNAME_SIZE], *sptr;
  struct product_hdr   PHeader;
  char temp_str[64];
  int temp_len;

  if (TRACE_ON) Lprintf( "ConvertINM called.\n" );
  extract_header_info(&Info);

  lOk = BuildIngestHeader(&IHeader, &Info );
  if (!lOk) exit(EXIT_FAILURE);

  memset( &PHeader, 0, PRODUCT_HDR_SIZE );
  PcfFromScratch( &PHeader.pcf, &IHeader.icf.VolumeYmds, "REFLECTIVITY" );
  PHeader.pcf.iptype = PROD_RAW; 
  /* The rest of the product header is filled in below in RawFromIngest */

  sptr = getenv( "IRIS_TEMP" );
  if (NULL == sptr) 
    strcpy( sStartPath, "/tmp/" );
  else
    strncpy( sStartPath, sptr, DIRECTORY_SIZE-1 );
  sStartPath[DIRECTORY_SIZE-1]=0;

  strcat( sStartPath, "InmToIris" );

  strcat( sStartPath, "BCN000000000000");
  temp_len = strlen(sStartPath);
  sprintf(temp_str, "%d", IHeader.icf.VolumeYmds.iyear-2000); 
  memcpy(&sStartPath[temp_len-10-strlen(temp_str)], temp_str, strlen(temp_str)); 
  sprintf(temp_str, "%d", IHeader.icf.VolumeYmds.imon); 
  memcpy(&sStartPath[temp_len-8-strlen(temp_str)], temp_str, strlen(temp_str)); 
  sprintf(temp_str, "%d", IHeader.icf.VolumeYmds.iday); 
  memcpy(&sStartPath[temp_len-6-strlen(temp_str)], temp_str, strlen(temp_str)); 
  sprintf(temp_str, "%d", IHeader.icf.VolumeYmds.isec/3600); 
  memcpy(&sStartPath[temp_len-4-strlen(temp_str)], temp_str, strlen(temp_str)); 
  sprintf(temp_str, "%d", (IHeader.icf.VolumeYmds.isec%3600)/60); 
  memcpy(&sStartPath[temp_len-2-strlen(temp_str)], temp_str, strlen(temp_str)); 
  sprintf(temp_str, "%d", IHeader.icf.VolumeYmds.isec%60); 
  memcpy(&sStartPath[temp_len-strlen(temp_str)], temp_str, strlen(temp_str)); 
  strcat( sStartPath, ".");
  ScanAndWrite( sStartPath, &IHeader, &Info );
  /* Make up a mask of the sweeps to be processed by this run.  This consists
   * either of all sweeps for a complete raw product, or the one matching the
   * ingest time for a sweep-by-sweep raw product.
   */
  memset( lSwpMask, TRUE, MAX_SWEEPS );
  istatus = RawFromIngest( sOutPath_a, sStartPath, &PHeader, &IHeader, lSwpMask,
			   "InmToIris        "/* Product gen site */,
			   0 /*Reference height */ );
  if (istatus!=SS_NORMAL) sig_signal( istatus );
  RemoveIngestFiles( &IHeader, sStartPath );

  return;
}

/* ======================================================================
 * Build the ingest header based on information from the first pass.
 * Returns nonzero if everything is OK to proceed.
 */
static UINT1 BuildIngestHeader
(struct ingest_header *pIHeader_a,
 const struct header_info *pInfo_a )
{
  if (TRACE_ON) Lprintf( "BuildIngestHeader called.\n" );

  memset( pIHeader_a, 0, sizeof(*pIHeader_a) );

  /* Fill in most of the Ingest Header Structure
   */
  pIHeader_a->hdr.id     = ST_INGEST_HDR;
  pIHeader_a->hdr.ivers  = SVER_INGEST_HDR_P;
  pIHeader_a->hdr.ibytes = INGEST_HEADER_SIZE;
  pIHeader_a->hdr.iflags = HD_STRUCTURE_COMPLETE;    /* Full RAW is always 'done' */
      
  /* Fill in the ingest_configuration
   */
  BuildIngestConfig( &pIHeader_a->icf, pInfo_a );
  
  BuildTaskConfig( &pIHeader_a->tcf, pInfo_a );

  BuildGparm( &pIHeader_a->GParm, pInfo_a );

  pIHeader_a->tcf.end.ing_time = pIHeader_a->icf.VolumeYmds;


  return TRUE;
}
/* ================================================================
 * Fills in the ingest configuration structure.
 */
static void BuildIngestConfig
(struct ingest_configuration *pIngCon_a,
 const struct header_info *pInfo_a )
{
  SINT4 iRaysInRev;

  if (TRACE_ON) Lprintf( "BuildIngestConfig called.\n" );

  iRaysInRev = pInfo_a->az_count+1;
  
  pIngCon_a->inrev  = iRaysInRev;    /* # rays in one revolution */
  pIngCon_a->isndx  = 0;             /* First ray's angle expressed as index*/
  pIngCon_a->irtotl = iRaysInRev;    /* total # rays in sweep */
  
  /* Volume scan start date and time
  */
  pIngCon_a->VolumeYmds.iyear = pInfo_a->iyear;
  pIngCon_a->VolumeYmds.imon = pInfo_a->imon;
  pIngCon_a->VolumeYmds.iday = pInfo_a->iday;
  pIngCon_a->VolumeYmds.isec = pInfo_a->isec;
  pIngCon_a->VolumeYmds.imills |= YMDS_FLG_UTC;
  pIngCon_a->iMinutesWest     =  0;
  pIngCon_a->iLocalWest = 0;
    
  pIngCon_a->isweeps_done = 0 ;               /* # of sweeps done */
  pIngCon_a->idfnum    = 0;                   /* # associated data files, and */
  pIngCon_a->idfsize   = 0;                   /* total size of same. */
  pIngCon_a->ib_rayhed = RAY_HSIZE;           /* Ray header size */
  pIngCon_a->ib_task   = TASK_CONFIG_SIZE;    /* Task conf size */
  pIngCon_a->ib_gparm  = DSP_GPARM_SIZE;      /* GPARM size */
  
  pIngCon_a->ib_xhdr   = 0;                   /* We are not making extended headers */
  
  memmove( pIngCon_a->sSitename, "Barcelona       ", 16 );
  memmove( pIngCon_a->sHardwareName, pIngCon_a->sSitename, 16 );
  strncpy( pIngCon_a->siris_version, IRIS_VERSION, 8 );
  pIngCon_a->siris_version[7] = 0;

  pIngCon_a->ilat      = iBin4FromFDeg( pInfo_a->lat);
  pIngCon_a->ilon      = iBin4FromFDeg( pInfo_a->lon );

  pIngCon_a->ialtitude = 100 * NINT(pInfo_a->radar_height*1000);
  pIngCon_a->ignd_hgt  = 0;
  pIngCon_a->irad_hgt  = NINT(pInfo_a->radar_height*1000);
      
  pIngCon_a->inu_vel[0] = 0;
  pIngCon_a->inu_vel[1] = 0;
  pIngCon_a->inu_vel[2] = 0;
  pIngCon_a->inu_offset[0] = 0;
  pIngCon_a->inu_offset[1] = 0;
  pIngCon_a->inu_offset[2] = 0;
  memcpy( pIngCon_a->sLocalTZName, "UTC     ", TZNAME_SIZE );
  return;
}
/* ================================================================
 * Fills in the task configuration structure.
 */
static UINT1 BuildTaskConfig
(struct task_configuration *pTaskCon_a,
 const struct header_info *pInfo_a )
{
  SINT4 iSweep;
  if (TRACE_ON) Lprintf( "BuildTaskConfig called.\n" );

  /* Header */
  pTaskCon_a->hdr.id     = ST_TASK_CONF;
  pTaskCon_a->hdr.ivers  = SVER_TASK_CONF_P;
  pTaskCon_a->hdr.ibytes = TASK_CONFIG_SIZE;

  pTaskCon_a->dsp.imajor_mode = PMODE_PPP;     /* Just a guess */
  pTaskCon_a->dsp.DataMask.iWord0 = 1<<DB_DBZ; 
  pTaskCon_a->dsp.iprf = 1000;                 /* Default if no PRT supplied */

  pTaskCon_a->dsp.ipw = 100;
  /* We will revisit this after we get the wavelength processed */
  pTaskCon_a->dsp.itrig = PRF_FIXED;
  pTaskCon_a->dsp.isamp = 32;

  /* Calibration info */
  pTaskCon_a->cal.iz_calib = (-40 * 16);

  /* range info */
  pTaskCon_a->rng.ibin_first    = 0;
  pTaskCon_a->rng.ibin_in_num   = pInfo_a->range_count;
  pTaskCon_a->rng.ibin_out_num  = pInfo_a->range_count;
  pTaskCon_a->rng.ibin_in_step  = NINT(pInfo_a->range_size *
                                  1000.0 * 100.0);
  pTaskCon_a->rng.ibin_out_step = NINT(pInfo_a->range_size *
                                  1000.0 * 100.0);
  pTaskCon_a->rng.ibin_last     = NINT((float)(pInfo_a->range_count) *
                                  pInfo_a->range_size * 1000.0 * 100.0);

  /* scan info */
  pTaskCon_a->scan.isweeps = pInfo_a->ele_count;
  pTaskCon_a->scan.ires1000 = NINT(1000.*(pInfo_a->az_count+1));
  pTaskCon_a->scan.iscan = TASK_SCAN_CONT;
  for (iSweep=0; iSweep<pInfo_a->ele_count; iSweep++)
  {
    pTaskCon_a->scan.u.ppi.iellst[iSweep] = 
    iBin2FromFDeg(pInfo_a->ele[iSweep]);
  }

  /* misc info */
  pTaskCon_a->misc.ilambda = 535;
  pTaskCon_a->misc.ipolar = POL_HORIZ_FIX;

  /* Height truncation is assumed off, set to the maximum range */
  pTaskCon_a->misc.itrunc = pTaskCon_a->rng.ibin_last;
  pTaskCon_a->misc.iHorzBeamWidth = iBin4FromFDeg( 1.0 );
  pTaskCon_a->misc.iVertBeamWidth = iBin4FromFDeg( 1.0 );

  /* end info */
  spacify_ncpy( pTaskCon_a->end.stname, "REFLECTIVITY", 12 );

  return TRUE;
}
/* ================================================================
 * Fills in the gparm structure.
 */
static UINT1 BuildGparm
(struct gparm *pGparm_a,
 const struct header_info *pInfo_a )
{
  /* Calibration info */
  pGparm_a->iz_calib = (-40 * 16);

  return TRUE;
}

struct ingest_file_state
{
  struct ingest_data_header *pIDH;
  UINT4                     *pTable;
  UINT1                     *pData;
  SINT4 iSize;
  SINT4 iChannel;
  SINT4 iDataUsed;
  UINT1 iMapTable[65536];
  UINT1 lMapTableFilled;
};
/* =====================================================================
 * Scan through the data and write it to the IRIS product.
 */
static void ScanAndWrite
( const char *sPathStart_a,        /* Start of pathnames for ingest files */
  const struct ingest_header *pIHeader_a,
  const struct header_info *pInfo_a )
{
  SINT4  iRayCount, iSweep;
  struct ingest_file_state Files[NUM_DEFINED_DATA];
  struct ymds_time SweepTime;
  struct ingest_file_state *pFile;
  struct ray_header RayHeader;
  struct data_ray Ray;
  float data_val, ray_mult;
  unsigned char *r_data;
  int iAz, iRaySize, iRange;
  float time1, time2, time3, time4;

  memset( Files, 0, sizeof(struct ingest_file_state));
  /* Loop reading in mandatory headers, and processing the results */
  iRayCount=0;
  iSweep = 0;
  for (iSweep=0;iSweep<pInfo_a->ele_count;iSweep++)
  {
    if (iSweep != 0) CloseOldFiles( Files );
    r_data = (unsigned char  *)malloc((pInfo_a->az_count+1) * pInfo_a->range_count);
    if (r_data <= 0) printf("malloc failed!\n");
    extract_radar_data(iSweep, pInfo_a->az_count, pInfo_a->range_count, r_data);
      
    ray_mult = 360.0 / (float)(pInfo_a->az_count + 1);
    SweepTime.iyear = pInfo_a->iyear;
    SweepTime.imon = pInfo_a->imon;
    SweepTime.iday = pInfo_a->iday;
    SweepTime.isec = pInfo_a->isec;
    SweepTime.imills = pInfo_a->imills;
    ymds_add_seconds( (pInfo_a->s_data[iSweep] / 10), &SweepTime );
    OpenNewFiles( Files, pIHeader_a, iSweep, &SweepTime, sPathStart_a );
    pFile = &Files[DB_DBZ];

    for (iAz = 0; iAz < pInfo_a->az_count+1; iAz++)
    {
      RayHeader.ibincount = pInfo_a->range_count;
      RayHeader.iaz_start = iBin2FromFDeg((ray_mult * (float)iAz) - (ray_mult / 2.0));
      RayHeader.iaz_end   = iBin2FromFDeg((ray_mult * (float)iAz) + (ray_mult / 2.0));
      RayHeader.iel_start = iBin2FromFDeg(pInfo_a->ele[iSweep]);
      RayHeader.iel_end   = iBin2FromFDeg(pInfo_a->ele[iSweep]);
      time1 = (float)(pInfo_a->s_data[iSweep+1] - pInfo_a->s_data[iSweep]);
      time2 = (float)iAz / (float)(pInfo_a->az_count+1);
      time3 = time1 * time2;
      time4 = time3 / 10.0;
      RayHeader.itime = (unsigned short)(NINT(time4));

      Ray.hdr = RayHeader;
      iRaySize = RayHeader.ibincount + sizeof(RayHeader);
      if (iRaySize&1) iRaySize++;

      for (iRange=0; iRange<=pInfo_a->range_count; iRange++)
      {
        data_val = ((float)(r_data[(iAz * pInfo_a->range_count) + iRange])*
              pInfo_a->data_slope) +
              pInfo_a->data_offset; 
        Ray.data.iData1[iRange] = NINT((data_val + 32.0) * 2.0); 
      }

      pFile->pTable[iAz] = pFile->iDataUsed+1;
      memcpy(&pFile->pData[pFile->iDataUsed], &Ray, iRaySize);
      pFile->iDataUsed += iRaySize;
      pFile->pIDH->iwritn++;
    }
  }

  /* Process to get last sweeps information */
  CloseOldFiles( Files );

  return;

}
/* ======================================================
 * Open all the sweep mapped files.
 */
static void OpenNewFiles
( struct ingest_file_state Files_a[NUM_DEFINED_DATA],
  const struct ingest_header *pIHeader_a,  /* Ingest header */
  SINT2  iSweepNumber_a,      /* New IRIS sweep number, origin 1 */
  const struct ymds_time *pSweepTimeLocal_a,
  const char *sPathStart_a )  /* Start of pathnames */
{
  SINT4 iFileSize, iRaySize;
  struct ingest_file_state *pFile;
  MESSAGE istatus;
  char sPath[PATHNAME_SIZE];
  iRaySize   = sizeof(struct ray_header) + pIHeader_a->tcf.rng.ibin_out_num;
  if (iRaySize&1) iRaySize++;
  iFileSize  = INGEST_DATA_HEADER_SIZE;
  iFileSize += 4*pIHeader_a->icf.irtotl;
  iFileSize += ((SINT4)pIHeader_a->icf.irtotl) * iRaySize;
  pFile = &Files_a[DB_DBZ];
  strcpy( sPath, sPathStart_a );
  strcat( sPath, sIngestEnd( DB_DBZ, iSweepNumber_a+1 ) );
  istatus = imapcreate( sPath, iFileSize, (void **)&pFile->pIDH, &pFile->iSize, 
		      &pFile->iChannel );
  if (istatus!= SS_NORMAL) sig_signal( istatus );
  pFile->pTable = (UINT4 *)(pFile->pIDH+1);
  pFile->pData  = (UINT1 *)(pFile->pTable+pIHeader_a->icf.irtotl);
  pFile->iDataUsed = 0;
  memset( pFile->pIDH, 0, sizeof(*pFile->pIDH) );
  memset( pFile->pData, 0, 4*pIHeader_a->icf.irtotl );

  pFile->pIDH->hdr.id     = ST_INGEST_DATA;
  pFile->pIDH->hdr.ivers  = SVER_INGEST_DATA_P;
  pFile->pIDH->hdr.ibytes = INGEST_DATA_HEADER_SIZE;
  pFile->pIDH->hdr.iflags = HD_STRUCTURE_COMPLETE;   
  pFile->pIDH->time       = *pSweepTimeLocal_a;
  pFile->pIDH->isweep     = iSweepNumber_a+1;
  pFile->pIDH->inrev      = pIHeader_a->icf.inrev;
  pFile->pIDH->isndx      = pIHeader_a->icf.isndx;
  pFile->pIDH->irtotl     = pIHeader_a->icf.irtotl;
  pFile->pIDH->iwritn     = 0;
  pFile->pIDH->iangle     = pIHeader_a->tcf.scan.u.ppi.iellst[iSweepNumber_a];
  pFile->pIDH->ibits_bin  = 8;
  pFile->pIDH->idata      = DB_DBZ;
  return;

}
/* ======================================================
 * Close all the old mapped files.
 */
static void CloseOldFiles
(struct ingest_file_state Files_a[NUM_DEFINED_DATA] )
{
  struct ingest_file_state *pFile;
  MESSAGE istatus;
  pFile = &Files_a[DB_DBZ];
  pFile->pIDH->hdr.ibytes = INGEST_DATA_HEADER_SIZE + 
    (4*(SINT4)pFile->pIDH->irtotl) + pFile->iDataUsed;
  istatus = imapclose( pFile->pIDH, pFile->iSize, pFile->iChannel );
  if (istatus!= SS_NORMAL) sig_signal( istatus );
  pFile->pIDH = NULL;
  return;
}
/* ======================================================
 * Remove all the ingest sweep files.
 */
static void RemoveIngestFiles
( const struct ingest_header *pIHeader_a,  /* Ingest header */
  const char *sPathStart_a )  /* Start of pathnames */
{
  SINT2 iSweepNumber;
  char sPath[PATHNAME_SIZE];
  int ierror;

  for (iSweepNumber=1; iSweepNumber<=pIHeader_a->tcf.scan.isweeps; iSweepNumber++)
  {
    strcpy( sPath, sPathStart_a );
    strcat( sPath, sIngestEnd( DB_DBZ, iSweepNumber ) );
    ierror = remove( sPath );
    if (ierror!=0) perror("remove");
  }
  return;
}

/* ======================================================================
 * 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, "InmToIris options:\n" );
  fprintf( stderr, "  -device:#  -- Specify origin 0 device number\n" );
  fprintf( stderr, "  -help      -- Print this list\n" );
  fprintf( stderr, "  -if:<file> -- Specify input filename\n" );
  fprintf( stderr, "  -ip:<path> -- Specify input pathname\n" );
  fprintf( stderr, "  -op:<path> -- Specify output pathname\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,
  const struct command_line *pCommand_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, "InmToIris.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, pCommand_a->iDevice );
      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.
 *
 * All blank lines and lines beginning with "#" are ignored. 
 * You cannot log to Lprintf() inside this function.
 *
 */
static UINT2 ProcessConfigLine
(char *sline_a,
 struct convert_config *pConfig_a,
 SINT4 iDevice_a )    /* Device number origin 0 of this pipe */
{
  char *stokens[9+1];
  UINT4 icount, ioffset;
  
  ioffset = 0;
  icount  = 0;
  /* Process up to 9 tokens, stop when the line is exhausted. */
  while (icount<(9+1)) 
    {
      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( "VERBOSE", stokens[0] ) )
    {
      pConfig_a->lVerbose = TRUE;
      return FALSE;
    }

  if ( 0 == strcmp( "VERBOSE2", stokens[0] ) )
    {
      pConfig_a->lVerbose2 = 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 )
{
  struct full_time_spec Time;
  char sTimeBuf[TIMENAME_SIZE];
  GetTimeFull( &Time, TIME_FLG_LOCAL );

  if (CSetup_c.lLogToTerm)
    {
      shhmmssddmonyyyy_r( &Time.Ymds, sTimeBuf );
      fprintf( stderr, "%s %s:", sTimeBuf, Time.sRecordTZName );
      fputs( sString_a, stderr );
    }

  if (CSetup_c.lLogToFile)
    {
      shhmmssddmonyyyy_r( &Time.Ymds, sTimeBuf );
      fprintf( CSetup_c.iLogFile, "%s %s:", sTimeBuf, Time.sRecordTZName );
      fputs( sString_a, CSetup_c.iLogFile );
      fflush( CSetup_c.iLogFile );
    }
}
/* ======================================================================
 * Function to print signaled errors to the loging file or terminal.
 */
static MESSAGE SignalHandler
(MESSAGE iStatus_a,
 UINT4 iCount_a,
 const UINT4 iSigArgs_a[] )
{
  char sMessage[170];

  strncpy( sMessage, message_to_text( iStatus_a, iCount_a, iSigArgs_a ), 165 );
  sMessage[165]=0;
  strcat( sMessage, "\n" );

  Lprintf( sMessage );
  return(SS_NORMAL);
}
