/* This include file handles spectra input, output and some specific
   comandline parsing. Routines supported:
   xmax=readspec(name,float[8192],error[8192],time[8192],string)
           reads the spectrum specified and
           returns the number of relevant channels.
           Spectra files can have the pure name supported,
           or have the extension ".spc".
           Error arrays are identified by the extension ".err".
      Time arrays are identified by the extension ".tim".
            Spectra may be specified with a range. eg. spc[100:300].
   result=checkopt(argc,argv,"string",stringvar)
           checks for the specified options, and returns true or false
           and the following string variable.
   writespec(name,float_array,error_array,xmax,typ,stringcomment)
      name is a string containing the name of the spectrum,
           typ is 0 for I2 spectra, 1 for I4 spectra and 2 for R4 spectra.
      If "1" is specified, then all data is saved as ASCII integer,
      while "2" denotes ASCII float.
   outspec(stream,float_array,xmax,typ,stringcomment)

   special care is taken, so that CPU (intel!) specific dependencies
   on binary formats should not occur.
   Options -i  (Integer ASCII output),
           -r  (float ASCII output),
           -i2 (short integer binary),
           -i4 (long integer binary),
           -r4 (float binary, NOT SUPPORTED yet),
           -o name (output goes to files [.spc and .err] and not to stdout)
           -h  (call help routine)
           -help (call help routine)
           -p n (sets grafic pipe number)
           -n (specifies a subwindow)
   are checked when checkopt is called.
   Notice, that a help() routine must be present in every program !

                                          Programmer: RAKO
*/

#include <math.h>
#include <strings.h>
#ifdef ICON_ON
#include <workbench/workbench.h>
#include <workbench/icon.h>
#endif

#ifndef TRUE
#define TRUE 1L
#endif
#ifndef FALSE
#define FALSE 0L
#endif

#ifndef _SPECHDR
#define _SPECHDR

int   _spc_outflg = -2,      /* signal "option not checked"  */
      _tekpipe = 0,
      _win_flg = 0,
      _sbeg , _send , _max,
      _lise_err = 0;
int _MAXSPCLEN = 16384;       /* was a constant before */
char  *_spc_onam = NULL,
      *_spc_0nam = NULL;
float _tica=1.0,
      *_uspc = NULL,
      *_uerr = NULL,
      *_utim = NULL;



void _help0()    /* call user help(), print out standard message and exit */
{
help();
printf("\nstandard spectra options:\n");
printf(" -i  (Integer ASCII output), \n");
printf(" -r  (float ASCII output),\n");
printf(" -i2 (short integer binary),\n");
printf(" -i4 (long integer binary),\n");
printf(" -r4 (float binary, !! NOT PORTABLE !! yet),\n");
printf(" -wsimple (write ASCII simple spectrum)\n");
printf(" -o name (output goes to files [.spc and .err] and not to stdout)\n");
printf(" -h  (call help routine)\n");
printf(" -help (call help routine)\n");
printf(" -p n (sets grafic pipe number)\n");
printf(" -n  (n=0..6 specifies a subwindow)\n\n");
#ifdef MAINVERSION
printf("LISE Version %s\n",MAINVERSION);
#endif
#ifdef CREATIONDATE
printf("last modified at %s\n",CREATIONDATE);
#endif
printf("Maximum spectra length is %d\n",_MAXSPCLEN);
printf("set the environment variable MAXSPCLEN to change from default\n");
printf("initial idea and implementations for UNIX and AMIGA by Rainer Kowallik\n");
exit(0);
}

float atosf(s)
char s[];
{
double atof();
float y;

   y=atof(s);
   return(y);
}

