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

#ifndef CBIT_H_
#define CBIT_H_

#include "component/ComponentRegistry.h"
#include "component/SyncComponent.h"
#include "io/LPC3Reg.h"
#include "io/AnalogToDigital.h"
#include "sensorModule/BPC1IF.h"
#include "controlModule/VerticalControlIF.h"

class UniversalDataReader;
class UniversalDataWriter;

/**
 *  The CBIT built-in-test (CBIT) component provides monitoring of
 *  vehicle health during a mission.  If it sees a fault, it will write to
 *  a fault flag.
 *
 *  CBIT.h should only be included by CBIT.cpp
 *  Other classes should include CBITIF.h
 *
 *  \ingroup modules_builtintest
 */
class CBIT : public SyncTestComponent
{
public:

    CBIT( const Module* module );

    virtual ~CBIT();

    /// Initialize function
    void initialize( void );

    /// The actual "payload" of the component
    void run();

    /// Uninit function
    void uninitialize( void );

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

protected:

    // Slate input setting variables

    /// When true (non-zero), clears the generic fault flag.
    DataReader *clearFaultCmdReader_;

    /// When true (non-zero), clears the leak fault flag.
    DataReader *clearLeakFaultCmdReader_;

    // For Onboard pressure/humidity and other components
    DataReader* pressureReader_;
    DataReader* humidityReader_;
    DataReader* temperatureReader_;
    DataReader* speedCmdReader_;
    DataReader* verticalModeReader_;
    DataReader* power24vConverterDataReader_;

    DataReader* empiricalFaultElevOffsetReader_;

    /// Platform depth, lat/lon
    UniversalDataReader* depthReader_;
    UniversalDataReader *depthRateReader_;
    UniversalDataReader *elevatorAngleReader_;
    UniversalDataReader* latitudeReader_;
    UniversalDataReader* longitudeReader_;
    UniversalDataReader* pitchReader_;
    UniversalDataReader* batteryVoltageReader_;
    UniversalDataReader* fixResidualPercentDistanceTraveledReader_;

    // Slate output variables

    /// Sets the generic fault flag.
    UniversalDataWriter *faultWriter_;

    /// Sets the leak fault flag.
    UniversalDataWriter *leakFaultWriter_;

    // State of shore power - True == ON False == OFF
    DataWriter* shorepowerWriter_;

    // How much cumulative energy has been used
    DataWriter* aHUsedWriter_;

    DataWriter* gfScanActiveWriter_;

    // Ground fault current
    DataWriter* gfChanA0CurrentWriter_;
    DataWriter* gfChanA1CurrentWriter_;
    DataWriter* gfChanA2CurrentWriter_;
    DataWriter* gfChanA3CurrentWriter_;
    DataWriter* gfChanB0CurrentWriter_;
    DataWriter* gfChanB1CurrentWriter_;
    DataWriter* gfChanB2CurrentWriter_;
    DataWriter* gfChanB3CurrentWriter_;
    DataWriter* gfChanOpenCurrentWriter_;

    // Emperical Fault Classifier writers
    DataWriter* empericalFaultDetectedWriter_;
    DataWriter* binnedDepthRateWriter_;
    DataWriter* empiricalFaultElevOffsetWriter_;

    // Configuration Readers
    ConfigReader* abortDepthCfgReader_;        // Depth at which we drop the weight. Should be greater than all depth envelopes
    ConfigReader* stopDepthCfgReader_;         // Depth at which we stop the mission. Should be greater than all depth envelopes and less than abort depth
    ConfigReader* humidityThresholdCfgReader_; // relative humidity
    ConfigReader* pressureThresholdCfgReader_; // Onboard pressure must measure greater than this offset from 1 ATM
    ConfigReader* tempThresholdCfgReader_;     // Only need to use kelvin for temperature deltas
    ConfigReader* vehicleOpenCfgReader_;
    ConfigReader* abortDepthTimeoutCfgReader_; // If this time has elapsed and we're still below abort depth, drop the weight, end the mission.
    ConfigReader* battFailReportCfgReader_;    // Report main battery failover at this interval
    ConfigReader* envTimeoutCfgReader_;        // If this time has elapsed and pressure or humidity are still above threshold, end the mission.
    ConfigReader* faultClassifierCfgReader_;   // Runs the empirical fault classifier as part of CBIT if true
    ConfigReader* elevOffsetCalcCfgReader_;    // Runs the empirical fault classifier's elevator offset calculator as part of CBIT if true
    ConfigReader* battTempThresholdCfgReader_; // The allowable threshold for battery temperature
    ConfigReader* navErrorThresholdCfgReader_;
    ConfigReader* allowAuxLeakCfgReader_;
    ConfigReader* navErrorCriticalCfgReader_;   // Will throw a critical is navigation error is above threshold
    ConfigReader* gfChanA0ThresholdCfgReader_;  // Current above baseline that triggers a ground fault
    ConfigReader* gfChanA1ThresholdCfgReader_;  // Current above baseline that triggers a ground fault
    ConfigReader* gfChanA2ThresholdCfgReader_;  // Current above baseline that triggers a ground fault
    ConfigReader* gfChanA3ThresholdCfgReader_;  // Current above baseline that triggers a ground fault
    ConfigReader* gfChanB0ThresholdCfgReader_;  // Current above baseline that triggers a ground fault
    ConfigReader* gfChanB1ThresholdCfgReader_;  // Current above baseline that triggers a ground fault
    ConfigReader* gfChanB2ThresholdCfgReader_;  // Current above baseline that triggers a ground fault
    ConfigReader* gfChanB3ThresholdCfgReader_;  // Current above baseline that triggers a ground fault
    ConfigReader* gfScanTimeoutCfgReader_;     // How often to scan for ground faults

