/****************************************************************************/
/* Copyright (c) 2000 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : AdaptiveSampler.cc                                            */
/* Author   : Rob McEwen                                                    */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 02/07/2000                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
#include "AdaptiveSampler.h"
#include "PeriodicTask.h"
#include "SerialDevice.h"
#include "Syslog.h"
#include "TimeP.h"
#include <AttributeParser.h>
#include <IntegerAttribute.h>
#include <FloatAttribute.h>
#include <StringAttribute.h>


AdaptiveSampler::AdaptiveSampler( Boolean test, char *config )
   : PeriodicTask("adaptiveSamplerDriver"), _config(config),
     _attributes(config), NotSpecified(-1), _test(test)
{
   Boolean debug = False;

   _log = new AdaptiveSamplerLog(this, DataLog::BinaryFormat);
   _output= new AdaptiveSamplerOutput();
   try 
   {
      _gulper = new GulperIF(GulperIFServerName);
   } 
   catch(...)
   {
      Syslog::write("AdaptiveSampler:: -- Failed to initialize connection "
		    "to GulperIF\n");
   }
   //
   // Zero interface pointers in case one or more doesn't open.
   _nav       = NULL;
   _ctd       = NULL;
   _ctd2       = NULL;
   _parosci   = NULL;
   _hydroscat = NULL;
// _biolume   = NULL;


   if( !_test )
   {
      try 
      {
	 _nav = new NavigationIF(NavigationIFServerName);
      } 
      catch(...)
      {
	 Syslog::write("AdaptiveSampler:: -- Failed to initialize connection "
		       "to NavigationIF\n");
      }

      try 
      {
	 _ctd = new CtdIF(CtdIFServerName, "ctdDriver");
	 _ctd2 = new CtdIF(CtdIFServerName, "ctdDriver2");
      } 
      catch(...)
      {
	 Syslog::write("AdaptiveSampler:: -- Failed to initialize connection "
		       "to CtdIF\n");
      }

      try 
      {
	 _parosci = new DepthSensorIF(DepthSensorIFServerName);
      } 
      catch(...)
      {
	 Syslog::write("AdaptiveSampler:: -- Failed to initialize connection "
		       "to DepthSensorIF\n");
      }

      try 
      {
	 _hydroscat = new HydroscatIF(HydroscatIFServerName);
      } 
      catch(...)
      {
	 Syslog::write("AdaptiveSampler:: -- Failed to initialize connection "
		       "to HydroscatIF\n");
      }

#if 0
      try 
      {
	 _biolume = new BiolumeIF(BiolumeIFServerName);
      } 
      catch(...)
      {
	 Syslog::write("AdaptiveSampler:: -- Failed to initialize connection "
		       "to BiolumeIF\n");
      }
#endif
   }
   else
     _ptr_input_file = fopen("dep_temp_fl_bb470_bb676.dat", "r");

   addPeriodicCallback(200, (CallbackMethod)AdaptiveSampler::readData);

   //for( int i=0; i<NGULPERS; i++ ) _gulperState[i] = AdaptiveSamplerIF::Unarmed;
   for( int i=0; i<NGULPERS; i++ ) 
      _output->data.gulperState[i] = AdaptiveSamplerIF::Unarmed;

   for( i=0; i<NGULPERS; i++ ) 
      for( int j=0; j<MAXSAMPLES; j++ ) 
	 _gulpArray[i][j] = False;

   char configFile[128];
   strcpy(configFile, System::configurationFile(_config));
   configFile[127]='\0';
   dprintf("Configuration file = %s\n", configFile);
   createCfgAttributes();
   loadConfigFile(configFile);
   System::copyToLogDir(configFile);
   printCfgAttributes();

   if (_option_RHOD >= 1)
     {
       _num_PeakSignals = 2;
       _cntr_rhod = 0;
       _rhod_maxInWindow = 0.0;
       _rhod_sumInWindow = 0.0;
       _rhod_AvgProfile = 0.0;

       for (i=0; i<=2; i++)
	 _rhod_lp[i] = 0.0;

       for (i=0; i<=(_len_window_full-1); i++)
	 _rhod_inwindow[i] = 0.0;

       for (i=0; i<=(_num_profiles_BaselineWindow-1); i++)
	 _rhod_avg_profile[i] = 0.0;

       _flag_crossingDepRhodMaxOnPrecedingProfile = 0;
       _crossingDepRhodMaxOnPrecedingProfileCheck = False;
     }
   else
     _num_PeakSignals = 1;

   if ((_option_RHOD == 0) || (_option_RHOD == 1))
     _indSignalCapture = 0; // Initialized to zero. 0 = chl, 1 = rhodamine.

   if (_option_RHOD == 2)
     _indSignalCapture = 1; // 1 = rhodamine.

   _cntr_gulp = 0;

   _cntr = 0;
   _cntr_fl_bb = 0;

   _cntr_profiles = 0; // A descent or ascent leg is a profile.
   _cntr_PtsOnProfile = 0;
   _cntr_ProfilesInUpwelling = 0;
   _cntr_ProfilesTempDiff = 0;
   _cntr_ProfilesInTempFront = 0;
   _cntr_ProfilesInFlFront = 0;
   _cntr_ProfilesFl = 0;

   _lastGulpTime = 0.;
   _timeCntr = 0;

   _flag_AllFired = 0;

   for(i=0; i<NGULPERS; i++)
     {
       _flag_gulperArmed[i] = 0;
       _timeGulperArmed[i] = 0.0;
     }

   _state_dep[0] = 1;
   _state_dep[1] = 1;

   for (i=0; i<=(MAXNUMPEAKSIGNALS-1); i++)
     {
       _flag_1stpk[i] = 0;
       _flag_ctrl[i] = 0;
       _state_dep_1stpk[i] = 1;
       _attitude_flop[i] = 0;
       _attitude_flop_flop[i] = 0;

       _peak_saved[i] = 0.0;
       _pk_ctrl[i] = 99; // 0: control sample; 1: peak sample; 99: invalid value.
       _peakCheck[i] = False;
       _cntr_trig[i] = 0;
       _cntr_peak[i] = 0;

       _state_var[i] = 1;

       _var_min[i] = 0.0;
       _var_max[i] = 0.0;
     }

   _dep_min = 0.0;
   _dep_max = 0.0;
   _dep_shallow = 0.0;
   _dep_deep = 0.0;

   _fl676_bkgnd = 0.0;
   _bb470_bkgnd = 0.0;
   _bb676_bkgnd = 0.0;

   _fl676_maxInWindow = 0.0;
   _bb470_maxInWindow = 0.0;
   _bb676_maxInWindow = 0.0;

   _fl676_sumInWindow = 0.0;
   _bb470_sumInWindow = 0.0;
   _bb676_sumInWindow = 0.0;

   for (i=0; i<=2; i++)
     {
       _fl676_lp[i] = 0.0;
       _bb470_lp[i] = 0.0;
     }

   _bb676_lp = 0.0;

   for (i=0; i<=(_len_window_full-1); i++)
     {
       _fl676_inwindow[i] = 0.0;
       _bb470_inwindow[i] = 0.0;
       _bb676_inwindow[i] = 0.0;
     }

   _fl676_AvgProfile = 0.0;
   _bb470_AvgProfile = 0.0;
   _bb676_AvgProfile = 0.0;

   for (i=0; i<=(_num_profiles_BaselineWindow-1); i++)
     {
       _fl676_avg_profile[i] = 0.0;
       _bb470_avg_profile[i] = 0.0;
       _bb676_avg_profile[i] = 0.0;
     }

   for (i=0; i<=(MAXNUMPEAKSIGNALS-1); i++)
     {
       for (int j=0; j<=(MAXSTOREDPEAKS-1); j++)
	 {
	   _peak[i][j] = 0.0;
	   _timeCntr_peak[i][j] = 0.0;
	 }
     }

   for (i=0; i<=(MAXSTOREDDEPTHS-1); i++)
     {
       _dep[i] = 0.0;
     }

   for (i=0; i<=3; i++)
     _tempDep[i] = 0.0;

   _flag_tempdiff_enabled = 1;
   _flag_temp_shallow = 0;
   _flag_temp_midshallow = 0;
   _flag_temp_middeep = 0;
   _flag_temp_deep = 0;
   _upwellingCheck = False;
   _valleyCheck = False;

   _flag_temp_front = 0;
   _flag_fl_front = 0;
   _frontCheck = False;

   _flag_crossingDepFlMaxOnPrecedingProfile = 0;
   _crossingDepFlMaxOnPrecedingProfileCheck = False;

   for(i=0; i<=(_num_ProfilesAvgTempDiff-1); i++)
     _temp_diff[i] = 0.0;

   _tempDiffSumInWindow = 0.0;

   for(i=0; i<=(_num_ProfilesAvgTempDiff+_num_ProfilesGapTempDiff); i++)
     _temp_diff_lp[i] = 0.0;

   _dep_minFrontTriggering = 0.0;
   _dep_maxFrontTriggering = 1.0e4;
   for(i=0; i<NGULPERS; i++)
   {
     if (_frontDetection[i] == 1)
       {
	 if (_minDepth[i] != NotSpecified)
	   {
	     if (_minDepth[i] > _dep_minFrontTriggering)
	       _dep_minFrontTriggering = _minDepth[i];
	   }

	 if (_maxDepth[i] != NotSpecified)
	   {
	     if (_maxDepth[i] < _dep_maxFrontTriggering)
	       _dep_maxFrontTriggering = _maxDepth[i];
	   }
       }
   }

   _flMaxOnProfile = 0.0;
   _dep_flMaxOnProfile = _dep_minFrontTriggering; // Initialized to _dep_minFrontTriggering, not zero meter.
   _dep_flMaxOnPrecedingProfile = _dep_minFrontTriggering; // Initialized to _dep_minFrontTriggering, not zero meter.

   _num_ProfilesFl = _num_ProfilesAvgFl + _num_ProfilesGapFl;
   _flag_fl_shallow = 0;
   _flag_fl_front = 0;

   _rhodMaxOnProfile = 0.0;
   _dep_rhodMaxOnProfile = _dep_minFrontTriggering; // Initialized to _dep_minFrontTriggering, not zero meter.
   _dep_rhodMaxOnPrecedingProfile = _dep_minFrontTriggering; // Initialized to _dep_minFrontTriggering, not zero meter.

   //
   // Check sample array size
   for( i=0; i< NGULPERS; i++) 
   {
      if( _nSamples[i] > MAXSAMPLES )
      {
	 _nSamples[i] = MAXSAMPLES;
	 Syslog::write("Number of samples for gulper %d is too high; "
		       "resetting to %d", i, MAXSAMPLES);
      }
   }
}

AdaptiveSampler::~AdaptiveSampler()
{
   Syslog::write(" AdaptiveSamplerDestructor Executing.");
   delete _log;
   delete _output;
   delete _gulper;
   if(_nav) delete _nav;
   if(_ctd) delete _ctd;
   if(_ctd2) delete _ctd2;
   if(_parosci) delete _parosci;
   if(_hydroscat) delete _hydroscat;
// if(_biolume) delete _biolume;
   if(_ptr_input_file) fclose(_ptr_input_file);
}


void AdaptiveSampler::initialize()
{
}