checkopt(argc,argv,s,sv)
int argc;
char *argv[],s[],sv[];
{
int   n,erg;
char  *z,*env;

   z = (char *) malloc(80);
   if(_spc_outflg==-2) {
      _spc_outflg = -1;        /* signal "no ouput option specified" */
      env = (char *) getenv("MAXSPCLEN");
      if(env != NULL) _MAXSPCLEN = atoi(env);
      if(_uspc == NULL) _uspc = (float *) calloc(_MAXSPCLEN,sizeof(float));
      if(_uerr == NULL) _uerr = (float *) calloc(_MAXSPCLEN,sizeof(float));
      if(_utim == NULL) _utim = (float *) calloc(_MAXSPCLEN,sizeof(float));
      if(_spc_onam == NULL) _spc_onam = (char *) malloc(80);
      if(_spc_0nam == NULL) _spc_0nam = (char *) malloc(80);
      strcpy(_spc_onam,"");    /* signal "no output file names */
      if(checkopt(argc,argv,"-h",z)) _help0();
      if(checkopt(argc,argv,"-help",z)) _help0();
      if(checkopt(argc,argv,"-i",z)) _spc_outflg='1';
      if(checkopt(argc,argv,"-r",z)) _spc_outflg='2';
      if(checkopt(argc,argv,"-i2",z)) _spc_outflg=0;
      if(checkopt(argc,argv,"-i4",z)) _spc_outflg=1;
      if(checkopt(argc,argv,"-r4",z)) _spc_outflg=2;
      if(checkopt(argc,argv,"-wsimple",z)) _spc_outflg = ' ';
      if(checkopt(argc,argv,"-0",z)) _win_flg=0;
      if(checkopt(argc,argv,"-1",z)) _win_flg=1;
      if(checkopt(argc,argv,"-2",z)) _win_flg=2;
      if(checkopt(argc,argv,"-3",z)) _win_flg=3;
      if(checkopt(argc,argv,"-4",z)) _win_flg=4;
      if(checkopt(argc,argv,"-5",z)) _win_flg=5;
      if(checkopt(argc,argv,"-6",z)) _win_flg=6;
      if(checkopt(argc,argv,"-o",z)) strcpy(_spc_onam,z);
      if(checkopt(argc,argv,"-p",z)) _tekpipe=atoi(z);
   }
   erg=FALSE;
   for(n=1;n<argc;n++) {
      if(strcmp(argv[n],s)==0) {
         erg=TRUE;
         if((n + 1) < argc) strcpy(sv,argv[n+1]);
      }
   }
   free(z);
   return(erg);
}

specin(stream,spc,s)
FILE *stream;
char s[];
float spc[];
{
unsigned char byte1,byte2;
char        c,z[80];
int         typ,n,max;
unsigned long int m;
union    fourbytes {
            float                real;
            long int             sig;
            unsigned long int    card;
         } b4;
union    twobytes {
            short int            sig;
            unsigned short int   card;
         } b2;

   byte1=fgetc(stream);
   if(byte1 == ' ') {               /* handle simple ASCII (MUST start with a blank)  */
      max = 0;
      _tica = 1.0;
      strcpy(s,"");
      while(!feof(stream)) {
         fscanf(stream,"%s\n",z);
         spc[max++] = atosf(z);
      }
      return(max);
   }

   if(byte1==0) {                   /* binary spectra formats */
      byte2=fgetc(stream);
      if(byte2 > 3) {
         fprintf(stderr,"%c  %d\n",byte2,byte2);
         fprintf(stderr,"spectra i/o:\n not a bin spectra file !\n");
         lise_exit(-1); return(-1);
      }
      typ=byte1*256+byte2; /* MSB LSB ! spectrum type */
      byte1=fgetc(stream); byte2=fgetc(stream);
      max=byte1*256+byte2; /* spectrum length in channels */
      for(n=0;n<=79;n++) {    /* read comment */
         s[n]=fgetc(stream);
         if(s[n]==0) continue;
         if(s[n]<32) s[n]=32;
      }
      m=0;                    /* read time calibration factor */
      m = fgetc(stream);
      m = (m << 8) + fgetc(stream);
      m = (m << 8) + fgetc(stream);
      m = (m << 8) + fgetc(stream);
      b4.card=m; _tica=b4.real;

      for(n=1;n<=8;n++) c=fgetc(stream); /* skip 4 spare words */
   } else {                   /* ASCII spectra formats */
      typ=byte1;
      if((byte1 != '1') && (byte1 != '2')) {
         fprintf(stderr,"%c  %d\n",byte1,byte1);
         fprintf(stderr,"spectra i/o:\n not an ASCII spectra file !\n");
         lise_exit(-1); return(-1);
      }
      c=0; while(c!='\n') c=fgetc(stream);
      fscanf(stream,"%d\n",&max);            /* read number of channels */
      n=0; c=0; while(c!='\n') {             /* read comment */
         c=fgetc(stream) ; s[n++]=c;
      }
      s[n]=0;
      fscanf(stream,"%s\n",z);
      _tica=atosf(z);                       /* read time calibration */
      fscanf(stream,"\n\n\n\n");
   }
   n=0;
   switch(typ) {
   case 0:                 /* binary short integer */
      for(n=0;n<max;n++) {
         if(feof(stream)) {
            max=n;         /* trap too few elements */
            break;
         }
         byte1=fgetc(stream);
         byte2=fgetc(stream);
         b2.card = (byte1 << 8) + byte2;
         spc[n]=b2.sig;
      }
      break;
   case 1:                 /* binary long integer */
      for(n=0;n<max;n++) {
         if(feof(stream)) {
            max=n;         /* trap too few elements */
            break;
         }
         m = fgetc(stream);
         m = (m << 8) + fgetc(stream);
         m = (m << 8) + fgetc(stream);
         m = (m << 8) + fgetc(stream);
         b4.card=m;
         spc[n]=b4.sig;
      }
      break;
   case 2:                         /* binary float */
      for(n=0;n<max;n++) {
         if(feof(stream)) {
            max=n;         /* trap too few elements */
            break;
         }
         m = fgetc(stream);
         m = (m << 8) + fgetc(stream);
         m = (m << 8) + fgetc(stream);
         m = (m << 8) + fgetc(stream);
         b4.card=m;
         spc[n]=b4.real;
      }
      break;
   case '1':                       /* ASCII integer */
      for(n=0;n<max;n++) {
         if(feof(stream)) {
            max=n;         /* trap too few elements */
            break;
         }
         fscanf(stream,"%d\n",&m);
         spc[n]=m;
      }
      break;
   case '2':                        /* ASCII float */
      for(n=0;n<max;n++) {
         if(feof(stream)) {
            max=n;         /* trap too few elements */
            break;
         }
         fscanf(stream,"%s\n",z);
         spc[n]=atosf(z);
      }
      break;
   }
   return(max);
}

