/* *******************************************
 * *                                         *
 * *  Ericsson EWIS  format viewer program   *
 * *                                         *
 * *******************************************
 * File: utils/ewis/ewisview.C
 *
 *                       COPYRIGHT (c) 2005 BY
 *          SIGMET INCORPORATED, 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 takes the filename of a ewis file and prints out diagnostic
 * information.
 */

#ifndef LINUX
#include <arpa/nameser.h>  /* Defines BYTE_ORDER on HP and SGI */
#endif

#include <errno.h>
#include <locale.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sigtypes.h"
#include "ericsson_ewis.h"

#include "user_lib.h"

/* Local function prototypes
 */
static void ProcessCommandLine
(int iArgc, 
 char *sArgv[],
 struct view_options *pOptions_a );

static void Usage( void );

static void PrintHeader
( const struct ewis_header *pHeader_a,
  const struct view_options *pOptions_a );

static void PrintHeaderType
( const struct ewis_header *pHeader_a );

static void PrintDataPolar
( const struct ewis_header *pHeader_a,
  const UINT1 *pDataBuffer_a,
  SINT4 iCount_a,                     /* Number of bytes in the buffer */
  const struct view_options *pOptions_a );

static void PrintRay
(const UINT1 pRay_a[],
 SINT4 iRay_a,
 const struct ewis_header *pHeader_a,
 const struct view_options *pOptions_a );

static void PrintDataXyz
( const struct ewis_header *pHeader_a,
  const UINT1 *pDataBuffer_a,         /* Pointer to the whole volume buffer */
  SINT4 iCount_a,                     /* Number of bytes in the buffer */
  const struct view_options *pOptions_a );

static void PrintDataHoriz
( const struct ewis_header *pHeader_a,
  const UINT1 *pDataBuffer_a,
  SINT4 iCount_a,                     /* Number of bytes in the buffer */
  const struct view_options *pOptions_a );

static char *sEwisPictureType
( char *sString_a, 
  int  iSize_a,
  int  iType_a );

static char *sEwisDataType
( char *sString_a, 
  int  iSize_a,
  int  iType_a );

struct view_options
{
  char sPath[PATHNAME_SIZE];
  UINT1 lVerbose;      /* Print full header info */
  UINT1 lPrintData;    /* Print full data info */
  SINT4 iRayCount;     /* Only print this many rays */
  SINT4 iRaySkip;      /* Skip this many rays */
  SINT4 iLineLength;   /* Line length to use for data listing */
  SINT4 iSweepIndex;   /* Which sweep to display from */
};

/* ===============================================================
 * Main program starts here.
 */
int main(int iArgc, char *sArgv[])
{
  SINT4 iCount;
  struct ewis_header_file HeaderFile;
  struct ewis_header Header;
  struct view_options Options;
  FILE *stream;

  setlocale( LC_ALL, "" ) ;

  /* Process the command line arguments */
  ProcessCommandLine( iArgc, sArgv, &Options );

  /* Read in the header */
  stream = fopen( Options.sPath, "r" );
  if (!stream)
    {
      sig_signal( errno_to_message_va(errno, 1, Options.sPath) );
      exit(EXIT_FAILURE);
    }

  /* Read and process header */
  iCount = fread( &HeaderFile, 1, 512, stream );
  HeaderFromFile( &Header, &HeaderFile );
  PrintHeader(&Header, &Options );

  /* Read and process data */

  if (Options.lPrintData)
    {
      SINT4 iReadSize;
      UINT1 *pDataBuffer;
      iReadSize = Header.pixel_cnt;
      pDataBuffer = (UINT1*)malloc( iReadSize );
      if (!pDataBuffer) { sig_signal( errno_to_message(errno) ); exit(EXIT_FAILURE);}
      iCount = fread( pDataBuffer, 1, iReadSize, stream );
      /* The read size might be rounded up to the next multiple of 512 blocks */
      if ( (iCount!=iReadSize) && 
	   ((SINT4)(0xFFFFFE00&(iCount+511))!=iReadSize) ) 
	{
	  fprintf(stderr, "Read error, Got %d wanted %d bytes\n", iCount, iReadSize );
	}
      switch( Header.pic_fil_typ )
	{
	case EWIS_PIC_FIL_POLAR_VOLUME:
	  PrintDataPolar( &Header, pDataBuffer, iCount, &Options );
	  break;
	case EWIS_PIC_FIL_XYZ_VOLUME:
	  PrintDataXyz  ( &Header, pDataBuffer, iCount, &Options );
	  break;
	case EWIS_PIC_FIL_HORIZ_PICTURE:
	  PrintDataHoriz( &Header, pDataBuffer, iCount, &Options );
	  break;
	}

      free(pDataBuffer);
    }

  fclose( stream );

  exit( EXIT_SUCCESS );
}
/* ======================================================================
 * Function to process the command line arguments.
 */