    // Readers for specific channel offsets due to leakage
    ConfigReader* gfBattOffsetCfgReader_;
    ConfigReader* gf24OffsetCfgReader_;
    ConfigReader* gf12OffsetCfgReader_;
    ConfigReader* gf5OffsetCfgReader_;
    ConfigReader* gf3_3OffsetCfgReader_;
    ConfigReader* gf3_15OffsetCfgReader_;
    ConfigReader* gfCommOffsetCfgReader_;

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

    friend class IBIT;
    friend class SBIT;

    // Is the WDT initialized properly?
    bool wdtInitialized_;

    bool readConfigCriticalReported_; // There was a critical reading config values but we only need to report it once

    // Runs the empirical fault classifier to detect anomolies
    // in vertical control
    void empiricalFaultClassification( void );

    // initialize vehicle config variables
    bool readConfig( void );

    // WDT and heartbeat
    void assertVitals( void );

    void checkBackplanePower( void );
    void checkBackplaneOvercurrent( void );
    void checkBacktrace( void );
    void checkCriticals( void );
    void checkDepth( void );

    void checkLeak( void );
    // Makes sure location is real
    void checkLocation( void );
    void checkMainBattery( void );
    void handleComponentFaults( void );
    void monitorBatteryTemps( void );
    void monitorCFCard( void );
    void checkNavigation( void );
    void monitorEnvironmentals( void );
    void monitorShorePower( void );
    void reportCoulombCount( void );

    // initiate GF scanning
    void scanGFChan( void );

    // Makes the appropriate log entry
    void reportGFScan( Str scanTxt );

    // Checks to make sure value read is within bounds of circuit. Returns true if within range
    bool checkGFBounds( float maxCurrent );

    // Allows access to set timeout
    static void SetGFScanForce( bool forceVal );

    // Returns true if water is detected in the pressure hull
    short waterDetected( void );

    // Holds the time of when abort/stop depth was reached
    Timestamp abortStartTime_;
    Timestamp stopDepthStartTime_;
    Timespan abortDepthTimeout_;

    // Holds the time of when environmental (pressure, humidity) failure was detected
    Timestamp envFailStartTime_;
    Timespan envFailTimeout_;

    // Holds the time of when battery threshold failure was detected
    Timestamp battThresholdFailStartTime_;
    Timespan battThresholdFailTimeout_;

    // Time of last fault message on battery failure report signal
    Timestamp battFailReportTime_;
    // Interval between battery failure fault messages
    Timespan battFailReportInterval_;

    // Holds the time of when GF scanning was started
    Timestamp gfStartTime_;
    Timespan gfScanTimeout_;
    Timespan gfChanSetupTimeout_;
    static bool GFScanForce_; // Used to force a scan immediately

    // Holds the time of when location was last checked to exist
    Timestamp locationCheckStartTime_;
    Timespan locationCheckTimeout_;
    bool nanLocationActive_; // True if location has been detected as nan
    bool nanLocationReported_;

    // How often to read the coulombCounter
    Timestamp coulombCountCheckTime_;
    Timespan coulombCountTimeout_;

    // True if we have reached abort depth and are taking action
    bool abortDepthActive_;
    bool previouslyBelowAbort_;

