
/* Arguments: input file, output file */

#include        <ctype.h>
#include        <strings.h>
#include        <string.h>
#include        <stdlib.h>
#include        <stdio.h>
#include        <errno.h>
#include        <time.h>

#include        "../../../lib/PPVL-1.10/PPVL.h"
#include        "../../../lib/PPVL-1.10/PPVL_selections.h"

typedef char          *Text;
typedef char unsigned  Byte;
typedef float (*funcptr)( long );

enum Data_order_code
        {
        DATA_ORDER_MSB_FIRST,
        DATA_ORDER_LSB_FIRST
        };

static int Data_order;

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

  PPVL_Parameter *theAggregate, *thisParameter, *theParent, *notesAggregate,
                 *bandbinAggregate, *cubeAggregate, *tempParameter,
		 *calibAggregate, *targetAggregate;
  PPVL_Value     **seq;
  unsigned long  total_scanned;
  static long    Record_bytes, Label_records, File_records, History_record,
                 Image_record, Image_dimensions[3], Pixel_bytes,
		 Suffix_bytes[3], Suffix_multiplier, Data_region[6];
  static Text    Record_type, Data_type_name, Samp_Suffix_type,
                 Band_Suffix_type, Mission_name, Power_state[2],
		 Gain_mode[2], Sampling_mode[3], Prep_done;
  Byte           *Cube_data, *Side_plane_data, *Back_plane_data,
                 *Bottom_plane_data;
  static double  Exposure_duration[2], Detector_temp[3], Optics_temp[3];

  Byte		 *trans_short_long(Byte infile[], long dsize);
  void           swap_bytes(Byte indata[], long dsize);
  void           swap_bytes_4(Byte indata[], long dsize);
  static int     Data_Order();

  funcptr        bp_trans(char*, char*);
  funcptr        funcs[10];
  char           units[10][64];

  short          dataval;

  int            i, j, temp, rdiff = 0, diff = 0, doswap = 0, Total_lines,
                 Total_bands, line, band, band_suffix, native, badfile,
		 extradatabytes, extradatarecs, head_recs, pad_out;
  long           offset, Line_bytes, Samp_suffix_bytes, Band_suffix_bytes,
                 offset_before, offset_after, tmplong, tmplong2;
  float	         tmpfloat;
  FILE           *infile, *outfile;
  Byte           *line_data, *samp_suffix_data, *band_suffix_data,
                 *out_samp_suffix_data, *out_band_suffix_data;
  char*          version  = "1.0";
  char           *date, *datechomp, *tempc, tmpstr[255], tmptext[64], buff[10],
                 history_line[256];
  time_t         timer;
  int            ivalue,nread;
  double         rvalue;
  const char*    mynull="\0";


  static PPVL_Parameter_Selections
    Parameter_selection_list[] = {
      {"RECORD_TYPE",              PPVL_TYPE_STRING,  1, &Record_type},
      {"RECORD_BYTES",             PPVL_TYPE_INTEGER, 1, &Record_bytes},
      {"FILE_RECORDS",             PPVL_TYPE_INTEGER, 1, &File_records},
      {"LABEL_RECORDS",            PPVL_TYPE_INTEGER, 1, &Label_records},
      {"/^HISTORY",                PPVL_TYPE_INTEGER, 1, &History_record},
      {"/^QUBE",                   PPVL_TYPE_INTEGER, 1, &Image_record},
      {"/QUBE/CORE_ITEMS",         PPVL_TYPE_INTEGER, 3, &Image_dimensions},
      {"/QUBE/CORE_ITEM_TYPE",     PPVL_TYPE_STRING,  1, &Data_type_name},
      {"/QUBE/CORE_ITEM_BYTES",    PPVL_TYPE_INTEGER, 1, &Pixel_bytes},
      {"/QUBE/SUFFIX_ITEMS",       PPVL_TYPE_INTEGER, 3, &Suffix_bytes},
      {"DATA_REGION",              PPVL_TYPE_INTEGER, 6, &Data_region},
      {"/QUBE/SUFFIX_BYTES",       PPVL_TYPE_INTEGER, 1, &Suffix_multiplier},
      {"SAMPLE_SUFFIX_ITEM_TYPE",  PPVL_TYPE_STRING,  1, &Samp_Suffix_type},
      {"BAND_SUFFIX_ITEM_TYPE",    PPVL_TYPE_STRING,  1, &Band_Suffix_type},
      {"MISSION_NAME",             PPVL_TYPE_STRING,  6, &Mission_name},
      {"POWER_STATE_FLAG",         PPVL_TYPE_STRING,  2, &Power_state},
      {"GAIN_MODE_ID",             PPVL_TYPE_STRING,  2, &Gain_mode},
      {"EXPOSURE_DURATION",        PPVL_TYPE_REAL,    2, &Exposure_duration},
      {"DETECTOR_TEMPERATURE",     PPVL_TYPE_REAL,    3, &Detector_temp},
      {"OPTICS_TEMPERATURE",       PPVL_TYPE_REAL,    3, &Optics_temp},
      {"SAMPLING_MODE_ID",         PPVL_TYPE_STRING,  3, &Sampling_mode},
      {"CUBE_PREP",                PPVL_TYPE_STRING,  1, &Prep_done},


      PPVL_PARAMETER_SELECTIONS_END
      };


  if (argc < 2) {
    printf ("Usage: cube_prep in_cube_filename out_cube_filename [swap]\n");
  return;
  }

  if (!(infile = fopen(argv[1], "r"))) {
    printf("ERROR: can't open input file %s\n",argv[1]);
  return;
  }

  /* Read header. */
  theAggregate = PPVL_read_aggregate (infile, 0, &total_scanned);

  /* Get all the header info we need to process the data. */
  i = PPVL_selections(theAggregate,Parameter_selection_list);

  printf ("Prep_done = %s\n",Prep_done);

  /* Open output file. */
  outfile = fopen(argv[2], "wb");

   /* If the user gave a 3rd argument, swap bytes. */
  if (argc >= 4) doswap = 1;

  /* If needed, change the CORE_ITEM_TYPE and other ITEM_TYPEs if doswap */
  if (doswap) {
    if (strcmp(Data_type_name, "SUN_INTEGER") == 0) {
      thisParameter = PPVL_find_parameter(theAggregate,
                                          PPVL_SEARCH_FROM_THE_TOP,
                                          PPVL_SELECT_NAME,
                                          "CORE_ITEM_TYPE",
                                          &theParent);
      if (thisParameter) thisParameter->content.value->data.string ="PC_INTEGER";

      thisParameter = PPVL_find_parameter(theAggregate,
                                          PPVL_SEARCH_FROM_THE_TOP,
                                          PPVL_SELECT_NAME,
                                          "SAMPLE_SUFFIX_ITEM_TYPE",
                                          &theParent);
      if (thisParameter) {
        if (PPVL_Type_Is_Sequence(thisParameter->content.value->type)) {
          seq = thisParameter->content.value->data.array;
          for (i=0; i < PPVL_count_all_values(thisParameter->content.value); i++) {
            seq[i]->data.string = "PC_INTEGER";
          }
        } else {
          thisParameter->content.value->data.string = "PC_INTEGER";
        }
      }

      thisParameter = PPVL_find_parameter(theAggregate,
                                          PPVL_SEARCH_FROM_THE_TOP,
                                          PPVL_SELECT_NAME,
                                          "BAND_SUFFIX_ITEM_TYPE",
                                          &theParent);
      if (thisParameter) {
        if (PPVL_Type_Is_Sequence(thisParameter->content.value->type)) {
          seq = thisParameter->content.value->data.array;
          for (i=0; i < PPVL_count_all_values(thisParameter->content.value); i++) {
            seq[i]->data.string = "PC_INTEGER";
          }
        } else {
          thisParameter->content.value->data.string = "PC_INTEGER";
        }
      }
    } else {
      thisParameter = PPVL_find_parameter(theAggregate,
                                          PPVL_SEARCH_FROM_THE_TOP,
                                          PPVL_SELECT_NAME,
                                          "CORE_ITEM_TYPE",
                                          &theParent);
      if (thisParameter) thisParameter->content.value->data.string ="SUN_INTEGER";
      thisParameter = PPVL_find_parameter(theAggregate,
                                          PPVL_SEARCH_FROM_THE_TOP,
                                          PPVL_SELECT_NAME,
                                          "SAMPLE_SUFFIX_ITEM_TYPE",
                                          &theParent);
      if (thisParameter) {
        if (PPVL_Type_Is_Sequence(thisParameter->content.value->type)) {
          seq = thisParameter->content.value->data.array;
          for (i=0; i < PPVL_count_all_values(thisParameter->content.value); i++) {
            seq[i]->data.string = "SUN_INTEGER";
          }
        } else {
          thisParameter->content.value->data.string = "SUN_INTEGER";
        }
      }
      thisParameter = PPVL_find_parameter(theAggregate,
                                          PPVL_SEARCH_FROM_THE_TOP,
                                          PPVL_SELECT_NAME,
                                          "BAND_SUFFIX_ITEM_TYPE",
                                          &theParent);
      if (thisParameter) {
        if (PPVL_Type_Is_Sequence(thisParameter->content.value->type)) {
          seq = thisParameter->content.value->data.array;
          for (i=0; i < PPVL_count_all_values(thisParameter->content.value); i++) {
            seq[i]->data.string = "SUN_INTEGER";
          }
        } else {
          thisParameter->content.value->data.string = "SUN_INTEGER";
        }
      }
    }
  }

  /* Change the SUFFIX_ITEM_BYTES and SAMPLE_SUFFIX_ITEM_BYTES keywords from 2 to 4
   * (if needed). Don't forget BAND_SUFFIX_ITEM_BYTES.
  */
  thisParameter = PPVL_find_parameter(theAggregate,
                                      PPVL_SEARCH_FROM_THE_TOP,
                                      PPVL_SELECT_NAME,
                                      "SUFFIX_BYTES",
                                      &theParent);
  if (thisParameter && thisParameter->content.value->data.integer == 2) {
    thisParameter->content.value->data.integer = (unsigned long) 4;
  }

  thisParameter = PPVL_find_parameter(theAggregate,
                                      PPVL_SEARCH_FROM_THE_TOP,
                                      PPVL_SELECT_NAME,
                                      "SAMPLE_SUFFIX_ITEM_BYTES",
                                      &theParent);
  if (thisParameter && thisParameter->content.value->data.integer == 2) {
    thisParameter->content.value->data.integer = (unsigned long) 4;
  }
  thisParameter = PPVL_find_parameter(theAggregate,
                                      PPVL_SEARCH_FROM_THE_TOP,
                                      PPVL_SELECT_NAME,
                                      "BAND_SUFFIX_ITEM_BYTES",
                                      &theParent);
  if (thisParameter) {
    if (PPVL_Type_Is_Sequence(thisParameter->content.value->type)) {
      seq = thisParameter->content.value->data.array;
      for (i=0; i < PPVL_count_all_values(thisParameter->content.value); i++) {
        seq[i]->data.integer = (unsigned long) 4;
      }
    } else {
      thisParameter->content.value->data.integer = (unsigned long) 4;
    }
  }

  /* Change the CORE_NULL value to -32768 */
  thisParameter = PPVL_find_parameter(theAggregate,
                                      PPVL_SEARCH_FROM_THE_TOP,
                                      PPVL_SELECT_NAME,
                                      "CORE_NULL",
                                      &theParent);
  if (thisParameter) {
    thisParameter->content.value->data.integer = (long) -32768;
  }

  /* Get the QUBE sub-aggregate */
  cubeAggregate = PPVL_find_parameter(theAggregate, PPVL_SEARCH_FROM_THE_TOP,
      PPVL_SELECT_CLASS, (PPVL_Object *)PPVL_CLASS_AGGREGATE, &theParent);
  while (strcmp(cubeAggregate->name, "QUBE") != 0) {
    cubeAggregate = PPVL_find_parameter(theAggregate, cubeAggregate,
        PPVL_SELECT_CLASS, (PPVL_Object *)PPVL_CLASS_AGGREGATE, &theParent);
  }

  /* Create the new group for CALIBRATION and add parameters to it. */
  /* (if needed) */
  thisParameter = PPVL_find_parameter(cubeAggregate, PPVL_SEARCH_FROM_THE_TOP,
		  PPVL_SELECT_NAME, "SET_SATURATED", &theParent);
  if (strcmp(theParent->name, "CALIBRATION") != 0) {

    calibAggregate = PPVL_new_parameter("CALIBRATION", PPVL_CLASS_BEGIN_GROUP,
      NULL,"\n this is the calibration group \n", NULL);

    PPVL_add_parameter(calibAggregate,
      PPVL_new_parameter("CUBE_PREP", PPVL_CLASS_ASSIGNMENT,PPVL_new_value(
	PPVL_TYPE_TEXT,"YES",10,NULL),
      NULL,NULL));
    PPVL_add_parameter(calibAggregate,
      PPVL_new_parameter("SET_SATURATED", PPVL_CLASS_ASSIGNMENT,PPVL_new_value(
	PPVL_TYPE_TEXT,"NO",10,NULL),
      NULL,NULL));
    PPVL_add_parameter(calibAggregate,
      PPVL_new_parameter("IR_BGND", PPVL_CLASS_ASSIGNMENT,PPVL_new_value(
	PPVL_TYPE_TEXT,"AUTO",10,NULL),
      NULL,NULL));
    PPVL_add_parameter(calibAggregate,
      PPVL_new_parameter("VIS_BGND", PPVL_CLASS_ASSIGNMENT,PPVL_new_value(
	PPVL_TYPE_TEXT,"NO",10,NULL),
      NULL,NULL));
    PPVL_add_parameter(calibAggregate,
      PPVL_new_parameter("IR_FLAT", PPVL_CLASS_ASSIGNMENT,PPVL_new_value(
	PPVL_TYPE_TEXT,"NO",10,NULL),
      NULL,NULL));
    PPVL_add_parameter(calibAggregate,
      PPVL_new_parameter("VIS_FLAT", PPVL_CLASS_ASSIGNMENT,PPVL_new_value(
	PPVL_TYPE_TEXT,"NO",10,NULL),
      NULL,NULL));
    PPVL_add_parameter(calibAggregate,
      PPVL_new_parameter("SPECIFIC_ENERGY",PPVL_CLASS_ASSIGNMENT,PPVL_new_value(
	PPVL_TYPE_TEXT,"NO",10,NULL),
      NULL,NULL));
    PPVL_add_parameter(calibAggregate,
      PPVL_new_parameter("RM_SOLAR", PPVL_CLASS_ASSIGNMENT,PPVL_new_value(
	PPVL_TYPE_TEXT,"NO",10,NULL),
      NULL,NULL));
    PPVL_add_parameter(calibAggregate,
      PPVL_new_parameter("GEO_CORR", PPVL_CLASS_ASSIGNMENT,PPVL_new_value(
	PPVL_TYPE_TEXT,"NO",10,NULL),
      NULL,NULL));

    PPVL_add_parameter(cubeAggregate,calibAggregate);

  }

  /* For each backplane, get the DN to EU translation function and the
   * resulting units string. */
  if (Suffix_bytes[1] > 0) {
    thisParameter = PPVL_find_parameter(theAggregate, PPVL_SEARCH_FROM_THE_TOP,
                    PPVL_SELECT_NAME, "BAND_SUFFIX_NAME", &theParent);
    if (!thisParameter ||
        strcmp(
          thisParameter->content.value->data.array[0]->data.string,"H_R_HK_1"
          ) == 0 ) {
      thisParameter=PPVL_find_parameter(theAggregate, PPVL_SEARCH_FROM_THE_TOP,
                    PPVL_SELECT_NAME, "IR_FAST_HK_ITEMS", &theParent);
    }
    if (Suffix_bytes[1] > 1) {
      seq = thisParameter->content.value->data.array;
      for (i=0; i<Suffix_bytes[1]; i++) {
        funcs[i] = bp_trans(seq[i]->data.string, units[i]);
        if (funcs[i] == NULL) {   
          printf ("WARNING: couldn't get function for backplane %s\n",
                  seq[i]->data.string);
        }
      }
    } else {
      funcs[0]=bp_trans(thisParameter->content.value->data.string, units[0]);
      if (funcs[0] == NULL) {
        printf ("WARNING: couldn't get function for backplane %s\n",
                thisParameter->content.value->data.string);
      }
    }
  }
  thisParameter = PPVL_find_parameter(theAggregate, PPVL_SEARCH_FROM_THE_TOP,
     PPVL_SELECT_NAME, "BAND_SUFFIX_UNIT", &theParent);