static void ProcessCommandLine
(int iArgc_a, 
 char *sArgv_a[],
 struct view_options *pOptions_a )
{

  int iArg;
  memset( pOptions_a, 0, sizeof(*pOptions_a) );
  pOptions_a->iLineLength = 80;

  /* Parse command line options
   */
  for( iArg=1 ; iArg<iArgc_a ; iArg++ )
    {
      const char *sArg = sArgv_a[iArg];
      /* fprintf( stderr, "Processing %d: '%s'\n", iArg, sArg ); */

      if (0 == strncmp( sArg, "-count:", 7 ))
	{
	  char *sEnd;
	  pOptions_a->iRayCount = strtol( &sArg[7], &sEnd, 10 );
	}
      else if (0 == strncmp( sArg, "-d", 2 ))
	{
	  pOptions_a->lPrintData=TRUE;
	}
      else if (0 == strncmp( sArg, "-file:", 6 ))
	{
	  strncpy( pOptions_a->sPath, sArg+6, PATHNAME_SIZE-1);
	}
      else if (0 == strncmp( sArg, "-h", 2 ))
	{
	  Usage();
	  exit(EXIT_FAILURE) ;
	}
      else if (0 == strncmp( sArg, "-length:", 8 ))
	{
	  char *sEnd;
	  pOptions_a->iLineLength = strtol( &sArg[8], &sEnd, 10 );
	  if (pOptions_a->iLineLength<30) pOptions_a->iLineLength=30;
	}
      else if (0 == strncmp( sArg, "-skip:", 6 ))
	{
	  char *sEnd;
	  pOptions_a->iRaySkip = strtol( &sArg[6], &sEnd, 10 );
	}
      else if (0 == strncmp( sArg, "-sweep:", 7 ))
	{
	  char *sEnd;
	  pOptions_a->iSweepIndex = strtol( &sArg[7], &sEnd, 10 );
	  if (pOptions_a->iSweepIndex<0) pOptions_a->iSweepIndex=0;
	}
      else if (0 == strncmp( sArg, "-v", 2 ))
	{
	  pOptions_a->lVerbose=TRUE;
	}
    }
  if (!pOptions_a->sPath[0])
    {
      printf( "ewisview requires a pathname arg.\n" );
      exit(EXIT_FAILURE);
    }
  return;
}
/* ==================================================
 */
static void Usage( void )
{
  fprintf( stderr, "Options: -count:N  (only print N rays)\n" );
  fprintf( stderr, "         -data     (print data values)\n" );
  fprintf( stderr, "         -help     (print this list and exit)\n" );
  fprintf( stderr, "         -length:N (max line length to use)\n" );
  fprintf( stderr, "         -skip:N   (skip the first N rays)\n" );
  fprintf( stderr, "         -sweep:N  (print from sweep or slice N (default 0))\n" );
  fprintf( stderr, "         -verbose  (print full header info)\n" );
  fprintf( stderr, "         -file:pathname (file to print)\n" );
  fprintf( stderr, "         (all other arguments ignored)\n" );
}

/* =====================================================
 * Print the header
 */
