/*************************************************************************     
*                   ----------------
*                   |  CLEMDCMP    |
*                   ----------------
*
*_TITLE CLEMDCMP Decompress clementine image into various formats
* 
*_DESC  CLEMDCMP will decompress a clementine image and format it into 
*       one of three possible formats:
*       1) decompressed pds image file, with pds labels, the historgram
*           object, and an image object, either the browse image or
*           the full image
*       2) decompressed image file, no labels
*       3) decompressed gif image
*       4) decompressed tiff image
*
*       CLEMDCMP has four command-line arguments.  The first argument
*       indicates the output format of the decompressed image and
*       the following are the options:
*         -p = decompressed pds image file
*         -n = decompressed unlabeled file
*         -t = decompressed tiff file
*         -g = decompressed gif file
*       The second argument indicates which image object to output:
*         -i = full resolution image
*         -b = browse image
*       The third argument is the filename of the input compressed clementine 
*         data file.
*       The fourth argument is the filename of the output decompressed
*         clementine image.
*
*_HIST  Aug 27 1994  Tracie Sucharski, USGS, Flagstaff Original Version
*
**************************************************************************/

#include 
#include 
#include 

#include "pds.h"

#define MM_TYPE 0x4D4D
#define II_TYPE 0x4949
#define BLKSIZE 32768L

