/*  wdt Copyright (c) 2001 Weather Decision Technologies, Inc. 2001-03-23 GMB
*
*   mergesat.c
*
*   Program to merge multiple ARPS satellite format files which cover the
*   same domain.  Non-missing values are averaged.
*
*   The program also writes an hdf image file for diagnostics.
*
*   This program was adapted from mci2arps written by:
*     Keith Brewster
*     CAPS/Univ of Oklahoma
*     September, 1997
*
*   WARNING - This code is untested.
*   Updated to handle 64-bit issues.  Changes are same as in "mci2arps.c".
*   Kevin W. Thomas
*   August, 2004.
*
*/

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>

#include "hdf.h"

#ifdef UNDERSCORE
  #define wtsatfld wtsatfld_
  #define ld2dgrid ld2dgrid_
  #define checkgrid2d checkgrid2d_
#endif
void wtsatfld();
void ld2dgrid();
void checkgrid2d();

int fill_flg = 1; /* no hole filling - 0, fill missing - 1 */

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

  Main program

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

main(argc,argv)
 
int argc;
char *argv[];
 
{

/* Input satellite data variables */

  int fd_sat;
  uint8 *sat_image;
  uint8 pix_val;
  int pix_int;

/* Remapping variables */

  int one=1;
  int two=2;
  float xp,yp;

/* ARPS grid variables */

  int nx_arps;
  int ny_arps;
  long grid_size;
  long nfield;
  float dx_arps;
  float dy_arps;
  float xnw,ynw;

/* ARPS output variables */

  float *satfld;
  float *satfld_in;
  float *sattot;
  int *satcnt;
  char arunnam[81] = {81*'\0'};
  char varname[7] = {7*'\0'};
  char outfname[101] = {101*'\0'};
  char satname[7];

  uint8 colors[256*3];
  uint16 status;
  char hdffname[100] = {100*'\0'};

  char rawfname[100] = {100*'\0'};
  int fd_raw;

  float miss_val=-999;

/* Misc local variables */

  int ireturn;
  long i,ii,ii2,j,jj,k,kk,koff,kmci,irad,iser,jser;
  long grid_i,grid_j,grid_k;
  long sum,knt,brite;
  uint8 abyte,bbyte;
  uint16 a2byte,b2byte;
  float fi,fj;
  /* Don't worry about source or time info in adas sat data file */
  long isource=0;
  long year=0,month=0,day=0,hour=0,min=0,sec=0;
  float sat_ctrlat=0,sat_ctrlon=0; /* variables meaningless in merged file */

  int mapproj;
  float dx,dy,ctrlat,ctrlon,trulat1,trulat2,trulon,sclfct;
  int nx_in,ny_in,nfield_in,mapproj_in;
  float dx_in,dy_in,ctrlat_in,ctrlon_in,trulat1_in,trulat2_in,
        trulon_in,sclfct_in;
  int grid_stat;

  long n_read;
  float f;
  int itbl;
  float xpix,ypix;

  int c;
  extern char *optarg;
  extern int optind;
  int errflg=0;
  int firstind;

  int dmpfmt;
  int hdf4cmpr;

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

  Begin executable code

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

  dmpfmt = 1;
  hdf4cmpr = 0;

  if( errflg || argc <= 2 ) {
      fprintf(stderr, " Usage: %s ", argv[0]);
      fprintf(stderr, 
         "[-b|-h 0-6] <file1> [<file2> ...] <Merged_arps_sat_file>\n");
      exit(1);

   }

  while ((c = getopt(argc, argv, "bh:")) != EOF) {
    switch (c) {
      case 'h':
         dmpfmt = 2;
         sscanf(optarg,"%d",&hdf4cmpr);
         printf("Write HDF4 format data with compression option %d.\n",hdf4cmpr);
         break;
      case 'b':
         dmpfmt = 1;
         printf("Write binary format data.\n");
         break;
      case '?':
         errflg++;
         break;
    }
  }

  firstind = optind;
  for (; optind < argc-1; optind++) { /* process each data file */

    printf("Reading %s\n",argv[optind]);
    if( (fd_sat = open(argv[optind],0)) == -1 ) {
        fprintf(stderr,"Unable to open arps format satellite data file %s\n",
           argv[optind] );
        exit(1);
     }

     /* read in header information */

  /* From SUBROUTINE rdsatfld in rdsatfld.f90:

  CHARACTER (LEN=6) :: satname
  CHARACTER (LEN=6) :: fldname(nfield)
  REAL :: satfld(nx,ny,nfield)
  CHARACTER (LEN=80  ) :: runname

    READ (iunit,ERR=200) satname
    READ (iunit,ERR=200) nxin,nyin,nfieldin,itime,idummy,               &
                         idummy,idummy,idummy,idummy,idummy
    READ (iunit,ERR=200) dummy_name
    READ (iunit,ERR=200) idummy,idummy,mprojin,idummy,idummy,          &
                 idummy,idummy,idummy,idummy,idummy
    READ (iunit,ERR=200) dxin,dyin,rdummy,rdummy,ctrlatin,  &
                 ctrlonin,trlat1in,trlat2in,trlonin,sclfctin,  &
                 latsat,lonsat,rdummy,rdummy,rdummy
    READ(iunit,ERR=200) fldname
    READ(iunit,ERR=200) satfld
  */

     /* satname - skip */
     lseek(fd_sat,14L,1);

     /* nx,ny,nfield */

     lseek(fd_sat,4L,1);
     read(fd_sat,&nx_in,4); 
     read(fd_sat,&ny_in,4); 
     read(fd_sat,&nfield_in,4); 
     lseek(fd_sat,32L,1);

     if (nfield_in != 1) {
       fprintf(stderr,"ERROR, nfield != 1 (%d)\n",nfield_in);
     }

     if (optind == firstind) {
       nx_arps = nx_in;
       ny_arps = ny_in;
       nfield = 1;
     }

     /* runname - skip */

     lseek(fd_sat,88L,1);

     /*  mapproj */

     lseek(fd_sat,12L,1);
     read(fd_sat,&mapproj_in,4);
     lseek(fd_sat,32L,1);
     if (optind == firstind) {
       mapproj = mapproj_in;
     }

     /* dx,dy,ctrlat,ctrlon,trulat1,trulat2,trulon,sclfct */

     lseek(fd_sat,4L,1);
     read(fd_sat,&dx_in,4);
     read(fd_sat,&dy_in,4);
     lseek(fd_sat,8L,1);
     read(fd_sat,&ctrlat_in,4);
     read(fd_sat,&ctrlon_in,4);
     read(fd_sat,&trulat1_in,4);
     read(fd_sat,&trulat2_in,4);
     read(fd_sat,&trulon_in,4);
     read(fd_sat,&sclfct_in,4);
     lseek(fd_sat,24L,1);
     if (optind == firstind) {
       dx = dx_in;
       dy = dy_in;
       ctrlat = ctrlat_in;
       ctrlon = ctrlon_in;
       trulat1 = trulat1_in;
       trulat2 = trulat2_in;
       trulon = trulon_in;
       sclfct = sclfct_in;
     }

     /* check grid information */
     
     if (optind == firstind) {
       ld2dgrid(&dx,&dy,&ctrlat,&ctrlon,
                &mapproj,&trulat1,&trulat2,&trulon,&sclfct);
     } else {
       checkgrid2d(&nx_arps,&ny_arps,&nx_in,&ny_in,
                   &dx,&dy,&ctrlat,&ctrlon,
                   &mapproj,&trulat1,&trulat2,&trulon,&sclfct,
                   &dx_in,&dy_in,&ctrlat_in,&ctrlon_in,
                   &mapproj_in,&trulat1_in,&trulat2_in,&trulon_in,&sclfct_in,
                   &grid_stat);
       if (grid_stat != 0) {
         fprintf(stderr,"ERROR: grids don't match between files (%s & %s)\n",
                 argv[firstind],argv[optind]);
       }
     }

     /* fldname */

     lseek(fd_sat,4L,1);
     if (optind == firstind) {
       n_read = read(fd_sat,varname,6);
       if (n_read != 6) {
         fprintf(stderr,"ERROR reading varname (only %d bytes read)\n",n_read);
         exit(1);
       }
     } else {
       lseek(fd_sat,6L,1);
     }
     lseek(fd_sat,4L,1);

     /* satfld */

     if (optind == firstind) { /* Allocate memory for ARPS output */
       grid_size=nx_arps*ny_arps;
       satfld_in = (float *)malloc(sizeof(float)*grid_size );
       satfld = (float *)malloc(sizeof(float)*grid_size ); 
       sattot = (float *)malloc(sizeof(float)*grid_size ); 
       satcnt = (int *)malloc(sizeof(int)*grid_size ); 
       for (ii=0; ii<grid_size; ii++) {
         satfld[ii] = miss_val;
         sattot[ii] = 0.;
         satcnt[ii] = 0;
       }
     }

     lseek(fd_sat,4L,1);

     n_read = read(fd_sat,satfld_in,nx_arps*ny_arps*nfield*4);
     if (n_read != nx_arps*ny_arps*4) {
       fprintf(stderr,
          "ERROR reading satellite data (read only %d of %d bytes)\n",
          n_read,nx_arps*ny_arps*4);
       exit(1);
     }
     lseek(fd_sat,4L,1);

     for (ii=0; ii<grid_size; ii++) {
       if (satfld_in[ii] != miss_val) {
/*if (satcnt[ii] == 1) {
 *printf("XXX %5.1f %5.1f\n",sattot[ii],satfld_in[ii]); } */
         sattot[ii] = sattot[ii] + satfld_in[ii];
         satcnt[ii] = satcnt[ii] + 1;
       }
     }

  } /* end loop for processing each data file */

  for (ii=0; ii<grid_size; ii++) {
    if (satcnt[ii] > 0) {
      satfld[ii] = sattot[ii]/satcnt[ii];
    }
  }

  strcpy(satname, "merged\0");

/* Fill any missing using average of neighbors */

  if (fill_flg == 1) {
    printf(" Hole Filling\n");
    for ( j = 0; j < ny_arps ; j++ ) {
       for ( i = 0; i < nx_arps ; i++ ) {
          k = i + (j*nx_arps);
          if ( *(satcnt+k) == 0 ) {
             for ( irad = 1; irad < 5 ; irad++) {
                sum = 0;
                knt = 0;
                for ( ii = -irad; ii < (irad+1) ; ii++ ) {
                   iser = i+ii;
                   if ( iser > -1 && iser < nx_arps ) {
                      for ( jj = -irad; jj < (irad+1) ; jj++) {
                         jser = j+jj;
                         if( jser > -1 && jser < ny_arps ) {
                            kk = iser + (jser*nx_arps);
                            if( *(satcnt+kk) > 0) {
                               sum = sum + *(sattot+kk);
                               knt = knt + *(satcnt+kk);
                            }
                         }
                      }
                   }
                }
                if ( knt > 0 ) {
                   *(satfld+k) = ((float)sum)/((float)knt);
                   break;
                }
             }
          }
       }
    }
  }
 
/* Write out results */


  sat_image = (uint8 *)malloc(sizeof(uint8)*grid_size );

  if (strncmp(varname,"satctt",6) == 0) {
    for (ii=0; ii<grid_size; ii++) {
      if (satfld[ii] == miss_val) {
        sat_image[ii] = 0;
      } else {
        if (satfld[ii] >= 240.) {
          pix_int = (420. - satfld[ii] + 0.5);
          if (pix_int < 255) {
            sat_image[ii] = pix_int;
          } else {
            sat_image[ii] = 1;
          }
        } else {
          pix_int = (660. - 2.*satfld[ii] + 0.5);
          if (pix_int > 1) {
            sat_image[ii] = pix_int;
          } else {
            sat_image[ii] = 255;
          }
        }
      }
    }
  } else if (strncmp(varname,"satalb",6) == 0) {
    for (ii=0; ii<grid_size; ii++) {
      if (satfld[ii] == miss_val) {
        sat_image[ii] = 0;
      } else {
        pix_int = (satfld[ii] * 254. + 0.5);
        if (pix_int > 254) {
          pix_int = 1;
        } else if (pix_int < 2) {
          pix_int = 255;
        }
        sat_image[ii] = pix_int;
      }
    }
  } else {
    fprintf(stderr, 
       "WARNING: unknown varname %s, blank 8-bit image made.\n", varname);
    for (ii=0; ii<grid_size; ii++) {
      sat_image[ii] = 0;
    }
  }

  /* flip the image */
  for (j=0; j<ny_arps/2; j++) {
    ii = j*nx_arps;
    ii2 = (ny_arps-j-1)*nx_arps;
    for (i=0; i<nx_arps; i++) {
      pix_val = sat_image[ii+i];
      sat_image[ii+i] = sat_image[ii2+i];
      sat_image[ii2+i] = pix_val;
    }
  }

/*
 *  sprintf( outfname, "%s.%s", argv[argc-1],varname );
 *  printf( " Output file name: %s\n",outfname);
 *  sprintf( hdffname, "%s.%s.hdf", argv[argc-1],varname );
 *  printf( " hdf image file name: %s\n",hdffname);
 *  sprintf( rawfname, "%s.%s.raw", argv[argc-1],varname );
 *  printf( " raw image file name: %s\n",rawfname);
 */
  sprintf( outfname, "%s", argv[argc-1] );
  printf( " Output file name: %s\n",outfname);
  sprintf( hdffname, "%s.hdf", argv[argc-1] );
  printf( " hdf image file name: %s\n",hdffname);
  sprintf( rawfname, "%s.raw", argv[argc-1] );
  printf( " raw image file name: %s\n",rawfname);

/*   Call FORTRAN routine to write ARPS gridded data */

  printf(" Calling FORTRAN write routine\n");
  nfield=1;
  wtsatfld(&nx_arps,&ny_arps,&nfield,
            outfname,satname,&sat_ctrlat,&sat_ctrlon,
            &year,&month,&day,&hour,&min,&sec,&isource,
            &dmpfmt,&hdf4cmpr,varname,satfld);
  printf(" Back from FORTRAN write routine\n");

/*   Write out raw image file */

  fd_raw = creat(rawfname,0664);
  write(fd_raw,sat_image,grid_size);
  close(fd_raw);

/*   Get the palette data from file. */

  status = DFPgetpal("palgrey.hdf",colors);
  printf("DFPgetpal return status: %d\n",status);

/*   Set the current palette. */

  status = DFR8setpalette(colors);
  printf("DFR8setpalette return status: %d\n",status);

/*   Write the image data to the file. */

  status=DFR8putimage(hdffname,sat_image,nx_arps,ny_arps,0);
  printf("DFR8putimage return status: %d\n",status);

  exit(0);

}