static void PrintHeader
( const struct ewis_header *pHeader_a, 
  const struct view_options *pOptions_a )
{

  char sBuffer[32];
  printf( "==========EWIS Header=========\n" );
  printf( "           Ident: %-8.8s\n",   nullify( pHeader_a->ident, 8 ) );
  printf( "   Header Length: %d block\n", pHeader_a->header_len);
  printf( "   Date and Time: %-12.12s\n", nullify( pHeader_a->date_time, 12 ) );
  printf( "           Scale: %d\n",       pHeader_a->scale);
  sEwisPictureType( sBuffer, 32, pHeader_a->pic_type);
  printf( "    Picture Type: %s (#%d)\n", sBuffer, pHeader_a->pic_type);
  sEwisDataType( sBuffer, 32, pHeader_a->quant );
  printf( "        Quantity: %s (#%d)\n", sBuffer, pHeader_a->quant);
  printf( "         Weather: %d\n",       pHeader_a->weath);
  printf( "       Comment 1: %-10.10s\n", nullify( pHeader_a->comment1, 10 ) );
  printf( "       Comment 2: %-30.30s\n", nullify( pHeader_a->comment2, 30 ) );
  printf( "       Signature: %-2.2s\n",   nullify( pHeader_a->signature, 2 ) );
  printf( "           Place: %-20.20s\n", nullify( pHeader_a->place, 20 ) );
  printf( "      Radar Type: %d\n",       pHeader_a->radar_type);
  printf( "      Compressed: %d\n",       pHeader_a->compressed);
  printf( "        Latitude: %7.5f\n",    pHeader_a->geo_lat);
  printf( "       Longitude: %7.5f\n",    pHeader_a->geo_lon);
  printf( "         Radar X: %5.4f\n",    pHeader_a->radar_x);
  printf( "         Radar Y: %5.4f\n",    pHeader_a->radar_y);
  printf( "  Pixels (ExNxV): %d x %d x %d\n", pHeader_a->ne,pHeader_a->nn,pHeader_a->nv);
  printf( "      Resolution: %5.3f x %5.3f x %5.3f km/pixel\n",
	  pHeader_a->e_inc, pHeader_a->n_inc, pHeader_a->v_inc );
  printf( "     Pixel count: %d\n", pHeader_a->pixel_cnt );
  printf( "   Pixel min/max: %d/%d\n", pHeader_a->store_min, pHeader_a->store_max );
  printf( " Slope, ord, off: %4.2f, %3.1f, %d\n",
	  pHeader_a->store_slope, pHeader_a->store_ord, pHeader_a->store_offset );
  printf( "           #bits: %d/%d\n", pHeader_a->store_bits, pHeader_a->store_align );
  printf( "       Data Type: %-8.8s\n", nullify( pHeader_a->store_quant, 8 ) );
  printf( "             Z/R: Const: %3.2f, Exponent: %3.2f\n", 
	  pHeader_a->rain_const1, pHeader_a->rain_const2 );
  printf( "    Radar Height: %1.0f m\n", 1000.0*pHeader_a->geo_height );
  printf( "      Projection: %d/%d\n", pHeader_a->map_proj, pHeader_a->sub_proj );
  printf( "          Center: %3.1f km E, %3.1f km N\n", 
	  pHeader_a->map_cen_e, pHeader_a->map_cen_n );
  printf( "East Coeficients: %3.2f %3.2f %3.2f %3.2f %3.2f\n", 
	  pHeader_a->e_const[0], pHeader_a->e_const[1], pHeader_a->e_const[2],
	  pHeader_a->e_const[3], pHeader_a->e_const[4] );
  printf( " Nor Coeficients: %3.2f %3.2f %3.2f %3.2f %3.2f\n", 
	  pHeader_a->n_const[0], pHeader_a->n_const[1], pHeader_a->n_const[2],
	  pHeader_a->n_const[3], pHeader_a->n_const[4] );
  printf( "   Volume params: 0x%x\n", pHeader_a->volume_params );

  PrintHeaderType( pHeader_a );
  return;

}
/* =================================================
 * Print header info which is file type dependent
 */