main(int argc, char *argv[])
{
  int c;                         /* character for command-line arguments */
  char format;                   /* Output file format */
  char img;                      /* Output image or browse image */
  char infile[128];              /* Input file name */
  char outfile[128];             /* Output file name */
  long lines;                    /* Number of lines and sample of image */
  long samps;
  int  i;                       
  FILE *fpi, *fpo;               /* Input and output file pointers */
  int ret;                       /* Return code */
  char b[2];
  short int *j;
  char bitord;
  unsigned int k, nblocks, rem;
  
  PDSINFO *p;

  int labmod(char *text, char img, char bitord);
  int writetif(FILE *fp, long nl, long ns, CHARH *buf, char bitord);

 

  for (i = 1; i < argc; i++) {
    if (argv[i][0] == '-') {
    argv[i][1] = tolower(argv[i][1]);
    switch (argv[i][1]) {
      case 'p': case 'n': case 'g': case 't':
	format = argv[i][1];
	break;
      case 'i': case 'b':
	img = argv[i][1];
	break;
      default:
	printf("ERROR:CLEMDCMP-Illegal option chosen %c\n", c);
	exit(1);
      }
  }
    else
      break;
  }

  if (argc-i != 2) {
    printf("ERROR:CLEMDCMP-You must specify an input and output file\n");
    exit(1);
  }

/*************************************************************************
*  Default is to output the full image in pds format
*************************************************************************/
  if (format == '\0') format = 'p';
  if (img == '\0') img = 'i';


  strcpy(infile, argv[i]);
  strcpy(outfile, argv[i+1]);


/************************************************************************
*  Determine the bit order
************************************************************************/

  j = (short int *) b;
  b[0] = 1;
  b[1] = 0;
  if (*j == 1) bitord = 'l';
  else bitord = 'm';


/****************************************************************************
*  The following call will open the compressed Clementine image and create
*  a structure containing the file objects.
****************************************************************************/
  p = PDSR(infile, &lines, &samps);

/****************************************************************************
*  If user chooses to output the browse image, make sure it exists.
****************************************************************************/
  if (img == 'b' && !(p->brw_imag)) {
    printf("ERROR:CLEMDCMP-This file does not contain a browse image");
    exit(1);
  }

/******************************************************************************
*  Open output file
******************************************************************************/
  fpo = fopen(outfile, "wb");

/*****************************************************************************
*  For the pds formatted option, the labels will need to be modified before 
*  writing out.  The uncompressed output file will either be the image or 
*  the browse image, so the pointer to the browse image will be deleted, 
*  and the image pointer will be modified to point to the start of the data.  
*  The pointer to the histogram will also need to be modified.  The 
*  ENCODING_COMPRESSION_RATIO will no longer be applicable, so the value is 
*  changed to "N/A". 
******************************************************************************/
  if (format == 'p') {
    printf("Writing PDS labeled file.\n");
    if (labmod(p->text, img, bitord) < 0) {
      printf("ERROR:CLEMDCMP-Error reformatting labels");
      exit(1);
    }
    fwrite(p->text, strlen(p->text), 1, fpo);
  }

/*****************************************************************************
*  If the output is a pds file write the histogram data followed by the image 
*  data, either the browse image or the full image.  If the output is an
*  unlabeled image file,  write only the image data out.
*****************************************************************************/
  if (format == 'p') fwrite(p->hist, sizeof(long), 256, fpo);

  if (format=='p' || format=='n') {
    if (format=='n') printf("Writing raw unlabeled file.\n");

    if (img == 'i') {
#ifdef __TURBOC__
      nblocks = (lines*samps) / BLKSIZE;
      rem = (lines*samps) % BLKSIZE;
      for (k=0; kimage+=BLKSIZE)
	fwrite(p->image,1,BLKSIZE,fpo);
      if ( rem > 0 )
	fwrite(p->image,1,rem,fpo);
#else
      fwrite(p->image, lines*samps, 1, fpo);
#endif
      if (format=='p')printf("PDS labeled file was successfully written.\n");
      if (format=='n') {
        printf("Raw unlabeled file was successfully written.\n");
	printf("\nThe size of the raw image created is %ld lines "
               "by %ld samples with no\n header or label data.\n\n", 
               lines, samps);
      }
    }

    if (img == 'b') {
      fwrite(p->brw_imag, p->browse_nrows*p->browse_ncols, 1, fpo);

      if (format=='p')printf("PDS labeled file was successfully written.\n");
      if (format=='n') {
	printf("Raw unlabeled file was successfully written..\n");
	printf("\n\nThe size of the raw image created is %ld lines "
	       "by %ld samples with no\n header or label data.\n\n", 
	       p->browse_nrows, p->browse_ncols);
      }
    }

  }


 
  if (format == 't') {    /*  TIFF format  */
    printf("Writing TIF file.\n");
    if (img == 'i') {
      if (writetif(fpo, lines, samps, p->image, bitord) < 0) {
	printf("ERROR:CLEMDCMP-Error writing full image in tiff format");
	exit(1);
      }
    }

    if (img == 'b') {  /* Write browse image */
      if (writetif(fpo, p->browse_nrows, p->browse_ncols, p->brw_imag, bitord) < 0) {
	printf("ERROR:CLEMDCMP-Error writing browse image in tiff format");
	exit(1);
      }
    }
    printf("TIF file was successfully written.\n");
  }
 
  if (format == 'g')  {   /*  GIF format  */
    if (img == 'i') {
      if (writegif(fpo, lines, samps, p->image) < 0) {
	printf("ERROR:CLEMDCMP-Error writing full image in gif format");
	exit(1);
      }
    }

    if (img == 'b') {
      if (writegif(fpo, p->browse_nrows, p->browse_ncols, p->brw_imag) < 0) {
	printf("ERROR:CLEMDCMP-Error writing browse image in gif format");
	exit(1);
      }
    }
  }	

  
  fclose(fpo);
  exit(0);
}





