/****
   mn.c:  The main module for "interpolate" 
   Written by Toby Orloff
   orloff@poincare.geom.umn.edu
   July 10, 1990
****/

/*
 * Copyright (c) 1990, Geometry Supercomputer Project
 *                     University of Minnesota
 *                     1200 Washington Ave. S
 *                     Minneapolis, MN  55415
 *
 * email address: software@geom.umn.edu
 *
 * This software is copyrighted as noted above.  It may be freely copied,
 * modified, and redistributed, provided that the copyright notice is
 * preserved on all copies.
 *
 * There is no warranty or other guarantee of fitness for this software,
 * it is provided solely "as is".  Bug reports or fixes may be sent
 * to the authors, who may or may not act on them as they desire.
 *
 * You may not include this software in a program or other software product
 * without supplying the source, or without informing the end-user that the
 * source is available for no extra charge.
 *
 * If you modify this software, you should include a notice giving the
 * name of the person performing the modification, the date of modification,
 * and the reason for such modification.
 */

#include <stdio.h>
#include "types.h"
#include "globals.c"

double atof();

main(argc,argv)

int argc;
char *argv[];

{

  InitializeInterp();
  ProcessInterpCommandLine(&argc,argv);

  if(argc < 4) {
     PrintUsageMessage();
     exit(0);
    }

  /* Create value lists */

  CreateValueLists(argc,argv);

  switch(type) {   /* Type of file */

     case ASCII:

       SkipAndPrintAsciiLines();
       ProcessAsciiFiles();
       break;

    case BINARY:
      
      SkipAndPrintBinaryBytes();
      ProcessBinaryFiles();
      break;
   }

  DeleteValueLists();

}


CreateValueLists(argc,argv)

int argc;
char *argv[];

{
  FileValueList *fvl_ptr;
  int i;

  /* create in value list */

  fvl_ptr = &in_fvl;
  for(i=0;i<argc-2;++i) {  
     fvl_ptr->next = (FileValueList *) malloc(sizeof(FileValueList));
     fvl_ptr = fvl_ptr->next;

     fvl_ptr->type = DOUBLE;
     fvl_ptr->time = in_time[i];
     fvl_ptr->offset = 0;
     strcpy(fvl_ptr->name,argv[i+1]);
     fvl_ptr->value.next = NULL;

    }
  fvl_ptr->next = NULL;


  /* Create out value list */

  fvl_ptr = &out_fvl;
  for(i=0;i<number;++i) {

      fvl_ptr->next = (FileValueList *) malloc(sizeof(FileValueList));
      fvl_ptr = fvl_ptr->next;
 
      fvl_ptr->type = DOUBLE;
      fvl_ptr->time = out_time[i];
      fvl_ptr->offset = 0;

      if(suffix[0] != '\0') {
         sprintf(fvl_ptr->name,"%s.%d.%s",argv[argc-1],i,suffix);
        }
      else {
         sprintf(fvl_ptr->name,"%s.%d",argv[argc-1],i);
        }

      fvl_ptr->value.next = NULL;


     }
  fvl_ptr->next = NULL;
}

DeleteValueLists()

{

}



SkipAndPrintBinaryBytes()

  
{
  /* Skip and print out requested number of bytes in binary file */

  FileValueList *fvl_ptr;
  char *buffer;
  FILE *infile,*outfile,*prototype;

  if(skip <= 0) {  /* Simply open outfiles and return */

     fvl_ptr = out_fvl.next;

     while(fvl_ptr != NULL) {
        outfile = fopen(fvl_ptr->name,"w");
        if(outfile == NULL) {
             fprintf(stderr,"Cannot open file %s.\n",fvl_ptr->name);
             exit(0);
            }

         fvl_ptr = fvl_ptr->next;
         fclose(outfile);
        }

     return(0);

    }

  fvl_ptr = in_fvl.next;
  while(fvl_ptr != NULL) {

     infile = fopen(fvl_ptr->name,"r");
     if(infile == NULL) {
          fprintf(stderr,"Cannot open file %s.\n",fvl_ptr->name);
          exit(0);
         }

     fvl_ptr->offset = skip;
     fclose(infile);

     fvl_ptr = fvl_ptr->next;
    }

  buffer = (char *) malloc(skip);
  if(buffer == NULL) {
     fprintf(stderr,"Catastrophic error!  Cannot allocate needed buffer!\n");
     exit(0);
    }

  prototype = fopen(in_fvl.next->name,"r");
  if(fread((void *) buffer,1,skip,prototype) != skip) {
     fprintf(stderr,"Error reading header.\n");
     fclose(prototype);
     exit(0);
    }

  fvl_ptr = out_fvl.next;

  while(fvl_ptr != NULL) {
     outfile = fopen(fvl_ptr->name,"w");
     if(outfile == NULL) {
          fprintf(stderr,"Cannot open file %s.\n",fvl_ptr->name);
          exit(0);
         }

     fwrite((void *) buffer,1,skip,outfile);
     fclose(outfile);
     fvl_ptr = fvl_ptr->next;
    }

  free(buffer);

}

