/* File:  prt_inp_struct.c		Alice Nakajima, SAIC, 10/96
   Func to print content of all of the Internal structs
Revisions:
09/10/98 atn:  display whether or not GRIB extensions are used.
*/
#include <math.h>
#include <stdio.h>
#include <string.h>
#define PRJN_NAME_NEEDED TRUE
#include "grib_lookup.h"	/* for Parm/Ctr/Levl/Mdl_defn */
#include "dprints.h"		/* for dprints */
#include "gribfuncs.h"		/* prototypes */

/* 
   Defines following Global var:
   int UseTables;   flag set if using lookuptbl
 
   Uses the external tables, defined in ld_enc_inputs.c:
   PARM_DEFN  db_parm_tbl[256*MAX_PARM_TBLS]  holds Parameter lookup info;
   LVL_DEFN   db_lvl_tbl[NLEVS]  holds Level lookup info;
   MODEL_DEFN db_mdl_tbl[NMODEL] hold Model lookup info;
   GEOM_DEFN  db_geom_tbl[NGEOM]   holds Geom lookup info;
               
*/
int UseTables=0;       /* GLOBALVAR:   default is no lookup table used */

extern PARM_DEFN  db_parm_tbl[];  	/* parameter conversion info */
extern MODEL_DEFN db_mdl_tbl[]; 	/* model conversion info */
extern LVL_DEFN   db_lvl_tbl[]; 	/* level conversion info */
extern GEOM_DEFN  db_geom_tbl[];	/* Geom conversion info  */
extern CTR_DEFN   db_ctr_tbl[];  	/* Ctr conversion info  */

