/* ****************************************
 * *                                      *
 * *  Archive 2 format support functions  *
 * *                                      *
 * ****************************************
 * File: utils/archive2/archive2Parse.C
 *
 *                  COPYRIGHT (c) 2002, 2004, 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.
 */

/* This program take the filename of an archive2 file and prints out diagnostic
 * information.
 */

#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "sigtypes.h"
#include "nexrad.h"

#include "user_lib.h"

#include "archive2_h.h"

/* ====================================================
 * Read the volume header  from the file.  This includes byte swapping.
 */
SINT4 ReadNrVolumeHeader
( struct nr_volume_header *pVHeader_a,
  FILE *pStream_a )
{
  SINT4 iCount;
  iCount = fread( pVHeader_a, 1, sizeof(*pVHeader_a), pStream_a );
  if (iCount != sizeof(*pVHeader_a)) 
    {
      printf( "Bad read, got%d, wanted%d bytes\n", iCount, sizeof(*pVHeader_a));
      return 0;
    }
  VolumeHeaderUnpack( pVHeader_a );
  return iCount;
}

/* ====================================================
 * Read a packet from the file.  This includes figuring out
 * what the size is and byte swapping the message header.
 */
SINT4 ReadNrPacket
( union nr_packet *pPacket_a,
  FILE *pStream_a )
{
  SINT4 iReadSize, iMsgSize, iCount;

  /* Always do fixed size record reads */
  iReadSize = NR_MAX_PACKET_LENGTH;  /* Includes the CTM header and trailer */
  iCount = fread( &pPacket_a->MessageHeader, 1, iReadSize, pStream_a );
  if (iCount<=0) return 0;
  if (iCount!=iReadSize)
    {
      printf( "Bad read, got:%d, wanted:%d bytes\n", iCount, iReadSize );
      return 0;
    }
  MessageHeaderUnpack(&pPacket_a->MessageHeader );

  /* Compute the remaining read size */
  iMsgSize = 2*pPacket_a->MessageHeader.iMsgSize;
  if (iMsgSize>NR_MAX_PACKET_LENGTH)
    {
      printf( "Packet length of:%d exceeds max of:%d bytes\n", iReadSize,
	      NR_MAX_PACKET_LENGTH );
      return 0;
    }
  if (iMsgSize<(((SINT4)sizeof(pPacket_a->MessageHeader))-12))
    {
      printf( "Packet length of:%d is smaller than message header\n", iReadSize );
      return 0;
    }

  return 2*pPacket_a->MessageHeader.iMsgSize;
}

/* =====================================================
 * Unpack the Volume Header structure
 */
void VolumeHeaderUnpack
( struct nr_volume_header *pTitle_a ) 
{
  /* Unpack the structure */
  Pack4( &pTitle_a->iFileDate );
  Pack4( &pTitle_a->iFileTime );

  return;

}

/* =====================================================
 * Unpack the message header
 */
void MessageHeaderUnpack
( struct nr_message_header *pMHeader_a )  /* Strings are byte swapped correctly */
{
  /* Unpack the structure, including fields unused by IRIS, but not
   * other unused fields.
   */
  Pack2( &pMHeader_a->CTM[0] );
  Pack2( &pMHeader_a->CTM[1] );
  Pack2( &pMHeader_a->CTM[2] );
  Pack2( &pMHeader_a->CTM[3] );
  Pack2( &pMHeader_a->CTM[4] );
  Pack2( &pMHeader_a->CTM[5] );
  Pack2( &pMHeader_a->iMsgSize );
  Pack2( &pMHeader_a->iIDSequence );
  Pack2( &pMHeader_a->iMsgDate );
  Pack4( &pMHeader_a->iMsgTime );
  Pack2( &pMHeader_a->iSegmentCount );
  Pack2( &pMHeader_a->iSegmentNumber );

  return;

}

/* =====================================================
 * Unpack the data header
 */
