/*********************************************************************
*
*  Task DBSMOOTH
*
*
* CODE  0 -> KALMAN FILTER SMOOTH
*       1 -> RUNNING AVERAGE SMOOTH
*/
#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"

#define SMLimit 500

char TMPFILE[_MAX_PATH]; /* Must be visible to BREAKREQ */
double DBUFF[SMLimit+1];

main(argc,argv)
short argc;
char *argv[];
   {
   struct FILEHDR FileHeader;
   char BUFFER[sizeof(struct TRData)]; /* Largest structure porcessed */
   struct RData *RDataPntr;
   struct TRData *TRDataPntr;
   double IDATA, ODATA;

   FILE *INSTR, *OUTSTR;
   double SUM=0, LASTVAL, YINMAX, YINMIN, YOUTMAX, YOUTMIN;
   double COUNT=0.,TOTAL=0.;
   short ERRFLAG=0, J=0, nBOX;
   short IFLAG=1, OFLAG=1, FFLAG=1, FLAG=0, K;
   char INFILE[_MAX_PATH], OUTFILE[_MAX_PATH];

   signal(SIGINT,BREAKREQ);

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

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

   if ((!CODE) && ((FACTOR >=1.) || (FACTOR <= 0.)))
      {
      Zencode(10,"DBSMOOTH: Invalid FACTOR for Kalman Filter\n");
      Zexit(1);
      }

   if ((CODE==1) && ((FACTOR <= 2.) || (FACTOR > (double)SMLimit)))
      {
      Zencode(10,"DBSMOOTH: Invalid FACTOR for Running Average Smooth\n");
      Zexit(1);
      }

   nBOX = (short)FACTOR;
   ZBuildFileName(M_inname,INFILE);
   ZBuildFileName(M_outname,OUTFILE);
   ZBuildFileName(M_tmpname,TMPFILE);

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

   switch (FileHeader.type)
      {
      case R_Data:
      case TR_Data:
         break;
      default:
         Zencode(10,"DBSMOOTH: Invalid File Type.\n");
         Zexit(1);
      }

   Zencode(2,"DBSMOOTH: Opening Scratch File '%s'\n",TMPFILE);
   if (((OUTSTR = Zopen(TMPFILE,O_writeb)) == NULL) ||
       (Zputhead(OUTSTR,&FileHeader))) Zexit(1);

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

   while (Zread(INSTR,BUFFER,FileHeader.type))
      {
      switch (FileHeader.type)
         {
         case R_Data:
            IDATA = RDataPntr->y;
            FLAG = RDataPntr->f;
            break;
         case TR_Data:
            IDATA = TRDataPntr->y;
            break;
         }

      if (!FLAG)
         {
         if (IFLAG)
            {
            YINMIN = YINMAX = IDATA;
            IFLAG = 0;
            }
         else
            {
            YINMAX = Max(YINMAX,IDATA);
            YINMIN = Min(YINMIN,IDATA);
            }
         switch (CODE)
            {
            case 0: /* Kalman Filter */
               if (FFLAG)
                  {
                  LASTVAL = IDATA;
                  FFLAG = 0;
                  }
               else
                  {
                  ODATA = (1.-FACTOR)*LASTVAL + FACTOR*IDATA;
                  LASTVAL = IDATA;
                  }
               break;
            case 1: /* Running Average */
               if (++COUNT < nBOX)
                  {
                  SUM += (DBUFF[J] = IDATA);
                  ODATA = SUM/++J;
                  }
                else
                  {
                  DBUFF[J] = IDATA;
                  K = J - nBOX;
                  if (K < 0) K += (nBOX + 1);
                  SUM += (DBUFF[J] - DBUFF[K]);
                  if (++J > nBOX) J=0;
                  ODATA = SUM/FACTOR;
                  }
                break;
            } /* End switch CODE */
         switch (FileHeader.type)
            {
            case R_Data:
               RDataPntr->y = ODATA;
               break;
            case TR_Data:
               TRDataPntr->y = ODATA;
               break;
            }
         if (OFLAG)
            {
            YOUTMIN = YOUTMAX = ODATA;
            OFLAG = 0;
            }
         else
            {
            YOUTMAX = Max(YOUTMAX,ODATA);
            YOUTMIN = Min(YOUTMIN,ODATA);
            }
         } /* End if FLAG */

      if (Zwrite(OUTSTR,BUFFER,FileHeader.type))
         {
         ERRFLAG = 1;
         break;
         }
      } /* End WHILE */

   if (ferror(INSTR)) ERRFLAG = 1;

   if (!ERRFLAG)
      {
      Zencode(2,"DBSMOOTH: %G Data Points Processed\n",TOTAL);
      Zencode(3,"DBSMOOTH: Old Amplitude Range %G,%G\n",YINMIN,YINMAX);
      Zencode(3,"DBSMOOTH: New Amplitude Range %G,%G\n",YOUTMIN,YOUTMAX);
      }
     
EXIT:
   Zclose(INSTR);
   Zclose(OUTSTR);
   ERRFLAG = Znameout(OUTFILE,TMPFILE,ERRFLAG);
   Zexit(ERRFLAG);
   }

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