#include "raw_proto.h"

/* compare_hdrs *****************************************************
* INPUT:    fh  pointer to first header record of current averaging *
*           ch  pointer to current header record.                   *
* RETURNS:  0   if no change was detected.                          *
*           1   if a change was detected.                           *
* PURPOSE:                                                          *
* determine if a change has taken place in header that warrants     *
* restarting averaging sequence.                                    *
********************************************************************/
int compare_hdrs(HarrisHeader *fh, HarrisHeader *ch)
{
    /****************************************
    * parameters in HarrisHeader to compare *
    * tu_nippsf, tu_ipp, tu_pw, tu_ng,      *
    * tu_sd, tu_tau, nippstw, nbaud,        *
    * n_tx_smp, n_nx_smp, nwords            *
    ****************************************/

    if(fh->tu_nippsf != 1)
        printf_exit("rawao_main: compare_hdrs: Can't handle %ld ipps per frame\n",
            fh->tu_nippsf);
    if(ch->tu_nippsf != 1)
        printf_exit("rawao_main: compare_hdrs: Can't handle %ld ipps per frame\n",
            ch->tu_nippsf);
    
    if(ch->tu_ipp != fh->tu_ipp) return(1);      /* did the ipp changed?         */
    if(ch->tu_pw != fh->tu_pw) return(1);        /* did the pulse width changed? */
    if(ch->tu_ng != fh->tu_ng) return(1);        /* did total gates change?      */
    if(ch->tu_sd != fh->tu_sd) return(1);        /* did sample delay change?     */
    if(ch->tu_tau != fh->tu_tau) return(1);      /* did double pulse change?     */
    if(ch->nippstw != fh->nippstw) return(1);    /* did # ipps saved change?     */
    if(ch->nbaudp != fh->nbaudp) return(1);      /* did barker code change?      */
    if(ch->n_tx_smp != fh->n_tx_smp) return(1);  /* did transmitter smps change? */
    if(ch->n_nx_smp != fh->n_nx_smp) return(1);  /* did noise smps change?       */
    if(ch->nwords != fh->nwords) return(1);      /* did total data words change? */

    return(0);
}

/* dump_ao_moments ******************************************
* INPUT:    pmdata    pointer to processed data buffer      *
*           fwp       file descriptor for output file       *
* PURPOSE:                                                  *
* provide a mean to write out a record of processed data    *
* each record should contain its own processed data header  *
************************************************************/
void dump_ao_moments(char *pmdata, int fwp)
{
    AOProcHeader *ph;
    
    ph = (AOProcHeader *) pmdata;

#ifdef DEBUG_FIO
    printf("file_io: dump_ao_moments: writing %ld bytes.\n",ph->totnbyts);
#endif /* DEBUG_FIO */

    write(fwp,pmdata,ph->totnbyts);
}

/* dump_moments *********************************************
* INPUT:    pmdata    pointer to data buffer                *
*           fwp        file descriptor for output file      *
* PURPOSE:                                                  *
* provide a mean to write out a record of processed data    *
* each record should contain its own processed data header  *
************************************************************/
void dump_moments(float *pmdata, int fwp)
{
    ProcHeader *ph;
    char *pc;
    
    ph = (ProcHeader *) pmdata;
    pc = (char *) pmdata;

#ifdef DEBUG_FIO
    printf("file_io: dump_moments: writing %ld bytes.\n",ph->totnbyts);
#endif /* DEBUG_FIO */

    write(fwp,pc,ph->totnbyts);
}