static void PrintHeaderType
( const struct ewis_header *pHeader_a )
{
  int ii;
  switch( pHeader_a->pic_fil_typ )
    {
    case EWIS_PIC_FIL_POLAR_VOLUME:
      printf( "\n       File type: Polar Volume\n" );
      printf( "  Number of cuts: %d\n", pHeader_a->Type.polar.elev_uppb );
      printf( "    Max az index: %d\n", pHeader_a->Type.polar.azim_uppb );
      printf( "  Number of bins: %d\n", pHeader_a->Type.polar.range_uppb );
      printf( "    Range limits: %d %d %d\n", 
	      pHeader_a->Type.polar.range_lim[0],
	      pHeader_a->Type.polar.range_lim[1],
	      pHeader_a->Type.polar.range_lim[2] );
      printf( "Range resolution: %3.2f %3.2f %3.2f\n", 
	      pHeader_a->Type.polar.range_siz[0],
	      pHeader_a->Type.polar.range_siz[1],
	      pHeader_a->Type.polar.range_siz[2] );
      printf( "       Scan size: %d\n", pHeader_a->Type.polar.scan_size );
      for ( ii=0; ii<MIN( pHeader_a->Type.polar.elev_uppb, 20 ); ii++)
	{
	  printf( "          Cut %2d: El:%4.2f, Block:%d\n", ii,
		  pHeader_a->Type.polar.elev[ii],
		  pHeader_a->Type.polar.elev_block_nr[ii] );
	}
      break;

    case EWIS_PIC_FIL_XYZ_VOLUME:
      printf( "\n       File type: XYZ Volume\n" );
      for ( ii=0; ii<MIN(pHeader_a->nv,17); ii++)
	{
	  printf( "        Slice %2d: Height:%6.3f km, Block:%d\n", ii,
		  pHeader_a->Type.xyz.pic_level[ii],
		  pHeader_a->Type.xyz.block_no[ii] );
	}
      break;

    case EWIS_PIC_FIL_HORIZ_PICTURE:
      printf( "\n       File type: Horizontal Picture\n" );
      printf( "          Height:%6.3f km, Number:%d\n",
	      pHeader_a->Type.horiz.hei, pHeader_a->Type.horiz.hei_nr );
      break;

    case EWIS_PIC_FIL_VERT_PICTURE:
      printf( "\n       File type: Vertical Picture\n" );
      break;
    case EWIS_PIC_FIL_COLOR_IMAGE:
      printf( "\n       File type: Color Image\n" );
      break;
    case EWIS_PIC_FIL_VERT_OBLIQUE_PICTURE:
      printf( "\n       File type: Vertical Oblique Picture\n" );
      break;
    }
}

/* ===============================================================
 * Print data from a polar volume on the terminal.
 */
static void PrintDataPolar
( const struct ewis_header *pHeader_a,
  const UINT1 *pDataBuffer_a,
  SINT4 iCount_a,                     /* Number of bytes in the buffer */
  const struct view_options *pOptions_a )
{
  SINT4 iOffset, iRay, iRayCount;
  const UINT1 *pSweepStart, *pRay;

  printf( "\nPrinting rays from sweep index %d:\n", pOptions_a->iSweepIndex );

  if (pOptions_a->iSweepIndex >= pHeader_a->Type.polar.elev_uppb )
    {
      printf( "Sorry, no such sweep\n" );
      return;
    }

  iOffset = 512*(pHeader_a->Type.polar.elev_block_nr[pOptions_a->iSweepIndex]-2);
  pSweepStart = pDataBuffer_a+iOffset;
  iRayCount=0;
  for (iRay=pOptions_a->iRaySkip; iRay<=pHeader_a->Type.polar.azim_uppb; iRay++)
    {
      pRay = pSweepStart+(iRay*(pHeader_a->Type.polar.range_uppb+4));
      PrintRay( pRay, iRay, pHeader_a, pOptions_a );
      iRayCount++;
      /* Done when the ray count is completed */
      if ((pOptions_a->iRayCount)&&(iRayCount>=pOptions_a->iRayCount)) return;
    }
}

