/* raw_main.c - main file for raw data processing */

#include "raw_proto.h"

/* main *****************************************************************
* INPUT:    argc    count of inputs on command line                     *
*           argv    array of input strings the name of file with        *
*                   the processing parameters should be specified.      *
*                   mumparms is the original file.  The 'u' specifies   *
*                   that a filename is provided at the end of the file  *
*                   defining the data file/tape from which to read data *
* PURPOSE:                                                              *
* This particular CUPRI program generates 3 moment files on either      *
* Ultrix or MacIntosh Workstations.  At present there is support only   *
* for 8bit data of single pulse (SP), double pulse (DP), Barker coded   *
* single pulse (BKSP), and Barker coded double pulse (BKDP)             *
* The raw data records must have data for 2^n ipps.                     * 
* ORIGIN:                                                               *
* based on code supplied by Wes Swartz, Dave Hysell, John Sahr,         *
* Tim Hall, John Cho, Phil Erikson                                      *
* CHANGES:                                                              *
* 94/04/07  Added Mac Compatibility to routines                         *
*           Changed float pointer for data arrays to ComplexFloat.      *
*           Added InputParm, DateTime and RawHeader structs.            *
* 94/04/11  Finished adding Barker Code routines.                       *
* 94/04/14  Finished adding double pulse routines.                      *
* 94/04/15  Added EOF check ch.h.totnwrds returns -1, files closed nice *
* 94/04/21  Added 2^n fft width input and flexibility to average data   *
*           with 2^i ipps per record where i must be a positive integer *
*           less than 8.  This allows for up to 128 pnt FFT widths.     *
* 94/09/05  Added support for up to 256 pnt FFT widths.                 *
* 94/10/16  Added selection of fftwidth via define in raw_proto.h, also *
*           added support for 2d coherence, ip.pm = 3.                  *
* 94/11/28  added support for spectral width calculations, ip.pm = 4.   *
************************************************************************/
void main(int argc, char **argv)
{
  char spfile[30],dpfile[30];     /* output file moms[mode].[ymd].[hms]   */
  char *buf;                      /* raw data input buffer                */
  char *data, *pdata;             /* pointer to beginning of data in buf  */
  InputParms ip;                  /* input parameters structure           */
  RawHeader ch,fsph,lsph,fdph,ldph, *pfh, *plh;
  /* current,first,last raw record header */
  DateTime irig, harris;          /* irig and harris times                */
  DateTime startdt, stopdt;       /* start and stop processing times      */
  long int start, stop, curr;     /* start,stop,current seconds in yr     */
  long int last_nbaudp;           /* what was nbaudp for last record?     */
  long int spwrec,dpwrec;         /* number of records written to file    */
  ProcHeader ph;                  /* processed data header                */
  float *pmdata;                  /* pointer to mode processed data       */
  ComplexFloat *pvrx;             /* pointer to converted data for ip.rx  */
  ComplexFloat *spspec, *dpspec, *pspec;
  /* complex power spectrum.              */
  ComplexFloat *spcoh, *dpcoh, *pcoh;
  /* complex coherence spectrums.         */
  /* 1 - (rx1 - rx0) gives vertical coh.  */
  /* assumes rx1 is "behind" rx0          */
  /* 2 - (rx0 - rx2) gives horizontal coh */
  /* assumes rx2 is west/south of rx0     */
  float *last_angle;              /* Used in unwrapping coherence phases. */
  ComplexFloat *wi;               /* array of wings for FFT               */
  int *br;                        /* array of bitrevered indeces          */
  int *bk;                        /* barker phase code sequence           */
  int frp,fwsp,fwdp;              /* input/output tape/file               */
  int sprec,dprec;                /* current rec of nrecs to average      */
  int changed;                    /* set to 1 if RawHeader params change. */
  int incr_pdata;                 /* do we increment pdata?               */
  int already_read = 0;           /* have we already read a raw record?   */
  int add_segs = 0;               /* additional segments available        */
  int first_sp =1, first_dp =1;   /* first time at output data loop?      */
  int curr_seg;                   /* current segment in record.  Used to  */
  /* recompute start and stop time of     */
  /* segment within harris raw record.    */
  
  /* allocation of memory */
  buf = (char *) malloc(MAX_CUPRI_BYTES*sizeof(char));
  pvrx = (ComplexFloat *) malloc(MAX_PROC_DATA*sizeof(ComplexFloat));
  spspec = (ComplexFloat *) malloc(MAX_PROC_DATA*sizeof(ComplexFloat));
  dpspec = (ComplexFloat *) malloc(MAX_PROC_DATA*sizeof(ComplexFloat));
  spcoh = (ComplexFloat *) malloc(MAX_PROC_DATA*sizeof(ComplexFloat));
  dpcoh = (ComplexFloat *) malloc(MAX_PROC_DATA*sizeof(ComplexFloat));
  last_angle = (float *) malloc(MAX_PROC_DATA*sizeof(ComplexFloat));
  br = (int *) malloc(MAX_FFT_SIZE*sizeof(int));
  wi = (ComplexFloat *) malloc(MAX_FFT_SIZE*sizeof(ComplexFloat));
  bk = (int *) malloc(MAX_BARKER_SIZE*sizeof(int));
  
  /* initializing variables */
  pdata = data = &buf[CUPRI_VOS_HEADER_SIZE];
  last_nbaudp = 0;
  spwrec = dpwrec = 0;
  already_read = 0;
  curr_seg = 0;
  sprec = dprec = 0;
  pmdata = (float *) pvrx;
  
#ifdef THINK_C
  /* the following call is needed for the Mac to provide an I/O window to input
   * parameters that would normally be entered on the command line in
   * other systems.
   */
  
  argc = ccommand(&argv);
#endif /* THINK_C */
  
  ip = get_input_parms(argv[1]);
  
#ifdef THINK_C
  initialize_graph_window();
#endif /* THINK_C */
  
  /* compute bit reversal and wings for ip.fftwdth */
  bitrev(br, ip.fftwdth);
  wings(wi, ip.fftwdth);
  
#if 1
  printf("raw_main: main: %s, %s, %ld, %ld, %s\n",
	 ip.start_str,ip.end_str,ip.maxrecs,ip.nrecs,ip.file);
#endif
  
  if((frp = open(ip.file,O_RDONLY)) == -1)
    printf_exit("raw_main: main: can't open read file\n",(long int)ip.file);
  
  /* convert input times */
  startdt = get_input_time(ip.start_str);
  stopdt = get_input_time(ip.end_str);
  
  /* convert start and stop times to seconds to use in search
   * and processing loops.
   */
  
  start = seconds(&startdt);
  stop = seconds(&stopdt);
  
#if 1
  printf("start %ld stop %ld\n",start,stop);
#endif

  /* skip first 10 records of tape ignoring timestamps */
  for(curr = 0; curr < 10; curr += 1)
  {
    get_raw_record(frp,buf,data);
  }
  
  /* loop through raw records until arrive at start time */
  printf("raw_main: main: Finding start location.\n");
  curr = 0;
  while(curr<start)
  {
    static long int last_dift = 0;
    long int li_dift;
    
    /* get current time from raw record */
    ch = get_raw_record(frp,buf,data);
    if(ch.h.totnwrds == -1)
      printf_exit("raw_main: main: Record Read Error, EOF detected\n",0);

    harris = decode_harris_time(ch.hdr);
    curr = seconds(&harris);
    
    li_dift = start - curr;
    if(!(li_dift%100) && li_dift != last_dift)
    {
      printf("%ld seconds remaining.\n",li_dift);
      last_dift = li_dift;
    }
  }
  
#if 1
  printf("raw_main: main: already_read status = %d\n",already_read);
  printf_time(&harris,"raw_main: main: Current Harris Time");
  printf("raw_main: main: current: %ld seconds.\n",curr);
  printf_time(&startdt,"raw_main: main: Start Time:");
  printf("raw_main: main: start: %ld seconds.\n",start);
  printf_time(&stopdt,"raw_main: main: Stop Time:");
  printf("raw_main: main: stop: %ld seconds.\n",stop);
#endif
  
  /* Now we can average FFT ip.nrecs times while we have not reached stop. */
  while(curr<stop)
  {
    /* reset averaging loop parameters */
    changed = 0;
    /* if averaged nrecs or if a change occurred then exit loop */
    while(dprec < ip.nrecs && sprec < ip.nrecs && !changed)
    {
      if(!already_read)
      {
	curr_seg = 0;    /* reset segment counter            */
	pdata = data;    /* reset to start of data buffer    */
	
	/* get_raw_data is called since we want to make sure we have
	 * at least a full fft width's worth of data in buffer.
	 * get_raw_data returns -1 on EOF or other error, add_segs
	 * is number of additional segments a record contains.
	 * add_segs will be greater than 0 only if the original nippstw
	 * is greater than fftwdth, eg. when taking 64pnt fft on 128ipp data.
	 */
	if((add_segs = get_raw_data(frp,buf,data,&ip,&ch)) != -1)
	{
	  harris = decode_harris_time(ch.hdr);
	  curr = seconds(&harris);
	  already_read = add_segs;
	}
	else
	{
	  /* should break out of averaging loop and terminate */
	  curr = stop;
	  break;
	}
      }
      
      /* set up pointers to current spectra & headers */
      if(ch.h.tu_tau)
      {
	pfh = &fdph;
	plh = &ldph;
	pspec = dpspec;
	pcoh = dpcoh;
      }
      else
      {
	pfh = &fsph;
	plh = &lsph;
	pspec = spspec;
	pcoh = spcoh;
      }
      
      if(!sprec && !ch.h.tu_tau || !dprec && ch.h.tu_tau)
      {
	*pfh = ch;
	pfh->h.start_seg = curr_seg;
	/*
	 * since first record, zero complex power spectrum array
	 * zero coherence arrays and last_angle arrays.
	 */
	/* are we using all three receivers? */
	if(ip.pm == 3 || ip.pm == 4)
	{
	  zero_array(pspec, 3 * ch.h.tu_ng * ip.fftwdth);
	  zero_array(pcoh, 3 * ch.h.tu_ng * ip.fftwdth);
	  if(ip.pm == 4)
	    zero_array((ComplexFloat *)last_angle,
		       3 * ch.h.tu_ng * ip.fftwdth);
	}
	else
	{
	  zero_array(pspec, ch.h.tu_ng * ip.fftwdth);
	}
	/* compute barker phase sequence if nbaudp changed */
	if(last_nbaudp != ch.h.nbaudp)
	{
	  /* get new barker decode only if data is barker coded. */
	  if(ch.h.nbaudp) barker(ch.h.nbaudp,bk);
	  last_nbaudp = ch.h.nbaudp;
	}
      }
      else changed = (ch.h.tu_tau ?
		      compare_hdrs(&fdph.h,&ch.h)
		      :
		      compare_hdrs(&fsph.h,&ch.h)
		      );
      
      if(!changed)
      {
	/* update last header while not changed */
	*plh = ch;
	plh->h.stop_seg = curr_seg;
	
	if(ch.h.tu_tau)
	  dprec++;
	else
	  sprec++;
	
#ifdef DEBUG_MAIN
	printf("raw_main: main: changed = %d sprec %d dprec %d\n",
	       changed,sprec,dprec);
#endif /* DEBUG_MAIN */
	
	/* Convert the data buffer to floats in time series */
	convert_data(pdata,&ch.h,&ip,pvrx);
	
	/* if additional segments in record, increment to next */
	
#if 0
	printf("raw_main: main: processing segment #%d\n",curr_seg);
#endif
	
	if(add_segs)
	{
	  pdata += ch.h.nchanls * ch.h.tu_ng * ip.fftwdth;
	  add_segs--;
	  curr_seg++;
	}
	else
	{
	  already_read = add_segs;
	}
	
	/* Barker sum range gates for Barker decoding, omit tx and nx. */
	if(ch.h.nbaudp != 0)
	  do_barker(pvrx,&ch.h,&ip,bk);
	
#ifdef DEBUG_TIME_DATA
#include "debug_time_data.h"
#endif
#ifdef DEBUG_RANGE_DATA
#include "debug_range_data.h"
#endif

	/* Take FFT of all data in all rx's of interest */
	df_fft_data(pvrx,&ch.h,&ip,wi,br,1);
	
#ifdef DEBUG_FFT_DATA
#include "debug_fft_data.h"
#endif
	
	/*
	 * Now compute the coherence for all range gates
	 * assume that double pulse will not affect and
	 * do for all range gates.
	 */
	if(ip.pm == 3 || ip.pm == 4)
	  accum_coherence_spectrum(pcoh,pvrx,&ch.h,&ip,last_angle);
	
	/* now find the power spectrum, omit tx and nx in double pulse */
	accum_power_spectrum(pspec,pvrx,&ch.h,&ip);
      }
    }
    
    if(first_sp && !plh->h.tu_tau || first_dp && plh->h.tu_tau)
    {
      /* open output files */
      get_day_in_month(&harris);
      
      if(!plh->h.tu_tau)
      {
	sprintf(spfile,"spmoms%ld.%04ld.%06ld",
		ip.pm,decimal_date(&harris),decimal_time(&harris)/10);
	
#ifdef THINK_C
	if ((fwsp = creat(spfile,O_BINARY)) == EOF)
#else /* must be MIPS */
	if ((fwsp = creat(spfile,PERMS)) == -1)
#endif /* THINK_C */
	  printf_exit("raw_main: main: Unable to open output file\n",0);
	
	first_sp = 0;
      }
      else
      {
	sprintf(dpfile,"dpmoms%ld.%04ld.%06ld",
		ip.pm,decimal_date(&harris),decimal_time(&harris)/10);
	
#ifdef THINK_C
	if ((fwdp = creat(dpfile,O_BINARY)) == EOF)
#else /* must be MIPS */
	if ((fwdp = creat(dpfile,PERMS)) == -1)
#endif /* THINK_C */
	  printf_exit("raw_main: main: Unable to open output file\n",0);
	
	first_dp = 0;
      }
      
      printf("raw_main: main: Generating processed data file %s\n",
	     (!plh->h.tu_tau ? spfile:dpfile));
    }
    
#if 1
    
    if(curr<stop)
      printf("raw_main: main: Writing %s record #%ld, %d recs ave, %ld seconds left.\n",
	     (plh->h.tu_tau ? "dp":"sp"),
	     (plh->h.tu_tau ? dpwrec:spwrec),
	     (plh->h.tu_tau ? dprec:sprec),
	     stop-curr);
#endif
    
    if(changed)
    {
      /* we shouldnt read another record in if we skipped due to change
       * add_segs should have been computed already, no need to recompute
       */
      already_read = 1;
    }
    /* rec has value of # of averages, fh & lh contain info of interest */
    fix_procHdr(pfh,plh,&ph,&ip,
		(plh->h.tu_tau ? dpwrec:spwrec),
		(plh->h.tu_tau ? dprec:sprec));
    if(ph.last_w == -1)
    {
      printf("raw_main: main: NOTICE: Nothing written to output file.\n");
    }
    else if(curr<stop)
    {
      switch(ip.pm)
      {
      case 1:
	compute_moments(&ph,pmdata,pspec);
	break;
      case 2:
	compute_spectra(&ph,pmdata,pspec);
	break;
      case 3:
      case 4:
	compute_coherence(&ph,pmdata,pspec,pcoh);
	break;
      default:
	printf("raw_main: main: switch error, invalid mode!\n");
	exit(-1);
	break;
      }
      
      if(ip.pm >= 1 && ip.pm <= 4)
	/* && ph.tu_ipp < 70) */
      {
	dump_moments(pmdata,(ph.tu_tau ? fwdp:fwsp));
      }
      else
      {
	printf("Data not saved, ipp was greater than 7 ms.\n");
      }

      /* increment processed record count. */
      if(ph.tu_tau)
	dpwrec++;
      else
	spwrec++;
    }
    /* reset rawrecord count of sp/dp counter. */
    if(ph.tu_tau)
      dprec = 0;
    else
      sprec = 0;
  }
  /* make sure you include an EOF indicator for processed data */
  
#if 1
  printf("raw_main: main: Closing input/output data files.\n");
#endif
  
  close(frp);
  close(fwsp);
  close(fwdp);
}