/* get_ao_input_parms ************************************************
* INPUT:    file         file for reading input parameters           *
* RETURNS:  AOInputParms a structure containing the input parameters *
*********************************************************************/
AOInputParms get_ao_input_parms(char *file)
{
    AOInputParms ip;
    int i;
    FILE *fp;
    char line[80];

    if((fp = fopen(file,"r")) == NULL)
        printf_exit("file_io.c: get_input_parms: Unable to open file %ld\n",(long int)fp);
    
    /* get start time string */
    fgets(line,80,fp);
    if(fgets(line,80,fp) == NULL)
        printf_exit("file_io.c: get_input_parms: Unable to get start time %ld\n",0L);
    strncpy(ip.start_str,line,30);
    
    /* get end time string */
    fgets(line,80,fp);
    if(fgets(line,80,fp) == NULL)
        printf_exit("file_io.c: get_input_parms: Unable to get end time %ld\n",1L);
    strncpy(ip.end_str,line,30);
    
    fgets(line,80,fp);
    if(fgets(line,80,fp) == NULL)
        printf_exit("file_io.c: get_input_parms: Unable to read parameter %ld\n",
                    (long int)(i+1));

    sscanf(line,"%ld",&ip.pm);

    if(file[1] == 'u')
    {
        fgets (line,80,fp);
        if(fgets(line,80,fp) == NULL)
            printf_exit("file_io.c: get_input_parms: Unable to read datafile name\n",0L);

        if(sscanf (line,"%s",ip.file) != 1)
            printf_exit("file_io.c: get_input_parms: Unable to decipher datafile name\n",
                0L);
    }
    fclose(fp);
    return(ip);
}

/* get_input_parms **************************************************
* INPUT:    file        file for reading input parameters           *
* RETURNS:  InputParms  a structure containing the input parameters *
********************************************************************/
InputParms get_input_parms(char *file)
{
    InputParms ip;
    int i;
    FILE *fp;
    char line[80];
    long int *pin;

    if((fp = fopen(file,"r")) == NULL)
        printf_exit("file_io.c: get_input_parms: Unable to open file %ld\n",(long int)fp);
    
    /* get start time string */
    fgets(line,80,fp);
    if(fgets(line,80,fp) == NULL)
        printf_exit("file_io.c: get_input_parms: Unable to get start time %ld\n",0L);
    strncpy(ip.start_str,line,30);
    
    /* get end time string */
    fgets(line,80,fp);
    if(fgets(line,80,fp) == NULL)
        printf_exit("file_io.c: get_input_parms: Unable to get end time %ld\n",1L);
    strncpy(ip.end_str,line,30);
    
    pin = &ip.maxrecs;
    for(i=2;i<NUMBER_OF_INPUT_PARMS;i++)
    {
        fgets(line,80,fp);
        if(fgets(line,80,fp) == NULL)
            printf_exit("file_io.c: get_input_parms: Unable to read parameter %ld\n",
                (long int)(i+1));

        sscanf(line,"%ld",pin++);

#ifdef DEBUG_FIO
        printf("file_io: get_input_parms: %ld line %s\n",*(pin-1),line);
#endif /* DEBUG_FIO */
    }
    
    if(file[1] == 'u')
    {
        fgets (line,80,fp);
        if(fgets(line,80,fp) == NULL)
            printf_exit("file_io.c: get_input_parms: Unable to read datafile name\n",0L);

        if(sscanf (line,"%s",ip.file) != 1)
            printf_exit("file_io.c: get_input_parms: Unable to decipher datafile name\n",
                0L);
    }
    fclose(fp);

    /* FFT width must be a multiple of 2, not greater than MAX_FFT_SIZE.
     * The default value is 64.
     * if read value is not a multiple of 2 or 0 then default is chosen.
     */

    if(frexp((double)ip.fftwdth,&i) / .5 != 1.0 || ip.fftwdth > MAX_FFT_SIZE)
    {
        ip.fftwdth = 64;
    }

#ifdef DEBUG_FIO
    printf("file_io: get_input_parms: Desired fft width is %ld\n",ip.fftwdth);
#endif /* DEBUG_FIO */

    return(ip);
}

