/* *************************
 * *                       *
 * * Display Contents of a *
 * *      RAW Product      *
 * *                       * 
 * ************************* 
 * File: iris/examiners/product_raw.C
 * 
 * COPYRIGHT (c) 1991, 1992, 1994, 1996, 1998, 2000, 2001, 2002, 2003,
 *                       2004, 2005, 2006 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. 
 */
#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 "product.h"

#include "user_lib.h"
#include "dsp_lib.h"

#include "examiners.h"

/* Co-Routine to extract bytes, and static variables used by the
 * routine.
 */
void get_raw_bytes( SINT2 *buf_a, SINT4 icnt_a ) ;

static SINT4  irec_c ;		/* Record number */
static SINT4  ioff_c ;		/* Offset within record */
static UINT1 *prod_c ;		/* Pointer to product */

#define PRODPTR (UINT1 *)(prod_c + (irec_c * TAPE_RECORD_LEN) + ioff_c)

/* ==============================================================
 * Print information about a RAW product.  Entered with a pointer
 * to the beginning (first 6144-byte record) of the full product.
 */
void product_raw
(const struct raw_product *pRaw_a,
  SINT4 iLineLength_a )
{
#define RAYSIZE MAX_BINS
  SINT2 isweepreq ; UINT2 iparam, lmissing ;
  SINT4 ii, iprms, irptr, idtypes[NUM_DEFINED_DATA], isweep, isweeplo, isweephi, iBinStart ;
  FLT4  fBinStartKm;
  UINT1 lPerformance;
  char sTZName[TZNAME_SIZE];
  const struct product_hdr *pPHeader;
  const struct ingest_header *inghdr ;

  /* The first two "records" of the product consist of a product
   * header structure and an ingest header structure.  Each is
   * padded out to one record.
   */
  prod_c = (UINT1 *) pRaw_a ;
  pPHeader = &pRaw_a->Record[0].PHeader;
  inghdr   = &pRaw_a->Record[1].IHeader;

  /* Make sure that this file really looks like a raw product.  Check
   * the ID's in the product and ingest headers.
   */
  if((pPHeader->hdr.id    != ST_PRODUCT_HDR) ||
     (inghdr->hdr.id     != ST_INGEST_HDR ) ||
     (inghdr->tcf.hdr.id != ST_TASK_CONF  ) ) {
       printf( "File headers contain invalid ID's\n" ) ;
     }

  TZNameBuild( sTZName, inghdr->icf.sLocalTZName, inghdr->icf.iMinutesWest,
	      inghdr->icf.VolumeYmds.imills );
  /* Print out a few values from the ingest header.
   */
  printf( "Information from INGEST Header\n" ) ;
  printf( "------------------------------\n" ) ;

  showsummary( inghdr ) ;

  /* Count up the number of parameters that were recorded.  This is
   * needed in order to skip through the sweeps properly.
   */
  for( iprms=ii=0 ; ii <NUM_DEFINED_DATA ; ii++ ) {
    if( lDspMaskTest(&inghdr->tcf.dsp.DataMask, ii) ) { idtypes[iprms] = ii ; iprms++ ; }
  }

  /* Get sweep limits for the data in this particular RAW product.  If
   * it is a single sweep product, then use just the one that is
   * selected in the PSI structure.  Otherwise query for which sweep
   * to select.
   */
  if( pPHeader->pcf.psi.raw.iflags & RAW_FLG_SWEEP ) {
    isweeplo  = pPHeader->pcf.psi.raw.isweep ;
    isweephi  = pPHeader->pcf.psi.raw.isweep ;
    isweepreq = pPHeader->pcf.psi.raw.isweep ;
    printf( "\nThis RAW product contains only sweep #%d.\n\n", isweepreq ) ;

  } else {
    isweeplo = 1 ;
    isweephi = inghdr->tcf.scan.isweeps ;
    printf( "\n" ) ; asksweep( isweephi, &isweepreq, isweeplo ) ;
  }

  /* Check which moment and starting range should be used.
   */
  askmoments( "What parameter do you wish to display? ", &inghdr->tcf.dsp.DataMask, 
	      &iparam, idtypes[0] ) ;
  lPerformance = lAskRange( &fBinStartKm, iparam ) ;
  if (lPerformance)
    iBinStart = 0;
  else
    {
      FLT4 fMaskStart, fMaskStep;
      fMaskStart = ((FLT4)inghdr->tcf.rng.ibin_first)/100000.0;
      fMaskStep  = ((FLT4)inghdr->tcf.rng.ibin_out_step)/100000.0;
      if (fMaskStep <= 0.0) fMaskStep = 1/100000.0;
      iBinStart = 1+NINT((fBinStartKm - fMaskStart)/fMaskStep);
      if (iBinStart<1) iBinStart = 1;
      if (iBinStart>inghdr->tcf.rng.ibin_out_num) iBinStart = inghdr->tcf.rng.ibin_out_num;
    }

  /* Initialize record pointer to the first data record (third one in)
   * and loop for each sweep that was recorded.  We will scan through
   * the entire product (to check for errors), and will perhaps print
   * some subset of it.
   */
  irec_c = 2 ;			/* Record number */
  ioff_c = 0 ;			/* Offset within record */

  printf( "\n" ) ;
  for( isweep = isweeplo ; isweep <= isweephi ; isweep++ ) {
    struct ingest_data_header idhdrs[32] ; SINT4 iprm ;
    char sTimeBuffer[21];

    /* Extract the INGEST data file headers for each of the parameters
     * that were recorded.  The headers appear sequentially in the
     * first record of each sweep.
     */
    for( iprm=0 ; iprm < iprms ; iprm++ ) {
      get_raw_bytes( (SINT2 *)&idhdrs[iprm], INGEST_DATA_HEADER_SIZE ) ;
    }
    printf( "Sweep began at: %s %s\n", shhmmssddmonyyyy_r( &idhdrs[0].time, sTimeBuffer ),
	    sTZName ) ;

    /* Read the data from each of the angles, and for each of the
     *  parameters that were recorded.
     */
    for( irptr=0 ; irptr < inghdr->icf.irtotl ; irptr++ ) {
      for( iprm=0 ; iprm < iprms ; iprm++ ) {

	struct data_ray ray ;
	SINT4 inlen, ioutlen ;

	uncompress_cowords
	  (get_raw_bytes,
	   pPHeader->hdr.ibytes - ((irec_c * TAPE_RECORD_LEN) + ioff_c),
	   &inlen, (SINT2 *)&ray, sizeof(ray)/2, &ioutlen ) ;

        lmissing = (ioutlen == 0) ;

	if( (isweep == isweepreq) && (idtypes[iprm] == iparam) ) {
	  raylist( &inghdr->tcf, &ray, &idhdrs[iprm], irptr, lmissing, iBinStart, 
		   inghdr, iLineLength_a ) ;
	}
      }
    }

    /* Done with this sweep.  Discard the remainder of this block, if
     * any.
     */
    if( ioff_c ) { ioff_c = 0 ; irec_c++ ; }
  }
}