int labmod(char *text, char img, char bitord)
/*****************************************************************************
*
*_TITLE  LABMOD - modify the clementine label to reflect the decompression
*
*_ARGS    Type    Variable     I/O  Description
*_PARM    char    *text;        I   Pointer to clementine label
*_PARM    char    img           I   Image Type (Full image or browse image)
*_PARM    char    bitord        I   Bit order of current machine
*_PARM    int     *ret          O   Return code
*                                   0 - OK
*
*_DESC  LABMOD will modify the clementine label to reflect the decompression,
*       and the possible rearranging of the browse image and image object.
*
*_HIST  Apr 13 1994 Tracie Sucharski, USGS, Flagstaff Original Version
*       Jun 27 1994 Tracie Sucharski,  Fixed bug when writing out the
*                       browse image.
*       Jul 14 1994 Tracie Sucharski,  Changed output value of ENCODING_
*                       TYPE keyword.
*       Aug 23 1994 Tracie Sucharski,  Added NOTE to image object if the
*                       output image is the browse image,  also correct
*                       the DATA_TYPE keyword in the histogram object
*                       to indicate the correct byte order.
*
****************************************************************************/
{
    int lbllen;                     /* Length of incoming label */
    int nlbllen;                    /* Length of outgoing label */
    char *start, *end;              /* Index pointers */
    char sdummy[17];
    int nc;                         /* Number of characters */
    char byte[4];                   /* Starting bytes of objects */
    int hbyte;                      /* Starting byte of Image Historgram */
    int ibyte;                      /* Starting byte of Image */
    int bbyte;                      /* Starting byte of Browse Image */
    int diff;                       /* Difference in bytes between input */
                                    /* label and output label */
    char *labels;                   /* Temporary buffer to hold labels */


    lbllen = strlen(text);
    labels = (char *)malloc(lbllen);

    start = strstr(text, "^IMAGE_HISTOGRAM ");
    sscanf(start, "%s = %d", sdummy, &hbyte);

    start = strstr(text, "^IMAGE ");
    sscanf(start, "%s = %d", sdummy, &ibyte);

    start = strstr(text, "^BROWSE_IMAGE ");
    sscanf(start, "%s = %d", sdummy, &bbyte);

/****************************************************************************
*  Get rid of pointer to browse image.
****************************************************************************/
    end = strchr(start,'\n');
    strcpy(start, end+1);

/***************************************************************************
*  If browse image is being written, get rid of IMAGE object, rename
*  BROWSE_IMAGE object to IMAGE and add a note to indicate the output
*  image is the browse image.
***************************************************************************/
    if (img == 'b') {
      start = strstr(text, "OBJECT = IMAGE\n");
      end = strstr(start, "END_OBJECT");
      strcpy(start, end+11);

      start = strstr(text, " BROWSE_IMAGE");
      end = strchr(start, '\n');
      strncpy(labels, text, (start-text)+1);
      *(labels+(start-text+1)) = '\0';
      strcat(labels, "IMAGE");
      strcat(labels, end);
      strcpy(text, labels);

      end = strstr(start, "END_OBJECT");
      strncpy(labels, text, (end-text)+1);
      *(labels+(end-text)) = '\0';
      strcat(labels, "  NOTE          = \"Averaged subsampled EDR image\"\n");
      strcat(labels, end);
      strcpy(text, labels);

    }

    if (img == 'i') {

/**************************************************************************
*  Get rid of the BROWSE_IMAGE object.
***************************************************************************/
      start = strstr(text, "OBJECT = BROWSE_IMAGE");
      end = strstr(start, "END_OBJECT");
      strcpy(start, end+11);

/***************************************************************************
*  If writing IMAGE object change ENCODING_COMPRESSION_RATIO and
*  ENCODING_TYPE keyvalues to "N/A", since the output file is uncompressed.
***************************************************************************/
      start = strstr(text, "ENCODING_TYPE ");
      end = strchr(start, '\n');
      strncpy(labels, text, (end-text)-1);
      *(labels+(end-text-1)) = '\0';
      strcat(labels, " DECOMPRESSED\"");
      strcat(labels, end);
      strcpy(text, labels);

      start = strstr(text, "ENCODING_COMPRESSION_RATIO ");
      end = strchr(start, '\n');
      strncpy(labels, text, (start-text)+29);
      *(labels+(start-text+29)) = '\0';
      strcat(labels, "\"N/A\"");
      strcat(labels, end);
      strcpy(text, labels);

    }

/****************************************************************************
*  If the bitorder is MSB which is different from that in the label(LSB),
*  change the label.
****************************************************************************/
    if (bitord == 'm') {
      start = strstr(text, "LSB_INTEGER");
      *start = 'M';
    }

/****************************************************************************
*  Adjust the object pointers.
****************************************************************************/
    nlbllen = strlen(text);
    hbyte = nlbllen + 1;
    ibyte = hbyte + 1024;

/*****************************************************************************
*  Now that there are new pointer values, write them out to the labels.
*****************************************************************************/
    sprintf(byte, "%d", hbyte);
    nc = strlen(byte);
    start = strstr(text, "^IMAGE_HISTOGRAM ");
    strncpy(start+19, byte, nc);

    sprintf(byte, "%d", ibyte);
    nc = strlen(byte);
    start = strstr(text, "^IMAGE ");
    strncpy(start+19, byte, nc);

    free(labels);
    return(0);

}

    