/*
*
************************************************************************
* A. FUNCTION:  prt_inp_input
*      to print content of the Internal Grib structures
*
*    INTERFACE:
*      void  prt_inp_struct (pds, gds, bms_input, bds_head_input, ppfarr)
*
*    ARGUMENTS (I=input, O=output, I&O=input and output):
*      (I) PDS_INPUT *pds;                
*          internal Product Defn Section struct to print
*      (I) grid_desc_sec  *gds;  
*          internal Grid Defn struct to print
*      (I) BMS_INPUT *bms_input;          
*          internal Bitmap Section  to print
*      (I) struct BDS_HEAD_INPUT *bds_head_input; 
*          internal 11-byte hdr of Binary Data Section to print
*      (I) float **ppfarr;    
*          unpacked & restored float data array to print
*
*    RETURN CODE: none
************************************************************************
*/
void	prt_inp_struct (PDS_INPUT 	*pds,
			grid_desc_sec   *gds,
			BMS_INPUT 	*bms_input,
			struct BDS_HEAD_INPUT *bds_head_input,
			float 		**ppfarr)
{
  const char *func= "prt_inp_struct"; /* name of function */
  float *farr;			/* ptr to float data aray */
  int D;			/* Decimal Scl Fctr */
  int indx,i;			/* index */

   fprintf(stdout,"\n--- Entering %s ---\n", func);
/*
*
* A.1       IF (PDS_INPUT struct is null) THEN
*               PRINT message
*           ELSE
*               PRINT out all of its fields, values and type
*           ENDIF
*/
   if (pds == NULL) fprintf(stdout,"**** PDS_INPUT is null****\n");
   else
   {             
     fprintf(stdout,"***  PDS_INPUT ****\n");
     p_ushort (pds->uslength);        
     p_ushort (pds->usEd_num);       
     p_ushort (pds->usParm_tbl);    
     p_ushort (pds->usCenter_id);  
     
     p_ushort (pds->usProc_id);   
     
     p_ushort (pds->usGrid_id);  
     if (UseTables) 
     
     p_ushort (pds->usGds_bms_id); 
     p_ushort (pds->usParm_id);   

     /*
      * The sub-tables cannot have GribCode Zero since it's Reserved
      * if the center doesn't use sub tables then they must set ParmSub to 0
      * when ParmId is between 250 (Tbl-A) and 254 (Tbl-E);
      */
     if (pds->usParm_id>=250 && pds->usParm_id<=254 && pds->usParm_sub!=0)
        {
          indx = 256 * (pds->usParm_id - 249) + pds->usParm_sub;
          p_ushort (pds->usParm_sub);
	  fprintf(stdout,"  (pid=%d, psub=%d) is Sub-ParmTbl Indx = %d\n",
	  pds->usParm_id, pds->usParm_sub, indx);
        }
      else  {
	  indx = pds->usParm_id;
	  fprintf(stdout,
	  "  usParm_sub not used (%ld), default to ParmTbl Indx= %d\n",
	  pds->usParm_sub, indx);
	}

     p_ushort (pds->usLevel_id); 
     p_ushort (pds->usLevel_octets); 
     p_ushort (pds->usHeight1);     
     p_ushort (pds->usHeight2);    
     
     p_ushort (pds->usYear);      
     p_ushort (pds->usMonth);    
     p_ushort (pds->usDay);     
     p_ushort (pds->usHour);   
     p_ushort (pds->usMinute);
     p_ushort (pds->usFcst_unit_id);   
     p_ushort(pds->usTime_range); 

     switch (pds->usTime_range ) {

	case 10: /* forecastper takes up both octets 19-20 */
	     p_ushort (pds->usP1); p_string ("usP2 notused");
	     break;

	default: /* treat all others as TRI=0 */
	     /* TRI=0:  P1=Oct19, P2=Oct20 */
	     p_ushort(pds->usP1); p_ushort(pds->usP2);  
	     break;
       }

     p_ushort (pds->usTime_range_avg);
     p_ushort (pds->usTime_range_mis);
     p_ushort (pds->usCentury); 
     p_ushort (pds->usCenter_sub);   
     p_short  (pds->sDec_sc_fctr);
     /* p_ushort (pds->ausZero[0]);
     p_ushort (pds->ausZero[1]);
     p_ushort (pds->ausZero[2]);
     p_ushort (pds->ausZero[3]);
     p_ushort (pds->ausZero[4]);
     p_ushort (pds->ausZero[5]);
     p_ushort (pds->ausZero[6]);
     p_ushort (pds->ausZero[7]);
     p_ushort (pds->ausZero[8]);
     p_ushort (pds->ausZero[9]);
     p_ushort (pds->ausZero[10]);
     p_ushort (pds->ausZero[11]); */

     if (pds->usExt_flag == (unsigned short)EXTENSION_FLAG) {
       fprintf(stdout,
       " (uns. short) pds->usExt_flag  = %u (Extensions used)\n",
       pds->usExt_flag);
       p_ushort (pds->usSecond);
       p_ushort (pds->usTrack_num);
       p_ushort (pds->usParm_sub);	
       p_ushort (pds->usSub_tbl); 
      }
     else fprintf(stdout,
 	" (uns. short) pds->usExt_flag  = %u (not used)\n" \
 	" (uns. short) pds->usSecond    = not avail\n" \
 	" (uns. short) pds->usTrack_num = not avail\n" \
 	" (uns. short) pds->usParm_sub  = not avail\n" \
 	" (uns. short) pds->usSub_tbl   = not avail\n", pds->usExt_flag );

   }

/*
*
* A.2       IF (GDS struct is null) THEN
*               PRINT message
*           ELSE
*               TEST the Projection type, skip if not a supported one;
*               PRINT out all of its fields, values and type
*               SWITCH (type of projection)
*                 > LatLon (0), Gaussian (4), 
*                 > Rotated LatLon (10), Rotated Gaussian (14), 
*                 > Stretched LatLon (20), Stretched Gaussian (24), 
*                 > Stretched Rotated Latlon(30), Stretched Rotated Gauss(34):
*                      CAST the projection block to type GDS_LATLON_INPUT
*                      and print its fields, value and type;
*                 > Lambert (3), Albers (8), Oblique Lambert Conf (13):
*                      CAST the projection block to type GDS_LAM_INPUT
*                      and print its fields, value and type;
*                 > Polar (5):  
*                      CAST the projection block to type GDS_PS_INPUT
*                      and print its fields, value and type;
*                 default: PRINT error  !unsupported projection
*               ENDSWITCH
*           ENDIF
*/
  if (gds == NULL) {
	fprintf(stdout,"\n*** GDS is null ***\n");
	goto CHECK_BMS;
	}

  fprintf(stdout,"\n*** GDS_HEAD_INPUT ***\n"); 
  fprintf(stdout,"sizeof(GDS_GRIB + projblk)= ");
  p_ushort (gds->head.uslength);
  p_ushort (gds->head.usNum_v);
  p_ushort (gds->head.usPl_Pv);

  /* test to see if the Data type is out of bound, or if it's
 	currently not supported;  if so, print msg got print next section.
  */
  if (gds->head.usData_type >= (unsigned short) PRJ_COUNT ||
     strstr((char*)prjn_name[gds->head.usData_type],(char*)"Unsupported Grid"))
    {
	fprintf(stdout,
	"Warning:  Projection #%d is not supported, skip this section\n",
	gds->head.usData_type);
	goto CHECK_BMS;
    }
     
  p_string (prjn_name[gds->head.usData_type]);
  switch (gds->head.usData_type) 
       	 {
           case LATLON_PRJ:
           case GAUSS_PRJ:
           case ROT_LATLON_PRJ:
           case ROT_GAUSS_PRJ:
           case STR_LATLON_PRJ:
           case STR_GAUSS_PRJ :
           case STR_ROT_LATLON_PRJ :
           case STR_ROT_GAUSS_PRJ :
		   p_int (gds->llg.usNi);      
		   p_int (gds->llg.usNj);     
		   p_long (gds->llg.lLat1);   
		   p_long (gds->llg.lLon1);  
		   p_ushort (gds->llg.usRes_flag);
		   p_long (gds->llg.lLat2);    
		   p_long (gds->llg.lLon2);   
		   p_int (gds->llg.iDi);    
		   p_int (gds->llg.iDj);   
		   p_ushort (gds->llg.usScan_mode);

		   if (gds->head.usData_type == LATLON_PRJ ||
		       gds->head.usData_type == GAUSS_PRJ) 
		   break;

		   /* 	02/98
		   remaining code is for the Stretch/Rotate parameters 
		   */
		   p_long (gds->llg.lLat_southpole);
		   p_long (gds->llg.lLon_southpole);
		   fprintf(stdout,"gds->llg.lRotate (%ld) tofloat= %.3f\n",
		   gds->llg.lRotate , 
		   grib_ibm_local((unsigned long)gds->llg.lRotate));
		   p_long (gds->llg.lPole_lat);    
		   p_long (gds->llg.lPole_lon);   
		   fprintf(stdout,"gds->llg.lStretch (%ld) tofloat= %.3f\n"
		   ,gds->llg.lStretch, 
		   grib_ibm_local((unsigned long)gds->llg.lStretch));
		break;

	   case MERC_PRJ:
		   p_int (gds->merc.cols); 
		   p_int (gds->merc.rows);
		   p_long (gds->merc.first_lat); 
		   p_long (gds->merc.first_lon);
		   p_ushort (gds->merc.usRes_flag);          
		   p_long (gds->merc.La2); 
		   p_long (gds->merc.Lo2);
		   p_long (gds->merc.latin);
		   p_ushort (gds->merc.usScan_mode);          
		   p_float (gds->merc.lon_inc); 
		   p_float (gds->merc.lat_inc);
		break;

           case LAMB_PRJ:  
           case ALBERS_PRJ:  
           case OBLIQ_LAMB_PRJ:  
		   p_int (gds->lam.iNx);                 
		   p_int (gds->lam.iNy);                 
		   p_long (gds->lam.lLat1);               
		   p_long (gds->lam.lLon1);               
		   p_ushort (gds->lam.usRes_flag);          
		   p_long (gds->lam.lLon_orient);         
		   p_ulong (gds->lam.ulDx);                
		   p_ulong (gds->lam.ulDy);                
		   p_ushort (gds->lam.usProj_flag);         
		   p_ushort (gds->lam.usScan_mode);         
		   p_long (gds->lam.lLat_cut1);          
		   p_long (gds->lam.lLat_cut2);           

		   if (gds->head.usData_type == LAMB_PRJ) break;
		   p_long (gds->lam.lLat_southpole);      
		   p_long (gds->lam.lLon_southpole);      
		 break;

           case POLAR_PRJ:  
		   p_ushort (gds->pol.usNx);                
		   p_ushort (gds->pol.usNy);                
		   p_long (gds->pol.lLat1);               
		   p_long (gds->pol.lLon1);               
		   p_ushort (gds->pol.usRes_flag);          
		   p_long (gds->pol.lLon_orient);         
		   p_ulong (gds->pol.ulDx);                
		   p_ulong (gds->pol.ulDy);                
		   p_ushort (gds->pol.usProj_flag);         
		   p_ushort (gds->pol.usScan_mode);         
		 break;
		
	   default:  fprintf(stdout,
		"Warning:  print code not available for Projection %d\n",
		gds->head.usData_type);

          } /* SWitch */


CHECK_BMS:
/*
*
* A.3       IF (BMS_INPUT struct is null) THEN
*               PRINT message
*           ELSE
*               PRINT out all of its fields, values and type
*           ENDIF
*/
   
  if (bms_input==NULL || bms_input->uslength <= 0) 
      fprintf(stdout,"\n*** BMS_INPUT is Null (no bms)  ***\n"); 
  else {
      fprintf(stdout,"\n*** BMS_INPUT  ***\n"); 
      p_ushort (bms_input->uslength);
      p_ushort (bms_input->usUnused_bits);
      p_ushort (bms_input->usBMS_id);
      p_ulong (bms_input->ulbits_set);
      fprintf(stdout,"(not going to print CHAR *bit_map)\n");
    } 

/*
*
* A.4       IF (BDS_INPUT struct is null) THEN
*               PRINT message
*           ELSE
*               PRINT out all of its fields, values and type
*           ENDIF
*/
  if (bds_head_input == NULL) 
	fprintf(stdout,"\n*** BDS_HEAD_INPUT is null ***\n");
  else {
    fprintf(stdout,"\n*** BDS_HEAD_INPUT ***\n");
    p_ulong (bds_head_input->length);
    p_ushort (bds_head_input->usBDS_flag);
    p_int (bds_head_input->Bin_sc_fctr);
    p_float (bds_head_input->fReference); 
    p_ushort (bds_head_input->usBit_pack_num);
    p_ulong (bds_head_input->ulGrid_size);  
    p_float (bds_head_input->fPack_null);  
  }

/*
*
* A.5       IF (Float array is null) THEN
*               PRINT message
*           ELSE
*               PRINT out up to 100 of its values (after taking out
*               the Decimal Scale Factor)
*           ENDIF
*/
  if (ppfarr == 0) fprintf(stdout,"\n*** FLOAT array is null ***\n");
  else {
     farr= *ppfarr;
     fprintf(stdout,
	"\n*** FLOAT ARRAY has %ld elements (print upto first 100) ***\n",
	bds_head_input->ulGrid_size);

     if (pds != NULL) {
	D= pds->sDec_sc_fctr;
        fprintf(stdout,"Dec_sc_fctr=%d\n", D );
	}
    else { 
	D= 0; 
	fprintf(stdout,"No PDS avail, assume Dec Scl Fctr to be 0\n");
	}
	
     /* Data was scaled up in Pack_Spatial in order to get the INT values
	to pack, so now need to change it back to its true value by
 	taking out the Decimal Scale Factor 
     */
     if (D >= 0)
        for (i=0; i<(int)bds_head_input->ulGrid_size && i < 100; i=i+5)
        fprintf(stdout,"%3d-  %.*f  %.*f  %.*f  %.*f  %.*f\n", 
	i+1, 
	D, farr[i], D, farr[i+1], D, farr[i+2], D, farr[i+3], D, farr[i+4] );
     else 
        for (i=0; i<(int)bds_head_input->ulGrid_size && i < 100; i=i+5)
        fprintf(stdout,"%3d-  %.0f  %.0f  %.0f  %.0f  %.0f\n", 
	i+1, farr[i], farr[i+1], farr[i+2], farr[i+3], farr[i+4] );
   }
/*
*
* A.6       RETURN w/nothing
*
*/
  fprintf(stdout,"--- Leaving %s ---\n\n", func);

/*
*
* END OF FUNCTION
*
*/
}