readspec(snam,spc,err,tim,s)
char snam[],s[];
float spc[],err[],tim[];
{
FILE        *stream,*fopen();
char        *fnam2,*range,*z;
int         io_flg,i,j,n,max;
float       x;


   if(_spc_onam == NULL) _spc_onam = (char *) malloc(80);
   if(_spc_0nam == NULL) _spc_0nam = (char *) malloc(80);

   fnam2 = (char *) malloc(80);
   range = (char *) malloc(80);
   z = (char *) malloc(80);

   if(_uspc == NULL) _uspc = (float *) calloc(_MAXSPCLEN,sizeof(float));
   if(_uerr == NULL) _uerr = (float *) calloc(_MAXSPCLEN,sizeof(float));
   if(_utim == NULL) _utim = (float *) calloc(_MAXSPCLEN,sizeof(float));

   io_flg=0;

   n=strlen(snam);
   if((n>0) && (n<80) && snam[0]!='-') {       /* do the parsing */
      j=instr("[",snam);
      if(j>0) {
         midstr(_spc_0nam,snam,0,j-1);
         midstr(range,snam,j+1,instr("]",snam)-1);
      } else {
         strcpy(_spc_0nam,snam);
         strcpy(range,"");
      }
      i=instr(":",range);
      if(strlen(range)==0) { /* handle spc[] */
         _sbeg=0;
         _send=_MAXSPCLEN;
         io_flg=1;
      } else {
         if(i<0) {             /* handle spc[n] */
            _sbeg=atoi(range);
            _send=_sbeg;
            io_flg=1;
         }
         if(i>0) {
            midstr(z,range,0,i-1); _sbeg=atoi(z);
            midstr(z,range,i+1,strlen(range)); _send=atoi(z);
            io_flg=1;
         }
         if(i==0) {
            _sbeg=0;
            midstr(z,range,i+1,strlen(range)); _send=atoi(z);
            io_flg=1;
         }
      }
   }

   j=instr(".spc",_spc_0nam);                   /* removing superflous .spc */
   if(j>0) {
      midstr(z,_spc_0nam,0,j-1);
      strcpy(_spc_0nam,z);
   }



   if(_sbeg > _send) {                           /* trapping obvious errors */
      fprintf(stderr,"starting channel higher than last channel !\n");
      lise_exit(-1); free(fnam2); free(range); free(z); return(-1);
   }
   if(_send > _MAXSPCLEN) {
      fprintf(stderr,"sorry, this LIESE Version can only handle spectra\n");
      fprintf(stderr,"up to %d channels\n", _MAXSPCLEN);
      lise_exit(-1); free(fnam2); free(range); free(z); return(-1);
   }

                                                      /* now read the data */
   if(io_flg==0) { /* reading from stdin */
      max=specin(stdin,_uspc,s);
   }
   if(io_flg==1) { /* reading from file, possible error and time arrays */
      strcpy(fnam2,_spc_0nam); strcpy(z,_spc_0nam);
      stream=fopen(z,"r");
      if(stream==NULL) {
         strcat(z,".spc");
         stream=fopen(z,"r");
         if(stream==NULL) {
 fprintf(stderr,"spectra i/o:\n unable to open file for read %s\n",_spc_0nam);
            lise_exit(-1); free(fnam2); free(range); free(z); return(-1);
         }
      }
      max=specin(stream,_uspc,s);                /* first read data */
   }
   _max=max; /* tell it to the user */
   fclose(stream);
   x = _tica;                                    /* get time calibration */
   stream=fopen("tica.all","r");                 /* try to read another tica */
   if(stream!=NULL) {
      fscanf(stream,"%s\n",z);
      x=atosf(z);
      fclose(stream);
   }
   for(n=0;n<_MAXSPCLEN;n++) {                   /* preset time and error */
      _uerr[n] = 0.0;
      _utim[n] = n * x ;
   }

   if(io_flg==1) { /* reading from file, possible error and time arrays */
      strcpy(z,_spc_0nam); strcat(z,".err");
      stream=fopen(z,"r");
      if(stream!=0) {                        /* read error array */
         specin(stream,_uerr,z);
         fclose(stream);
      }      strcpy(z,_spc_0nam); strcat(z,".tim");
      stream=fopen(z,"r");
      if(stream!=0) {                       /* read time array */
         specin(stream,_utim,z);
         fclose(stream);
      }
      i=0; n=_sbeg;
      _tica = x; /* value from *.spc should overwrite value from *.err */
      while(n<=_send) {                   /* cut specified range */
         spc[i]=_uspc[n];
         err[i]=_uerr[n];
         tim[i]=_utim[n];
         i=i+1; n=n+1;
      }
      if((_send-_sbeg)<max) {
         max=_send-_sbeg+1;
      }
   }
   free(fnam2); free(range); free(z); return(max);
}