/* get_raw_data *****************************************************************
* INPUT:    frp         file descriptor of data file                            *
*           buf         character buffer start address to dump header           *
*           data        character buffer start address to dump data in record   *
* RETURNS:  long int    count of how many extra fftwdth of data are in record.  *
*                       if -1 then an error occurred in reading data EOF likely *
*                       if  0 then it read one record and matched to fftwdth    *
*                       if >0 then it has that many wdths to add to average     *
* PURPOSE:                                                                      *
* generic interface between get_raw_record routine and data processing routine. *
* returning at least the minimum amount of data requested by fftwdth or a       *
* multiple of fftwdth.  Allows for division of records and for the joining of   *
* several records into a larger record to allow for full FFT widths of 128 pnts *
********************************************************************************/
long int get_raw_data(int frp, char *buf, char *data, InputParms *ip, RawHeader *ch)
{
    RawHeader tmpHdr;
    static char *tmpbuf, *tmpdata;
    static int first_time = 1;
    int done = 0, changed = 0;
    long int data_size, hmmrtr;
    char *ao,*ai,*ao_last;
    
    if(first_time)
    {
        /* allocate temporary space */
        tmpbuf = (char *) malloc(MAX_CUPRI_BYTES*sizeof(char));
        tmpdata = &tmpbuf[CUPRI_VOS_HEADER_SIZE];
        first_time = 0;
    }
    
    while(!done)
    {
        /* get first raw record */
        if(!changed)
        {
            *ch = get_raw_record(frp,buf,data);
        }
        else /* raw record mode changed, have to start over */
        {
            *ch = tmpHdr;
            ao_last = tmpbuf + VOS_WORD_SIZE * ch->h.totnwrds;
            for(ao = tmpbuf,ai = buf;ao < ao_last;*ai++ = *ao++);
            changed = 0;
        }
        
        /* exit if EOF or other error occurred */
        if(ch->h.totnwrds == -1) return(ch->h.totnwrds);
        
        /* if fft width does not exceed nippstw then we can return. */
        if(ch->h.nippstw >= ip->fftwdth)
            return(ch->h.nippstw / ip->fftwdth - 1);
        
        /* how many records to read until fft width is achieved counting first. */
        hmmrtr = ip->fftwdth / ch->h.nippstw;
        
        data_size = ch->h.nwords * VOS_WORD_SIZE;
        ai = data + data_size;
        while(--hmmrtr)
        {
            /* read next record */
            tmpHdr = get_raw_record(frp,tmpbuf,tmpdata);
            if((changed = compare_hdrs(&tmpHdr.h,&ch->h)) != 0)
            {
                /* record type changed break from loop and start over */
                break;
            }
            /* append new data to data buffer */
            ao_last = tmpdata + data_size;
            for(ao = tmpdata;ao < ao_last;*ai++ = *ao++);
        }
        if(!changed) return(hmmrtr);
    }
}

/* get_rawao_record *************************************************************
* INPUT:    frp          file descriptor of data file                           *
*           buf          character buffer start address to dump header          *
*           data         character buffer start address to dump data in record  *
* RETURNS:  RawHeader    a raw record header decoded from buf.                  *
********************************************************************************/
RawAOHeader get_rawao_record(int frp, char *buf, char *data)
{
    long int tmp,hs;
    RawAOHeader ah;
    
    hs = CUPRI_VOS_HEADER_SIZE;

#ifdef THINK_C
    /* since on disk, read the header portion first
     * VOS INTEGERs are 3 bytes long
     * CUPRI records have header of 112 VOS INTEGERs
     * We are reading from a data file on disk
     * so need to read a section at a time. 
     */
    
    if((tmp = read(frp,buf,hs)) != hs)
    {
        printf("file_io: get_rawao_record: Trouble reading header: %ld.\n",tmp);
        ah.h.nwords2 = -1;
        return(ah);
    }
    
    ah = convert_ao_header(buf);

    /* now read the data in the record
     * ch.h.nwords contains the # of words of data to read
     * since the data is 8bits long there is no need to convert it.
     */
    
    tmp = VOS_WORD_SIZE * ah.h.nwords2 - hs;

#ifdef DEBUG_FIO
    printf("file_io: get_rawao_record: reading: %ld bytes = %ld VOS words\n",
        tmp,tmp / VOS_WORD_SIZE);
#endif /* DEBUG_FIO */

    if((hs = read(frp,data,tmp)) != tmp)
    {
        printf("file_io: get_rawao_record: Error: read: %ld bytes out of %ld\n",
            hs,tmp);
        ah.h.nwords2 = -1;
        return(ah);
    }

#ifdef DEBUG_FIO
    printf("file_io: get_rawao_record: read: %ld bytes\n",tmp);
#endif /* DEBUG_FIO */

#else /* THINK_C not defined : Assume on mips machine */
    
    /* We are reading from a data file on tape
     * so need to read the entire record at once 
     */
    tmp = MAX_CUPRI_BYTES;
    if((tmp = read(frp,buf,tmp)) < hs)
    {
        printf("file_io: get_rawao_record: Having trouble reading raw record %ld.\n",tmp);
        ah.h.nwords2 = -1;
        return(ah);
    }

    ah = convert_ao_header(buf);
    /* for the Unix machines, if you need to do something other than
     * a simple 8-bit unpacking then call the routines here, and make
     * sure data is defined in the routine that calls this one.
     */
    
#endif /* THINK_C */

    return(ah);
}