/**************************************************************
 * C. FUNCTION:   grib_ibm_local
 *      convert local_float from IBM floating point to
 *      local floating point.
 *
 *    INTERFACE:
 *      float grib_ibm_local(ibm_float)
 *
 *    ARGUMENTS (I=input, O=output, I&O=input and output):
 *      (I)  double local_float      float value in local format
 *
 *     RETURNS:
 *        the actual local floating point
 **************************************************************
 */
float grib_ibm_local( unsigned long ibm_float)
{
/*
  Convert ibm_float from IBM floating point stored in a 4-byte integer 
  to local floating point.
*
* C.1       DETERMINE local floating point
*           ! IBM floating point is stored in 4 bytes as:  
*           ! saaaaaaa bbbbbbbb bbbbbbbb bbbbbbbb
*           ! where s is sign bit, 0 -> positive, 1 -> negative
*           !       a is 7-bit characteristic
*           !       b is 24-bit fraction
*           ! local_float (local 32-bit float) is recovered from 
*           ! s, a and b as
*           ! local_float = (-1)**s * 2**(-24) * b * 16**(a-64)
*/

    long a, b;
    float local_float;

    a = (ibm_float >> 24) & 0x0000007f;
    b = ibm_float & 0x00ffffff;
    local_float = (float) b * pow(16., (double) (a - 70));
    if (ibm_float >> 31) local_float = -local_float;
/*
*
* C.2       RETURN floating point
*/
    return local_float;
/*
* END OF FUNCTION
*
*/ 
}
