/*********************************************************************
*
*  Task DBMOD
*
* Task to modity the vlaues in a data base.
* Time time information is not affected.
*
* C does not allow for negative values to be raised to ANY power.
* This deficiency will be compensated for at a later date.
*
* If the file is complex, then ZFACTOR is the complex factor value.
*
* CODE  0 -> ADD FACTOR TO DATA
*       1 -> MULTIPLY FACTOR INTO DATA
*       2 -> DIVIDE FACTOR INTO DATA
*       3 -> DIVIDE DATA INTO FACTOR
*       4 -> RAISE DATA TO FACTOR POWER
*       5 -> LOG OF DATA IN BASE FACTOR
*       6 -> ANTI-LOG OF DATA IN BASE FACTOR
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <io.h>
#include <time.h>
#include <dos.h>
#include <process.h>
#include <ctype.h>
#include <signal.h>

#include "TISAN.H"

short FPERROR(void);
void  BombOff(int);

char szTemporaryFile[_MAX_PATH];  /* Must be global so BREAKREQ can see it */
struct FILESTRUCT InputFileStruct, OutputFileStruct;

main(argc,argv)
short argc;
char *argv[];
   {
   struct FILEHDR FileHeader;
   double TCNT=0., TIME, Rval, IVAL=0.;
   double LOGF;
   struct complex Zval, Zfactor, Zlogf;
   short I, FLAG=0;
   int iErrorReturn = 0;
   char szInputFile[_MAX_PATH], szOutputFile[_MAX_PATH];
   char BUFFER[sizeof(struct TXData)];
   char *DVZP = "DBMOD   : Divide By Zero, Returned 0.\n";
   struct RData  *RDataPntr;
   struct TRData *TRDataPntr;
   struct XData  *XDataPntr;
   struct TXData *TXDataPntr;

   signal(SIGINT,BREAKREQ);
   signal(SIGFPE,FPERROR);

   if (zTaskInit("DBMOD",argv[0])) Zexit(1);

   if ((CODE < 0) || (CODE > 6))
      {
      zMessage(10,"DBMOD   : CODE Out of Range\n");
      Zexit(1);
      }

   ZBuildFileName(M_inname,szInputFile);   /* Build file names */
   ZBuildFileName(M_outname,szOutputFile);
   ZBuildFileName(M_tmpname,szTemporaryFile);

   zMessage(2,"DBMOD   : Opening Input File '%s'\n",szInputFile);
   if (zFileOpen(&InputFileStruct ,szInputFile, OF_READ, 16384)) Zexit(1);
   if (!zGetHeader(&InputFileStruct,&FileHeader)) BombOff(1);

   zMessage(2,"DBMOD   : Opening Scratch File '%s'\n",szTemporaryFile);
   if (zFileOpen(&OutputFileStruct,szTemporaryFile,
                 OF_READWRITE | OF_CREATE, 16384)) BombOff(1);

   if (zPutHeader(&OutputFileStruct,&FileHeader)) BombOff(1);

   Zfactor = cmplx(ZFACTOR[0],ZFACTOR[1]);
/*
** Now trap invalid combinations
*/
   switch (FileHeader.type)
      {
      case R_Data:
      case TR_Data:
         switch (CODE)
            {
            case 2:
               if (!FACTOR)
                  {
                  zMessage(10,"DBMOD   : FACTOR = 0 with CODE = 2\n");
                  BombOff(1);
                  }
               break;
            case 5:
            case 6:
               if (FACTOR<=0)
                  {
                  zMessage(10,"DBMOD   : FACTOR <= 0 as Log Base\n");
                  BombOff(1);
                  }
               break;
            }
         break;
      case X_Data:
      case TX_Data:
         switch (CODE)
            {
            case 2:
               if (!cabs(Zfactor))
                  {
                  zMessage(10,"DBMOD   : |ZFACTOR| = 0 with CODE = 2\n");
                  BombOff(1);
                  }
               break;
            case 5:
            case 6:
               if (!cabs(Zfactor))
                  {
                  zMessage(10,"DBMOD   : |ZFACTOR| = 0 as Complex Log Base\n");
                  BombOff(1);
                  }
               break;
            }
         break;
      default:  /* File type is not known */
         printf("DBMOD   : Invalid File Type.\n");
         BombOff(1);
      }

   if (cabs(Zfactor)) Zlogf = c_ln(Zfactor);
   if (FACTOR > 0.) LOGF = log(FACTOR);

   RDataPntr =  (struct RData *)BUFFER;
   TRDataPntr = (struct TRData *)BUFFER;
   XDataPntr =  (struct XData *)BUFFER;
   TXDataPntr = (struct TXData *)BUFFER;

   while (!zIndexedRead(&InputFileStruct,-1L,BUFFER,FileHeader.type))
      {
      switch (FileHeader.type)  /* Fill DATA, TIME and FLAG values */
         {
         case R_Data:    /* Real Time Series */
            Rval = RDataPntr->y;
            TIME = TCNT*FileHeader.m + FileHeader.b;
            FLAG =RDataPntr->f;
            break;
         case TR_Data:  /* Real Time Labeled */
            Rval = TRDataPntr->y;
            TIME = TRDataPntr->t;
            break;
         case X_Data:   /* Complex Time Series */
            Zval = XDataPntr->z;
            TIME = TCNT*FileHeader.m + FileHeader.b;
            FLAG = XDataPntr->f;
            break;
         case TX_Data:   /* Complex Time Labeled */
            Zval = TXDataPntr->z;
            TIME = TXDataPntr->t;
            break;
         }
      if (!FLAG)   /* Only apply calculations to valid data points */
         {
         switch (CODE)
            {
            case 0: /* Add FACTOR */
               switch (FileHeader.type)
                  {
                  case R_Data:
                  case TR_Data:
                     Rval += FACTOR;
                     break;
                  case X_Data:
                  case TX_Data:
                     Zval = c_add(Zval,Zfactor);
                     break;
                  }
               break;
            case 1: /* Multiply by FACTOR */
               switch (FileHeader.type)
                  {
                  case R_Data:
                  case TR_Data:
                     Rval *= FACTOR;
                     break;
                  case X_Data:
                  case TX_Data:
                     Zval = c_mul(Zval,Zfactor);
                     break;
                  }
               break;
            case 2: /* Divide by FACTOR */
               switch (FileHeader.type)
                  {
                  case R_Data:
                  case TR_Data:
                     Rval /= FACTOR;
                     break;
                  case X_Data:
                  case TX_Data:
                     Zval = c_div(Zval,Zfactor);
                     break;
                  }
               break;
            case 3: /* Divide data into FACTOR */
               switch (FileHeader.type)
                  {
                  case R_Data:
                  case TR_Data:
                     if (!Rval)
                        {
                        zMessage(8,DVZP);
                        Rval = 0.;
                        }
                     else
                        Rval = FACTOR/Rval;
                     break;
                  case X_Data:
                  case TX_Data:
                     if (!cabs(Zval))
                        {
                        zMessage(8,DVZP);
                        Rval = 0.;
                        }
                     else
                        Zval = c_div(Zfactor,Zval);
                     break;
                  }
               break;
            case 4: /* Raise data to FACTOR power */
               switch (FileHeader.type)
                  {
                  case R_Data:
                  case TR_Data:
                     Rval = pow(Rval,FACTOR);
                     break;
                  case X_Data:
                  case TX_Data:
                     Zval = c_pow(Zval,Zfactor);
                     break;
                  }
               break;
            case 5: /* Log of data in base FACTOR */
               switch (FileHeader.type)
                  {
                  case R_Data:
                  case TR_Data:
                     Rval = log(Rval)/LOGF;
                     break;
                  case X_Data:
                  case TX_Data:
                     Zval = c_div(c_ln(Zval),Zlogf);
                     break;
                  }
               break;
            case 6: /* Anti-log of data in base factor */
               switch (FileHeader.type)
                  {
                  case R_Data:
                  case TR_Data:
                     Rval = pow(FACTOR,Rval);
                     break;
                  case X_Data:
                  case TX_Data:
                     Zval = c_pow(Zfactor,Zval);
                     break;
                  }
               break;
            } /* End Switch */
         switch (FileHeader.type)  /* Fill data value buffer */
            {
            case R_Data:    /* Real Time Series */
               RDataPntr->y  = Rval;
               break;
            case TR_Data:  /* Real Time Labeled */
               TRDataPntr->y = Rval;
               break;
            case X_Data:   /* Complex Time Series */
               XDataPntr->z = Zval;
               break;
            case TX_Data:   /* Complex Time Labeled */
               TXDataPntr->z = Zval;
               break;
            }
         } /* End IF */
      if (zIndexedWrite(&OutputFileStruct,-1L, BUFFER, FileHeader.type))
         BombOff(1);
      ++TCNT;  /* Count number of writes */
      } /* End WHILE */

   if (InputFileStruct.iEoF < 0) BombOff(1);

   zMessage(2,"DBMOD   : %G Data Points Processed\n",TCNT);

   iErrorReturn  = zFileClose(&InputFileStruct,TRUE) ? 1 : 0;
   iErrorReturn |= zFileClose(&OutputFileStruct,TRUE) ? 1 : iErrorReturn;
   iErrorReturn = Znameout(szOutputFile,szTemporaryFile,iErrorReturn);
   Zexit(iErrorReturn);
   }

/***************************************************************
**
** Process ^C Interrupt
*/
short BREAKREQ()
   {
   zFileClose(&InputFileStruct, TRUE);
   zFileClose(&OutputFileStruct, TRUE);
   unlink(szTemporaryFile);
   Zexit(3);
   }

short FPERROR()
   {
   zFileClose(&InputFileStruct, TRUE);
   zFileClose(&OutputFileStruct, TRUE);
   unlink(szTemporaryFile);
   Zexit(1);
   }

void BombOff(i)
int i;
   {
   zFileClose(&InputFileStruct, TRUE);
   zFileClose(&OutputFileStruct, TRUE);
   unlink(szTemporaryFile);
   Zexit(i);
   }