putreal(stream,x)
FILE *stream;
float x;
{
unsigned char byte1,byte2,byte3,byte4;
unsigned long int m;
union    fourbytes {
            float                real;
            long int             sig;
            unsigned long int    card;
         } b4;

         b4.real=x; m=b4.card;
                    byte1 = m >> 24 ;
                    byte2 = (m >> 16) & 255 ;
                    byte3 = (m >> 8) & 255 ;
                    byte4 = m & 255;
         fputc(byte1,stream); fputc(byte2,stream);
         fputc(byte3,stream); fputc(byte4,stream);
   return(0);
}

outspec(stream,spc,max,typ1,s)
char     s[];
float    spc[];
int      max,typ1;
FILE     *stream;
{
unsigned char byte1,byte2,byte3,byte4;
int      n,typ;
char     *z;
unsigned long int m;
union    fourbytes {
            float                real;
            long int             sig;
            unsigned long int    card;
         } b4;
union    twobytes {
            short int            sig;
            unsigned short int   card;
         } b2;

   z = (char *) malloc(80);

   typ=typ1;
   if(_spc_outflg >= 0) typ=_spc_outflg;        /* force user requested output */

   switch(typ) {
   case 0:                                      /* binary short integer */
      fputc(0,stream); fputc(typ,stream);       /* write type     */
      byte1 = max >> 8 ; byte2 = max & 255;
      fputc(byte1,stream); fputc(byte2,stream); /* write length in channels */
      for(n=0;n<80;n++) fputc(s[n],stream);     /* write comment  */
      putreal(stream,_tica);                    /* time calibration */
      for(n=1;n<=8;n++) fputc(0,stream);        /* 4 spare words  */
      for(n=0;n<max;n++) {                      /* write data     */
         b2.sig=spc[n]; m=b2.card;
         byte1 = m >> 8; byte2= m & 255;
         fputc(byte1,stream); fputc(byte2,stream);
      }
      break;
   case 1:                                      /* binary long integer */
      fputc(0,stream); fputc(typ,stream);       /* write type     */
      byte2 = max & 255 ; byte1 = max >> 8;
      fputc(byte1,stream); fputc(byte2,stream); /* write length in channels */
      for(n=0;n<80;n++) fputc(s[n],stream);     /* write comment  */
      putreal(stream,_tica);                    /* time calibration */
      for(n=1;n<=8;n++) fputc(0,stream);        /* 4 spare words  */
      for(n=0;n<max;n++) {                      /* write data     */
         b4.sig=spc[n]; m=b4.card;
                    byte1 = m >> 24 ;
                    byte2 = (m >> 16) & 255 ;
                    byte3 = (m >> 8) & 255 ;
                    byte4 = m & 255;
         fputc(byte1,stream); fputc(byte2,stream);
         fputc(byte3,stream); fputc(byte4,stream);
      }
      break;
   case 2:                 /* binary float */
      fputc(0,stream); fputc(typ,stream);       /* write type     */
      byte1 = max >> 8 ; byte2 = max & 255;
      fputc(byte1,stream); fputc(byte2,stream); /* write length in channels */
      for(n=0;n<80;n++) fputc(s[n],stream);     /* write comment  */
      putreal(stream,_tica);                    /* time calibration */
      for(n=1;n<=8;n++) fputc(0,stream);        /* 4 spare words  */
      for(n=0;n<max;n++) putreal(stream,spc[n]);
      break;
   case '1':               /* ASCII integer */
      fprintf(stream,"1\n%d\n%s\n%E\n\n\n\n\n",max,s,_tica);
      for(n=0;n<max;n++) {m=spc[n]; fprintf(stream,"%d\n",m);}
      break;
   case '2':               /* ASCII float */
      fprintf(stream,"2\n%d\n%s\n%E\n\n\n\n\n",max,s,_tica);
      for(n=0;n<max;n++) fprintf(stream,"%E\n",spc[n]);
      break;
   case ' ' :               /* simple ASCII */
      for(n = 0; n < max; n++) fprintf(stream," %f\n",spc[n]);
      break;
   }
   free(z);
   return(0);
}

