/*********************************************************************
*
*  Task DBSUBSET
*
*  Task to take a subset of a data base by time and value.
*  For time labeled file, points that fall out of range or deleted.
*  For time series files, points are only deleted if the time stamp
*  is outside the specified window, values with an amplitude outside
*  the specified window are flagged as bad since thier position is
*  is inpartant
*  value (b) must be updated if leading points are removed.
*
*  CODE is used to select the type of editing, if 1 then 
*  all points inside the selected time range are deleted
*  if 2 all points in the YRANGE are deleted, if 3 then
*  all points in TRANGE and YRANGE are deleted.
*
*/
#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 TMPFILE[_MAX_PATH];  /* Must be visible to BREAKREQ */

main(argc,argv)
short argc;
char *argv[];
   {
   char INFILE[_MAX_PATH], OUTFILE[_MAX_PATH], BUFFER[sizeof(struct TXData)];
   double TIME, VALUE, FCNT=0., WCNT=0., DCNT=0., TCNT=0., TB;
   FILE *INSTR, *OUTSTR;
   struct FILEHDR FileHeader;
   short ERRFLAG=0;
   struct RData  *RDataPntr;
   struct TRData *TRDataPntr;
   struct XData  *XDataPntr;
   struct TXData *TXDataPntr;

   signal(SIGINT,BREAKREQ);  /* Setup ^C Interrupt */

   if (Ztskinit("DBSUBSET",argv[0])) Zexit(1);  /* Intialize task */

   if ((CODE<0) || (CODE>3)) CODE = 0;

   ZBuildFileName(M_inname,INFILE);    /* Build file names */
   ZBuildFileName(M_outname,OUTFILE);
   ZBuildFileName(M_tmpname,TMPFILE);

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

   Zencode(2,"DBSUBSET: Opening Scratch File '%s'\n",TMPFILE);
   if (((OUTSTR = Zopen(TMPFILE,O_writeb)) == NULL) ||
        Zputhead(OUTSTR,&FileHeader))
      {
      ERRFLAG=1;
      goto EXIT;
      }

   TB = FileHeader.b;  /* Save time intercept in case we change it */

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

   while (Zread(INSTR,BUFFER,FileHeader.type))
      {
      switch (FileHeader.type)
         {
         case R_Data:   /* Real time series */
            TIME = TCNT*FileHeader.m + FileHeader.b;
            VALUE = RDataPntr->y;
            switch (CODE)
               {
               case 0:  /* Delete values outside time range */
                  if (((TIME < TRANGE[0])  ||   
                      (TIME > TRANGE[1])) &&
                      (TRANGE[0] < TRANGE[1]))
                     {
                     ++DCNT;        /* Count deleted  points*/
                     if (TIME < TRANGE[0])
                        TB = (TCNT+1.)*FileHeader.m + FileHeader.b;
                     }
                  else
                    {
                    if (((VALUE < YRANGE[0])  ||
                        (VALUE > YRANGE[1])) &&
                        (YRANGE[0] < YRANGE[1]))
                       {
                       RDataPntr->f = 1;
                       ++FCNT;                /* Count flagged points */
                       }
                    if (Zwrite(OUTSTR,BUFFER,R_Data))
                       {
                       ERRFLAG = 1;
                       goto EXIT;
                       }
                    ++WCNT;       /* Count points written */
                    }
                  break;
               case 1:  /* Delete values inside time range */
                  if ((TIME >= TRANGE[0]) && (TIME <= TRANGE[1]))
                    {
                    RDataPntr->f = 1;
                    ++FCNT;                /* Count flagged points */
                    }
                  if (Zwrite(OUTSTR,BUFFER,R_Data))
                    {
                    ERRFLAG = 1;
                    goto EXIT;
                    }
                  ++WCNT;       /* Count points written */
                  break;
               case 2:  /* Delete values inside Amp range */
                  if ((VALUE >= YRANGE[0]) && (VALUE <= YRANGE[1]))
                    {
                    RDataPntr->f = 1;
                    ++FCNT;                /* Count flagged points */
                    }
                  if (Zwrite(OUTSTR,BUFFER,R_Data))
                    {
                    ERRFLAG = 1;
                    goto EXIT;
                    }
                  ++WCNT;       /* Count points written */
                  break;
               case 3:  /* Delete values inside time and Amp range */
                  if (((TIME >= TRANGE[0] ) && (TIME <= TRANGE[1] )) &&
                      ((VALUE >= YRANGE[0]) && (VALUE <= YRANGE[1])))
                    {
                    RDataPntr->f = 1;
                    ++FCNT;                /* Count flagged points */
                    }
                  if (Zwrite(OUTSTR,BUFFER,R_Data))
                    {
                    ERRFLAG = 1;
                    goto EXIT;
                    }
                  ++WCNT;       /* Count points written */
                  break;
               }
            break;
         case TR_Data:
            TIME = TRDataPntr->t;
            VALUE = TRDataPntr->y;
            switch (CODE)
               {
               case 0:  /* Delete values outside time range */
                  if ((((VALUE < YRANGE[0])     ||
                        (VALUE > YRANGE[1]))    &&
                       (YRANGE[0] < YRANGE[1])) ||
                      (((TIME < TRANGE[0])      ||
                        (TIME > TRANGE[1]))     &&
                       (TRANGE[0] < TRANGE[1])))
                     {
                     ++DCNT;                       /* Count deletes */
                     }
                  else
                     {
                     if (Zwrite(OUTSTR,BUFFER,TR_Data))
                        {
                        ERRFLAG = 1;
                        goto EXIT;
                        }
                     ++WCNT;
                     }
                  break;
               case 1:  /* Delete values inside time range */
                  if ((TIME >= TRANGE[0]) && (TIME <= TRANGE[1]))
                     {
                     ++DCNT;                       /* Count deletes */
                     }
                  else
                     {
                     if (Zwrite(OUTSTR,BUFFER,TR_Data))
                        {
                        ERRFLAG = 1;
                        goto EXIT;
                        }
                     ++WCNT;
                     }
                  break;
               case 2:  /* Delete values inside Amp range */
                  if ((VALUE >= YRANGE[0]) && (VALUE <= YRANGE[1]))
                     {
                     ++DCNT;                       /* Count deletes */
                     }
                  else
                     {
                     if (Zwrite(OUTSTR,BUFFER,TR_Data))
                        {
                        ERRFLAG = 1;
                        goto EXIT;
                        }
                     ++WCNT;
                     }
                  break;
               case 3:  /* Delete values inside time and Amp range */
                  if (((TIME >= TRANGE[0] ) && (TIME <= TRANGE[1] )) &&
                      ((VALUE >= YRANGE[0]) && (VALUE <= YRANGE[1])))
                     {
                     ++DCNT;                       /* Count deletes */
                     }
                  else
                     {
                     if (Zwrite(OUTSTR,BUFFER,TR_Data))
                        {
                        ERRFLAG = 1;
                        goto EXIT;
                        }
                     ++WCNT;
                     }
                  break;
               }
            break;
         case X_Data:
            TIME = TCNT*FileHeader.m + FileHeader.b;
            VALUE = cabs(XDataPntr->z);
            switch (CODE)
               {
               case 0:  /* Delete values outside time range */
                  if (((TIME < TRANGE[0])  ||
                      (TIME > TRANGE[1])) &&
                      (TRANGE[0] < TRANGE[1]))
                     {
                     ++DCNT;
                     if (TIME < TRANGE[0])
                        TB = (TCNT+1.)*FileHeader.m + FileHeader.b;
                     }
                  else
                    {
                    if (((VALUE < YRANGE[0])  ||
                        (VALUE > YRANGE[1])) &&
                        (YRANGE[0] < YRANGE[1]))
                       {
                       XDataPntr->f = 1;
                       ++FCNT;                     /* Count flags */
                       }
                    if (Zwrite(OUTSTR,BUFFER,X_Data))
                       {
                       ERRFLAG = 1;
                       goto EXIT;
                       }
                    ++WCNT;                        /* Count writes */
                    }
                  break;
               case 1:  /* Delete values inside time range */
                  if ((TIME >= TRANGE[0]) && (TIME <= TRANGE[1]))
                     {
                     XDataPntr->f = 1;
                     ++FCNT;                     /* Count flags */
                     }
                  if (Zwrite(OUTSTR,BUFFER,X_Data))
                     {
                     ERRFLAG = 1;
                     goto EXIT;
                     }
                  ++WCNT;                        /* Count writes */
                  break;
               case 2:  /* Delete values inside Amp range */
                  if ((VALUE >= YRANGE[0]) && (VALUE <= YRANGE[1]))
                     {
                     XDataPntr->f = 1;
                     ++FCNT;                     /* Count flags */
                     }
                  if (Zwrite(OUTSTR,BUFFER,X_Data))
                     {
                     ERRFLAG = 1;
                     goto EXIT;
                     }
                  ++WCNT;                        /* Count writes */
                  break;
               case 3:  /* Delete values inside time and Amp range */
                  if (((TIME >= TRANGE[0] ) && (TIME <= TRANGE[1]) ) &&
                      ((VALUE >= YRANGE[0]) && (VALUE <= YRANGE[1])))
                     {
                     XDataPntr->f = 1;
                     ++FCNT;                     /* Count flags */
                     }
                  if (Zwrite(OUTSTR,BUFFER,X_Data))
                     {
                     ERRFLAG = 1;
                     goto EXIT;
                     }
                  ++WCNT;                        /* Count writes */
                  break;
               }
            break;
         case TX_Data:
            TIME = TXDataPntr->t;
            VALUE = cabs(TXDataPntr->z);
            switch (CODE)
               {
               case 0:  /* Delete values outside time range */
                  if ((((VALUE < YRANGE[0])     ||
                        (VALUE > YRANGE[1]))    &&
                       (YRANGE[0] < YRANGE[1])) ||
                      (((TIME < TRANGE[0])      ||
                        (TIME > TRANGE[1]))     &&
                       (TRANGE[0] < TRANGE[1])))
                     {
                     ++DCNT;                       /* Count deletes */
                     }
                  else
                     {
                     if (Zwrite(OUTSTR,BUFFER,TX_Data))
                        {
                        ERRFLAG = 1;
                        goto EXIT;
                        }
                     ++WCNT;                       /* Count writes */
                     }
                  break;
               case 1:  /* Delete values inside time range */
                  if ((TIME >= TRANGE[0]) && (TIME <= TRANGE[1]))
                     {
                     ++DCNT;                       /* Count deletes */
                     }
                  else
                     {
                     if (Zwrite(OUTSTR,BUFFER,TX_Data))
                        {
                        ERRFLAG = 1;
                        goto EXIT;
                        }
                     ++WCNT;                       /* Count writes */
                     }
                  break;
               case 2:  /* Delete values inside Amp range */
                  if ((VALUE >= YRANGE[0]) && (VALUE <= YRANGE[1]))
                     {
                     ++DCNT;                       /* Count deletes */
                     }
                  else
                     {
                     if (Zwrite(OUTSTR,BUFFER,TX_Data))
                        {
                        ERRFLAG = 1;
                        goto EXIT;
                        }
                     ++WCNT;                       /* Count writes */
                     }
                  break;
               case 3:  /* Delete values inside time and Amp range */
                  if (((TIME >= TRANGE[0] ) && (TIME <= TRANGE[1] ))&&
                      ((VALUE >= YRANGE[0]) && (VALUE <= YRANGE[1])))
                     {
                     ++DCNT;                       /* Count deletes */
                     }
                  else
                     {
                     if (Zwrite(OUTSTR,BUFFER,TX_Data))
                        {
                        ERRFLAG = 1;
                        goto EXIT;
                        }
                     ++WCNT;                       /* Count writes */
                     }
                  break;
               }
            break;
         }
      ++TCNT;                                /* Count data read */
      } /* End WHILE */

   FileHeader.b = TB;                       /* Update intercept */
   if ((Zputhead(OUTSTR,&FileHeader)) ||
       (ferror(INSTR)))
      ERRFLAG = 1;
   else
      {
      Zencode(2,"DBSUBSET: %G Data Points Processed\n",TCNT);
      Zencode(3,"DBSUBSET: %G Data Points Written\n",WCNT);
      switch (FileHeader.type)
         {
         case R_Data:  /* Only time series can have flagged points */
         case X_Data:
            Zencode(3,"DBSUBSET: %G Data Points Flagged\n",FCNT);
         case TR_Data:
         case TX_Data:
            Zencode(3,"DBSUBSET: %G Data Points Deleted\n",DCNT);
            break;
         }
      }

EXIT:
   Zclose(INSTR);
   Zclose(OUTSTR);
   ERRFLAG = Znameout(OUTFILE,TMPFILE,ERRFLAG);
   Zexit(ERRFLAG);
   }

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