/*************************************************************************
*                       ------------
*                       | WRITETIF |
*                       ------------
*
*_TITLE  WRITETIF  Writes decompressed Clementine data into TIF format
*
*_DESC   WRITETIF takes decompressed Clementine data and writes an 
*        uncompressed TIF formatted image.
*
*_HIST   May 04 1994  Tracie Sucharski, USGS, Flagstaff Original Version
*
*************************************************************************/

int writetif(FILE *fp, long nl, long ns, CHARH *buf, char bitord)
{
  unsigned int j, nblocks, rem; /* Added by Luis Perez 06/29/94 */

  int fputword(FILE *fp, short int n);
  int fputlong(FILE *fp, long n);


/********************************************************************
*  Write out the TIF header
********************************************************************/
  if (bitord == 'm')  fputword(fp, MM_TYPE);
  if (bitord == 'l')  fputword(fp, II_TYPE);
  fputword(fp,42);
  fputlong(fp,8L);

/********************************************************************
*  Construct the Image File Directory (IFD)
********************************************************************/
  fputword(fp, 8);     /* Eight Tags */

  fputword(fp, 254);   /* NewSubfileType */
  fputword(fp, 4);     /* Long */
  fputlong(fp, 1L);
  fputlong(fp, 0L);

  fputword(fp, 256);   /* ImageWidth */
  fputword(fp, 3);     /* Short */
  fputlong(fp, 1L);    
  if (bitord == 'm')
    fputlong(fp, ns*65536); /* Shift value into the two high order bytes */
  if (bitord == 'l')
    fputlong(fp, ns);

  fputword(fp, 257);   /* ImageLength */
  fputword(fp, 3);     /* Short */
  fputlong(fp, 1L);
  if (bitord == 'm')
    fputlong(fp, nl*65536);  /* Shift value into the two high order bytes */
  if (bitord == 'l')
    fputlong(fp, nl);

  fputword(fp, 258);   /* BitsPerSample */
  fputword(fp, 3);     /* Short */
  fputlong(fp, 1L);
  if (bitord == 'm') 
    fputlong(fp, 524288L); /* 8 Shifted into the two high order bytes */
  if (bitord == 'l')
    fputlong(fp, 8L);

  fputword(fp, 259);   /* Compression */
  fputword(fp, 3);     /* Short */
  fputlong(fp, 1L);
  if (bitord == 'm')
    fputlong(fp, 65536L);    /* No compression */
  if (bitord == 'l')
    fputlong(fp, 1L);

  fputword(fp, 262);   /* PhotometricInterpretation */
  fputword(fp, 3);     /* Short */
  fputlong(fp, 1L);
  if (bitord == 'm')
    fputlong(fp, 65536L);  /* 1 Shifted into the two high order bytes */
  if (bitord == 'l')
    fputlong(fp, 1L);

  fputword(fp, 273);   /* StripOffsets - Start of image data */
  fputword(fp, 4);     /* Long */
  fputlong(fp, 1L);
  fputlong(fp, 110L);

  fputword(fp, 277);   /* SamplesPerPixel */
  fputword(fp, 3);     /* Short */
  fputlong(fp, 1L);
  if (bitord == 'm')
    fputlong(fp, 65536L);
  if (bitord == 'l')
    fputlong(fp, 1L);

  fputlong(fp, 0L);

/***********************************************************************
*  Write image data
***********************************************************************/
  /*!!!!!! BE CAREFUL HERE !!!!!!*/
  /* The third argument in fwrite is of type size_t, which under Turbo C
     becomes an unsigned short int (16 bit integer). This means you have
     to write the image data out in blocks of 64K bytes or less (32K is a
     good number).
     Added by Luis Perez 06/29/94. */
#ifdef __TURBOC__
  nblocks = (nl*ns) / BLKSIZE;
  rem = (nl*ns) % BLKSIZE;
  for (j=0; j 0 )
	 fwrite(buf,1,rem,fp);
#else
  fwrite(buf, 1, nl*ns, fp);
#endif

  return(0);
 
}




int fputword(FILE *fp, short int n)
{
  fwrite(&n, 2, 1,fp);
  
}

int fputlong(FILE *fp, long n)
{
  fwrite(&n, 4, 1, fp);

}