void AdaptiveSampler::readData()
{
   int i, j, k;
   DeviceIF::Status status;
   Boolean gulp = False;
   Boolean depthEnbl, depthEnblMaxWait, ctdEnbl, hs2Enbl;
   Boolean newDepth, newSal, newHs2;

   float cond, cfreq, tfreq;
   double cDist, dummy;
   unsigned short  cId;

   float v1, v2, v3, v4, v5, v6;

   _timeCntr++;
 
   _output->read();
//   for(int j=0; j<NGULPERS; j++) printf("%d", _output->data.gulpersToArm[j]); 
//   printf("\n");

//
// Check to see if more gulpers have become armed.  This state will persist
// from waypoint to waypoint, so that gulpers that are armed on one waypoint
// can remain available during subsequent waypoints, unless the FireTheGulper
// behavior fires one.
//
   _gulper->state( _gulperDriverState );
   for( i=0; i<NGULPERS; i++ )
   {
      if( _gulperDriverState[i] == GulperIF::Used )
      {
	 _output->data.gulperState[i] = AdaptiveSamplerIF::Fired;
      }
      if( _output->data.gulpersToArm[i] == True )
      {
	 if( _output->data.gulperState[i] == AdaptiveSamplerIF::Fired )
	 {
	    Syslog::write("AdaptiveSampler::readData - "
			  "Cannot arm Gulper %d.  It has already fired.",i);
	    _output->data.gulpersToArm[i] = False;
	 } 
	 else _output->data.gulperState[i] = AdaptiveSamplerIF::Armed;
      }
   }
   _cntr++;
   if( _cntr >= 30000 ) _cntr = 0;
   _output->data.cntr = _cntr;
   _output->write();

   struct timespec timeSpec;
   double now;
   clock_gettime(CLOCK_REALTIME, &timeSpec);
   now = Time::seconds(&timeSpec);

   if( !_test )
     {
       //
       // Read in navigation data and sensor values:
       //
       _nav->state( &_position, &_attitude );

       //
       // CTD
       //
       //debug
       //rhodamine
       // Double check the signal channel: which CTD? Which v?
       if (_option_RHOD >= 1)
	 {
	   status = _ctd2->voltages(&v1, &v2, &v3, &v4, &v5, &v6);
	   _rhod = (double) v1;
	 }

       status = _ctd->conductivity( &cond,         &cfreq, &_condTime);
       status = _ctd->temperature(  &_temperature, &tfreq, &_tempTime);
       status = _ctd->salinity( &_salinity );
       if( ( (_condTime.seconds     != _condTimeLast.seconds)     ||
	     (_condTime.nanoSeconds != _condTimeLast.nanoSeconds) ||
	     (_tempTime.seconds     != _tempTimeLast.seconds)     ||
	     (_tempTime.nanoSeconds != _tempTimeLast.nanoSeconds) )  &&
	   status == DeviceIF::Ok )
	 newSal = True;
       else
	 newSal = False;

       _condTimeLast.seconds      = _condTime.seconds;
       _condTimeLast.nanoSeconds  = _condTime.nanoSeconds;
       _tempTimeLast.seconds      = _tempTime.seconds;
       _tempTimeLast.nanoSeconds  = _tempTime.nanoSeconds;
       //
       // Parosci
       //
       status = _parosci->depth( &_depth, &_depthTime );
       if( ( (_depthTime.seconds     != _depthTimeLast.seconds)     ||
	     (_depthTime.nanoSeconds != _depthTimeLast.nanoSeconds) )  &&
	   status == DeviceIF::Ok )
	 newDepth = True;
       else
	 newDepth = False;

       _depthTimeLast.seconds     = _depthTime.seconds;
       _depthTimeLast.nanoSeconds = _depthTime.nanoSeconds;
       //
       // HS2
       //
       status = _hydroscat->getData( &_hs2data );
       if( ( (_hs2data.seconds      != _hs2LastSeconds)     ||
	     (_hs2data.hseconds     != _hs2LastMicroSeconds) )  &&
	   status == DeviceIF::Ok )
	 newHs2 = True;
       else
	 newHs2 = False;

       _hs2LastSeconds      = _hs2data.seconds;
       _hs2LastMicroSeconds = _hs2data.hseconds;

       _fl676 = _hs2data.calculated.fl676_uncorr;
       _bb470 = _hs2data.calculated.bb470;
       _bb676 = _hs2data.calculated.bb676; 

       // Only a new valid depth reading is used in the "if (newHs2)" loop.
       if (newDepth  && (_depth > SHALLOWLIMIT_DEPTH))
	 {
	   // _dep[0] stores the newest depth. _dep[4] stores the oldest depth.
	   for (i=3; i>=0; i--)
	     _dep[i+1] = _dep[i];
	   
	   _dep[0] = _depth;
	 }

      for (i=0; i<=(_num_PeakSignals-1); i++)
	{
	  _peakCheck[i] = False;
	  _pk_ctrl[i] = 99; // 0: control sample; 1: peak sample; 99: invalid value.
	}

       _flag_peakOrCtrlTriggered = 0;

       _valleyCheck = False;

       _crossingDepFlMaxOnPrecedingProfileCheck = False;

       if (_option_RHOD >= 1)
	 _crossingDepRhodMaxOnPrecedingProfileCheck = False;

       // Bit 0 of _hs2data.error == 1: too high background
       // Bit 1 of _hs2data.error == 1: too high signal
       // See page 33 in
       // "HydroScat2 Spectral Backscattering Sensor User's Manual, Revision H, June 2008"
       if (newHs2 && ((_hs2data.error & 3) == 0) && 
	   (_fl676 > LOWERLIMIT_FL_BB) && (_fl676 < UPPERLIMIT_FL_BB) &&
	   (_bb470 > LOWERLIMIT_FL_BB) && (_bb470 < UPPERLIMIT_FL_BB) &&
	   (_bb676 > LOWERLIMIT_FL_BB) && (_bb676 < UPPERLIMIT_FL_BB))
	 peakDetection();
     }
   else
     {
      // Hardcode sensor readings
      if( !(_cntr % 2) ) _salinity = 35.;
      else _salinity = 10.;
      if( !(_cntr % 2) ) _depth = 3.;
      else _depth = 1.;
      newDepth = True;
      newSal   = True;
      newHs2   = True;

      if(_ptr_input_file)
	 fscanf(_ptr_input_file, "%lf %lf %f %lf %lf %lf", &_timeFromDataFile, &_depth, &_temperature, &_fl676, &_bb470, &_bb676);

      //debug
      //printf("%f %f %f %f %f %f\n", _timeFromDataFile, _depth, _temperature, _fl676, _bb470, _bb676);

       if (_option_RHOD >= 1)
	 {
	   //hack.
	   _rhod = _bb470;
	 }

      for (i=0; i<=(_num_PeakSignals-1); i++)
	{
	  _peakCheck[i] = False;
	  _pk_ctrl[i] = 99; // 0: control sample; 1: peak sample; 99: invalid value.
	}

      _flag_peakOrCtrlTriggered = 0;

      _valleyCheck = False;

      _crossingDepFlMaxOnPrecedingProfileCheck = False;

       if (_option_RHOD >= 1)
	 _crossingDepRhodMaxOnPrecedingProfileCheck = False;

      // Only a new valid depth reading is used in the "if (newHs2)" loop.
      if (newDepth  && (_depth > SHALLOWLIMIT_DEPTH))
	{
	   // _dep[0] stores the newest depth. _dep[4] stores the oldest depth.
	  for (i=3; i>=0; i--)
	    _dep[i+1] = _dep[i];

	  _dep[0] = _depth;
	}

      if (newHs2 && 
	  (_fl676 > LOWERLIMIT_FL_BB) && (_fl676 < UPPERLIMIT_FL_BB) &&
	  (_bb470 > LOWERLIMIT_FL_BB) && (_bb470 < UPPERLIMIT_FL_BB) &&
	  (_bb676 > LOWERLIMIT_FL_BB) && (_bb676 < UPPERLIMIT_FL_BB))
	peakDetection();
     }
 
#if 0
   _cntr++;
   if( !(_cntr % 10) )
      for( i=0; i<NGULPERS; i++ ) 
	 Syslog::write("gulperToArm[%d] = %d, gulperState[%d] = %d, "
		    "gulperDriverState[%d] = %d",
		    i, _output->data.gulpersToArm[i], 
		    i, _output->data.gulperState[i], 
		    i, _gulperDriverState[i]);
#endif

// Record the time when each gulper is armed.
   for( i=0; i<NGULPERS; i++ )
     {
       if ((_flag_gulperArmed[i] == 0) && (_output->data.gulperState[i] == AdaptiveSamplerIF::Armed))
	 {
	   clock_gettime(CLOCK_REALTIME, &timeSpec);
	   _timeGulperArmed[i] = Time::seconds(&timeSpec);
	   _flag_gulperArmed[i] = 1;
	   //debug
	   //printf("Gulper arming time, _flag_gulperArmed[%d] = %f, %d\n", i, _timeGulperArmed[i], _flag_gulperArmed[i]);
	 }
     }

//
// Now walk the list and fire any that are armed and meet the criterion.
   for( i=0; i<NGULPERS; i++ )
   {
      if( _output->data.gulperState[i] == AdaptiveSamplerIF::Armed )
      {
	if ( _peakDetection[i] == 0          &&
	     _upwellingDetection[i] == 0     &&
	     _frontDetection[i] == 0         &&
	     _minDepth[i]    == NotSpecified &&
	     _maxDepth[i]    == NotSpecified &&
	     _minSal[i]      == NotSpecified &&
	     _maxSal[i]      == NotSpecified &&
	     _minTemp[i]     == NotSpecified &&
	     _maxTemp[i]     == NotSpecified &&
	     _minfl676[i]    == NotSpecified &&
	     _maxfl676[i]    == NotSpecified &&
	     _minbb470[i]    == NotSpecified &&
	     _maxbb470[i]    == NotSpecified &&
	     _minbb676[i]    == NotSpecified &&
	     _maxbb676[i]    == NotSpecified &&
	     _minrhod[i]    == NotSpecified &&
	     _maxrhod[i]    == NotSpecified &&
	     _minTempDiffVert[i] == NotSpecified &&
	     _maxTempDiffVert[i] == NotSpecified
	     ) continue;

	 //
	 // Initialize tests:
	 _depthCheck = True; depthEnbl = False;
	 _salCheck   = True; ctdEnbl   = False;
	 _tempCheck  = True; 
	 _fl676Check = True; hs2Enbl   = False;
	 _bb470Check = True;
	 _bb676Check = True;
	 _rhodCheck = True;
	 _tempDiffVertCheck = True;
	 _depthCheckMaxWait = True; depthEnblMaxWait = False;

	 gulp = False;

	 if( (_minDepth[i] != NotSpecified) || 
	     (_maxDepth[i] != NotSpecified)   ) depthEnbl = True;

	 if( (_minDepth[i] != NotSpecified) && (_depth < _minDepth[i]) )
	    _depthCheck = False;
	 if( (_maxDepth[i] != NotSpecified) && (_depth > _maxDepth[i]) )
	    _depthCheck = False;

	 if( (_minDepthMaxWait[i] != NotSpecified) || 
	     (_maxDepthMaxWait[i] != NotSpecified) ) depthEnblMaxWait = True;

	 if (((_minDepthMaxWait[i] != NotSpecified) && 
	      (_depth < _minDepthMaxWait[i])) || 
	     ((_maxDepthMaxWait[i] != NotSpecified) && 
	      (_depth > _maxDepthMaxWait[i])))
	   _depthCheckMaxWait = False;

	 if( (_minSal[i]  != NotSpecified) || 
	     (_maxSal[i]  != NotSpecified) ||
	     (_minTemp[i] != NotSpecified) ||
	     (_maxTemp[i] != NotSpecified)   ) ctdEnbl = True;

	 if( (_minSal[i] != NotSpecified) && (_salinity < _minSal[i]) )
	    _salCheck = False;
	 if( (_maxSal[i] != NotSpecified) && (_salinity > _maxSal[i]) )
	    _salCheck = False;

	 if( (_minTemp[i] != NotSpecified) && (_temperature < _minTemp[i]) )
	    _tempCheck = False;
	 if( (_maxTemp[i] != NotSpecified) && (_temperature > _maxTemp[i]) )
	    _tempCheck = False;
	 if ((_minDepChange[i] != NotSpecified) &&
	     ((_depth - _lastGulpDepth) >= (-_minDepChange[i])) &&
	     ((_depth - _lastGulpDepth) <= _minDepChange[i]))
	   _tempCheck = False;

	 if( (_minfl676[i] != NotSpecified) || 
	     (_maxfl676[i] != NotSpecified) ||  
	     (_minbb470[i] != NotSpecified) || 
	     (_maxbb470[i] != NotSpecified) ||  
	     (_minbb676[i] != NotSpecified) || 
	     (_maxbb676[i] != NotSpecified) ||
	     (_minrhod[i] != NotSpecified) || 
	     (_maxrhod[i] != NotSpecified) ||
	      _len_window_full != NotSpecified) hs2Enbl = True;

	 if( (_minfl676[i] != NotSpecified) && (_fl676 < _minfl676[i]) )
	    _fl676Check = False;
	 if( (_maxfl676[i] != NotSpecified) && (_fl676 > _maxfl676[i]))
	    _fl676Check = False;

	 if( (_minbb470[i] != NotSpecified) && (_bb470 < _minbb470[i]) )
	    _bb470Check = False;
	 if( (_maxbb470[i] != NotSpecified) && (_bb470 > _maxbb470[i]))
	    _bb470Check = False;

	 if( (_minbb676[i] != NotSpecified) && (_bb676 < _minbb676[i]) )
	    _bb676Check = False;
	 if( (_maxbb676[i] != NotSpecified) && (_bb676 > _maxbb676[i]))
	    _bb676Check = False;

	 if( (_indSignalCapture == 1) && (_minrhod[i] != NotSpecified) && (_rhod < _minrhod[i]) )
	    _rhodCheck = False;
	 if( (_indSignalCapture == 1) && (_maxrhod[i] != NotSpecified) && (_rhod > _maxrhod[i]))
	    _rhodCheck = False;

	 if(((_minTempDiffVert[i] != NotSpecified) && (_temp_diff[0] < _minTempDiffVert[i])) ||
	    ((_maxTempDiffVert[i] != NotSpecified) && (_temp_diff[0] > _maxTempDiffVert[i])))
	   _tempDiffVertCheck = False;

	 if (((_peakDetection[i] == 0) &&
	      (_upwellingDetection[i] == 0) &&
	      (_frontDetection[i] == 0) &&
	      _depthCheck    && 
	      _salCheck      && 
	      _tempCheck     && 
	      _fl676Check    &&    
	      _bb470Check    &&  
	      _bb676Check    &&
              _rhodCheck)                ||
	     ((_peakDetection[i] == 1) &&
	      (_upwellingDetection[i] == 0) &&
	      (_frontDetection[i] == 0) &&
	      _peakCheck[_indSignalCapture]     &&
	      _depthCheck    && 
	      _salCheck      && 
	      _tempCheck     && 
	      _fl676Check    &&    
	      _bb470Check    &&  
	      _bb676Check    &&
              _rhodCheck     &&
	      _tempDiffVertCheck)        ||
	     ((_peakDetection[i] == 0) &&
	      (_upwellingDetection[i] == 1) &&
	      (_frontDetection[i] == 0) &&
	      _upwellingCheck     &&
	      ((depthEnbl && _depthCheck) ||
	       (!depthEnbl && _valleyCheck))    && 
	      _salCheck      && 
	      _tempCheck     && 
	      _fl676Check    &&    
	      _bb470Check    &&
	      _bb676Check    &&
              _rhodCheck)               ||
	     ((_peakDetection[i] == 0) &&
	      (_upwellingDetection[i] == 0) &&
	      (_frontDetection[i] == 1) &&
	      _frontCheck    &&
	      _depthCheck    && 
	      _salCheck      && 
	      _tempCheck     && 
	      _fl676Check    &&    
	      _bb470Check    &&
	      _bb676Check    &&
              _rhodCheck))
	   {
	     gulp = True;
	   }

	 if ((_timeMaxWait[i] != NotSpecified)    &&
	     ((((_GulperNumberRefMaxWait[i] == NotSpecified) && (_flag_gulperArmed[i] == 1) && ((_timeGulperArmed[i] + _timeMaxWait[i]) < now)) || 
	       ((_GulperNumberRefMaxWait[i] != NotSpecified) && 
		(_output->data.gulperState[_GulperNumberRefMaxWait[i]] == AdaptiveSamplerIF::Fired) && 
		((_lastGulpTime + _timeMaxWait[i]) < now))) &&
	      ((depthEnblMaxWait && _depthCheckMaxWait) || 
	       ((!depthEnblMaxWait) && 
		(((_peakDetection[i] == 1) &&
		  ((_indSignalCapture == 0) && 
		   _crossingDepFlMaxOnPrecedingProfileCheck) ||
		  ((_indSignalCapture == 1) &&
		   _crossingDepRhodMaxOnPrecedingProfileCheck)) ||
		 ((_peakDetection[i] == 0) && _tempCheck))))))
	   {
	     gulp = True;

	     if (_peakDetection[i] == 1)
	       {
		 _cntr_trig[_indSignalCapture]++; // Maxwait peak also counted as a peak.
		 if (_cntr_trig[_indSignalCapture] >= _ratio_pktrigs_ctrltrigs)
		   _flag_ctrl[_indSignalCapture] = 1; // Enable control triggering.
	       }
	   }
	   	 
#if 0
	 if( !(_cntr % 10) || gulp )
	 {
	    Syslog::write("_depthCheck = %d\n"
			  "_salCheck   = %d\n"
			  "_fl676Check = %d\n",
			  _depthCheck,
			  _salCheck, _fl676Check);
	    Syslog::write("Gulper %d;  gulp = %d\n", i, gulp);
	 }
#endif
	 //
	 // Track how many hits there have been in the last nsamples: (I know
	 // this is lame - I'll implement a ring buffer later when (ha) I get
	 // time.)
	 //
	 // This inherently latches depth, ctd, and hs2 values since the
	 // instruments are asynchronous, that is, they don't update together.
	 //

	 if( (depthEnbl && newDepth) ||
	     (ctdEnbl   && newSal)   ||
	     (hs2Enbl   && newHs2)      )
	    for( j=0; j<_nSamples[i]-1; j++ ) 
	       _gulpArray[i][j] = _gulpArray[i][j+1];
	 
	 _gulpArray[i][_nSamples[i]-1] = gulp;

	 // Now add them up and see if there are enough to gulp:
	 short ngood = 0;
	 for( j=0; j<_nSamples[i]; j++ ) if(_gulpArray[i][j]) ngood++;

#if 0
	 if( _test )
	 {
	    printf("_gulpArray[%d] = ", i);
	    for( int k=0; k<_nSamples[i]; k++ ) printf("%d ", _gulpArray[i][k]);
	    printf("\n");
	    printf("ngood = %d\n", ngood);
	 }
#endif

	 if( ngood >= _nGood[i] )
	 {
	   if (((_peakDetection[i] == 1) || 
		((_peakDetection[i] == 0) && 
		 (_upwellingDetection[i] == 0) && 
		 (_frontDetection[i] == 0)))           &&
	       ((((_pk_ctrl[_indSignalCapture] == 1) 
		  || (_pk_ctrl[_indSignalCapture] == 99)) &&
		 (((_timeLockOutPeak[i] > 0.0) && 
		   (_lastGulpTime + _timeLockOutPeak[i] > now)) ||
		  ((_GulperNumberFiredBefore[i] != NotSpecified) && 
		   (_output->data.gulperState[_GulperNumberFiredBefore[i]] != AdaptiveSamplerIF::Fired)) || 
		  ((_timeLockOutAtStart[i] != NotSpecified) && 
		   (_flag_gulperArmed[i] == 1) && 
		   ((_timeGulperArmed[i] + _timeLockOutAtStart[i]) > now))))  ||
		((_pk_ctrl[_indSignalCapture] == 0) && (_lastGulpTime + 5.0 > now)))) // 5 seconds minimum interval for control sampling.
	     {
	       continue;
	     }

	   if ((_upwellingDetection[i] == 1)   && 
	       (((_timeLockOutUpwelling[i] != NotSpecified) &&
		 (_lastGulpTime + _timeLockOutUpwelling[i] > now)) ||
		((_GulperNumberFiredBefore[i] != NotSpecified) && 
		 (_output->data.gulperState[_GulperNumberFiredBefore[i]] != AdaptiveSamplerIF::Fired)) ||
		((_timeLockOutAtStart[i] != NotSpecified) && 
		 (_flag_gulperArmed[i] == 1) && 
		 ((_timeGulperArmed[i] + _timeLockOutAtStart[i]) > now))))
	     {
	       continue;
	     }

	   if ((_frontDetection[i] == 1)   && 
	       (((_timeLockOutFront[i] != NotSpecified) && 
		 (_lastGulpTime + _timeLockOutFront[i] > now)) ||
		((_GulperNumberFiredBefore[i] != NotSpecified) && 
		 (_output->data.gulperState[_GulperNumberFiredBefore[i]] != AdaptiveSamplerIF::Fired)) ||
		((_timeLockOutAtStart[i] != NotSpecified) && 
		 (_flag_gulperArmed[i] == 1) && 
		 ((_timeGulperArmed[i] + _timeLockOutAtStart[i]) > now))))
	     {
	       continue;
	     }

	    struct timespec timeSpec;
	    clock_gettime(CLOCK_REALTIME, &timeSpec);

	    if (_option_FireAll == 1)
	      {
		if (_flag_AllFired == 0)
		  {
		    _gulper->fireGulper(NGULPERS); // Sends firing signal to the virtual gulper #20 to fire all 20 gulpers.
		    _flag_AllFired = 1;
		  }
	      }
	    else
	      {
		_gulper->fireGulper( i );
		_cntr_gulp++;
	      }

	    if ((!((_peakCheck[_indSignalCapture] 
		    && (_peakDetection[i] == 1)) || 
		   (_upwellingCheck && (_upwellingDetection[i] == 1)) || 
		   (_frontCheck && (_frontDetection[i] == 1)))) && 
		(_timeMaxWait[i] != NotSpecified) &&
		(((_GulperNumberRefMaxWait[i] == NotSpecified) && ((_timeGulperArmed[i] + _timeMaxWait[i]) < now)) || 
		 ((_GulperNumberRefMaxWait[i] != NotSpecified) && 
		  (_output->data.gulperState[_GulperNumberRefMaxWait[i]] == AdaptiveSamplerIF::Fired) && 
		  ((_lastGulpTime + _timeMaxWait[i]) < now))))
		Syslog::write("On max wait-time. Signal type: %d\n", _indSignalCapture);

	    _lastGulpTime = Time::seconds(&timeSpec);
	    _lastGulpDepth = _depth;

	    if (_flag_AllFired == 1)
	      Syslog::write("The Adaptive Sampler has fired all 10 gulpers at t = %.2f\n", _lastGulpTime);
	    else
	      Syslog::write("The Adaptive Sampler has fired gulper %d "
			  "at t = %.2f\n", i, _lastGulpTime);
	    if(_test)
	      Syslog::write("_timeFromDataFile = %.6f\n", _timeFromDataFile);

	    //debug
	    //printf("_cntr_gulp = %d\n", _cntr_gulp);
	    //printf("_peakCheck[%d] = %d\n", _indSignalCapture, _peakCheck[_indSignalCapture]);

	    if (_peakCheck[_indSignalCapture] && (_peakDetection[i] == 1))
	      {
		_flag_peakOrCtrlTriggered = 1;
		Syslog::write("Peak (or control) sample:\n");
		Syslog::write("_pk_ctrl[%d] = %d\n", _indSignalCapture, _pk_ctrl[_indSignalCapture]);
	      }
	    else
	      {
		if (_upwellingCheck && (_upwellingDetection[i] == 1))
		  {
		    Syslog::write("In upwelling water column:\n");
		  }
		else
		  {
		    if (_frontCheck && (_frontDetection[i] == 1))
		      {
			Syslog::write("In front:\n");
		      }
		  }
	      }
	    Syslog::write("_fl676 = %6.2e\n", _fl676);
	    Syslog::write("_bb470 = %6.2e\n", _bb470);
	    Syslog::write("_bb676 = %6.2e\n", _bb676);

	    if (_option_RHOD >= 1)
	      Syslog::write("_rhod = %6.2e\n", _rhod);

	    for (k=0; k<=3; k++)
	      Syslog::write("_tempDep[%d] = %.1f\n", k, _tempDep[k]);

	    Syslog::write("_tempDepAvg = %.1f\n", _tempDepAvg);
	    Syslog::write("_temp_diff[0] = %.1f\n", _temp_diff[0]);
	    Syslog::write("_temp_diff_lp[0] = %.1f\n", _temp_diff_lp[0]);
	    Syslog::write("_temp_diff_lp[0]-_temp_diff_lp[%d] = %.1f\n", (_num_ProfilesAvgTempDiff+_num_ProfilesGapTempDiff), (_temp_diff_lp[0]-_temp_diff_lp[_num_ProfilesAvgTempDiff+_num_ProfilesGapTempDiff]));
	    Syslog::write("_temperature = %.1f\n", _temperature);
	    Syslog::write("_depth = %.1f\n", _depth);

	    if ((_option_RHOD == 1) && (_cntr_gulp == _gulps_ChlOrRhod))
	      {
		_indSignalCapture = 1 - _indSignalCapture; // Switch signal for capture.
		_cntr_gulp = 0;
	      }

	    if (_flag_AllFired == 1)
	      {
		for (k=0; k<NGULPERS; k++)
		  {
		    _output->data.gulperState[k] = AdaptiveSamplerIF::Fired;
		    _output->data.gulpersToArm[k] = False;
		  }
	      }
	    else
	      {
		_output->data.gulperState[i] = AdaptiveSamplerIF::Fired;
		_output->data.gulpersToArm[i] = False;
	      }

	    if( _test )
	    {
	       printf("_gulpArray[%d] = ", i);
	       for( int k=0; k<_nSamples[i]; k++ ) printf("%d ", _gulpArray[i][k]);
	       printf("\n");
	    }
            // for(j=0; j<NGULPERS; j++) printf("%d", _gulperState[j]); 
            // printf("\n");
            // printf("_gulpersToArm = ");
            // for(j=0; j<NGULPERS; j++) 
	    //   printf("%d", _output->data.gulpersToArm[j]); 
            // printf("\n");

	    //
	    // Log the data.
	    _gnum = i;
	    _log->write();
	    _log->flush();
	    if(_flag_AllFired == 1)
	    {
	       //
	       // Capture the gulper state, then jump out of the loop and
	       // if all gulpers have been fired.
	       _output->write();
	       break;
	    }
	 }  //if( ngood >= _nGood[i] )
	 //
	 // Capture the gulper state
	 _output->write();
	 //

	 // If no control-sample triggering for a long time, disable control-sample triggering (thus enabling peak-sample triggering).
	 // Don't add condition (_cntr_trig == _ratio_pktrigs_ctrltrigs) because _pk_ctrl, _flag_ctrl, _cntr_trig = 0, 1, 0 can occur.
	 if ((_peakDetection[i] == 1) && !_peakCheck[_indSignalCapture] 
	     && (_flag_ctrl[_indSignalCapture] == 1) && 
	     (_timeLockOutPeak[i] > 0.0) && ((_lastGulpTime+_timeLockOutPeak[i]) < now))
	   {
	     //debug
	     //printf("No control-sample triggering for a long time:\n");
	     //printf("_lastGulpTime, _timeLockOutPeak[i], now = %f, %f, %f\n\n", _lastGulpTime, _timeLockOutPeak[i], now);

	     _flag_ctrl[_indSignalCapture] = 0;
	     _cntr_trig[_indSignalCapture] = 0;
	   }
      } // if armed
   } //for( i=0; i<NGULPERS; i++ )

   if (_peakCheck[_indSignalCapture] && (_flag_peakOrCtrlTriggered == 0))
     {
       if (_pk_ctrl[_indSignalCapture] == 1)
	 {
	   if ((_cntr_trig[_indSignalCapture] == _ratio_pktrigs_ctrltrigs) 
	       && (_flag_ctrl[_indSignalCapture] == 1))
	     _flag_ctrl[_indSignalCapture] = 0;
	   
	   _cntr_trig[_indSignalCapture]--;

	   //debug	   
	   //printf("_pk_ctrl = 1. Reverse. _cntr_trig = %d\n", _cntr_trig);
	   //printf("_lastGulpTime, now, now-_lastGulpTime = %f, %f, %f\n", _lastGulpTime, now, now-_lastGulpTime);
	   //printf("_depth, _fl676, _temp_diff[0] = %.1f, %6.2e, %.1f\n\n", _depth, _fl676, _temp_diff[0]);
	 }

       if (_pk_ctrl[_indSignalCapture] == 0)
	 {
	   _flag_ctrl[_indSignalCapture] = 1;

	   //debug
	   //printf("_flag_ctrl[%d] = %d\n", _indSignalCapture, _flag_ctrl[_indSignalCapture]);

	   //debug	   
	   //printf("_pk_ctrl = 0. Reverse. _cntr_trig = %d\n", _cntr_trig);
	   //printf("_lastGulpTime, now, now-_lastGulpTime = %f, %f, %f\n", _lastGulpTime, now, now-_lastGulpTime);
	   //printf("_depth, _fl676, _temp_diff[0] = %.1f, %6.2e, %.1f\n\n", _depth, _fl676, _temp_diff[0]);
	 }
     }
}


