/*********************************************************************
*
*  Task DBCALC
*
*
* ITYPE 0 -> INTEGRATE FACTOR TIMES
*       1 -> DIFFERENTIATE FACTOR TIMES 
*
* if FACTOR <= 0 and ITYPE=0 then DO NOT create an output file.
*
* CODE is the moment of integration
*
*/
#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"

char TMPFILE1[_MAX_PATH], TMPFILE2[_MAX_PATH]; /* Must be visible to BREAKREQ */

main(argc,argv)
short argc;
char *argv[];
   {
   struct FILEHDR FileHeader;
   double TCNT, TIME, DATA, FVAL;
   short FLAG=0, PHASE2=1;
   char BUFFER[sizeof(struct TRData)];  /* Largest Data Type Processed */
   struct RData  *RDataPntr;
   struct TRData *TRDataPntr;
   FILE *INSTR, *OUTSTR, *TMPSTR;
   double LASTTIME, LASTVAL, VALUE=0.;
   short ERRFLAG=0, COUNT, II, FFLAG, FWFLAG, MFFLG=1, I;
   char InputFile[_MAX_PATH], OutputFile[_MAX_PATH];

   signal(SIGINT,BREAKREQ);

   if (Ztskinit("DBCALC",argv[0])) Zexit(1);

   if ((ITYPE < 0) || (ITYPE > 1))
      {
      Zencode(10,"DBCALC  : ITYPE Out of Range\n");
      Zexit(1);
      }

   if (CODE < 0)
      {
      Zencode(10,"DBCALC  : CODE Out of Range\n");
      Zexit(1);
      }

   if (FACTOR <= 0) MFFLG = 0;
   if (ITYPE) MFFLG=1;

   ZBuildFileName(M_inname,InputFile);

   Zencode(2,"DBCALC  : Opening Input File '%s'\n",InputFile);
   if (((INSTR = Zopen(InputFile,O_readb)) == NULL) ||
       (!Zgethead(INSTR,&FileHeader))) Zexit(1);

   if ((FileHeader.type != R_Data) &&
       (FileHeader.type != TR_Data))
     {
     Zencode(10,"DBCALC  : Not a Real Data File.\n");
     Zexit(1);
     }

   if (MFFLG)
      {
      ZBuildFileName(M_tmpname,TMPFILE1);
      Zencode(2,"DBCALC  : Opening Scratch File '%s'\n",TMPFILE1);
      if ((OUTSTR = Zopen(TMPFILE1,O_writeb)) == NULL) Zexit(1);
      ZBuildFileName(M_tmpname,TMPFILE2);
      Zencode(2,"DBCALC  : Opening Scratch File '%s'\n",TMPFILE2);
      if ((TMPSTR = Zopen(TMPFILE2,O_writeb)) == NULL) Zexit(1);

      FileHeader.b += FileHeader.m;  /* First point is lost */
      if (Zputhead(OUTSTR,&FileHeader))
         {
         ERRFLAG = 1;
         goto EXIT;
         }
      FileHeader.b -= FileHeader.m;  /* Undo the patch */
      }

   RDataPntr  = (struct  RData *)BUFFER;
   TRDataPntr = (struct TRData *)BUFFER;

   COUNT = Max(1,(short)FACTOR);  /* Number of integrations or */
   for (II=1;II<=COUNT;++II)      /* differentiations.         */
      {
      TCNT = 0.;
      VALUE = 0.;
      FWFLAG = FFLAG = 1;
      PHASE2 = PHASE2 ? 0 : 1;   /* Toggle PHASE flag */
      while (Zread(INSTR,BUFFER,FileHeader.type))
         {
         switch (FileHeader.type)
            {
            case R_Data:
               TIME = TCNT*FileHeader.m + FileHeader.b;
               ++TCNT;
               DATA = RDataPntr->y;
               FLAG = RDataPntr->f;
               break;
            case TR_Data:
               TIME = TRDataPntr->t;
               DATA = TRDataPntr->y;
               break;
            }

         if (!FLAG)
            {
            if (!FFLAG)
               {
               switch (ITYPE)
                  {
                  case 0: /* INTEGRATE */
                     FVAL = (TIME-LASTTIME)*(DATA+LASTVAL)/2.;

                     for (I=0; I<CODE; ++I)
                        FVAL *= (TIME+LASTTIME)/2.;

                     VALUE += FVAL;
                     break;
                  case 1: /* DIFFERENTIATE */
                     VALUE = (DATA-LASTVAL)/(TIME-LASTTIME);
                     break;
                  }
               switch (FileHeader.type)
                  {
                  case R_Data:
                     RDataPntr->y = VALUE;
                     break;
                  case TR_Data:
                     TRDataPntr->y = VALUE;
                     break;
                  }
               }
            LASTTIME = TIME;
            LASTVAL = DATA;
            FFLAG = 0;
            }

         if (!FWFLAG &&
              MFFLG  &&
              (Zwrite(OUTSTR,BUFFER,FileHeader.type)))
            {
            ERRFLAG=1;
            goto EXIT;
            }

         FWFLAG = FFLAG;
         } /* End WHILE */

      if (ferror(INSTR))
         {
         ERRFLAG = 1;
         goto EXIT;
         }

      if (!ITYPE) Zencode(3,"DBCALC  : Pass %d Integral = %G\n",II,VALUE);

      if (II < COUNT)
         {
         INSTR = OUTSTR;
         OUTSTR = TMPSTR;
         TMPSTR = INSTR;
         chsize(fileno(OUTSTR),0L);
         if (!Zgethead(INSTR,(struct FILEHDR *)NULL))
            {
            ERRFLAG = 1;
            goto EXIT;
            }
         FileHeader.b += FileHeader.m;  /* First point is lost */
         if (Zputhead(OUTSTR,&FileHeader))
            {
            ERRFLAG = 1;
            goto EXIT;
            }
         FileHeader.b -= FileHeader.m;  /* Undo the patch */
         }  /* End if */
      } /* End FOR */

EXIT:
   fcloseall();
   if (MFFLG)
      {
      ZBuildFileName(M_outname,OutputFile);
      if (PHASE2)
         {
         ERRFLAG = Znameout(OutputFile,TMPFILE2,ERRFLAG);
         unlink(TMPFILE1);
         }
      else
         {
         ERRFLAG = Znameout(OutputFile,TMPFILE1,ERRFLAG);
         unlink(TMPFILE2);
         }
      }
   Zexit(ERRFLAG);
   }

/***************************************************************
**
** Process ^C Interrupt
*/
short BREAKREQ()
     {
     fcloseall();
     unlink(TMPFILE1);
     unlink(TMPFILE2);
     Zexit(3);
     }