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

#ifndef CTD_SEABIRD_H_
#define CTD_SEABIRD_H_

#include <vector>       // std::vector

#include "component/AsyncComponent.h"
#include "io/LoadControl.h"
#include "io/UartStream.h"
#include "logger/Logger.h"
#include "utils/BinFilter1D.h"


class UniversalDataReader;
class UniversalDataWriter;

/**
 *  Software interface to Neil Brown CTD.  Also provides interface
 *  to SimSlate for providing simulated temperature, salinity, and
 *  depth.
 *
 *  \note still needs to be coded for the actual Neil Brown CTD
 *
 *  CTD_Seabird.h should only be included by CTD_Seabird.cpp
 *  Other classes should include CTD_SeabirdIF.h
 *
 *  \ingroup modules_science
 */
class CTD_Seabird: public AsyncComponent
{
public:
    CTD_Seabird( const Module* module );
    virtual ~CTD_Seabird();

    virtual void run();

    /// Do what needs to be done to run
    /// Similar to initialize, in old init/run/uninit sequence
    virtual RunState start();

    /// Might follow a STOP...START sequence
    virtual RunState starting();

    /// Pause for a short period (indicated by pauseTime)
    virtual RunState pause();

    /// Should eventually follow a PAUSE request: should set continueTime
    virtual RunState paused();

    /// Resume from PAUSE
    virtual RunState resume();

    /// Might follow a PAUSE...RESUME sequence
    virtual RunState resuming();

    /// Should eventually follow a START request or RESETTING
    virtual RunState runnable();

    /// Might occur in case of Error
    virtual RunState resetting()
    {
        return stop();
    }

    /// Initial state -- can be later followed by START
    virtual RunState stop();

    virtual RunState stopping();

    /// Initial state -- can be later followed by START
    virtual RunState stopped();

    void uninitialize();

    /// Should return [myNamespace]::SIMULATE_HARDWARE, or [myNamespace]::POWER, etc
    virtual ConfigURI getConfigURI( ConfigOption configOption ) const;

private:

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

    /// Async thread cycle period
    static const Timespan PERIOD;

    void readConfig();

    bool parseResponse();

    // returns true if data is requested from one of the readers
    bool isDataRequested();

    bool isDepthNeeded();

    void setWritersInvalid();

    // Debugging outputs
    bool debug_;

    // Verbosity level setting
    int verbosity_;

    // Scratch buffer
    char buf_[256];

    // Instance of load controller
    LoadControl loadControl_;

    /// Time data request started
    Timestamp startTime_;

    /// Time runnable cycle started
    Timestamp runTime_;

    /// Time data was recivied
    Timestamp dataTime_;

    /// Timeout for getting data
    Timespan ctdTimeout_;

    // Power on timeout. Allows time for the pump to flush the CTD's plumbing
    Timespan poTimeout_;

    // Holds the communications device
    UartStream uart_;

    // Defines the number of messages allowed to queue up in the buffer
    // If exceeded, we assume we're out of sync with the device and flush the buffer
    static const unsigned short MAX_DEVICE_MSG_QUEUE_SIZE;

    // Holds the expected device response size
    static const unsigned int MAX_DEVICE_RESPONSE_SIZE = 255;

    // Stores the current response from the device
    char deviceResponse_[MAX_DEVICE_RESPONSE_SIZE + 1];


    // Universal Slate outputs
    UniversalDataWriter* densityWriter_;
    UniversalDataWriter* depthWriter_;
    UniversalDataWriter* pressureWriter_;
    UniversalDataWriter* salinityWriter_;
    UniversalDataWriter* temperatureWriter_;
    UniversalDataWriter* conductivityWriter_;
    UniversalDataWriter* speedOfSoundWriter_;
    UniversalDataWriter* oxygenConcentrationWriter_;

    // Slate outputs
    DataWriter* oxygenFreqWriter_;
    DataWriter* binMedianTemperatureWriter_;
    DataWriter* binMeanTemperatureWriter_;
    DataWriter* binStandardDeviationTemperatureWriter_;
    DataWriter* binMedianSalinityWriter_;
    DataWriter* binMeanSalinityWriter_;
    DataWriter* binStandardDeviationSalinityWriter_;

    // Slate inputs
    UniversalDataReader* depthReader_;
    UniversalDataReader* latitudeReader_;
    DataReader* gfScanActiveReader_;

    // Configuration inputs
    ConfigReader* sbe43FSerialNumberCfgReader_;
    ConfigReader* oxygenCalCoeffFOffsetCfgReader_;
    ConfigReader* oxygenCalCoeffSocCfgReader_;
    ConfigReader* oxygenCalCoeffACfgReader_;
    ConfigReader* oxygenCalCoeffBCfgReader_;
    ConfigReader* oxygenCalCoeffCCfgReader_;
    ConfigReader* oxygenCalCoeffECfgReader_;
    ConfigReader* maxPressBoundCfgReader_;
    ConfigReader* minPressBoundCfgReader_;
    ConfigReader* maxSalinityBoundCfgReader_;
    ConfigReader* minSalinityBoundCfgReader_;
    ConfigReader* offsetCfgReader_;
    ConfigReader* verbosityCfgReader_;

    // SBE 43F OXYGEN CALIBRATION COEFFICIENTS
    // See SBE APPLICATION NOTE NO. 64-2: SBE 43 Dissolved Oxygen Sensor Calibration and Data Corrections
    // The values for these coeffs can be found on the sensor's calibration sheet.
    int sbe43FSerialNumber_;
    double FOFFSET_;
    double SOC_;
    double A_;
    double B_;
    double C_;
    double E_;

    // Device offsets and limits
    float pressureOffset_;
    float maxPressBound_;
    float minPressBound_;
    float maxSalinityBound_;
    float minSalinityBound_;

    // Latitude input
    float latitude_;

    // Raw GPCTD readings: pressure (dbar), temperature (ITS-90, C), conductivity (S/m)
    float pressureDB_, temperature_, conductivity_;

    // SBE 43F oxygen sensor output (Hz)
    float oxygenFreq_;

    // Processed data products
    float depth_, salinity_, density_, soundSpeed_, oxygenConcentration_;

    // Data validity flags
    bool badPressure_, badTemperature_, badConductivity_, badSalinity_;

    // Containers for temporal binning
    BinFilter1D<float> temperatureBin_;
    BinFilter1D<float> salinityBin_;

    // Attempt to read data from the SimSlate
    bool getSimulatedData();

    // Attempt to read data from the UART
    bool getUartData();

    // Get the latest message in the UART queue
    bool readUntilLatest();

    // Removes whitspace char from device response
    void trimResponse();

    // Converts SBE 43F oxygen sensor data to oxygen concentration following Owens & Millard (1985)
    void oxygenConcentration();

    // Perform onboard processing and quality checks
    void preprocessData();

    // Write data out to the slate and/or publish on LCM
    void writeData();

    // Update the onboard binning
    void updateTemporalBin();

    // Calculate statistics when bin is full
    void calculateAndReportTemporalBinStatistics();

};

#endif /* CTD_SEABIRD_H_ */