void AdaptiveSampler::createCfgAttributes()
{
   char nameStr[64];
   for( int i=0; i< NGULPERS; i++ )
   {
      sprintf( nameStr, "timelockoutpeak%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_timeLockOutPeak[i], NotSpecified ) );
      sprintf( nameStr, "timelockoutupwelling%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_timeLockOutUpwelling[i], NotSpecified ) );
      sprintf( nameStr, "timelockoutfront%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr,
					  &_timeLockOutFront[i], NotSpecified ) );
      sprintf( nameStr, "timeLockOutAtStart%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr,
					  &_timeLockOutAtStart[i], NotSpecified ) );
      sprintf( nameStr, "GulperNumberFiredBefore%d", i );
      _attributes.add( new IntegerAttribute(nameStr, nameStr, 
					    &_GulperNumberFiredBefore[i], NotSpecified));
      sprintf( nameStr, "GulperNumberRefMaxWait%d", i );
      _attributes.add( new IntegerAttribute(nameStr, nameStr, 
					    &_GulperNumberRefMaxWait[i], NotSpecified));
      sprintf( nameStr, "timemaxwait%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_timeMaxWait[i], NotSpecified ) );
      sprintf( nameStr, "repeat%d", i );
      _attributes.add( new IntegerAttribute(nameStr, nameStr, 
					    &_repeat[i], 0 ) );
      sprintf( nameStr, "peakDetection%d", i );
      _attributes.add( new IntegerAttribute(nameStr, nameStr, 
					    &_peakDetection[i], 0 ) );
      sprintf( nameStr, "upwellingDetection%d", i );
      _attributes.add( new IntegerAttribute(nameStr, nameStr, 
					    &_upwellingDetection[i], 0 ) );
      sprintf( nameStr, "frontDetection%d", i );
      _attributes.add( new IntegerAttribute(nameStr, nameStr, 
					    &_frontDetection[i], 0 ) );
      sprintf( nameStr, "mindepth%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_minDepth[i], NotSpecified ) );
      sprintf( nameStr, "maxdepth%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_maxDepth[i], NotSpecified ) );
      sprintf( nameStr, "mindepthmaxwait%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_minDepthMaxWait[i], NotSpecified ) );
      sprintf( nameStr, "maxdepthmaxwait%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_maxDepthMaxWait[i], NotSpecified ) );
      sprintf( nameStr, "minsalinity%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_minSal[i], NotSpecified ) );
      sprintf( nameStr, "maxsalinity%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_maxSal[i], NotSpecified ) );
      sprintf( nameStr, "mintemperature%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_minTemp[i], NotSpecified ) );
      sprintf( nameStr, "maxtemperature%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_maxTemp[i], NotSpecified ) );
      sprintf( nameStr, "mindepthchange%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_minDepChange[i], NotSpecified ) );
      sprintf( nameStr, "minfl676_%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_minfl676[i], NotSpecified ) );
      sprintf( nameStr, "maxfl676_%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_maxfl676[i], NotSpecified ) );
      sprintf( nameStr, "minbb470_%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_minbb470[i], NotSpecified ) );
      sprintf( nameStr, "maxbb470_%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr,
					  &_maxbb470[i], NotSpecified ) );
      sprintf( nameStr, "minbb676_%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_minbb676[i], NotSpecified ) );
      sprintf( nameStr, "maxbb676_%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr,
					  &_maxbb676[i], NotSpecified ) );
      sprintf( nameStr, "minrhod%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_minrhod[i], NotSpecified ) );
      sprintf( nameStr, "maxrhod%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr,
					  &_maxrhod[i], NotSpecified ) );
      sprintf( nameStr, "minTempDiffVert%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_minTempDiffVert[i], NotSpecified ) );
      sprintf( nameStr, "maxTempDiffVert%d", i );
      _attributes.add( new FloatAttribute(nameStr, nameStr, 
					  &_maxTempDiffVert[i], NotSpecified ) );
      sprintf( nameStr, "ngood%d", i );
      _attributes.add( new IntegerAttribute(nameStr, nameStr, 
					    &_nGood[i], 1 ) );
      sprintf( nameStr, "nsamples%d", i );
      _attributes.add( new IntegerAttribute(nameStr, nameStr, 
					    &_nSamples[i], 1 ) );
   }

   sprintf(nameStr, "option_FireAll");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_option_FireAll, NotSpecified));

   sprintf(nameStr, "option_PTL_INL");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_option_PTL_INL, NotSpecified));

   sprintf(nameStr, "option_RHOD");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_option_RHOD, NotSpecified));

   sprintf(nameStr, "gulps_ChlOrRhod");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_gulps_ChlOrRhod, NotSpecified));

   sprintf(nameStr, "option_Front_TempOrFl");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_option_Front_TempOrFl, NotSpecified));

   sprintf(nameStr, "option_BaselineWindow_RunningOrSliding");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_option_BaselineWindow_RunningOrSliding, NotSpecified));

   sprintf(nameStr, "num_profiles_BaselineWindow");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_num_profiles_BaselineWindow, NotSpecified));

   sprintf(nameStr, "option_ClosenessOfTwoCrossings");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_option_ClosenessOfTwoCrossings, NotSpecified));

   sprintf(nameStr, "option_PeaksAtSurface");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_option_PeaksAtSurface, NotSpecified));

   sprintf(nameStr, "ratio_pktrigs_ctrltrigs");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_ratio_pktrigs_ctrltrigs, NotSpecified));

   sprintf(nameStr, "len_window_full");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_len_window_full, NotSpecified));

   sprintf(nameStr, "timewindow_peakbaseline");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_timewindow_peakbaseline, NotSpecified));

   sprintf(nameStr, "alpha_fl");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_alpha_fl, NotSpecified));

   sprintf(nameStr, "alpha_bb");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_alpha_bb, NotSpecified));

   sprintf(nameStr, "alpha_rhod");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_alpha_rhod, NotSpecified));

   sprintf(nameStr, "beta_fl");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_beta_fl, NotSpecified));

   sprintf(nameStr, "beta_bb");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_beta_bb, NotSpecified));

   sprintf(nameStr, "beta_rhod");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_beta_rhod, NotSpecified));

   sprintf(nameStr, "delta_dep");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_delta_dep, NotSpecified));

   sprintf(nameStr, "delta_fl_bb_rise");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_delta_fl_bb_rise, NotSpecified));

   sprintf(nameStr, "delta_fl_bb_drop");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_delta_fl_bb_drop, NotSpecified));

   sprintf(nameStr, "delta_rhod_rise");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_delta_rhod_rise, NotSpecified));

   sprintf(nameStr, "delta_rhod_drop");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_delta_rhod_drop, NotSpecified));

   sprintf(nameStr, "option_into_upwelling");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_option_into_upwelling, NotSpecified));

   sprintf(nameStr, "dep_shallow_upwelling");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_dep_shallow_upwelling, NotSpecified));

   sprintf(nameStr, "dep_midshallow_upwelling");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_dep_midshallow_upwelling, NotSpecified));

   sprintf(nameStr, "dep_middeep_upwelling");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_dep_middeep_upwelling, NotSpecified));

   sprintf(nameStr, "dep_deep_upwelling");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_dep_deep_upwelling, NotSpecified));

   sprintf(nameStr, "thresh_TempDiffInUpwelling");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_thresh_TempDiffInUpwelling, NotSpecified));

   sprintf(nameStr, "thresh_NumProfilesInUpwelling");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_thresh_NumProfilesInUpwelling, NotSpecified));

   sprintf(nameStr, "num_ProfilesAvgTempDiff");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_num_ProfilesAvgTempDiff, NotSpecified));
   sprintf(nameStr, "num_ProfilesGapTempDiff");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_num_ProfilesGapTempDiff, NotSpecified));

   sprintf(nameStr, "step_TempDiffInTempFront");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_step_TempDiffInTempFront, NotSpecified));

   sprintf(nameStr, "thresh_TempDiffInTempFront");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_thresh_TempDiffInTempFront, NotSpecified));

   sprintf(nameStr, "thresh_NumProfilesInTempFront");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_thresh_NumProfilesInTempFront, NotSpecified));

   sprintf(nameStr, "dep_shallow_fl");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_dep_shallow_fl, NotSpecified));

   sprintf(nameStr, "num_ProfilesAvgFl");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_num_ProfilesAvgFl, NotSpecified));

   sprintf(nameStr, "num_ProfilesGapFl");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_num_ProfilesGapFl, NotSpecified));

   sprintf(nameStr, "step_FlInFlFront");
   _attributes.add( new FloatAttribute(nameStr, nameStr, &_step_FlInFlFront, NotSpecified));

   sprintf(nameStr, "thresh_NumProfilesInFlFront");
   _attributes.add( new IntegerAttribute(nameStr, nameStr, &_thresh_NumProfilesInFlFront, NotSpecified));
}