/* ==================================================
 * Co-Routine to read the next run of bytes from the raw product file,
 * skipping and checking the record headers as we go.
 */
void get_raw_bytes( SINT2 *buf_a, SINT4 icnt_a )
{
  SINT4 icnt, iremain = icnt_a ; UINT1 *pbuf = (UINT1 *)buf_a ;

  while( iremain > 0 ) {
    /* If the offset is zero, then get the next record header and
     * compare the record numbers.  Exit if there is a mismatch.
     */
    if( ioff_c == 0 ) {
      struct raw_prod_bhdr bhdr ;
      memcpy( (void *)&bhdr, PRODPTR, RAW_PROD_BHDR_SIZE ) ;
      if( bhdr.irec != irec_c ) {
	printf( "Block header mismatch (%d) at block %d\n", bhdr.irec, irec_c ) ;
	exit(1) ;
      }
      ioff_c += RAW_PROD_BHDR_SIZE ;
    }

    /* Extract as many bytes out of this record as we can.  Bump record
     * number and zero the offset if we read it all.
     */
    icnt = TAPE_RECORD_LEN - ioff_c ;
    if( icnt > iremain ) icnt = iremain ;

    memcpy( pbuf, PRODPTR, icnt ) ;
    iremain -= icnt ; ioff_c += icnt ; pbuf += icnt ;

    if( ioff_c == TAPE_RECORD_LEN ) { ioff_c = 0 ; irec_c++ ; }
  }
  return;
}
