/* generates matlab files for oneus or fourus data */
#include "raw_proto.h"
#include "matlab.h"

/* global variables */
struct gvs
{
  int gatewidth;
  int desiredwidth;
  long int ranges;
  long int currentranges;
  long int date_stamp;
  long int curr_date;
}gvs;

/* convert_ao_hrs ***
*/
float convert_ao_hrs(long int aot)
{
  float t;

  t = .1 * (aot % 1000);
  aot /= 1000;
  t += 60. * (aot % 100);
  aot /= 100;
  t += 3600. * aot;
  return t / 3600.;
}

/* dump_ao_proc_hdr *********************************
* INPUT:    ph    the current processed data header *
* PURPOSE:                                          *
* Items in the header are printed                   *
****************************************************/
void dump_ao_proc_hdr(AOProcHeader *ph)
{
    printf("encode: dump_ao_proc_hdr: Processed Data Header:\n");
    printf("pd_rec       : %ld\n",ph->pd_rec);
    printf("mode         : %ld\n",ph->mode);
    printf("date         : %ld\n",ph->date);
    printf("start_time   : %ld\n",ph->start_time);
    printf("stop_time    : %ld\n",ph->stop_time);
    printf("ipp          : %ld\n",ph->ipp);
    printf("gatewidth    : %ld\n",ph->gatewidth);
    printf("ngates       : %ld\n",ph->ngates);
    printf("sd           : %ld\n",ph->sd);
    printf("nave         : %ld\n",ph->nave);
    printf("nbytes       : %ld\n",ph->nbytes);
    printf("size         : %ld\n",ph->size);
    printf("totnbyts     : %ld\n",ph->totnbyts);
    printf("noise        : %.2f\n",ph->noise);
    printf("start_zen    : %.2f\n",ph->start_zen);
    printf("end_zen      : %.2f\n",ph->end_zen);
    printf("start_az     : %.2f\n",ph->start_az);
    printf("end_az       : %.2f\n",ph->end_az);
}

/* FlipBytes *******************************************
* INPUT:    buf    buffer of four byte ints or floats  *
*           hSize  size of buffer                      *
* PURPOSE:                                             *
* reverses byte order from 0,1,2,3 to 3,2,1,0          *
* WARNING: Be very careful with use of this routine    *
* improper use of pointers can lead to chaos           *
*******************************************************/
void FlipBytes(char *buf, long int hSize)
{
    char a,*last_buf;

    for(last_buf = buf + hSize;buf<last_buf;buf += 4)
    {
        a = buf[0]; buf[0] = buf[3]; buf[3] = a;
        a = buf[1]; buf[1] = buf[2]; buf[2] = a;
    }
}

int get_procao_record(int frp, char *buf)
{
    AOProcHeader *ph;
    long int hSize,rstep;
    int flip = 0,err=0;
    char *data;
    
    hSize = sizeof(AOProcHeader);
    data = buf + hSize;

    if(read(frp,buf,hSize) != hSize) err = 1;
    ph = (AOProcHeader *) buf;
    if(ph->size != hSize)
    {
        flip = 1;
        /* need to reverse byte order, mac to mips, or mips to mac */
        FlipBytes(buf,hSize);
        if(ph->size != hSize)
            printf_exit("file_io: get_moms_record: Bad header size %ld\n",ph->size);
    }

    if(!err && (read(frp,data,ph->nbytes) != ph->nbytes)) err = 1;
    if(!err && flip)
        FlipBytes(data,ph->nbytes);

    rstep = ph->nbytes / sizeof(float);
    gvs.gatewidth = ph->gatewidth;
    gvs.currentranges = ph->ngates;
    gvs.curr_date = ph->date;

#if 0 /* def DEBUG_FIO_2 */
    printf("err %d hSize %ld rstep %ld nbytes %ld width %d gatewidth %ld\n",
           err,hSize,rstep,ph->nbytes,gvs.gatewidth,ph->gatewidth);
#endif
#if 0
    dump_ao_proc_hdr(ph);
#endif
  if(gvs.gatewidth == gvs.desiredwidth)
    printf("date: %ld start_time: %ld\n",ph->date,ph->start_time);

    return(err);
}

/* AORecCount *****************************************
* INPUT:    frp    file number of processed data file *
*           recArr array to store record pointers in  *
*           buf    buffer to dump data being read     *
******************************************************/
long int AORecCount(int frp, long int *recArr, char *buf)
{
    long int count = 0;
    int err = 0;
    int g_width;
    float *fHdl;
    
    while(!err && (recArr[count] = tell(frp)) != EOF)
    {
        if(!(err = get_procao_record(frp,buf)) && gvs.gatewidth == gvs.desiredwidth)
        {
          if(!count)
          {
            gvs.ranges = gvs.currentranges;
	    gvs.date_stamp = gvs.curr_date;
          }
          else if(gvs.currentranges > gvs.ranges)
          {
            gvs.ranges = gvs.currentranges;
          }
          count++;
        }
    	if(count==MAX_PROC_RECS)
    		printf_exit("count: limit about to be exceeded %ld\n",count);
    }
    
    return(count);
}