/* get_raw_record ***************************************************************
* INPUT:    frp          file descriptor of data file                           *
*           buf          character buffer start address to dump header          *
*           data         character buffer start address to dump data in record  *
* RETURNS:  RawHeader    a raw record header decoded from buf.                  *
********************************************************************************/
RawHeader get_raw_record(int frp, char *buf, char *data)
{
    long int tmp,hs;
    RawHeader ch;
    
    hs = CUPRI_VOS_HEADER_SIZE;

#ifdef THINK_C
    /* since on disk, read the header portion first
     * VOS INTEGERs are 3 bytes long
     * CUPRI records have header of 112 VOS INTEGERs
     * We are reading from a data file on disk
     * so need to read a section at a time. 
     */
    
    if((tmp = read(frp,buf,hs)) != hs)
    {
        printf("file_io: get_raw_record: Trouble reading header: %ld.\n",tmp);
        ch.h.totnwrds = -1;
        return(ch);
    }
    
    ch = convert_header(buf);

    /* now read the data in the record
     * ch.h.nwords contains the # of words of data to read
     * since the data is 8bits long there is no need to convert it.
     */
    
    tmp = VOS_WORD_SIZE * ch.h.nwords;

#ifdef DEBUG_FIO
    printf("file_io: get_raw_record: reading: %ld bytes = %ld VOS words\n",
        tmp,ch.h.nwords);
#endif /* DEBUG_FIO */

    if((hs = read(frp,data,tmp)) != tmp)
    {
        printf("file_io: get_raw_record: Error: read: %ld bytes out of %ld\n",
            hs,tmp);
        ch.h.totnwrds = -1;
        return(ch);
    }

#ifdef DEBUG_FIO
    printf("file_io: get_raw_record: read: %ld bytes\n",tmp);
#endif /* DEBUG_FIO */

#else /* THINK_C not defined : Assume on mips machine */
    
    /* We are reading from a data file on tape
     * so need to read the entire record at once 
     */
    tmp = MAX_CUPRI_BYTES;
    if((tmp = read(frp,buf,tmp)) < hs)
    {
        printf("file_io: get_raw_record: Having trouble reading raw record %ld.\n",tmp);
        ch.h.totnwrds = -1;
        return(ch);
    }

    ch = convert_header(buf);
    /* for the Unix machines, if you need to do something other than
     * a simple 8-bit unpacking then call the routines here, and make
     * sure data is defined in the routine that calls this one.
     */
    
#endif /* THINK_C */

    return(ch);
}

/* printf_exit **************************************************
* INPUT:    s       character string message                    *
*           err     error code or misc int to print in message. *
*                   This routine forces the program to end.     *
****************************************************************/
void printf_exit(char *s, long int err)
{
    printf(s,err);
    exit(err);
}
