/** \file
 *
 *  Contains the PeakDetectVsDepth class declaration.
 *
 *  PeakDetectVsDepth.h should only be included by PeakDetectVsDepth.cpp
 *  Other classes should include PeakDetectVsDepthIF.h
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef PEAKDETECTVSDEPTH_H_
#define PEAKDETECTVSDEPTH_H_

#include "component/Behavior.h"

class UniversalDataReader;

/**
 *  Contains the PeakDetectVsDepth Behavior/Command
 *
 *  TBD
 *
 *  PeakDetectVsDepth.h should only be included by PeakDetectVsDepth.cpp
 *  Other classes should include PeakDetectVsDepthIF.h
 *
 *  \ingroup modules_trigger
**/

class PeakDetectVsDepth : public Behavior
{
public:

    PeakDetectVsDepth( const Str& prefix, const Module* module );

    virtual ~PeakDetectVsDepth();

    /// Initialize function
    void initialize( void );

    /// Read in the parameters for satisfied or runIfUnsatisfied: return true if OK.
    bool readParams( float& depth, float& temperature, float& detect, double& lat, double& lon );

    /// Perform the satisfied: return true if envelope "satisfied"
    bool calcSatisfied( const float depth, const float temperature, const float detect, const double lat, const double lon );

    /// Just do the run: ignore the results of the satisfied
    void run();

    /// Just do the satisfied: return true if envelope "satisfied"
    bool isSatisfied();

    /// Do the run, and return true if envelope "satisfied"
    bool runIfUnsatisfied();

    /// Uninit function
    void uninitialize( void );

    /// Mission Component factory interface
    static Behavior* CreateBehavior( const Str& prefix, const Module* module );

protected:

    /// Default values for input settings
    /// (Supplied so outputs can be directed to these inputs)

    /// if no "depthSurrogate" setting is provided, what to use
    static const Str DEFAULT_DEPTH_SURROGATE_SETTING;

    /// if no "consecutiveDepths" setting is provided, what to use
    static const int DEFAULT_CONSECUTIVE_DEPTHS;

    /// if no "depthChangeThresh" setting is provided, what to use
    static const float DEFAULT_DEPTH_CHANGE_THRESH;

    /// if no "windowLength" setting is provided, what to use
    static const int DEFAULT_WINDOW_LENGTH;

    /// if no "medianFilterLength" setting is provided, what to use
    static const int DEFAULT_MEDIAN_FILTER_LENGTH;

    // Slate input setting variables

    /// Sets variable to detect the peak of (e.g., chl concentration)
    SettingReader *detectSettingReader_;

    /// Sets variable that is used instead of depth (e.g., distance)
    SettingReader *depthSurrogateSettingReader_;

    /// Sets consecutiveDepths to detect a turn
    SettingReader *consecutiveDepthsSettingReader_;

    /// Sets depthChangeThresh to detect a turn
    SettingReader *depthChangeThreshSettingReader_;

    /// Sets windowLength for low-pass filtering
    SettingReader *windowLengthSettingReader_;

    /// Sets medianFilterLength for median filtering
    SettingReader *medianFilterLengthSettingReader_;

    // Minimum / Maximum depth at which to detect
    SettingReader *shallowBoundSettingReader_;
    SettingReader *deepBoundSettingReader_;

    /// Sets time window out of which to report a peak (e.g., 5 minutes)
    SettingReader *timeWindowPeakReportSettingReader_;

    // Actual values from settings

    /// Optional consecutiveDepths
    int consecutiveDepthsSetting_;

    /// Optional depthChangeThresh
    float depthChangeThreshSetting_;

    /// Optional windowLength
    int windowLengthSetting_;

    /// Optional medianFilterLength
    int medianFilterLengthSetting_;

    const Unit* detectBaseUnit_;

    const Unit* depthBaseUnit_;

    // Slate input measurements

    /// The value being detected as a peak (e.g., chl concentration)
    DataReader* detectReader_;

    /// The value used to define the independent axis (e.g., depth)
    DataReader* depthReader_;

    /// Reads latitude
    DataReader* latitudeReader_;

    /// Reads longitude
    DataReader* longitudeReader_;

    /// Reads temperature
    DataReader* temperatureReader_;

    // Argument output variables
    DataWriter* peakDetectWriter_;
    DataWriter* troughDetectWriter_;
    DataWriter* peakDepthWriter_;
    DataWriter* peakLatitudeWriter_;
    DataWriter* peakLongitudeWriter_;
    DataWriter* peakTemperatureWriter_;

    /// Value of the peak when it occurs.
    float peakDetect_;
    float troughDetect_;
    float peakDepth_;
    float peakTemperature_;
    double peakLatitude_;
    double peakLongitude_;
    float peakShallowBound_;
    float peakDeepBound_;
    Timespan timeWindowPeakReport_;
    float timeWindowPeakReportSetting_;

#define MAX_COSEC_DEPTH 10
#define MAX_WINDOW_LENGTH 100
#define MAX_MEDIAN_FILTER_LENGTH 11

    int cntrVar_;
    int stateDepth_[2];
    float dep_[MAX_COSEC_DEPTH];
    float depMax_, depMin_;
    float varProfileInWindow_[MAX_MEDIAN_FILTER_LENGTH + MAX_MEDIAN_FILTER_LENGTH + 1];
    float depthInWindow_[MAX_WINDOW_LENGTH + MAX_MEDIAN_FILTER_LENGTH + 1];
    float tempInWindow_[MAX_WINDOW_LENGTH + MAX_MEDIAN_FILTER_LENGTH + 1];
    double latInWindow_[MAX_WINDOW_LENGTH + MAX_MEDIAN_FILTER_LENGTH + 1];
    double lonInWindow_[MAX_WINDOW_LENGTH + MAX_MEDIAN_FILTER_LENGTH + 1];
    float varProfileMedianInWindow_[MAX_WINDOW_LENGTH + MAX_MEDIAN_FILTER_LENGTH + 1];
    float varLowPass_;
    float depthLowPass_;
    float tempLowPass_;
    double latLowPass_;
    double lonLowPass_;
    float peakProfile_;
    float troughProfile_;
    Timestamp startTimeWindowPeakReport_;

private:

    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    PeakDetectVsDepth( const PeakDetectVsDepth& old ); // disallow copy constructor

    void initVars();
};

#endif /*PEAKDETECTVSDEPTH_H_*/