void DataHeaderUnpack
( struct nr_radar_data_header *pDHeader_a )  /* Strings are byte swapped correctly */
{

  /* Unpack the structure, including fields unused by IRIS, but not
   * other unused fields.
   */
  Pack4( &pDHeader_a->iDataTime );
  Pack2( &pDHeader_a->iDataDate );
  Pack2( &pDHeader_a->iUnambRange );
  Pack2( &pDHeader_a->iAzimuth );
  Pack2( &pDHeader_a->iRayNumber );
  Pack2( &pDHeader_a->iRayStatus );
  Pack2( &pDHeader_a->iElevation );
  Pack2( &pDHeader_a->iSweepNumber );
  Pack2( (UINT2*)&pDHeader_a->iBinStartRef );
  Pack2( (UINT2*)&pDHeader_a->iBinStartDop );
  Pack2( &pDHeader_a->iBinStepRef );
  Pack2( &pDHeader_a->iBinStepDop );
  Pack2( &pDHeader_a->iBinNumberRef );
  Pack2( &pDHeader_a->iBinNumberDop );
  Pack2( &pDHeader_a->iSectorNumber );
  Pack4( (UINT4*)&pDHeader_a->fSystemCal );  /* May need special float function */
  Pack2( &pDHeader_a->iRefPointer );
  Pack2( &pDHeader_a->iVelPointer );
  Pack2( &pDHeader_a->iWidPointer );
  Pack2( &pDHeader_a->iVelocityRes );
  Pack2( &pDHeader_a->iVolumePattern );
  Pack2( &pDHeader_a->ref_ptrp );
  Pack2( &pDHeader_a->vel_ptrp );
  Pack2( &pDHeader_a->spc_ptrp );
  Pack2( &pDHeader_a->iNyquistVel );
  Pack2( (UINT2*)&pDHeader_a->iAttenuation );
  Pack2( &pDHeader_a->min_dif );

  return;

}
/* ==========================
 * Accumulate adaptation data from multiple packets.
 */
void AdaptationAccumulate
( const struct nr_generic_packet *pPacket_a,
  struct nr_rda_adaptation *pAdaptation_a )
{
  SINT4 iOffset, iSize;
  /* Based on packet number, compute the offset into the adaptation structure */
  iOffset = 2400*(pPacket_a->MessageHeader.iSegmentNumber-1);
  iSize   = 2*(pPacket_a->MessageHeader.iMsgSize-8); 

  if ((iOffset+iSize)>(SINT4)sizeof(*pAdaptation_a) ) return;
  memcpy( ((char*)pAdaptation_a)+iOffset, pPacket_a->iData, iSize );

}

/* =================================
 * Byte swap the adaptation data.
 */
void AdaptationUnpack
( struct nr_rda_adaptation *pAdaptation_a )
{
  Pack4( &pAdaptation_a->itfreq_mhz ); 
  Pack4( (UINT4*)&pAdaptation_a->fbeam_width ); 

  Pack4( (UINT4*)&pAdaptation_a->fLatSec ); 
  Pack4( (UINT4*)&pAdaptation_a->fLonSec ); 
  Pack4( &pAdaptation_a->iLatDeg ); 
  Pack4( &pAdaptation_a->iLatMin ); 
  Pack4( &pAdaptation_a->iLonDeg ); 
  Pack4( &pAdaptation_a->iLonMin ); 

  Pack4( (UINT4*)&pAdaptation_a->ignd_hgt ); 
  Pack4( (UINT4*)&pAdaptation_a->irad_hgt ); 
  return;
}

/* =========================
 * Byte swapping functions.  Swap from/to the big endian format of the
 * concurent computers. 
 */
void Pack2( UINT2 *pData2_a )
{
  UINT1 *pData1;
  UINT2 Data2;

  pData1    = (UINT1 *)pData2_a;
  Data2     = pData1[0];
  Data2     = Data2<<8;
  Data2    += pData1[1];
  *pData2_a = Data2;
}

void Pack4( UINT4 *pData4_a )
{
  UINT1 *pData1;
  UINT4 Data4;

  pData1    = (UINT1 *)pData4_a;
  Data4     = pData1[0];
  Data4     = Data4<<8;
  Data4    += pData1[1];
  Data4     = Data4<<8;
  Data4    += pData1[2];
  Data4     = Data4<<8;
  Data4    += pData1[3];
  *pData4_a = Data4;
}

/* ==================================================================
 * Convert time formats.
 */
void YmdsFromNrTime
( struct ymds_time *pYmds_a,
  UINT4 iDate_a,    /* Date in days */
  UINT4 iTime_a )   /* Time in ms */
{
  struct tm RayTm;
  time_t Time;
  
  Time = (iDate_a-1)*(24*60*60);
  Time += iTime_a / 1000;

  gmtime_r( &Time, &RayTm );

  memset( pYmds_a, 0, sizeof(*pYmds_a) );
  pYmds_a->iyear = RayTm.tm_year+1900;
  pYmds_a->imon = RayTm.tm_mon+1;
  pYmds_a->iday = RayTm.tm_mday;
  pYmds_a->isec = iPackTime( RayTm.tm_hour, RayTm.tm_min, RayTm.tm_sec );

  pYmds_a->imills = MILLS_FROM_MS_FLAGS(iTime_a % 1000, YMDS_FLG_UTC);
  return;
}
