/*
 * hdf2wsi.c
 *
 * Converts HDF NOWrad file from MSFC to WSI format.
 *
 * Install HDF4 (not HDF5) and refer to its include files and libraries when compiling: 
 * gcc -Wall -o hdf2wsi hdf2wsi.c -I/usr/local/hdf/include -L/usr/local/hdf/lib -lmfhdf \
 *  -ldf -ljpeg -lz
 *
 * usage: hdf2wsi hdffile [debug]
 * (here, debug is any argument)
 *---------------------------------------------------------------------------------------
 * Took out dependence on wsi_header file.  Hard-wired header info into source code.
 *
 * Removed everything from original readWSI.c source code, except for reading the HDF image data.
 * Added stuff to run-length encode the image in WSI's format (so gempak can read it). 
 * Right now, it uses the file './wsi_header' (in the same directory as 
 * the user) to get the header information. This forces the date to be 0000 UTC 1 Jan 1970.
 *  
 * Jan 2008 David Ahijevych
 *
 *
 * readWSI.c
 *
 * Version 1.0 10/27/95
 *
 * Written by: Paul J. Meyer
 * NASA/MSFC:  10/26/95
 *
 * 02/20/97 - corrected error:  tag and ref were not set to 0 before calling
 *	      Hfind for the first time.  This error did not affect SGI, but
 *            caused code to fail on Sun Solaris 2.4 with cc and gcc.
 *            Evans A Criswell
 *
 * 02/06/97 - corrected line 164 (combined into one line) Judy Fennelly
 *
 * 10/27/95 - Added additional command line parameters
 *          - Accounted that pixelTotals, and echoes.echoes might be 0
 *          - Determined whether a gif image was available for the hdf file
 * 10/28/95 - Added additional error checks, comments
 *          - Bypassed status code check if status data not available
 *          - Corrected bug when no path component included in hdfName
 * 01/22/95 - Converted from meta file generation software to a simple
 *            data reader program.
 *
 *
 * The purpose of this program is to extract meta information from WSI nowrad
 * data files which have been translated into HDF file format.
 * It also shows how to read the HDF formatted data file.
 *
 */


#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "hdf.h"


enum boolean { False, True } ;