// Load the config attributes and do some sanity checking
//
void AdaptiveSampler::loadConfigFile(const char* configFile)
{
  try 
  {
     AttributeParser::parse(configFile, &_attributes); 
  }
  catch(...)
  {
     Syslog::write("Error reading adaptivesampler.cfg.");
     exit(0);
  }

// Validate the input data, that is, check ranges here.

}

// Record the attributes in Syslog
//
void AdaptiveSampler::printCfgAttributes()
{
   //
   // Convert the integer byte values to engineering units in the argument
   // list below.
   //
   Syslog::write("AdaptiveSampler -- configuration:\n");

   Syslog::write("\tOption to fire all gulpers  = %d (0 = No; 1 = Yes)\n", _option_FireAll);

   Syslog::write("\tLayer type = %d (0 = Phytoplankton Thin Layer (PTL); 1 = Intermediate Nepheloid Layer (INL))\n", _option_PTL_INL);

   Syslog::write("\tUsing the rhodamine signal? %d (0 = No rhodamine; 1 = chl and rhodamine alternately; 2 = rhodamine only)\n", _option_RHOD);

   Syslog::write("\tIf alternately capturing chl and rhodamine, number of gulps for each signal = %d (This parameter is only relevant for option_RHOD == 1)\n", _gulps_ChlOrRhod);

   Syslog::write("\tFront type  = %d (0 = temperature front; 1 = fluorescence front)\n", _option_Front_TempOrFl);

   Syslog::write("\tFlying into upwelling water column? %d (0 = out-of-upwelling; 1 = into-upwelling)\n", _option_into_upwelling);

   Syslog::write("\tWindow type for calculating the signal baseline = %d (0 = from time zero to now; 1 = over a number of yo-yo profiles)\n", _option_BaselineWindow_RunningOrSliding);

   Syslog::write("\tNumber of yo-yo profiles for calculating the average signal background = %d (No more than 200. Used only when window type for calculating the signal baseline = 1)\n", _num_profiles_BaselineWindow);

   Syslog::write("\tRequiring closeness of the 1st and 2nd crossings  = %d (0 = No; 1 = Yes)\n", _option_ClosenessOfTwoCrossings);

   Syslog::write("\tPeaks likely at sea surface  = %d (0 = No; 1 = Yes)\n", _option_PeaksAtSurface);

   Syslog::write("\tRatio of peak-triggerings to control-triggerings  = %d\n", _ratio_pktrigs_ctrltrigs);

   Syslog::write("\tLow-pass filter window length  = %d\n", _len_window_full);

   Syslog::write("\tSliding window width (in seconds) for calculating peaks baseline  = %.1f\n", _timewindow_peakbaseline);

   Syslog::write("\tThreshold ratio of fl over bkgnd = %.1f\n", _alpha_fl);

   Syslog::write("\tThreshold ratio of bb over bkgnd = %.1f\n", _alpha_bb);

   Syslog::write("\tThreshold ratio of rhod over bkgnd = %.1f\n", _alpha_rhod);

   Syslog::write("\tThreshold ratio of fl below bkgnd = %.1f\n", _beta_fl);

   Syslog::write("\tThreshold ratio of bb below bkgnd = %.1f\n", _beta_bb);

   Syslog::write("\tThreshold ratio of rhod below bkgnd = %.1f\n", _beta_rhod);

   Syslog::write("\tMinimum depth change for flipping depth state = %.1f meter\n", _delta_dep);

   Syslog::write("\tMinimum fl_bb rise for qualifying as a rise = %.1e (raw measurement)\n", _delta_fl_bb_rise);

   Syslog::write("\tMinimum fl_bb drop for qualifying as a drop = %.1e (raw measurement)\n", _delta_fl_bb_drop);

   Syslog::write("\tMinimum rhod rise for qualifying as a rise = %.1e (raw measurement)\n", _delta_rhod_rise);

   Syslog::write("\tMinimum rhod drop for qualifying as a drop = %.1e (raw measurement)\n", _delta_rhod_drop);

   Syslog::write("\tShallow depth bound for calculating deltaTvert in water column = %.1f (meters)\n", _dep_shallow_upwelling);

   Syslog::write("\tMid-shallow depth for calculating deltaTvert in water column = %.1f (meters)\n", _dep_midshallow_upwelling);

   Syslog::write("\tMid-deep depth for calculating deltaTvert in water column = %.1f (meters)\n", _dep_middeep_upwelling);

   Syslog::write("\tDeep depth bound for calculating deltaTvert in water column = %.1f (meters)\n", _dep_deep_upwelling);

   Syslog::write("\tThreshold of deltaTvert for detecting an upwelling water column = %.2f (Deg. C)\n", _thresh_TempDiffInUpwelling);

   Syslog::write("\tMinimum number of consecutive profiles for declaring an upwelling water column = %d\n", _thresh_NumProfilesInUpwelling);

   Syslog::write("\tWindow length (number of profiles) for low-pass filtering deltaTvert = %d\n", _num_ProfilesAvgTempDiff);

   Syslog::write("\tGap (in number of profiles) btn low-pass filtered deltaTvert for front detection = %d\n", _num_ProfilesGapTempDiff);

   Syslog::write("\tStep change (horizontal) of deltaTvert for detecting a temperature front = %.1f (Deg. C)\n", _step_TempDiffInTempFront);

   Syslog::write("\tUpper limit of deltaTvert for detecting a front = %.1f (Deg. C)\n", _thresh_TempDiffInTempFront);

   Syslog::write("\tMinimum number of consecutive profiles for declaring a temperature front = %d\n", _thresh_NumProfilesInTempFront);

   Syslog::write("\tShallow depth bound in fluorescence front detection = %.1f (meters)\n", _dep_shallow_fl);

   Syslog::write("\tNumber of profiles for calculating the average profile-max fluorescence = %d\n", _num_ProfilesAvgFl);

   Syslog::write("\tGap (number of profiles) to the nearest profile in the window for calculating the average profile-max fl = %d\n", _num_ProfilesGapFl);

   Syslog::write("\tStep change (horizontal) of profile-max fluorescence for detecting a fluorescence front = %.1e\n", _step_FlInFlFront);

   Syslog::write("\tMinimum number of consecutive profiles for declaring a fluorescence front = %d\n", _thresh_NumProfilesInFlFront);

   for( int i=0; i<NGULPERS; i++ )
   {
      Syslog::write("Gulper %d :\n");
      Syslog::write("\tpeak detection (0=off,1=on) = %d\n"
		    "\tUpwelling detection (0=off,1=on) = %d\n"
		    "\tFront detection (0=off,1=on) = %d\n"
		    "\tMin/Max depth     = % 6.2e/% 6.2e m\n"
		    "\tMin/Max temperature  = % 6.3e/% 6.3e deg.C\n"
		    "\tMin depth change of isotherm from the last gulp = % 6.2e m\n"
		    "\tMin/Max salinity  = % 6.2e/% 6.2e Psu\n"
		    "\tMin/Max fl676     = % 6.2e/% 6.2e unitless\n"
		    "\tMin/Max bb470     = % 6.2e/% 6.2e unitless\n"
		    "\tMin/Max bb676     = % 6.2e/% 6.2e unitless\n"
		    "\tMin/Max rhod     = % 6.2e/% 6.2e unitless\n"
		    "\tMin/Max deltaTvert = % 6.2e/% 6.2e deg.C\n"
		    "\tGulper number fired before = %d\n"
		    "\tLock-out time for peak triggerings = %.2f seconds\n"
		    "\tLock-out time for upwelling triggerings = %.2f seconds\n"
		    "\tLock-out time for front triggerings = %.2f seconds\n"
		    "\tLock-out time at start = %.2f seconds\n"
		    "\tGulper number max-wait is referenced to = %d\n"
		    "\tMax-wait time = %.2f seconds\n"
		    "\tMin/Max depth (for max-wait only) = % 6.2e/% 6.2e m\n"
		    "\tNmbr good samples = %d \n"
		    "\tNmbr of samples   = %d \n",
		    _peakDetection[i],
		    _upwellingDetection[i],
		    _frontDetection[i],
		    _minDepth[i], _maxDepth[i],
		    _minTemp[i],  _maxTemp[i],
		    _minDepChange[i],
		    _minSal[i],   _maxSal[i],
		    _minfl676[i], _maxfl676[i],
		    _minbb470[i], _maxbb470[i],
		    _minbb676[i], _maxbb676[i],
		    _minrhod[i], _maxrhod[i],
		    _minTempDiffVert[i], _maxTempDiffVert[i],
		    _GulperNumberFiredBefore[i],
		    _timeLockOutPeak[i],
		    _timeLockOutUpwelling[i],
		    _timeLockOutFront[i],
		    _timeLockOutAtStart[i],
		    _GulperNumberRefMaxWait[i],
		    _timeMaxWait[i],
		    _minDepthMaxWait[i], _maxDepthMaxWait[i],
		    _nGood[i], _nSamples[i]);
   }
}