/* ===============================================================
 * Print data from a single ray.
 */
static void PrintRay
(const UINT1 pRay_a[],
 SINT4 iRay_a,
 const struct ewis_header *pHeader_a,
 const struct view_options *pOptions_a )
{
  SINT4 iBin;
  SINT4 iTotalLength, iLine;
  FLT4  fAzimuth;
  UINT4 iRayTime;
  char sThreshold[20];    /*String to display for threshold case */
  char sFormat[20];       /*Format string for data printing */
  

  strcpy(sThreshold, "  -.- " ) ;
  strcpy(sFormat, "%5.1f " ) ;

  iRayTime  = ((UINT4)pRay_a[0]);
  iRayTime += ((UINT4)pRay_a[1])<<8;
  fAzimuth  = 360.0*((FLT4)iRay_a)/(FLT4)(pHeader_a->Type.polar.azim_uppb+1);
  iTotalLength = printf( "%5.1fDeg %4d:", fAzimuth, 0 );
  iLine=0;
  for (iBin=0; iBin<pHeader_a->Type.polar.range_uppb; iBin++)
    {
      UINT1 iValue;
      SINT4 iThisLength;
      iValue = pRay_a[iBin+4];
      if( iTotalLength+6 > pOptions_a->iLineLength )
	{
	  if (iLine==0)
	    iTotalLength = printf( "\n%5.1fSec %4d:", ((FLT4)iRayTime)/10.0, iBin ); 
	  else
	    iTotalLength = printf( "\n         %4d:", iBin );
	  iLine++;
	  iTotalLength--;  /* Remove count for newline */
	}
      if( iValue == 0 )
	iThisLength = printf( "%s", sThreshold ) ;
      else
	{
	  FLT4 fValue;
	  fValue = (((SINT4)(UINT4)iValue) - pHeader_a->store_offset) * 
	    pHeader_a->store_slope + pHeader_a->store_ord;
	  iThisLength = printf( sFormat, fValue ) ;
	}
      iTotalLength += iThisLength;
    }  
  printf( "\n" ) ;

}

/* ===============================================================
 * Print data from a XYZ Volume on the terminal.
 */
static void PrintDataXyz
( const struct ewis_header *pHeader_a,
  const UINT1 *pDataBuffer_a,         /* Pointer to the whole volume buffer */
  SINT4 iCount_a,                     /* Number of bytes in the buffer */
  const struct view_options *pOptions_a )
{
  SINT4 iCutOffset;
  const struct ewis_header_file *pCutHeaderFile;
  struct ewis_header CutHeader;
  const UINT1 *pCutBuffer;


  if (pOptions_a->iSweepIndex >= pHeader_a->nv)
    {
      printf( "Sorry, no such slice.\n" );
      return;
    }
  
  iCutOffset = 512*(pHeader_a->Type.xyz.block_no[pOptions_a->iSweepIndex]-2);
  pCutHeaderFile = (const struct ewis_header_file*)(pDataBuffer_a+iCutOffset);
  pCutBuffer = pDataBuffer_a+iCutOffset+512;

  HeaderFromFile( &CutHeader, pCutHeaderFile );

  printf( "Displaying data from slice %d, size %d bytes.\n",
	  pOptions_a->iSweepIndex, CutHeader.pixel_cnt );

  PrintHeaderType( &CutHeader );
  PrintDataHoriz( &CutHeader, pCutBuffer, iCount_a-(iCutOffset+512), pOptions_a );
}
/* ===============================================================
 * Print data from a horizontal picture on the terminal.
 */