/*  if (thisParameter && funcs[0] != NULL) {
    seq = thisParameter->content.value->data.array;
    for (i=0; i < Suffix_bytes[1]; i++) {
      seq[i]->data.string = units[i];
    }
  }
*/

  /* Use PPVL_write_parameter to write the label. */
  PPVL_write_parameter (theAggregate, outfile, 0);

  offset = ftell(outfile);

  /* If the header changed length, adjust for this and update all related
   * keywords.
   * */
  if (offset % Record_bytes == 0) {
    diff = (offset/Record_bytes) - Label_records;
  } else {
    diff = (offset/Record_bytes) + 1 - Label_records;
  }
  if (diff < 0) diff = 0;

  thisParameter = PPVL_find_parameter(theAggregate,
				      PPVL_SEARCH_FROM_THE_TOP,
				      PPVL_SELECT_NAME,
				      "LABEL_RECORDS",
				      &theParent);
  if (thisParameter) thisParameter->content.value->data.integer += diff;
  Label_records += diff;
  thisParameter = PPVL_find_parameter(theAggregate,
				      PPVL_SEARCH_FROM_THE_TOP,
				      PPVL_SELECT_NAME,
				      "FILE_RECORDS",
				      &theParent);
  if (thisParameter) thisParameter->content.value->data.integer += (diff+2);
  thisParameter = PPVL_find_parameter(theAggregate,
				      PPVL_SEARCH_FROM_THE_TOP,
				      PPVL_SELECT_NAME,
				      "^HISTORY",
				      &theParent);
  if (thisParameter) thisParameter->content.value->data.integer += (diff);
  thisParameter = PPVL_find_parameter(theAggregate,
				      PPVL_SEARCH_FROM_THE_TOP,
				      PPVL_SELECT_NAME,
				      "^QUBE",
				      &theParent);
  if (thisParameter) thisParameter->content.value->data.integer += (diff+2);
  Image_record += (diff+2);
  
  rewind(outfile);
  PPVL_write_parameter (theAggregate, outfile, 0);
  offset = ftell(outfile);

  /* pad out to end of header records */
  for (i=0; i < Label_records * Record_bytes - offset; i++) {
    temp = putc(32, outfile);
  }

  offset_before = ftell(outfile);

  /* Read history from input image, if any, write it to the output image. */
  offset = (History_record-1) * Record_bytes;
  fseek(infile, offset, SEEK_SET);

  fgets(history_line, (int)256, infile);
  while (!(strncmp(history_line, "END", 3)  == 0 &&
	   strncmp(history_line, "END_", 4) != 0)) {
    fprintf(outfile, "%s", history_line);
    fgets(history_line, (int)256, infile);
  }

  timer = time(NULL);
  fprintf(outfile, "\015\012");
  fprintf(outfile, "GROUP = CUBE_PREP\015\012");
  fprintf(outfile, "   VERSION = %s\015\012",version);
  date = asctime(localtime(&timer));
  *strchr(date,(char)10) = (char)0;
  fprintf(outfile, "   CUBE_PREP_DATE = \"%s\"\015\012",date);
  fprintf(outfile,
  "   SOFTWARE_DESC = \"Add calibration group, translate backplanes\"\015\012");
  fprintf(outfile, "   INPUT_FILE = \"%s\"\015\012", argv[1]);
  fprintf(outfile, "   OUTPUT_FILE = \"%s\"\015\012", argv[2]);
  if (doswap) {
    fprintf(outfile, "   DO_SWAP = YES\015\012");
  } else {
    fprintf(outfile, "   DO_SWAP = NO\015\012");
  }
  fprintf(outfile, "END_GROUP = CUBE_PREP\015\012");

  fprintf(outfile, "END\015\012");

  offset_after = ftell(outfile);
  rdiff = offset_after - offset_before;

  if (rdiff % Record_bytes == 0) {
    head_recs = rdiff/Record_bytes;
    pad_out = 0;
  } else {
    head_recs = rdiff/Record_bytes + 1;
    pad_out = Record_bytes - (rdiff % Record_bytes);
  }

  /* Pad out history record with spaces. */
  if (pad_out > 0) {
    for (i=0; i < pad_out; i++) {
      temp = putc(32, outfile);
    }
  }

  /* If the data doesn't start here, pad out to start of data. */
  offset = ftell(outfile);

  if (offset/Record_bytes+1 < Image_record) {
    rdiff = Image_record - (offset/Record_bytes+1);
    for (i=0; i < Record_bytes*rdiff; i++) {
      temp = putc(32, outfile);
    }
  }

  /* Read data from input image, translate if necessary, write output image. */
  /* swap the bytes if requested */
  /* if there are suffix items that are 2 bytes, transform them to 4 bytes */
  offset = ((Image_record-1) - (diff+2)) * Record_bytes;
  fseek(infile, offset, SEEK_SET);

  Line_bytes = Image_dimensions[0] * Pixel_bytes;
  line_data = (Byte *)calloc(Line_bytes, 1);
  Total_lines = Image_dimensions[2];
  Total_bands = Image_dimensions[1];
  Samp_suffix_bytes = Suffix_bytes[0] * Suffix_multiplier;
  samp_suffix_data = (Byte *)calloc(Samp_suffix_bytes, 1);
  Band_suffix_bytes = Image_dimensions[0] * Suffix_multiplier;
  band_suffix_data = (Byte *)calloc(Band_suffix_bytes, 1);

  for (line = 0; line < Total_lines; line++) {
    for (band = 0; band < Total_bands; band++) {
      fread(line_data, Line_bytes, 1, infile);

      /* Change any CORE_NULL values from -8192 to -32768. */
      if (strcmp(Data_type_name, "SUN_INTEGER") == 0) {
	for (i=0; i < Line_bytes - 1; i+=2) {
	  dataval =  (short)((line_data[i] << 8) + line_data[i+1]);
	  /* core_null update */
	  if (dataval == -8192) {
	    dataval = -32768;
	  }
	  line_data[i] = (Byte)(dataval >> 8); 
	  line_data[i+1] = (Byte)(dataval & 0x00FF); 
	}
      } else {
	for (i=0; i < Line_bytes - 1; i+=2) {
	  dataval =  (short)((line_data[i+1] << 8) + line_data[i]);
	  if (dataval == -8192) {
	    dataval = -32768;
	  }
	  line_data[i+1] = (Byte)(dataval >> 8); 
	  line_data[i] = (Byte)(dataval & 0x00FF); 
	}
      }

      if (doswap) swap_bytes(line_data, Line_bytes);
      fwrite(line_data, Line_bytes, 1, outfile);

      if (Suffix_bytes[0] > 0) {
        fread(samp_suffix_data, Samp_suffix_bytes, 1, infile);
        if (Suffix_multiplier == 2) {
          if (native == 0) {
            swap_bytes(samp_suffix_data, Samp_suffix_bytes);
            out_samp_suffix_data = trans_short_long (samp_suffix_data,
                                                     Samp_suffix_bytes);
            if (!doswap) swap_bytes_4(out_samp_suffix_data, Samp_suffix_bytes * 2);
          } else {
            out_samp_suffix_data = trans_short_long (samp_suffix_data,
                                                     Samp_suffix_bytes);
            if (doswap) swap_bytes_4(out_samp_suffix_data, Samp_suffix_bytes * 2);
          }
          fwrite(out_samp_suffix_data, 2 * Samp_suffix_bytes, 1, outfile);
        } else {
          if (doswap) swap_bytes_4(samp_suffix_data, Samp_suffix_bytes);
          fwrite(samp_suffix_data, Samp_suffix_bytes, 1, outfile);
        }
      }
    }

    if (Suffix_bytes[1] > 0) {
      for (band_suffix = 0; band_suffix < Suffix_bytes[1]; band_suffix++) {
	nread = fread(band_suffix_data, Band_suffix_bytes, 1, infile);

        if (Suffix_multiplier == 2) {
          if (native == 0) {
            swap_bytes(band_suffix_data, Band_suffix_bytes);
            out_band_suffix_data = trans_short_long (band_suffix_data,
                                                     Band_suffix_bytes);
	    if (!Prep_done) {
	      for (i=0;i<Suffix_bytes[1];i++) {
		memcpy(&tmplong,&out_band_suffix_data[i*4], 4);

/*		if (funcs[i] != NULL) {
		  tmpfloat = (funcs[i])(tmplong);
		} else {
		  tmpfloat = tmplong;
		}
*/
		memcpy(&out_band_suffix_data[i*4], &tmplong, 4);
	      }
	    }

            if (!doswap) swap_bytes_4(out_band_suffix_data, Band_suffix_bytes);
          } else {
            out_band_suffix_data = trans_short_long (band_suffix_data,
                                                     Band_suffix_bytes);
	    if (!Prep_done) {
	      for (i=0;i<Suffix_bytes[1];i++) {
		memcpy(&tmplong,&out_band_suffix_data[i*4], 4);
/*		if (funcs[i] != NULL) {
		  tmpfloat = (funcs[i])(tmplong);
		} else {
		  tmpfloat = tmplong;
		}
*/
		memcpy(&out_band_suffix_data[i*4], &tmplong, 4);
	      }
	    }
            if (doswap) swap_bytes_4(out_band_suffix_data, Band_suffix_bytes);
          }
          fwrite(out_band_suffix_data, 2 * Band_suffix_bytes, 1, outfile);
        } else {
          if (native == 0) {
            swap_bytes_4(band_suffix_data, Band_suffix_bytes);
	    if (!Prep_done) {
	      for (i=0;i<Suffix_bytes[1];i++) {
		memcpy(&tmplong,&band_suffix_data[i*4], 4);
/*		if (funcs[i] != NULL) {
		  tmpfloat = (funcs[i])(tmplong);
		} else {
		  tmpfloat = tmplong;
		}
*/
		memcpy(&band_suffix_data[i*4], &tmplong, 4);
	      }
	    }
            if (!doswap) swap_bytes_4(band_suffix_data, Band_suffix_bytes);
	  } else {
	    if (!Prep_done) {
	      for (i=0;i<Suffix_bytes[1];i++) {
		memcpy(&tmplong,&band_suffix_data[i*4], 4);
/*		if (funcs[i] != NULL) {
		  tmpfloat = (funcs[i])(tmplong);
		} else {
		  tmpfloat = tmplong;
		}
*/
		memcpy(&band_suffix_data[i*4], &tmplong, 4);
	      }
	    }
            if (doswap) swap_bytes_4(band_suffix_data, Band_suffix_bytes);
	  }
          fwrite(band_suffix_data, Band_suffix_bytes, 1, outfile);
        }

        if (Suffix_bytes[0] > 0) {
          fread(samp_suffix_data, Samp_suffix_bytes, 1, infile);
          if (Suffix_multiplier == 2) {
            if (native == 0) {
              swap_bytes(samp_suffix_data, Samp_suffix_bytes);
              out_samp_suffix_data = trans_short_long (samp_suffix_data,
                                                       Samp_suffix_bytes);
              if (!doswap) swap_bytes_4(out_samp_suffix_data, Samp_suffix_bytes * 2);
            } else {
              out_samp_suffix_data = trans_short_long (samp_suffix_data,
                                                       Samp_suffix_bytes);
              if (doswap) swap_bytes_4(out_samp_suffix_data, Samp_suffix_bytes * 2);
            }
            fwrite(out_samp_suffix_data, 2 * Samp_suffix_bytes, 1, outfile);
          } else {
            if (doswap) swap_bytes_4(samp_suffix_data, Samp_suffix_bytes);
            fwrite(samp_suffix_data, Samp_suffix_bytes, 1, outfile);
          }
        }
      }
    }
  }

  /* do bottom planes here */
  /* this is currently not implemented */
  
  fclose(infile);

  /* Close output file. */
  fclose(outfile);

}