void AdaptiveSampler::peakDetection()
{
  int k, m, n, p, q, r, r_max=0, s, s_max=0, t, t_max = 0, u, v;
  int score_dep_change, k_signal;
  short len_window_fl_bb, len_window_rhod, len_window_TempDiff, num_stored_peaks, num_accumulated_peaks;
  double dep_mid, tmp, array_sort[5], array_median[20], peaksaved_previous, tempDiff;
  Boolean cond_closeness=True;

  _cntr_fl_bb++;
  if (_cntr_fl_bb >= 2000000000) _cntr_fl_bb = 1; // Don't reset _cntr_fl_bb to zero. Note that _cntr_fl_bb (long) hits ceiling at 2x(10^9)-1. 

  if (_option_RHOD >= 1)
    {
      _cntr_rhod++;
      if (_cntr_rhod >= 2000000000) _cntr_rhod = 1; // Don't reset _cntr_rhod to zero. Note that _cntr_rhod (long) hits ceiling at 2x(10^9)-1. 
    }
  
  if (_cntr_fl_bb == 1)
    {
      _dep_max = _dep[0];
      _dep_min = _dep[0];
    }

  score_dep_change = 0;
  for (k=0; k<=3; k++)
    {
      if (_dep[k] < _dep[k+1])
	score_dep_change = score_dep_change - 1;
      else
	{
	  if (_dep[k] > _dep[k+1])
	    score_dep_change = score_dep_change + 1;
	}
    }

  _state_dep[1] = _state_dep[0]; // Save the preceding depth state.
  if (_state_dep[0] == 1)
    {
      if (_dep[0] > _dep_max)
	{
	  _dep_max = _dep[0]; // Continue to track the maximum depth.
	  _state_dep[0] = 1;
	}
      else
	{
	  if (((_dep[0] - _dep_max) < -_delta_dep) && (score_dep_change <= (-3)))
	    {
	      _dep_deep = _dep_max; // The vehicle has reached the deepest point.
	      _dep_min = _dep[0]; // Switch to tracking the minimum depth.
	      _state_dep[0] = 0;
	    }
	  else
	    {
	      _state_dep[0] = 1;
	    }
	}
    }
  else
    {
      if (_dep[0] < _dep_min)
	{
	  _dep_min = _dep[0]; // Continue to track the minimum depth.
	  _state_dep[0] = 0;
	}
      else
	{
	  if (((_dep[0] - _dep_min) > _delta_dep) && (score_dep_change >= 3))
	    {
	      _dep_shallow = _dep_min; // The vehicle has reached the most shallow point.
	      _dep_max = _dep[0]; // Switch to tracking the maximum depth.
	      _state_dep[0] = 1;

	      //debug
	      //printf("_dep[0], _dep_min = %f, %f\n", _dep[0], _dep_min);

	    }
	  else
	    {
	      _state_dep[0] = 0;
	    }
	}
    }

  dep_mid = (_dep_shallow + _dep_deep) * 0.5;

  //debug
  //  printf("_timeFromDataFile, _state_dep[0], _state_dep_1stpk, _fl676, _fl676_inwindow[0]: %f %d %d %f %f\n", _timeFromDataFile, _state_dep[0], _state_dep_1stpk, _fl676, _fl676_inwindow[0]);

  if (_cntr_fl_bb <= _len_window_full)
    len_window_fl_bb = _cntr_fl_bb;
  else
    len_window_fl_bb = _len_window_full;

  if (_option_RHOD >= 1)
    {
      if (_cntr_rhod <= _len_window_full)
	len_window_rhod = _cntr_rhod;
      else
	len_window_rhod = _len_window_full;
    }
  
  // Calculate low-pass filtered values, but excluding the maximum-value sample in the window
  // in order to remove any singular spurious spike (except when window-length is one).
  // _fl676_lp[0] stores the newest low-pass filtered value.
  // _fl676_lp[2] stores the oldest.
  // Same for _bb470_lp[].
  //
  // _fl676_inwindow[0] stores the newest sample.
  // _fl676_inwindow[len_window_fl_bb-1] stores the oldest.
  // Same for _bb470_inwindow[] and _bb676_inwindow[].

  if (_cntr_fl_bb == 1)
    {
      _fl676_lp[0] = _fl676;
      _fl676_sumInWindow = _fl676;

      _bb470_lp[0] = _bb470;
      _bb470_sumInWindow = _bb470;

      _bb676_lp = _bb676;
      _bb676_sumInWindow = _bb676;
    }
  else
    {
      _fl676_sumInWindow = _fl676_sumInWindow - _fl676_inwindow[len_window_fl_bb-1] + _fl676;
      _bb470_sumInWindow = _bb470_sumInWindow - _bb470_inwindow[len_window_fl_bb-1] + _bb470;
      _bb676_sumInWindow = _bb676_sumInWindow - _bb676_inwindow[len_window_fl_bb-1] + _bb676;

      if (_option_PTL_INL == 0)
	{
	  if (_cntr_fl_bb >= 3)
	    _fl676_lp[2] = _fl676_lp[1];
	  
	  _fl676_lp[1] = _fl676_lp[0];
	}
      else
	{
	  if (_cntr_fl_bb >= 3)
	    _bb470_lp[2] = _bb470_lp[1];

	  _bb470_lp[1] = _bb470_lp[0];
	}

      if (len_window_fl_bb >= 2)
	{
	  if (_fl676 > _fl676_maxInWindow)
	    _fl676_lp[0] = (_fl676_sumInWindow - _fl676) / (len_window_fl_bb-1);
	  else
	    _fl676_lp[0] = (_fl676_sumInWindow - _fl676_maxInWindow) / (len_window_fl_bb-1);

	  if (_bb470 > _bb470_maxInWindow)
	    _bb470_lp[0] = (_bb470_sumInWindow - _bb470) / (len_window_fl_bb-1);
	  else
	    _bb470_lp[0] = (_bb470_sumInWindow - _bb470_maxInWindow) / (len_window_fl_bb-1);

	  if (_bb676 > _bb676_maxInWindow)
	    _bb676_lp = (_bb676_sumInWindow - _bb676) / (len_window_fl_bb-1);
	  else
	    _bb676_lp = (_bb676_sumInWindow - _bb676_maxInWindow) / (len_window_fl_bb-1);
	}
      else
	{
	  _fl676_lp[0] = _fl676_sumInWindow / len_window_fl_bb;
	  _bb470_lp[0] = _bb470_sumInWindow / len_window_fl_bb;
	  _bb676_lp = _bb676_sumInWindow / len_window_fl_bb;
	}
    }

  //debug
  //printf("_fl676, _fl676_inwindow[0], _fl676_inwindow[1], _fl676_inwindow[2], _fl676_inwindow[3], _fl676_inwindow[4], _fl676_inwindow[5], _fl676_inwindow[6], _fl676_inwindow[7], _fl676_maxInWindow, _fl676_lp[0] = \n%f %f %f %f %f %f %f %f %f %f %f\n", _fl676, _fl676_inwindow[0], _fl676_inwindow[1], _fl676_inwindow[2], _fl676_inwindow[3], _fl676_inwindow[4], _fl676_inwindow[5], _fl676_inwindow[6], _fl676_inwindow[7], _fl676_maxInWindow, _fl676_lp[0]);

  _fl676_maxInWindow = 0.0;
  _bb470_maxInWindow = 0.0;
  _bb676_maxInWindow = 0.0;

  if (_option_RHOD >= 1)
    {
      if (_cntr_rhod == 1)
	{
	  _rhod_lp[0] = _rhod;
	  _rhod_sumInWindow = _rhod;
	}
      else
	{
	  _rhod_sumInWindow = _rhod_sumInWindow - _rhod_inwindow[len_window_rhod-1] + _rhod;
	  if (_cntr_rhod >= 3)
	    _rhod_lp[2] = _rhod_lp[1];
      
	  _rhod_lp[1] = _rhod_lp[0];

	  if (len_window_rhod >= 2)
	    {
	      if (_rhod > _rhod_maxInWindow)
		_rhod_lp[0] = (_rhod_sumInWindow - _rhod) / (len_window_rhod-1);
	      else
		_rhod_lp[0] = (_rhod_sumInWindow - _rhod_maxInWindow) / (len_window_rhod-1);
	    }
	  else
	    _rhod_lp[0] = _rhod_sumInWindow / len_window_rhod;
	}
      _rhod_maxInWindow = 0.0;
    }

  if (len_window_fl_bb >= 2)
    {
      for (k=(len_window_fl_bb-2); k>=0; k--)
	{
	  _fl676_inwindow[k+1] = _fl676_inwindow[k];
	  _bb470_inwindow[k+1] = _bb470_inwindow[k];
	  _bb676_inwindow[k+1] = _bb676_inwindow[k];

	  if (k <= len_window_fl_bb-3)
	    {
	      if (_fl676_inwindow[k] > _fl676_maxInWindow)
		_fl676_maxInWindow = _fl676_inwindow[k];

	      if (_bb470_inwindow[k] > _bb470_maxInWindow)
		_bb470_maxInWindow = _bb470_inwindow[k];

	      if (_bb676_inwindow[k] > _bb676_maxInWindow)
		_bb676_maxInWindow = _bb676_inwindow[k];
	    }
	}
    }

  _fl676_inwindow[0] = _fl676;
  if (_fl676_inwindow[0] > _fl676_maxInWindow)
    _fl676_maxInWindow = _fl676_inwindow[0];

  _bb470_inwindow[0] = _bb470;
  if (_bb470_inwindow[0] > _bb470_maxInWindow)
    _bb470_maxInWindow = _bb470_inwindow[0];

  _bb676_inwindow[0] = _bb676;
  if (_bb676_inwindow[0] > _bb676_maxInWindow)
    _bb676_maxInWindow = _bb676_inwindow[0];

  if (_option_RHOD >= 1)
    {
      if (len_window_rhod >= 2)
	{
	  for (k=(len_window_rhod-2); k>=0; k--)
	    {
	      _rhod_inwindow[k+1] = _rhod_inwindow[k];

	      if (k <= len_window_rhod-3)
		{
		  if (_rhod_inwindow[k] > _rhod_maxInWindow)
		    _rhod_maxInWindow = _rhod_inwindow[k];
		}
	    }
	}
      _rhod_inwindow[0] = _rhod;
      if (_rhod_inwindow[0] > _rhod_maxInWindow)
	_rhod_maxInWindow = _rhod_inwindow[0];
    }

  if (_state_dep[0] == _state_dep[1])
    {
      if (_flag_tempdiff_enabled == 1)
	{
	  if (_state_dep[0] == 1)
	    {
	      if ((_flag_temp_shallow == 0) && (_dep[0] >= _dep_shallow_upwelling))
		{
		  _tempDep[0] = _temperature;
		  _flag_temp_shallow = 1;
		}

	      if ((_flag_temp_midshallow == 0) &&(_dep[0] >= _dep_midshallow_upwelling))
		{
		  _tempDep[1] = _temperature;
		  _flag_temp_midshallow = 1;
		}

	      if ((_flag_temp_middeep == 0) &&(_dep[0] >= _dep_middeep_upwelling))
		{
		  _tempDep[2] = _temperature;
		  _flag_temp_middeep = 1;
		}

	      if ((_flag_temp_deep == 0) && (_dep[0] >= _dep_deep_upwelling))
		{
		  _tempDep[3] = _temperature;
		  _flag_temp_deep = 1;
		}
	    }
	  else
	    {
	      if ((_flag_temp_deep == 0) && (_dep[0] <= _dep_deep_upwelling))
		{
		  _tempDep[3] = _temperature;
		  _flag_temp_deep = 1;
		}

	      if ((_flag_temp_middeep == 0) &&(_dep[0] <= _dep_middeep_upwelling))
		{
		  _tempDep[2] = _temperature;
		  _flag_temp_middeep = 1;
		}

	      if ((_flag_temp_midshallow == 0) &&(_dep[0] <= _dep_midshallow_upwelling))
		{
		  _tempDep[1] = _temperature;
		  _flag_temp_midshallow = 1;
		}

	      if ((_flag_temp_shallow == 0) && (_dep[0] <= _dep_shallow_upwelling))
		{
		  _tempDep[0] = _temperature;
		  _flag_temp_shallow = 1;
		}
	    }
	}

      if ((_flag_fl_shallow == 0) && 
	  (((_state_dep[0] == 1) && (_dep[0] >= _dep_shallow_fl)) || 
	   ((_state_dep[0] == 0) && (_dep[0] <= _dep_shallow_fl))))
	_flag_fl_shallow = 1;

      if ((_dep[0] >= _dep_minFrontTriggering) && (_dep[0] <= _dep_maxFrontTriggering) && (_fl676_lp[0] > _flMaxOnProfile))
	{
	  _flMaxOnProfile = _fl676_lp[0];
	  _dep_flMaxOnProfile = _dep[0];

	  //debug
	  //printf("_timeFromDataFile, _dep_flMaxOnProfile, _flMaxOnProfile = %f, %f, %f\n", _timeFromDataFile, _dep_flMaxOnProfile, _flMaxOnProfile);
	}

      if ((_option_RHOD >= 1) && (_dep[0] >= _dep_minFrontTriggering) && (_dep[0] <= _dep_maxFrontTriggering) && (_rhod_lp[0] > _rhodMaxOnProfile))
	{
	  _rhodMaxOnProfile = _rhod_lp[0];
	  _dep_rhodMaxOnProfile = _dep[0];
	}
    }
  else
    {
      if ((_flag_temp_shallow == 1) && (_flag_temp_deep == 1))
	{
	  _cntr_ProfilesTempDiff++;

	  _tempDepAvg = 0.0;
	  for (v=0; v<=3; v++)
	    {
	      _tempDepAvg = _tempDepAvg + _tempDep[v];
	    }
	  _tempDepAvg = _tempDepAvg / 4.0;

	  tempDiff = 0.0;
	  for (v=0; v<=3; v++)
	    {
	      if ((_tempDep[v] - _tempDepAvg) >= 0.0)
		tempDiff = tempDiff + (_tempDep[v] - _tempDepAvg);
	      else
		tempDiff = tempDiff - (_tempDep[v] - _tempDepAvg);
	    }
	  tempDiff = tempDiff / 4.0;

	  // Move _temp_diff_lp[0] to _temp_diff_lp[1], and so on.
	  if ((_cntr_ProfilesTempDiff-1) >= 1)
	    {
	      if ((_cntr_ProfilesTempDiff-1) < (_num_ProfilesAvgTempDiff+_num_ProfilesGapTempDiff))
		s_max = (_cntr_ProfilesTempDiff-1);
	      else
		s_max = (_num_ProfilesAvgTempDiff+_num_ProfilesGapTempDiff);

	      for (s=s_max; s>=1; s--)
		_temp_diff_lp[s] = _temp_diff_lp[s-1];
	    }

	  // Compute low-pass filtered tempDiff.
	  if (_cntr_ProfilesTempDiff < _num_ProfilesAvgTempDiff)
	    len_window_TempDiff = _cntr_ProfilesTempDiff;
	  else
	    len_window_TempDiff = _num_ProfilesAvgTempDiff;

	  if (_cntr_ProfilesTempDiff == 1)
	    {
	      _tempDiffSumInWindow = tempDiff;
	      _temp_diff_lp[0] = tempDiff;
	    }
	  else
	    {
	      _tempDiffSumInWindow = _tempDiffSumInWindow - _temp_diff[len_window_TempDiff-1] + tempDiff;
	      _temp_diff_lp[0] = _tempDiffSumInWindow / len_window_TempDiff;
	    }

	  // Move _temp_diff[0] to _temp_diff[1], and so on.
	  if (((_cntr_ProfilesTempDiff-1) >= 1) && (_num_ProfilesAvgTempDiff >= 2))
	    {
	      if ((_cntr_ProfilesTempDiff-1) < (_num_ProfilesAvgTempDiff-1))
		t_max = (_cntr_ProfilesTempDiff-1);
	      else
		t_max = (_num_ProfilesAvgTempDiff-1);

	      for (t=t_max; t>=1; t--)
		_temp_diff[t] = _temp_diff[t-1];
	    }

	  _temp_diff[0] = tempDiff;

	  //debug
	  //printf("_timeFromDataFile, _tempDep[0], _tempDep[1], _tempDep[2], _tempDep[3] = \n%f, %f, %f, %f, %f\n", _timeFromDataFile, _tempDep[0], _tempDep[1], _tempDep[2], _tempDep[3]);
	  //printf("_temp_diff[0], _temp_diff[1], _temp_diff[2] = \n%f, %f, %f\n", _temp_diff[0], _temp_diff[1], _temp_diff[2]);
	  //printf("_temp_diff_lp[0], _temp_diff_lp[1], _temp_diff_lp[2], _temp_diff_lp[3], _temp_diff_lp[4], _temp_diff_lp[5], _temp_diff_lp[6], _temp_diff_lp[7], _temp_diff_lp[8] = \n%f, %f, %f, %f, %f, %f, %f, %f, %f\n\n", _temp_diff_lp[0], _temp_diff_lp[1], _temp_diff_lp[2], _temp_diff_lp[3], _temp_diff_lp[4], _temp_diff_lp[5], _temp_diff_lp[6], _temp_diff_lp[7], _temp_diff_lp[8]);

	  if (_cntr_ProfilesTempDiff >= ((_num_ProfilesAvgTempDiff*2)+_num_ProfilesGapTempDiff))
	    {
	      if (((_option_into_upwelling == 0) && 
		   ((_temp_diff_lp[0]-_temp_diff_lp[_num_ProfilesAvgTempDiff+_num_ProfilesGapTempDiff]) >= _step_TempDiffInTempFront) &&
		   (_temp_diff[0] >= _thresh_TempDiffInTempFront)) ||
		  ((_option_into_upwelling == 1) && 
		   ((_temp_diff_lp[0]-_temp_diff_lp[_num_ProfilesAvgTempDiff+_num_ProfilesGapTempDiff]) <= -_step_TempDiffInTempFront) &&
		   (_temp_diff[0] <= _thresh_TempDiffInTempFront)))
		_cntr_ProfilesInTempFront = _cntr_ProfilesInTempFront + 1;
	      else
		_cntr_ProfilesInTempFront = 0;
	      
	      if (_cntr_ProfilesInTempFront >= _thresh_NumProfilesInTempFront)
 		_flag_temp_front = 1;
	      else
 		_flag_temp_front = 0;
	    }

	  if (_temp_diff[0] <= _thresh_TempDiffInUpwelling)
	    {
	      _cntr_ProfilesInUpwelling++;

	      //debug
	      //printf("_timeFromDataFile = %.6f\n", _timeFromDataFile);
	      //printf("_temp_shallow = %.1f\n", _temp_shallow);
	      //printf("_temp_deep = %.1f\n", _temp_deep);
	      //printf("_temperature = %.1f\n", _temperature);
	      //printf("_depth = %.1f\n", _depth);
	      //printf("_cntr_ProfilesInUpwelling = %d\n", _cntr_ProfilesInUpwelling);
	    }
	  else
	    _cntr_ProfilesInUpwelling = 0;
	}
      //      else
      //	_cntr_ProfilesInUpwelling = 0;

      if ((_flag_fl_shallow == 1) && (_flMaxOnProfile > 0.0))
	{
	  if (_cntr_ProfilesFl >= 1)
	    {
	      if (_cntr_ProfilesFl < (_num_ProfilesFl-1))
		s_max = _cntr_ProfilesFl;
	      else
		s_max = (_num_ProfilesFl-1);

	      for (s=s_max; s>=1; s--)
		_fl_maxOnProfile[s] = _fl_maxOnProfile[s-1];
	    }

	  _fl_maxOnProfile[0] = _flMaxOnProfile;

	  if (_cntr_ProfilesFl >= (_num_ProfilesFl-1))
	    {
	      _flMaxOnProfile_avg = 0.0;
		  
	      for (u=_num_ProfilesGapFl; u<=(_num_ProfilesFl-1); u++)
		_flMaxOnProfile_avg = _flMaxOnProfile_avg + _fl_maxOnProfile[u];
	      
	      _flMaxOnProfile_avg = _flMaxOnProfile_avg / _num_ProfilesAvgFl;

	      if (((_fl_maxOnProfile[0]-_flMaxOnProfile_avg) >= _step_FlInFlFront) ||
		   ((_fl_maxOnProfile[0]-_flMaxOnProfile_avg) <= -_step_FlInFlFront))
		_cntr_ProfilesInFlFront = _cntr_ProfilesInFlFront + 1;
	      else
		_cntr_ProfilesInFlFront = 0;

	      if (_cntr_ProfilesInFlFront >= _thresh_NumProfilesInFlFront)
 		_flag_fl_front = 1;
	      else
 		_flag_fl_front = 0;
	    }

	  _cntr_ProfilesFl = _cntr_ProfilesFl + 1;
	}

      if (_cntr_ProfilesInUpwelling >= _thresh_NumProfilesInUpwelling)
	_upwellingCheck = True;
      else
	_upwellingCheck = False;

      if ((_state_dep[1] == 1) && (_state_dep[0] == 0))
	_valleyCheck = True;

      _flag_temp_shallow = 0;
      _flag_temp_midshallow = 0;
      _flag_temp_middeep = 0;
      _flag_temp_deep = 0;

      _flag_fl_shallow = 0;
      
      if (((_state_dep[0] == 1) && (_dep[0] <= _dep_shallow_upwelling)) || ((_state_dep[0] == 0) && (_dep[0] >= _dep_deep_upwelling)))
	_flag_tempdiff_enabled = 1;
      else
	_flag_tempdiff_enabled = 0;

      _flMaxOnPrecedingProfile = _flMaxOnProfile;
      _dep_flMaxOnPrecedingProfile = _dep_flMaxOnProfile;
      _flMaxOnProfile = 0.0;
      _dep_flMaxOnProfile = _dep_minFrontTriggering; // Reset to _dep_minFrontTriggering, not zero meter.
      _flag_crossingDepFlMaxOnPrecedingProfile = 0;

      //debug
      //printf("\n_dep_flMaxOnPrecedingProfile = %f\n", _dep_flMaxOnPrecedingProfile);

      if (_option_RHOD >= 1)
	{
	  _rhodMaxOnPrecedingProfile = _rhodMaxOnProfile;
	  _dep_rhodMaxOnPrecedingProfile = _dep_rhodMaxOnProfile;
	  _rhodMaxOnProfile = 0.0;
	  _dep_rhodMaxOnProfile = _dep_minFrontTriggering; // Reset to _dep_minFrontTriggering, not zero meter.
	  _flag_crossingDepRhodMaxOnPrecedingProfile = 0;
	}
    }

  if ((_cntr_profiles >= 1) && 
      (_flag_crossingDepFlMaxOnPrecedingProfile == 0) && 
      (((_state_dep[0] == 1) && (_dep[0] >= _dep_flMaxOnPrecedingProfile)) || 
       ((_state_dep[0] == 0) && (_dep[0] <= _dep_flMaxOnPrecedingProfile))))
    {
      _flag_crossingDepFlMaxOnPrecedingProfile = 1;
      _crossingDepFlMaxOnPrecedingProfileCheck = True;

      //debug
      //printf("\n_timeFromDataFile, _dep[0], _dep[1] = %f, %f, %f\n", _timeFromDataFile, _dep[0], _dep[1]);
    }

  if ((_option_RHOD >= 1) && (_cntr_ProfilesTempDiff >= 1) && 
      (_flag_crossingDepRhodMaxOnPrecedingProfile == 0) && 
      (((_state_dep[0] == 1) && (_dep[0] >= _dep_rhodMaxOnPrecedingProfile)) || 
       ((_state_dep[0] == 0) && (_dep[0] <= _dep_rhodMaxOnPrecedingProfile))))
    {
      _flag_crossingDepRhodMaxOnPrecedingProfile = 1;
      _crossingDepRhodMaxOnPrecedingProfileCheck = True;
    }

  if ((((_option_Front_TempOrFl == 0) && (_flag_temp_front == 1)) || 
       ((_option_Front_TempOrFl == 1) && (_flag_fl_front == 1))) &&
      (((_state_dep[0] == 1) && (_dep[0] >= _dep_flMaxOnPrecedingProfile)) || 
       ((_state_dep[0] == 0) && (_dep[0] <= _dep_flMaxOnPrecedingProfile))))
    {

      //debug
      //printf("\n_frontCheck = True. _timeFromDataFile, _dep[0], _dep[1] = %f, %f, %f\n", _timeFromDataFile, _dep[0], _dep[1]);

      _frontCheck = True;
      _upwellingCheck = False; // _frontCheck overrides _upwellingCheck.

      if (_flag_temp_front == 1)
	_flag_temp_front = 0;

      if (_flag_fl_front == 1)
	_flag_fl_front = 0;
    }
  else
    _frontCheck = False;

  for (k_signal=0; k_signal<=(_num_PeakSignals-1); k_signal++)
    {
      if (_state_dep[0] == (1 - _state_dep_1stpk[k_signal]))
	{
	  _attitude_flop[k_signal] = 1;

	  if ((_option_PeaksAtSurface == 1) && 
	      (_attitude_flop_flop[k_signal] == 1))
	    {
	      _attitude_flop[k_signal] = 0;
	      _attitude_flop_flop[k_signal] = 0;
	      _flag_1stpk[k_signal] = 0; // Reset the 1st-peak flag.
	    }

	  if ((_flag_1stpk[k_signal] == 1) && (_flag_ctrl[k_signal] == 0) &&
	      (((k_signal == 0) && (_indSignalCapture == 0) && 
		(((_option_PTL_INL == 0) && 
		  (_fl676_inwindow[0] >= _peak_saved[_indSignalCapture]) &&
		  (_fl676_inwindow[1] >= _peak_saved[_indSignalCapture]) &&
		  !(((_fl676_inwindow[0] >= (_fl676_inwindow[2]*5.0)) &&
		     (_fl676_inwindow[0] >= (_fl676_inwindow[3]*5.0))) ||
		    ((_fl676_inwindow[1] >= (_fl676_inwindow[2]*5.0)) &&
		     (_fl676_inwindow[1] >= (_fl676_inwindow[3]*5.0)))))      ||
		 ((_option_PTL_INL == 1) &&
		  (_bb470_inwindow[0] >= _peak_saved[_indSignalCapture]) &&
		  (_bb470_inwindow[1] >= _peak_saved[_indSignalCapture]) &&
		  !(((_bb470_inwindow[0] >= (_bb470_inwindow[2]*5.0)) &&
		     (_bb470_inwindow[0] >= (_bb470_inwindow[3]*5.0))) ||
		    ((_bb470_inwindow[1] >= (_bb470_inwindow[2]*5.0)) &&
		     (_bb470_inwindow[1] >= (_bb470_inwindow[3]*5.0)))) &&
		  (_fl676_inwindow[0] < _fl676_bkgnd))))                      ||
	       ((k_signal == 1) && (_indSignalCapture == 1) && 
		(_rhod_inwindow[0] >= _peak_saved[_indSignalCapture]) &&
		(_rhod_inwindow[1] >= _peak_saved[_indSignalCapture]) &&
		!(((_rhod_inwindow[0] >= (_rhod_inwindow[2]*5.0)) &&
		   (_rhod_inwindow[0] >= (_rhod_inwindow[3]*5.0))) ||
		  ((_rhod_inwindow[1] >= (_rhod_inwindow[2]*5.0)) &&
		   (_rhod_inwindow[1] >= (_rhod_inwindow[3]*5.0)))))))
	    {
	      //debug
	      //if (k_signal == 1)
	      //printf("_indSignalCapture, _peak_saved[_indSignalCapture], _fl676_inwindow[0], _fl676_inwindow[1], _rhod_inwindow[0], _rhod_inwindow[1] = %d, %f, %f, %f, %f, %f\n", _indSignalCapture, _peak_saved[_indSignalCapture], _fl676_inwindow[0], _fl676_inwindow[1], _rhod_inwindow[0], _rhod_inwindow[1]);

	      _peakCheck[k_signal] = True;
	      _pk_ctrl[k_signal] = 1; // A peak sample.
	      _cntr_trig[k_signal]++;

	      //printf("Deep peak. _cntr_trig = %d\n", _cntr_trig);

	      _flag_1stpk[k_signal] = 0; // Reset the 1st-peak flag.

#if 0
	      //debug
	      printf("\n");
	      printf("_peakCheck = True!\n");
	      printf("_pk_ctrl: %d\n", _pk_ctrl);
	      printf("_timeCntr: %d\n", _timeCntr);
	      printf("_state_dep[0] _state_var _flag_1stpk _attitude_flop: %d %d %d %d\n", _state_dep[0], _state_var, _flag_1stpk, _attitude_flop);
	      printf("_timeFromDataFile _dep[0] _dep_shallow _dep_deep: %f %f %f %f\n", _timeFromDataFile, _dep[0], _dep_shallow, _dep_deep);
	      printf("_fl676 _fl676_lp[0] _fl676_bkgnd: %f %f %f\n", _fl676, _fl676_lp[0], _fl676_bkgnd);
	      printf("_bb470 _bb470_lp[0] _bb470_bkgnd: %f %f %f\n", _bb470, _bb470_lp[0], _bb470_bkgnd);
	      printf("_bb676 _bb676_lp _bb676_bkgnd: %f %f %f\n", _bb676, _bb676_lp, _bb676_bkgnd);
	      printf("_peak_saved: %f", _peak_saved);
	      printf("\n");
#endif

	      if (_cntr_trig[k_signal] >= _ratio_pktrigs_ctrltrigs)
		_flag_ctrl[k_signal] = 1; // Enable control triggering.
	    }
	}
      else
	{
	  if (_attitude_flop[k_signal] == 1)
	    {
	      if (_option_PeaksAtSurface == 1)
		{
		  _attitude_flop_flop[k_signal] = 1;

		  if ((_flag_1stpk[k_signal] == 1) && 
		      (_flag_ctrl[k_signal] == 0) &&
		      (((k_signal == 0) && (_indSignalCapture == 0) && 
			(((_option_PTL_INL == 0) && 
			  (_fl676_inwindow[0] >= _peak_saved[_indSignalCapture]) &&
			  (_fl676_inwindow[1] >= _peak_saved[_indSignalCapture]) &&
			  !(((_fl676_inwindow[0] >= (_fl676_inwindow[2]*5.0)) &&
			     (_fl676_inwindow[0] >= (_fl676_inwindow[3]*5.0))) ||
			    ((_fl676_inwindow[1] >= (_fl676_inwindow[2]*5.0)) &&
			     (_fl676_inwindow[1] >= 
			      (_fl676_inwindow[3]*5.0))))) ||
			 ((_option_PTL_INL == 1) &&
			  (_bb470_inwindow[0] >= _peak_saved[_indSignalCapture]) &&
			  (_bb470_inwindow[1] >= _peak_saved[_indSignalCapture]) &&
			  !(((_bb470_inwindow[0] >= (_bb470_inwindow[2]*5.0)) &&
			     (_bb470_inwindow[0] >= (_bb470_inwindow[3]*5.0))) ||
			    ((_bb470_inwindow[1] >= (_bb470_inwindow[2]*5.0)) &&
			     (_bb470_inwindow[1] >= 
			      (_bb470_inwindow[3]*5.0)))) &&
			  (_fl676_inwindow[0] < _fl676_bkgnd)))) ||
		       ((k_signal == 1) && (_indSignalCapture == 1) && 
			(_rhod_inwindow[0] >= _peak_saved[_indSignalCapture]) &&
			(_rhod_inwindow[1] >= _peak_saved[_indSignalCapture]) &&
			!(((_rhod_inwindow[0] >= (_rhod_inwindow[2]*5.0)) &&
			   (_rhod_inwindow[0] >= (_rhod_inwindow[3]*5.0))) ||
			  ((_rhod_inwindow[1] >= (_rhod_inwindow[2]*5.0)) &&
			   (_rhod_inwindow[1] >= (_rhod_inwindow[3]*5.0)))))))
		    {
		      //debug
		      //if (k_signal == 1)
		      //printf("_indSignalCapture, _peak_saved[_indSignalCapture], _fl676_inwindow[0], _fl676_inwindow[1], _rhod_inwindow[0], _rhod_inwindow[1] = %d, %f, %f, %f, %f, %f\n", _indSignalCapture, _peak_saved[_indSignalCapture], _fl676_inwindow[0], _fl676_inwindow[1], _rhod_inwindow[0], _rhod_inwindow[1]);

		      _peakCheck[k_signal] = True;
		      _pk_ctrl[k_signal] = 1; // A peak sample.
		      _cntr_trig[k_signal]++;

		      //printf("Surface peak. _cntr_trig, _depth = %d, %f\n", _cntr_trig, _depth);

		      _flag_1stpk[k_signal] = 0; // Reset the 1st-peak flag.

		      if (_cntr_trig[k_signal] >= _ratio_pktrigs_ctrltrigs)
			_flag_ctrl[k_signal] = 1; // Enable control triggering.
		    }
		}
	      else
		{
		  _attitude_flop[k_signal] = 0;
		  _flag_1stpk[k_signal] = 0; // Reset the 1st-peak flag.
		}
	    }
	}

      //debug
      //printf("_fl676, _fl676_inwindow[0], _fl676_inwindow[1] = %f, %f, %f\n", _fl676, _fl676_inwindow[0], _fl676_inwindow[1]);

      if ((_flag_ctrl[k_signal] == 1) &&
	  (((k_signal == 0) &&
	   (((_option_PTL_INL == 0) && 
	     (_fl676_inwindow[0] <= (_fl676_bkgnd*_beta_fl)) &&
	    (_fl676_inwindow[1] <= (_fl676_bkgnd*_beta_fl)))   || 
	   ((_option_PTL_INL == 1) && 
	    (_bb470_inwindow[0] <= (_bb470_bkgnd*_beta_bb)) &&
	    (_bb470_inwindow[1] <= (_bb470_bkgnd*_beta_bb)))))   ||
	   ((k_signal == 1) && 
	    (_rhod_inwindow[0] <= (_rhod_bkgnd*_beta_rhod)) &&
	    (_rhod_inwindow[1] <= (_rhod_bkgnd*_beta_rhod)))))
	{
	  //printf("Got here: _flag_ctrl == 1\n");
	  
	  //debug
	  //printf("k_signal, _fl676_bkgnd, _fl676_inwindow[0], _fl676_inwindow[1], _rhod_bkgnd, _rhod_inwindow[0], _rhod_inwindow[1] = %d, %f, %f, %f, %f, %f, %f\n", k_signal, _fl676_bkgnd, _fl676_inwindow[0], _fl676_inwindow[1], _rhod_bkgnd, _rhod_inwindow[0], _rhod_inwindow[1]);

	  _peakCheck[k_signal] = True;
	  _pk_ctrl[k_signal] = 0; // A control sample.
	  _flag_ctrl[k_signal] = 0;
	  _cntr_trig[k_signal] = 0;

#if 0
	  //debug
	  printf("\n");
	  printf("_peakCheck = True!\n");
	  printf("_pk_ctrl: %d\n", _pk_ctrl);
	  printf("_timeCntr: %d\n", _timeCntr);
	  printf("_state_dep[0] _state_var _flag_1stpk _attitude_flop: %d %d %d %d\n", _state_dep[0], _state_var, _flag_1stpk, _attitude_flop);
	  printf("_timeFromDataFile _dep[0] _dep_shallow _dep_deep: %f %f %f %f\n", _timeFromDataFile, _dep[0], _dep_shallow, _dep_deep);
	  printf("_fl676 _fl676_lp[0] _fl676_bkgnd: %f %f %f\n", _fl676, _fl676_lp[0], _fl676_bkgnd);
	  printf("_bb470 _bb470_lp[0] _bb470_bkgnd: %f %f %f\n", _bb470, _bb470_lp[0], _bb470_bkgnd);
	  printf("_bb676 _bb676_lp _bb676_bkgnd: %f %f %f\n", _bb676, _bb676_lp, _bb676_bkgnd);
	  printf("_peak_saved: %f", _peak_saved);
	  printf("\n");
#endif
	}
    }

  // Calculate background level of fl and bb.
  // Note when "newHs2 == True", we must already have "status == DeviceIF::Ok".
  if (_option_BaselineWindow_RunningOrSliding == 0)
    {
      if (_cntr_fl_bb == 1)
	{
	  _fl676_bkgnd = _fl676;
	  _bb470_bkgnd = _bb470;
	  _bb676_bkgnd = _bb676;
	}
      else
	{
	  _fl676_bkgnd = ((_fl676_bkgnd * (_cntr_fl_bb-1)) + _fl676) / _cntr_fl_bb;
	  _bb470_bkgnd = ((_bb470_bkgnd * (_cntr_fl_bb-1)) + _bb470) / _cntr_fl_bb;
	  _bb676_bkgnd = ((_bb676_bkgnd * (_cntr_fl_bb-1)) + _bb676) / _cntr_fl_bb;
	}

      if (_option_RHOD >= 1)
	{
	  if (_cntr_rhod == 1)
	    {
	      _rhod_bkgnd = _fl676;
	    }
	  else
	    {
	      _rhod_bkgnd = ((_rhod_bkgnd * (_cntr_rhod-1)) + _rhod) / _cntr_rhod;
	    }
	}
    }
  else
    {
      if (_state_dep[0] == _state_dep[1])
	{
	  _fl676_AvgProfile = (_fl676_AvgProfile*_cntr_PtsOnProfile + _fl676) / (_cntr_PtsOnProfile+1);
	  _bb470_AvgProfile = (_bb470_AvgProfile*_cntr_PtsOnProfile + _bb470) / (_cntr_PtsOnProfile+1);
	  _bb676_AvgProfile = (_bb676_AvgProfile*_cntr_PtsOnProfile + _bb676) / (_cntr_PtsOnProfile+1);

	  if (_option_RHOD >= 1)
	    _rhod_AvgProfile = (_rhod_AvgProfile*_cntr_PtsOnProfile + _rhod) / (_cntr_PtsOnProfile+1);

	  _cntr_PtsOnProfile = _cntr_PtsOnProfile + 1;

	  if (_cntr_profiles == 0)
	    {
	      _fl676_bkgnd = _fl676_AvgProfile;
	      _bb470_bkgnd = _bb470_AvgProfile;
	      _bb676_bkgnd = _bb676_AvgProfile;

	      if (_option_RHOD >= 1)
		_rhod_bkgnd = _rhod_AvgProfile;
	    }
	}
      else
	{
	  if (_cntr_profiles <= (_num_profiles_BaselineWindow-1))
	    {
	      _fl676_bkgnd = ((_fl676_bkgnd*_cntr_profiles) + _fl676_AvgProfile) / (_cntr_profiles+1);
	      _bb470_bkgnd = ((_bb470_bkgnd*_cntr_profiles) + _bb470_AvgProfile) / (_cntr_profiles+1);
	      _bb676_bkgnd = ((_bb676_bkgnd*_cntr_profiles) + _bb676_AvgProfile) / (_cntr_profiles+1);

	      if (_option_RHOD >= 1)
		_rhod_bkgnd = ((_rhod_bkgnd*_cntr_profiles) + _rhod_AvgProfile) / (_cntr_profiles+1);
	    }
	  else
	    {
	      _fl676_bkgnd = ((_fl676_bkgnd*_num_profiles_BaselineWindow) - _fl676_avg_profile[_num_profiles_BaselineWindow-1] + _fl676_AvgProfile) / _num_profiles_BaselineWindow;
	      _bb470_bkgnd = ((_bb470_bkgnd*_num_profiles_BaselineWindow) - _bb470_avg_profile[_num_profiles_BaselineWindow-1] + _bb470_AvgProfile) / _num_profiles_BaselineWindow;
	      _bb676_bkgnd = ((_bb676_bkgnd*_num_profiles_BaselineWindow) - _bb676_avg_profile[_num_profiles_BaselineWindow-1] + _bb676_AvgProfile) / _num_profiles_BaselineWindow;

	      if (_option_RHOD >= 1)
		_rhod_bkgnd = ((_rhod_bkgnd*_num_profiles_BaselineWindow) - _rhod_avg_profile[_num_profiles_BaselineWindow-1] + _rhod_AvgProfile) / _num_profiles_BaselineWindow;
	    }

	  if (_cntr_profiles >= 1)
	    {
	      if (_cntr_profiles < (_num_profiles_BaselineWindow-1))
		r_max = _cntr_profiles;
	      else
		r_max = (_num_profiles_BaselineWindow-1);
                
	      if (r_max >= 1)
		{
		  for (r=r_max; r>=1; r--)
		    {
		      _fl676_avg_profile[r] = _fl676_avg_profile[r-1];
		      _bb470_avg_profile[r] = _bb470_avg_profile[r-1];
		      _bb676_avg_profile[r] = _bb676_avg_profile[r-1];

		      if (_option_RHOD >= 1)
			_rhod_avg_profile[r] = _rhod_avg_profile[r-1];
		    }
		}
	    }

	  _fl676_avg_profile[0] = _fl676_AvgProfile;
	  _bb470_avg_profile[0] = _bb470_AvgProfile;
	  _bb676_avg_profile[0] = _bb676_AvgProfile;

	  if (_option_RHOD >= 1)
	    _rhod_avg_profile[0] = _rhod_AvgProfile;

#if 0
	  //debug
	  if (_cntr_profiles <= 20)
	    printf("_cntr_profiles, _fl676_avg_profile[0], _fl676_avg_profile[1], _fl676_avg_profile[2], _fl676_bkgnd = %d, %f, %f, %f, %f\n", _cntr_profiles, _fl676_avg_profile[0], _fl676_avg_profile[1], _fl676_avg_profile[2], _fl676_bkgnd);
#endif

	  _cntr_profiles = _cntr_profiles + 1;

	  _fl676_AvgProfile = 0.0;
	  _bb470_AvgProfile = 0.0;
	  _bb676_AvgProfile = 0.0;

	  if (_option_RHOD >= 1)
	    _rhod_AvgProfile = 0.0;
	  
	  _cntr_PtsOnProfile = 0;
	}
    }

  for (k_signal=0; k_signal<=(_num_PeakSignals-1); k_signal++)
    {
      switch (k_signal)
	{
	case 0:
	  if (_option_PTL_INL == 0)
	    {
	      _ptr_var_lp = _fl676_lp;
	      _var_bkgnd = _fl676_bkgnd;
	      _alpha_var = _alpha_fl;
	      _ptr_var_inwindow = _fl676_inwindow;
	    }
	  else
	    {
	      _ptr_var_lp = _bb470_lp;
	      _var_bkgnd = _bb470_bkgnd;
	      _alpha_var = _alpha_bb;
	      _ptr_var_inwindow = _bb470_inwindow;
	    }
	  _delta_var_rise = _delta_fl_bb_rise;
	  _delta_var_drop = _delta_fl_bb_drop;
	  break;

	case 1:
	  _ptr_var_lp = _rhod_lp;
	  _var_bkgnd = _rhod_bkgnd;
	  _alpha_var = _alpha_rhod;
	  _ptr_var_inwindow = _rhod_inwindow;
	  _delta_var_rise = _delta_rhod_rise;
	  _delta_var_drop = _delta_rhod_drop;
	  break;
	}

      if (_state_var[k_signal] == 1)
	{
	  if ((*_ptr_var_lp > _var_max[k_signal]) ||
	      (*_ptr_var_lp < (_var_bkgnd * _alpha_var)))
	    {
	      _var_max[k_signal] = *_ptr_var_lp; // Continue to track the maximum value.
	      _state_var[k_signal] = 1;
	    }
	  else
	    {
	      if (((*_ptr_var_lp - _var_max[k_signal]) < -_delta_var_drop) || 
		  ((*_ptr_var_lp < *(_ptr_var_lp + 1)) && (*(_ptr_var_lp + 1) < *(_ptr_var_lp + 2))))
		{
		  _var_min[k_signal] = *_ptr_var_lp; // Switch to tracking the minimum value.
		  _state_var[k_signal] = 0;

		  if (((k_signal == 0) && 
		      (((_option_PTL_INL == 0) && 
			((_bb470_lp[0] > (_bb470_bkgnd * _alpha_bb)) || 
			 (_bb676_lp > (_bb676_bkgnd * _alpha_bb))))  ||
		       ((_option_PTL_INL == 1) && 
			(_fl676_lp[0] < _fl676_bkgnd)))) ||
		      (k_signal == 1))
		    {
		      _cntr_peak[k_signal]++;
		  
		      // Save peaks in an array:
		      // _peak[0] stores the newest peak.
		      // _peak[num_stored_peaks-1] stores the oldest.
		      // _timeCntr_peak[] stores the corresponding time stamp.

		      if (_cntr_peak[k_signal] >= 2)
			{
			  if (_cntr_peak[k_signal] <= MAXSTOREDPEAKS)
			    num_stored_peaks = _cntr_peak[k_signal];
			  else
			    num_stored_peaks = MAXSTOREDPEAKS;
		      
			  for (k=(num_stored_peaks-2); k>=0; k--)
			    {
			      _peak[k_signal][k+1] = _peak[k_signal][k];
			      _timeCntr_peak[k_signal][k+1] = _timeCntr_peak[k_signal][k];
			    }
			}

		      _peak[k_signal][0] = *_ptr_var_lp;
		      _timeCntr_peak[k_signal][0] = _timeCntr;

		      if (_cntr_peak[k_signal] == 1)
			_peak_baseline[k_signal] = _peak[k_signal][0];
		      else
			{
			  _peak_baseline[k_signal] = _peak[k_signal][0];
			  num_accumulated_peaks = 1;
		      
			  for (k=1; k<=(num_stored_peaks-1); k++)
			    {
			      if ((_timeCntr-_timeCntr_peak[k_signal][k]) 
				  > (_timewindow_peakbaseline*5.0)) // 5 Hz.
				break;

			      _peak_baseline[k_signal] = _peak_baseline[k_signal] + _peak[k_signal][k];
			      num_accumulated_peaks++;
			    }
			  _peak_baseline[k_signal] = _peak_baseline[k_signal] / num_accumulated_peaks;
			}

		      if (_option_ClosenessOfTwoCrossings == 1)
			cond_closeness = (((_state_dep[0] == 1) && 
					   (_dep[0] > dep_mid)) || 
					  ((_state_dep[0] == 0) && 
					   (_dep[0] < dep_mid)));
		      else
			cond_closeness = True;

#if 0
		      //debug
		      printf("_timeFromDataFile, _flag_ctrl, _flag_1stpk, _peak[0], _peak_baseline, _peak_saved, cond_closeness = %f %d %d %f %f %f %d\n", _timeFromDataFile, _flag_ctrl, _flag_1stpk, _peak[0], _peak_baseline, _peak_saved, cond_closeness);
#endif

		      if ((_flag_ctrl[k_signal] == 0) &&
			  (((_flag_1stpk[k_signal] == 0) &&
			    (_peak[k_signal][0] >= _peak_baseline[k_signal]) 
			    && (_cntr_peak[k_signal] >= 2)) ||
			   ((_flag_1stpk[k_signal] == 1) 
			    && (_peak[k_signal][0] >= _peak_saved[k_signal]))) &&
			  cond_closeness)
			{
			  if (_flag_1stpk[k_signal] == 1)
			    peaksaved_previous = _peak_saved[k_signal];

			  // Get the true peak height (after 5-state median filtering) which has been saved in the window.
			  for (m=0; m<=(_len_window_full-5); m++)
			    {
			      for (q=0; q<=4; q++)
				array_sort[q] = *(_ptr_var_inwindow + m + q);
			  
			      //printf("Before. array_sort[] = %f, %f, %f, %f, %f\n", array_sort[0], array_sort[1], array_sort[2], array_sort[3], array_sort[4]);

			      for (n=0; n<=3; n++) // Bubble sorting for a 5-state median filter.
				{
				  for (p=4; p>=(n+1); p--)
				    {
				      if (array_sort[p-1] > array_sort[p])
					{
					  tmp = array_sort[p];
					  array_sort[p] = array_sort[p-1];
					  array_sort[p-1] = tmp;
					}
				    }
				}

			      //printf("After. array_sort[] = %f, %f, %f, %f, %f\n", array_sort[0], array_sort[1], array_sort[2], array_sort[3], array_sort[4]);

			      array_median[m] = array_sort[2]; // Take the median value.
			    }

			  _peak_saved[k_signal] = array_median[0];

			  for (k=1; k<=(_len_window_full-5); k++)
			    {
			      if (array_median[k] > _peak_saved[k_signal])
				_peak_saved[k_signal] = array_median[k];
			    }

			  //debug
			  //printf("_timeFromDataFile, array_median[], _peak_saved[k_signal] = %f, %f, %f, %f, %f, %f\n", _timeFromDataFile, array_median[0], array_median[1], array_median[2], array_median[3], _peak_saved[k_signal]);

			  if (_flag_1stpk[k_signal] == 0)
			    {
			      if (_peak_saved[k_signal] >= (_var_bkgnd * _alpha_var))
				{
				  _flag_1stpk[k_signal] = 1;
				  _state_dep_1stpk[k_signal] = _state_dep[0];
				  _attitude_flop[k_signal] = 0;
				  _attitude_flop_flop[k_signal] = 0;
				}
			    }
			  else
			    {
			      if (_peak_saved[k_signal] >= peaksaved_previous)
				{
				  _state_dep_1stpk[k_signal] = _state_dep[0];
				  _attitude_flop[k_signal] = 0;
				  _attitude_flop_flop[k_signal] = 0;
				}
			      else
				_peak_saved[k_signal] = peaksaved_previous;
			    }

#if 0
			  //debug
			  printf("Prepeak:\n");
			  printf("_timeFromDataFile, _var_max[k_signal], *_ptr_var_lp, *(_ptr_var_lp + 1), *(_ptr_var_lp + 2), _peak_saved, _peak_baseline = %f %f %f %f %f %f %f\n", _timeFromDataFile, _var_max[k_signal], *_ptr_var_lp, *(_ptr_var_lp + 1), *(_ptr_var_lp + 2), _peak_saved, _peak_baseline);
#endif
			}
		    }
		}
	      else
		_state_var[k_signal] = 1;
	    }
	}
      else
	{
	  if (*_ptr_var_lp < _var_min[k_signal])
	    {
	      _var_min[k_signal] = *_ptr_var_lp; // Continue to track the minimum value.
	      _state_var[k_signal] = 0;
	    }
	  else
	    {
	      if ((*_ptr_var_lp - _var_min[k_signal]) > _delta_var_rise)
		{
		  _var_max[k_signal] = *_ptr_var_lp; // Switch to tracking the maximum value.
		  _state_var[k_signal] = 1;
		}
	      else
		_state_var[k_signal] = 0;
	    }
	}
    }
}