int main(int argc, char **argv)
{

    long  hdfId;                  /* File identifier for the hdf file */


    uint16 tag;                   /* Tag for the Annotation */
    uint16 ref;                   /* Reference # for the annotation */
    int32 findOffset;             /* Offset into the file for the annotation */
    int32 findLength;             /* Length of the annotation block */

    short descBufSize;            /* Size of the description buffer */

    int width;                    /* width of the image (columns) */
    int height;                   /* height of image (rows) */
    int ispal;                    /* Is there a palette associated with the image */

    int nel;                      /* counter for looping thru each element (column) */
    unsigned short nline;         /* counter variable for looping thru each line */
    unsigned int drun, dcolr, old_dcolr;
    unsigned char rle1;

    int lastHdf_refI;             /* The most recently referenced HDF image */

    int expectedArgs;             /* expected # of command line arguments */

    int debug;                    /* Do we perform debug output lines */
    char *descBuf;                /* Pointer to the annotation buffer */

    char *labelBuf;               /* Hdf image annotation */
    int  labelBuf_sz;


    char *progName;               /* Handle to name of this program */
    char *hdfName;                /* Input file name */
    FILE  * wsifp;                /* pointer to wsi output file */

    char *lastSlash;              /* Last / in a pathname */

    char hdfFile[256];            /* Base Name of the hdf File */
    char wsiNAME[256];            /* Output file name */
    char hh_UTC[3];               /* UTC time read from description buffer */
    char mm_UTC[3];               /* UTC time read from HDF desc buffer */
    char dd[3];                   /* day read from HDF desc buff */
    char month[5];                /* 3-char month from HDF desc buff */
    char yy[3];                   /* year read from HDF desc buff */

    unsigned char *inputImage;    /* Pointer to the Radar image data */


    /*****************************************************************************/

    progName = argv[0];

    expectedArgs = 2;
    if (argc < expectedArgs) {
	fprintf(stderr, "Usage: %s hdfName (debug)\n", progName);
	exit(1);
    }

    debug = (argc > expectedArgs) ? True : False;

    hdfName = argv[1];

    /* Obtain the location of the Base HDF file name */
    /* Of course the `basename()` routine works as well (hindsight 20-20) */
    lastSlash = strrchr(hdfName, '/');
    if (lastSlash) {          /* Was there a slash '/' in input name? */
        lastSlash++;          /* get to actual file name, next char after '/'
*/
    } else {
        lastSlash = hdfName;  /* no '/' in the input name */
    }

    /* Obtain the basename of the hdf files fully qualified path name */
    strcpy(hdfFile, lastSlash);

    /* Open hdf file */

    hdfId = Hopen(hdfName, DFACC_READ, 0);

    tag = 0;
    ref = 0;

    if (Hfind(hdfId, DFTAG_RIG, DFREF_WILDCARD, &tag, &ref, &findOffset,
        &findLength, DF_FORWARD) == FAIL) {
        fprintf(stderr, "Error finding a reference tag\n");
        exit(1);
    }


    /* Now determine the size of and obtain the description buffer */
    if ((descBufSize = DFANgetdesclen(hdfName, tag, ref)) == FAIL) {
        fprintf(stderr, "Error determining description buffer length\n");
        exit(1);
    }


    if((descBuf = (char *) calloc(descBufSize+1, sizeof(char))) == NULL) {
        fprintf(stderr, "Error obtaining memory for description buffer\n");
        exit(1);
    }

    if (debug) {fprintf(stderr, "Allocated space for Description buffer\n");}

    if ((DFANgetdesc(hdfName, tag, ref, descBuf, descBufSize)) == FAIL) {
        fprintf(stderr, "Error obtaining description buffer\n");
        exit (1);
    }

    /* Get day and month strings from description buffer (bytes 132-133 and 135-138) */
    if (debug) {fprintf(stdout, "%s", descBuf);}
    memmove(dd, descBuf+132, 2);
    dd[2]='\0';
    memmove(month, descBuf+135, 3);
    month[3]='\0';
    fprintf(stderr,"day and month from HDF description: %s-%s\n", dd, month);

    /* Read image data */

    if ( DFR8getdims(hdfName, (int32 *) &width, (int32 *) &height, &ispal) != 0 ) {
       fprintf(stderr,"Error reading dimensions of the RIS8 image \n");
       exit(1);
    }

    /* Allocate space for input image */
    inputImage = (unsigned char *) calloc (width * height, sizeof (unsigned char));
    if (!inputImage) {
        fprintf(stderr, "%s: Error allocating memory for input image\n", progName);
        exit (1);
    }

    /* Read image data into memory */
    if(DFR8getimage(hdfName, inputImage, width, height, NULL) != 0 ) {
        fprintf(stderr,"%s: Error in reading the RIS8 image \n", progName);
        exit(1);
    }


    /* Obtain the annotation label */
    if ((lastHdf_refI = DFR8lastref() ) != -1 ) {
        if ((labelBuf_sz = DFANgetlablen(hdfName, DFTAG_RIG,
	          lastHdf_refI)) != -1 ) {
            labelBuf = (char *) calloc(labelBuf_sz+1, sizeof(char));
	     }
        /* grab the hour, minute, and year from it */
	     if (DFANgetlabel(hdfName, DFTAG_RIG, lastHdf_refI,
	         labelBuf, labelBuf_sz) != -1 ) {
            fprintf(stderr,"HDF Label: %s\n", labelBuf);
            strncpy(hh_UTC, labelBuf, 2);
            hh_UTC[2]='\0';
            memmove(mm_UTC, labelBuf+2, 2);
            mm_UTC[2]='\0';
            memmove(yy, labelBuf+5, 2);
            yy[2]='\0';
            fprintf(stderr,"2-digit year and time from HDF image annotation label: %s %s:%s UTC\n", yy, hh_UTC, mm_UTC);
	     }
    }


    if (debug) {
        fprintf(stderr,"hdfFile = %s\n", hdfFile);
        fprintf(stderr,"strlen(hdfFile) = %d\n", strlen(hdfFile));
        fprintf(stderr,"strlen(wsiNAME) = %d\n", strlen(wsiNAME));
    }

    strncpy (wsiNAME, hdfFile, 12);
    wsiNAME[12] = '\0';
    strcat (wsiNAME,".MASTER15");
    if (debug) {fprintf(stderr, "wsiNAME=%s\n", wsiNAME);}
    wsifp = fopen (wsiNAME, "wb");
    if (wsifp == NULL) {fputs("file error", stderr); exit(1);}

    /* write WSI header */
    putc(0x00, wsifp);
    putc(0xf0, wsifp);
    putc(0x09, wsifp);
    putc(0x15, wsifp);
    fputs("NA   ", wsifp);
    /* Put date/times grabbed from the HDF file into the WSI header */
    fputs(hh_UTC, wsifp);
    fputs(":", wsifp);
    fputs(mm_UTC, wsifp);
    fputs(" NOWRADHD  ", wsifp);
    putc(0x15, wsifp);
    putc(0x00, wsifp);
    putc(0xf0, wsifp);
    putc(0x0a, wsifp);
    fputs("1837 3661", wsifp);
    putc(0x00, wsifp);
    putc(0xf0, wsifp);
    putc(0x03, wsifp);
    fputs("NOWrad Master Sector", wsifp);
    fputs(hh_UTC, wsifp);
    fputs(":", wsifp);
    fputs(mm_UTC, wsifp);
    fputs(" ", wsifp);
    fputs(dd, wsifp);
    fputs("-", wsifp);
    fputs(month, wsifp);
    fputs("-", wsifp);
    fputs(yy, wsifp);
    fputs("                                             ", wsifp);
    putc(0x00, wsifp);
    putc(0xf0, wsifp);
    putc(0x0b, wsifp);
    fputs("C -1.658063e+00 9.250243e-01 -6.108653e-01 3.135320e-04 3.337150e-04", wsifp);
    
    /* I used to read the header from an old file and use fseek(wsifp, 0, SEEK_END);  to jump around */
    /* Done with header. Move on to image array */
 
    // Write run length encoded (RLE) pixels of image array.  Start anew at each new image line.
    for (nline = 1; nline <= height; nline++){
      //  write new line flag
      putc(0x00, wsifp);
      putc(0xf0, wsifp);
      putc(0x0c, wsifp);
      //  write line number (byte swapped)
		putc(nline<<8>>8, wsifp);
		putc(nline>>8, wsifp);
      if (debug && nline % 100 == 0) { fprintf (stderr, "%d ", nline);}
		drun = 0;
      for (nel = 0; nel < width; nel++){
			dcolr = inputImage[(nline-1)*width+nel];
			if (drun > 0 && (dcolr != old_dcolr || drun == 65536 || nel == width-1)) {
				if (nel == width-1) {drun++;}
				// One-byte RLE.  High nibble is drun-1, low nibble is dcolr.
				if (drun <= 13) {
					rle1 = old_dcolr + 16*(drun-1);
					putc(rle1, wsifp);
				} else if (drun <=256) {
				// Two-byte RLE.  High nibble of first byte is 0xe, low nibble is dcolr.
				// Second byte is drun-1.
					rle1 = old_dcolr + 16*0xe;
					putc(rle1, wsifp);
					putc(drun-1, wsifp);
				}  else {
				// Three-byte RLE.  High nibble of first byte is 0xd, low nibble is dcolr.
				// Second byte and third bytes are drun-1, byte swapped.
					rle1 = old_dcolr + 16*0xd;
					putc(rle1, wsifp);
					putc(((drun-1)<<8)>>8, wsifp);
					putc((drun-1)>>8, wsifp);
				}

			   if (debug) {fprintf(stderr, "(%d,%d)=%d,drun=%d ", nel, nline, dcolr, drun);}
				drun = 0;
			} 
			drun++;
			old_dcolr = dcolr;
		}
    }
    //  end of data flag
    putc(0x00, wsifp);
    putc(0xf0, wsifp);
    putc(0x02, wsifp);
    fclose(wsifp);
    fprintf(stderr, "wrote %s\n", wsiNAME);

    free (inputImage);
    free (labelBuf);
    free (descBuf);

    Hclose (hdfId);

    exit(0);
}