writespec(name0,spc,err,max,typ,s)
char     name0[],s[];
float    spc[],err[];
int      max,typ;
{
int      n;
char     *z,*name;
FILE     *stream,*fopen();
#ifdef ICON_ON
struct DiskObject *object;
#endif

   z = (char *) malloc(80);
   name = (char *) malloc(80);

   n=instr(".tim",name0);
   if(n>0) {                     /* write only time spectrum */
      stream=fopen(name0,"w");
      outspec(stream,spc,max,typ,s);
#ifdef UNIX
   chmod(z,0666);
#endif
      fclose(stream);
      free(name); free(z);
      return(0);
   }
   n=instr(".err",name0);
   if(n>0) {                     /* write only error spectrum */
      stream=fopen(name0,"w");
      outspec(stream,spc,max,typ,s);
      fclose(stream);
#ifdef UNIX
   chmod(z,0666);
#endif
      free(name); free(z);
      return(0);
   }
   strcpy(name,name0);
   if(strlen(_spc_onam)>0) strcpy(name,_spc_onam);
   if(strlen(name)==0) {
      outspec(stdout,spc,max,typ,s);
      free(name); free(z);
      return(0);
   }
   strcpy(z,name); strcat(z,".spc");
   stream=fopen(z,"w");
   if(stream==NULL) {
      fprintf(stderr,"spectra io:\n can not open file for write %s\n",z);
      free(name); free(z);
      return(-1);
   }
   outspec(stream,spc,max,typ,s);
   fclose(stream);
#ifdef UNIX
   chmod(z,0666);
#endif
   strcpy(z,name); strcat(z,".err");
   stream=fopen(z,"w");
   if(stream==NULL) {
      fprintf(stderr,"spectra io:\n can not open file for write %s\n",z);
      free(name); free(z);
      return(-1);
   }
   outspec(stream,err,max,typ,s);
   fclose(stream);
#ifdef UNIX
   chmod(z,0666);
#endif
#ifdef ICON_ON
   object = GetDiskObject("LISE:Spectrum_Default"); /* generate Icon for Spectrum */
   if(object == NULL) return(0);
   object->do_Magic = WB_DISKMAGIC;
   object->do_Version = WB_DISKVERSION;
   object->do_CurrentX = NO_ICON_POSITION;
   object->do_CurrentY = NO_ICON_POSITION;
   strcpy(z,name); strcat(z,".spc");
   PutDiskObject(z,object);
   FreeDiskObject(object);
#endif
   free(name); free(z);
}
lise_exit(n)
int n;
{
   if(_lise_err == 0) exit(n);
   _lise_err = n;
   return(0);
}
#endif