static void PrintDataHoriz
( const struct ewis_header *pHeader_a,
  const UINT1 *pDataBuffer_a,
  SINT4 iCount_a,                     /* Number of bytes in the buffer */
  const struct view_options *pOptions_a )
{
  SINT4 iSkipFactor, iY, iX, iPictureSize;
  iSkipFactor = (pHeader_a->ne+pOptions_a->iLineLength-9)/(pOptions_a->iLineLength-8);

  iPictureSize = pHeader_a->nn+pHeader_a->ne;
  if (iPictureSize>iCount_a)
    {
      printf( "Sorry, data needed %d bytes, found %d\n", iPictureSize, iCount_a );
      return;
    }

  for (iY=pHeader_a->nn-1; iY>=0; iY-=iSkipFactor)
    {
      printf( "%4d:", iY );
      for (iX=0; iX<pHeader_a->ne; iX+=iSkipFactor)
	{
	  SINT4 iPos= (iY*pHeader_a->ne) + iX;
	  UINT1 iValue = pDataBuffer_a[iPos];
	  if (iValue)
	    {
	      if (iValue==0xff)
		{
		  printf( " " );
		}
	      else
		{
		  FLT4 fValue;
		  fValue = (((SINT4)(UINT4)iValue) - pHeader_a->store_offset) * 
		    pHeader_a->store_slope + pHeader_a->store_ord;
		  // printf( "%X", iValue>>4);
		  if (fValue<0.0) fValue=0.0;
		  printf( "%X", NINT(fValue/10.0) );
		}
	    }
	  else
	    {
	      printf( "." );
	    }
	}
      printf( "\n" );
    }
}

/* ===========================================================
 * Returns a string describing the picture type
 */
static char *sEwisPictureType
( char *sString_a, 
  int  iSize_a,
  int  iType_a )
{
  switch( iType_a )
    {
    case EWIS_PICTYPE_NONE:
      strncpy( sString_a, "None", iSize_a );            break;
    case EWIS_PICTYPE_CAPPI:
      strncpy( sString_a, "CAPPI", iSize_a );           break;
    case EWIS_PICTYPE_MAX:
      strncpy( sString_a, "Max", iSize_a );             break;
    case EWIS_PICTYPE_HEIGHT_MAX:
      strncpy( sString_a, "Height of Max", iSize_a );   break;
    default:
      strncpy( sString_a, "UNKNOWN", iSize_a );         break;
    }
  return sString_a;
}
/* ===========================================================
 * Returns a string describing the data type
 */
static char *sEwisDataType
( char *sString_a, 
  int  iSize_a,
  int  iType_a )
{
  switch( iType_a )
    {
    case EWIS_DTYPE_NONE:
      strncpy( sString_a, "None", iSize_a );            break;
    case EWIS_DTYPE_REFLECTIVITY:
      strncpy( sString_a, "Reflectivity", iSize_a );    break;
    case EWIS_DTYPE_RAINRATE:
      strncpy( sString_a, "Rain Rate", iSize_a );       break;
    case EWIS_DTYPE_VELOCITY:
      strncpy( sString_a, "Velocity", iSize_a );        break;
    case EWIS_DTYPE_WIDTH:
      strncpy( sString_a, "Width", iSize_a );           break;
    case EWIS_DTYPE_HEIGHT_REF:
      strncpy( sString_a, "Height/Ref", iSize_a );      break;
    case EWIS_DTYPE_HEIGHT_VEL:
      strncpy( sString_a, "Height/Vel", iSize_a );      break;
    case EWIS_DTYPE_HEIGHT_WID:
      strncpy( sString_a, "Height/Wid", iSize_a );      break;
    case EWIS_DTYPE_RAIN_ACC:
      strncpy( sString_a, "Rainfall Accum", iSize_a );  break;
    case EWIS_DTYPE_HEIGHT:
      strncpy( sString_a, "Height", iSize_a );          break;
    case EWIS_DTYPE_VPI:
      strncpy( sString_a, "VPI", iSize_a );             break;
    case EWIS_DTYPE_HORZ_REFL:
      strncpy( sString_a, "Horiz Reflect.", iSize_a );  break;
    case EWIS_DTYPE_ZDR:
      strncpy( sString_a, "ZDR", iSize_a );             break;
    case EWIS_DTYPE_LIQUID:
      strncpy( sString_a, "Liquid", iSize_a );          break;
    default:
      strncpy( sString_a, "UNKNOWN", iSize_a );         break;
    }
  return sString_a;
}