/* swap every 2 bytes in a byte array */
void swap_bytes(Byte inarray[], long dsize)
{
  Byte   temp_byte;
  int    i;

  for (i = 0; i<dsize; i=i+2) {
    temp_byte = inarray[i];
    inarray[i] = inarray[i+1];
    inarray[i+1] = temp_byte;
  }
}

/* reverse order of every 4 bytes in a byte array */
void swap_bytes_4(Byte inarray[], long dsize)
{
  Byte   temp_byte;
  int    i;

  for (i = 0; i<dsize; i=i+4) {
    temp_byte = inarray[i];
    inarray[i] = inarray[i+3];
    inarray[i+3] = temp_byte;
    temp_byte = inarray[i+1];
    inarray[i+1] = inarray[i+2];
    inarray[i+2] = temp_byte;
  }
}

/* translate a short array of integers to a long (4 bytes) array of integers */
Byte *trans_short_long(Byte indata[], long dsize)
{
  int i, temp_int;
  long temp_long;
  Byte bytes[2], *outdata;
  
  outdata = (Byte *)calloc(dsize*2,1);

  for (i = 0; i<dsize; i=i+2) {
    bytes[0] = indata[i];
    bytes[1] = indata[i+1];

    memcpy(&temp_int, bytes, (size_t) 2);
    temp_long = (long)temp_int;
    memcpy(&outdata[i*2], &temp_long, (size_t) 4);
  }

  return(outdata);
}

/* figure out the data order of the machine we are running on */
static int Data_Order ()
{
  union {
    unsigned int    integer;
    unsigned char   byte[sizeof (int)];
  } value;

  value.integer = 0;
  value.byte[0] = 1;

  return ((value.integer == 1) ?  DATA_ORDER_LSB_FIRST : DATA_ORDER_MSB_FIRST);
}