SkipAndPrintAsciiLines()

{
  FileValueList *fvl_ptr;
  int total;
  FILE *infile,*outfile,*prototype;
  char ch;

  /* Skip and print out requested number of lines in ascii files */

       fvl_ptr = in_fvl.next;
       while(fvl_ptr != NULL) {

          infile = fopen(fvl_ptr->name,"r");
          if(infile == NULL) {
               fprintf(stderr,"Cannot open file %s.\n",fvl_ptr->name);
               exit(0);
              }

          total = 0;
          while(total < skip) {
            if(fscanf(infile,"%c",&ch) == EOF) {
               fprintf(stderr,"End of file reached before %d lines.\n",skip); 
               exit(0);
              }
             if(ch == '\r' || ch == '\n') total++;
            }

          fvl_ptr->offset = ftell(infile);
          fclose(infile);

          fvl_ptr = fvl_ptr->next;
         }

      /* Print out skipped lines in each outfile */

      prototype = fopen(in_fvl.next->name,"r");

      fvl_ptr = out_fvl.next;

      while(fvl_ptr != NULL) {

         rewind(prototype);

         outfile = fopen(fvl_ptr->name,"w");
         if(outfile == NULL) {
            fprintf(stderr,"Cannot open output file %s.\n",fvl_ptr->name);
            exit(0);
           }

          total = 0;
          while(total < skip) {
             fscanf(prototype,"%c",&ch); 
             putc(ch,outfile);
             
             if(ch == '\r' || ch == '\n') total++;
            }

         fclose(outfile);
         fvl_ptr = fvl_ptr->next;
        }

     fclose(prototype);
}



ProcessBinaryFiles()

{

  char *data;
  FileValueList *fvl_ptr;
  FILE *infile,*outfile;
  int in_values,i,position;
  int index,first_read,done;
  ValueList *val_ptr;

  /* Allocate space for data */

  data = (char *) malloc(chunk * bytes);
  if(data == NULL) {
     fprintf(stderr,"Cannot allocate space for data.\n");
     exit(0);
    }

  done = 0;
  first_read = 1;
  position = -chunk;

  while(!done) {

     position += chunk;

     /* Read in and process data a chunk at a time */

     fvl_ptr = in_fvl.next;
     while(fvl_ptr != NULL) {

        /* Open file and find position there */

        infile = fopen(fvl_ptr->name,"r");

        fseek(infile,fvl_ptr->offset,0);

        /* Read in values in file */

        in_values = fread(data,bytes,chunk,infile);

        /* Place values in list */

        val_ptr = &(fvl_ptr->value);
        index = 0;

        for(i=0;i<in_values;++i) {


           if(first_read) {   /* Have to allocate input values */
              val_ptr->next = (ValueList *) malloc(sizeof(ValueList));
              if(val_ptr->next == NULL) {
                 fprintf(stderr,"Not enough memory to hold values.\n");
                 exit(0);
                }
              val_ptr->next->next = NULL;
             }

           val_ptr = val_ptr->next;
           switch(bytes) {

              case 1:   /* Unsigned 8 bit numbers */
                val_ptr->value = (double) 
                                     ((int) (((unsigned char *) data)[index]));
                index++;
                break;

              default:
                fprintf(stderr,"Unknown data size: %d bytes\n",bytes);
                exit(0);
         
             }

          }

        fprintf(stderr,"processing %d values in file %s.\n",in_values,
                                fvl_ptr->name);


        if(in_values < chunk) {  /* Must have finished reading */
           done = 1;
          }
        else {
           fvl_ptr->offset = ftell(infile);
          }

        fclose(infile);
        fvl_ptr = fvl_ptr->next;
       }

      if(first_read)  {  /* Allocate output value lists */

         fvl_ptr = out_fvl.next;

         while(fvl_ptr != NULL) {
            val_ptr = &(fvl_ptr->value);
            for(i=0;i<in_values;++i) {
               val_ptr->next = (ValueList *) malloc(sizeof(ValueList));
               if(val_ptr->next == NULL) {
                  fprintf(stderr,"Not enough memory to hold values.\n");
                  exit(0);
                 }
                val_ptr = val_ptr->next;
              }
            val_ptr->next = NULL;
            fvl_ptr = fvl_ptr->next;
           }
        }

      attr.type = style;
      attr.num = in_values;
      attr.position = position;

      interp(in_fvl.next,out_fvl.next,&attr);

      /* Print out the values */

      fvl_ptr = out_fvl.next;
      while(fvl_ptr != NULL) {
         outfile = fopen(fvl_ptr->name,"a");

         /* Package data */

         val_ptr = fvl_ptr->value.next;
         for(i=0;i<attr.num;++i) {

            switch(bytes) {

               case 1:
                 if(val_ptr->value < 0.0) {
                    ((unsigned char *) data)[i] = 0;
                    break;
                   }
                 if(val_ptr->value > 255.0) {
                    ((unsigned char *) data)[i] = 255;
                    break;
                   }

                 ((unsigned char *) data)[i] = 
                      (unsigned char) ((int) val_ptr->value);
                 break;

               default:
                 break;

              }

            val_ptr = val_ptr->next;
           }

         fwrite(data,bytes,attr.num,outfile);

         fclose(outfile);
         fvl_ptr = fvl_ptr->next;
        }


/*
printf("Out file values:\n\n");
PrintFileValueList(stdout,out_fvl.next,attr.num);
*/

     first_read = 0;
    }

  free(data);
}