    // True if we have reached stop depth and are taking action
    bool stopDepthActive_;
    bool previouslyBelowStop_;


    // True if we have detected water and have stopped the mission and triggered a critical
    bool waterDetectedCriticalSet_;
    // True if we have detected water and activated the burnwire
    bool waterDetectedBurnwireActivated_;
    // True if aux-only water alarm should skip burnwire
    bool allowAuxLeak_;

    // Variable is incremented each time water is detected, and decremented until 0 each time there isn't water detected.
    int waterDetectionCount_;

    enum WaterAlarm
    {
        WATER_ALARM_BOW,
        WATER_ALARM_STERN,
        WATER_ALARM_AUX,
    };

    // True if we have detected a load control backplane power loss and can't restore power.
    bool backplaneFailed_;

    // True if we have detected an over threshold value for humidity or pressure
    bool envFailed_;
    bool envExcursionFault_;

    // True if we have detected an over threshold value for battery data
    bool battThresholdFailed_;

    // For storing "baseline" environmental data
    float avgHumidity_;
    float samples_;

    // Values for checking navigation
    int navErrorThreshold_; // percentage of allowable nav error
    bool navErrorCriticalReporting_; // When true, throw a critical

    // True if the CF card is missing and we are taking action
    bool cfMissing_;

    // indicates a GF scan is ongoing
    bool gfScanInProgress_;
    int Pwr24On_; // is 24V power on or not

    // Counts successive bounding errors for GF scans.
    int gfScanBoundErrors_;


    typedef enum
    {
        CHAN_A0_SCAN,    // Activate and read chan 5 - 0
        CHAN_A1_SCAN,
        CHAN_A2_SCAN,
        CHAN_A3_SCAN,
        BANK_DELAY,
        CHAN_B0_SCAN,
        CHAN_B1_SCAN,
        CHAN_B2_SCAN,
        CHAN_B3_SCAN,
        OPEN_SCAN,
        CALCULATE,    // Determine GF and write values
    } GFSequence;

    GFSequence gfScan_;

    LPC3Reg::GFChan gfChan_;

    // Channel to read GF value
    AnalogToDigital adGFCurrent_;
    AnalogToDigital adWaterAlarmBow_, adWaterAlarmStern_, adWaterAlarmAux_;

    // Holds the time of when last fault classifier debug messege was published
    Timestamp debugEFCTimestamp_;
    Timespan debugEFCTimeout_;
    bool runFaultClassifier_;
    bool runElevOffsetCalc_;

    // EFC
    int   empiricalFaultCounter_;
    float empiricalFaultBinSum_;
    float empiricalFaultEleTmp_;
    float empiricalFaultPitchTmp_;
    double empiricalFaultDepth_;
    int empiricalFaultPositiveFlagCount_;
    Timestamp empiricalFaultTimestamp_;

    // EOM
    int   elevOffsetCounter_;
    bool  clearCounterEOM_;
    float elevOffsetEleTmp_;

    // Debugging outputs
    bool debug_;

    float gfCurrentA0_, gfCurrentA1_, gfCurrentA2_, gfCurrentA3_, gfCurrentB0_, gfCurrentB1_, gfCurrentB2_, gfCurrentB3_, gfCurrentOpen_;

    struct BattPack
    {
        // Constructor
        BattPack();

        // The battery voltage
        float voltage_;
        DataReader *battVoltageReader_;

        // The battery current
        float current_;
        DataReader *battCurrentReader_;

        // The battery temp
        float temp_;
        DataReader *battTempReader_;
    };

    DataReader *tmpTempReader_;
    // Array to store the battery packs and their associated writers
    BattPack battPacks_[BPC1AIF::NUMBATTS + BPC1BIF::NUMBATTS];


    ///*------------------- vehicle parameters --------------------------*/
    float abortDepth_;
    float stopDepth_;
    double bitHumidityThreshold_;
    double bitPressureThreshold_;
    double bitTempThreshold_;
    double battTempThreshold_;
    bool cbitVehicleOpen_;
    float gfChanA0Threshold_, gfChanA1Threshold_, gfChanA2Threshold_, gfChanA3Threshold_, gfChanB0Threshold_, gfChanB1Threshold_, gfChanB2Threshold_, gfChanB3Threshold_;

    // offsets for leakage current
    float gfBattOffset_, gf24Offset_, gf12Offset_, gf5Offset_, gf3_3Offset_, gf3_15Offset_, gfCommOffset_;
    ///////////////////////////////////

};

#endif /*CBIT_H_*/