/* argv: 1: filename 2:gatewidth (us) */
void main(int argc, char **argv)
{
  char *buf;                    /* data buffer                           */
  int frp, fwp;                 /* read and write file numbers           */
  int width;                    /* gatewidth to process                  */
  long int recCnt;              /* count of records                      */
  long int rec;                 /* current record index                  */
  long int *recArr;             /* array of record pointers in data file */
  AOProcHeader *ph;             /* pointer to processed data header      */
  float *pdata;                 /* pointer to processed data             */
  char wfile[40];               /* write file name                       */
  char *matname;
  long int nrange, ran, dran, rowsiz, colsiz, fullsiz;
  MatMatrixHeader *mnoise;      float *noise;      char *pnoise = "noise";
  MatMatrixHeader *msig;        float *sig;        char *psig = "sig";
  MatMatrixHeader *mstart_time; float *start_time; char *pstart_time = "start_time";
  MatMatrixHeader *mstart_az;   float *start_az;   char *pstart_az = "start_az";
  MatMatrixHeader *mstart_zen;  float *start_zen;  char *pstart_zen = "start_zen";
  MatMatrixHeader *mend_time;   float *end_time;   char *pend_time = "end_time";
  MatMatrixHeader *mend_az;     float *end_az;     char *pend_az = "end_az";
  MatMatrixHeader *mend_zen;    float *end_zen;    char *pend_zen = "end_zen";
  MatMatrixHeader *mrange;      float *range;      char *prange = "range";

#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 */

  if(argc != 3)
    printf_exit("Syntax: prog filename gatewidth\n",0);
  
  if(sscanf(argv[2],"%d",&width)!=1)
    printf_exit("matlab: main: Incorrect gatewidth specification\n",0);
  
  printf("selected gatewidth: %d\n",width);
  gvs.desiredwidth = width;

  /* open the processed data input file */
  if((frp = open(argv[1],O_RDONLY)) == -1)
  {
    printf("matlab: main: can't open processed data file %s\n",argv[1]);
    exit(-1);
  }
  else
  {
    printf("matlab: main: opening data file %s\n",argv[1]);
  }
  
  /* Initialize arrays */
  buf = (char *) malloc(64000*sizeof(float));
  recArr = (long int *) malloc(MAX_PROC_RECS*sizeof(long int));
  ph = (AOProcHeader *) buf;
  pdata = (float *) (buf + sizeof(AOProcHeader));
  
  /* count records in file, return array of record start locations */
  recCnt = AORecCount(frp, recArr, buf);
  nrange = gvs.ranges;
  
  printf("%ld records found in file\n",recCnt);

  sprintf(wfile,"powr%d.%ld.mat",width,gvs.date_stamp);

#ifdef THINK_C
  if ((fwp = creat(wfile,O_BINARY)) == EOF)
#else /* must be MIPS */
  if ((fwp = creat(wfile,PERMS)) == -1)
#endif /* THINK_C */
    printf_exit("procao: main: Unable to create output file\n",0);

  /* initialize arrays for data to save */
  rowsiz = recCnt*sizeof(float);
  colsiz = nrange*sizeof(float);
  fullsiz = recCnt*nrange*sizeof(float);

  noise = (float *) malloc(rowsiz);
  start_time = (float *) malloc(rowsiz);
  start_az = (float *) malloc(rowsiz);
  start_zen = (float *) malloc(rowsiz);
  end_time = (float *) malloc(rowsiz);
  end_az = (float *) malloc(rowsiz);
  end_zen = (float *) malloc(rowsiz);
  range = (float *) malloc(colsiz);
  sig = (float *) malloc(fullsiz);
  
  if(noise == NULL)
    printf_exit("Unable to allocate memory for noise.\n",0);
  if(start_time == NULL)
    printf_exit("Unable to allocate memory for start_time.\n",0);
  if(start_az == NULL)
    printf_exit("Unable to allocate memory for start_az.\n",0);
  if(start_zen == NULL)
    printf_exit("Unable to allocate memory for start_zen.\n",0);
  if(end_time == NULL)
    printf_exit("Unable to allocate memory for end_time.\n",0);
  if(end_az == NULL)
    printf_exit("Unable to allocate memory for end_az.\n",0);
  if(end_zen == NULL)
    printf_exit("Unable to allocate memory for end_zen.\n",0);
  if(range == NULL)
    printf_exit("Unable to allocate memory for range.\n",0);
  if(sig == NULL)
    printf_exit("Unable to allocate memory for sig.\n",0);
    
  mnoise = (MatMatrixHeader *) malloc(sizeof(MatMatrixHeader));
  mstart_time = (MatMatrixHeader *) malloc(sizeof(MatMatrixHeader));
  mstart_az = (MatMatrixHeader *) malloc(sizeof(MatMatrixHeader));
  mstart_zen = (MatMatrixHeader *) malloc(sizeof(MatMatrixHeader));
  mend_time = (MatMatrixHeader *) malloc(sizeof(MatMatrixHeader));
  mend_az = (MatMatrixHeader *) malloc(sizeof(MatMatrixHeader));
  mend_zen = (MatMatrixHeader *) malloc(sizeof(MatMatrixHeader));
  mrange = (MatMatrixHeader *) malloc(sizeof(MatMatrixHeader));
  msig = (MatMatrixHeader *) malloc(sizeof(MatMatrixHeader));

  mnoise->type = MOPT;
  mnoise->mrows = 1;
  mnoise->ncols = recCnt;
  mnoise->imagf = 0;
  mnoise->namlen = 6;
  
  *mstart_time = *mnoise;
   mstart_time->namlen = 11;
   
  *mstart_az = *mnoise;
   mstart_az->namlen = 9;

  *mstart_zen = *mnoise;
   mstart_zen->namlen = 10;
  
  *mend_time = *mnoise;
   mend_time->namlen = 9;
  
  *mend_az = *mnoise;
   mend_az->namlen = 7;
  
  *mend_zen = *mnoise;
   mend_zen->namlen = 8;
  
  *mrange = *mnoise;
   mrange->ncols = nrange;
   mrange->namlen = 6;
  
  *msig = *mnoise;
   msig->namlen = 4;
   msig->mrows = nrange;
   msig->ncols = recCnt;

  /* get desired processed data record */
  lseek(frp,recArr[0],SEEK_SET);
  get_procao_record(frp,buf);
  /* fix range matrix data using first record */
  for(ran=0;ran<nrange;ran++)
  {
    range[ran] = 0.15 * (ph->sd + (ran-1) * ph->gatewidth);
  }
  printf("First range %f nave %ld\n",range[0],ph->nave);
  
  for(rec=0;rec<recCnt;rec++)
  {
    /* get desired processed data record */
    lseek(frp,recArr[rec],SEEK_SET);
    get_procao_record(frp,buf);

    noise[rec] = ph->noise/ph->nave;
    start_time[rec] = convert_ao_hrs(ph->start_time);
    start_az[rec] = ph->start_az;
    start_zen[rec] = ph->start_zen;
    end_time[rec] = convert_ao_hrs(ph->stop_time);
    end_az[rec] = ph->end_az;
    end_zen[rec] = ph->end_zen;

    dran = rec * nrange;
    for(ran=0;ran<ph->ngates;ran++)
    {
      sig[dran+ran] = pdata[ran] / ph->nave;
    }
  }

  write(fwp,(char *) mnoise, sizeof(MatMatrixHeader));
  write(fwp, pnoise, 6);
  write(fwp,(char *) noise, rowsiz);

  write(fwp,(char *) mstart_time, sizeof(MatMatrixHeader));
  write(fwp, pstart_time, 11);
  write(fwp,(char *) start_time, rowsiz);

  write(fwp,(char *) mstart_az, sizeof(MatMatrixHeader));
  write(fwp, pstart_az, 9);
  write(fwp,(char *) start_az, rowsiz);

  write(fwp,(char *) mstart_zen, sizeof(MatMatrixHeader));
  write(fwp, pstart_zen, 10);
  write(fwp,(char *) start_zen, rowsiz);

  write(fwp,(char *) mend_time, sizeof(MatMatrixHeader));
  write(fwp, pend_time, 9);
  write(fwp,(char *) end_time, rowsiz);

  write(fwp,(char *) mend_az, sizeof(MatMatrixHeader));
  write(fwp, pend_az, 7);
  write(fwp,(char *) end_az, rowsiz);

  write(fwp,(char *) mend_zen, sizeof(MatMatrixHeader));
  write(fwp, pend_zen, 8);
  write(fwp,(char *) end_zen, rowsiz);

  write(fwp,(char *) mrange, sizeof(MatMatrixHeader));
  write(fwp, prange, 6);
  write(fwp,(char *) range, colsiz);

  write(fwp,(char *) msig, sizeof(MatMatrixHeader));
  write(fwp, psig, 4);
  write(fwp,(char *) sig, fullsiz);

  close(frp);
  close(fwp);
}