ProcessAsciiFiles()

{
  FileValueList *fvl_ptr;
  FILE *infile,*outfile,*prototype;
  int i,in_values,done,first_read,total;
  int position;
  char ch,strng[80];
  double temp;
  long offset;   /* Offset into input files */
  ValueList *val_ptr;

       done = 0;
       first_read = 1;  /* First time reading data */
       position = -chunk;
        
       prototype = fopen(in_fvl.next->name,"r");

       while(!done) {

          position += chunk;  /* Ordinal position of first data element */ 

          /* Read in and process data a chunk at a time */

          fvl_ptr = in_fvl.next;

          /* save offset for printing outfiles */

          offset = fvl_ptr->offset;  /* Offset of prototype */

          while(fvl_ptr != NULL) {

             /* Open file and find position there */

             infile = fopen(fvl_ptr->name,"r");

             fseek(infile,fvl_ptr->offset,0);

             val_ptr = &(fvl_ptr->value);

             /* Read in values in file */

             in_values = 0;
             while(in_values < chunk) {

                if(fscanf(infile,"%s",strng) == EOF) break;

                if(is_a_float(strng)) {

                   if(first_read) {   /* Have to allocate input values */
                      val_ptr->next = (ValueList *) malloc(sizeof(ValueList));
                      if(val_ptr->next == NULL) {
                         fprintf(stderr,"Not enough memory to hold values.\n");
                         exit(0);
                        }
                      val_ptr->next->next = NULL;
                     }

                   val_ptr = val_ptr->next;
                   val_ptr->value = atof(strng);
                   in_values++;
                  }
               }
              fprintf(stderr,"processing %d values in file %s.\n",in_values,
                                      fvl_ptr->name);

              if(in_values < chunk) {  /* Must have finished reading */
                 done = 1;
                }
              else {
                 fvl_ptr->offset = ftell(infile);
                }

              fclose(infile);
              fvl_ptr = fvl_ptr->next;
              
             }

       if(first_read)  {  /* Allocate output value lists */

          fvl_ptr = out_fvl.next;

          while(fvl_ptr != NULL) {
             val_ptr = &(fvl_ptr->value);
             for(i=0;i<in_values;++i) {
                val_ptr->next = (ValueList *) malloc(sizeof(ValueList));
                if(val_ptr->next == NULL) {
                   fprintf(stderr,"Not enough memory to hold values.\n");
                   exit(0);
                  }
                 val_ptr = val_ptr->next;
               }
             val_ptr->next = NULL;
             fvl_ptr = fvl_ptr->next;
            }
         }

       attr.type = style;
       attr.num = in_values;
       attr.position = position;

       interp(in_fvl.next,out_fvl.next,&attr);

       /* Print out the values */

       fvl_ptr = out_fvl.next;
       while(fvl_ptr != NULL) {
          fseek(prototype,offset,0);
          outfile = fopen(fvl_ptr->name,"a");

          total = 0;
          val_ptr = fvl_ptr->value.next;

          while(total < attr.num) {
             /* Print whitespace */

             if(fscanf(prototype,"%[ \t\r\n]",strng) != 0) {
                fprintf(outfile,"%s",strng);
               }

             fscanf(prototype,"%s",strng);
             /* Try to determine type of string */

            if(!is_a_float(strng))  {  /* Not a floating point number */
               fprintf(outfile,"%s",strng);
              }
            else {  /* Print interpolated value */
               fprintf(outfile,"%lf",val_ptr->value);
               total++;
               val_ptr = val_ptr->next;
              }
           }

        if(done) {  /* Print remaining characters from prototype */
           while(fscanf(prototype,"%c",&ch) == 1) {
              putc(ch,outfile);
             }
          }

        fclose(outfile);
        fvl_ptr = fvl_ptr->next;
       }

/*
       printf("Out file values:\n\n");
       PrintFileValueList(stdout,out_fvl.next,attr.num);
*/

       first_read = 0;
      }

    fclose(prototype);
}
