/** \file
 *
 *  Contains the BPC1 class declaration.
 *
 *  BPC1.h should only be included by BPC1.cpp
 *  Other classes should include BPC1IF.h
 *
 *  Copyright (c) 2014 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */


#ifndef BPC1_H
#define BPC1_H

#include <vector>
#include "component/SyncComponent.h"
#include "io/LoadControl.h"
#include "io/UartStream.h"
#include "logger/Logger.h"
#include "BPC1_BattBank.h"
#include "BPC1IF.h"

class UniversalDataReader;
class UniversalDataWriter;

/**
 *  Provides software interface to the Battery Pack Controller.
 *
 *  BPC1.h should only be included by BPC1.cpp
 *  Other classes should include BPC1IF.h
 *
 *  \ingroup modules_sensor
 */

class BPC1 : public SyncSensorComponent
{
public:

    BPC1( const Module* module );

    virtual ~BPC1();

    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();

    /// Waiting to be paused
    virtual RunState pausing();

    /// 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();

    virtual void uninitialize();

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

protected:

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

    // scan configuraiton settings
    bool readConfig();

    /// Pointer to the singleton-like instance of this component
    static BPC1* Instance_;

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

    // Debugging outputs
    bool debug_;

    // Time keeping variables
    Timespan battTimeout_, muxTimeout_, poTimeout_;
    Timestamp startTime_, muxTime_, hibernationTime_;
    float muxCycleTime_;

    // Stores a list of bank classes and bank iterator
    // The iterator obj returns a pointer to a vector element (in this case a pointer to a
    // pointer), thus, one can access a BattBank using the iterator like so: ( *bank_ )->functionCall
    std::vector<BattBank*> bankList_;
    std::vector<BattBank*>::iterator bank_;

    // Enumerates battery banks (currently 2 banks supported)
    typedef enum
    {
        BPC1A,
        BPC1B // Add as needed (bank configuration is implemented in BPC1IF)
    } BattBankID;

    // Stores the totals
    float totalCapacity_;
    float totalVoltage_;
    float reserveCapacity_;
    float reserveVoltage_;
    short totalChargingSticks_;

    // Threshold values from IBIT config
    float battCapacityThreshold_;
    float battVoltageThreshold_;

    // Threshold values from BPC config
    float battStickCommsTimeoutCfg_;
    float battSamplingInterval_;
    int missingStickThreshold_;

    // Holds indices of missing sticks
    std::vector<int> missingSticks_;

    DataWriter* reserveBatteryChargeWriter_;
    DataWriter* reserveBatteryVoltageWriter_;
    DataWriter* chargingSticksWriter_;

    UniversalDataWriter* batteryChargeWriter_;
    UniversalDataWriter* batteryVoltageWriter_;
    UniversalDataWriter* dischargeStatusWriter_;

    // IBIT Configuration Readers
    ConfigReader* battCapacityThresholdCfgReader_;  // Amount of charge left at which we return to the surface
    ConfigReader* battVoltageThresholdCfgReader_;   // Amount of voltage left at which we return to the surface

    // BPC Configuration Readers
    ConfigReader* battStickCommsTimoutCfgReader_;  // Max time allowed since last stick check-in
    ConfigReader* battSamplingIntervalCfgReader_;  // Time between battery status checks
    ConfigReader* battMuxCycleTimeCfgReader_;      // Time it takes OceanServer to cycle over all battry banks
    ConfigReader* missingStickThresholdCfgReader_; // Number of missing sticks allowed before we return to the surface

    // Creates the battery bank objects
    void createBatteryBanks( void );

    // Initializes the battery stick writers
    void initStickWriters( void );

    // A return value of true indicates that data for a given stick has been recorded.
    // Relies on setVoltagesNull to clear them again for further checking
    bool voltagesPopulated( void );

    // Sets the voltage for each battery stick to null as a
    // flag to indicate that recent data has not been obtained
    // for a given stick
    void setVoltagesNull( void );

    // Sets the writer's validity to invalid for true or valid for false
    void setWritersInvalid( bool invalid );

    // Sets the stick writer's validity to invalid for true or valid for false
    void setStickWritersInvalid( bool invalid );

    // Once all battery sticks have been freshly populated with
    // data, this function will add up all the grand totals
    void calculateTotals( void );

    // Checks to see that our current capacity is above the threshold
    void checkBatt( const float capacity, const float voltage );

    // Enables bank UART ports
    bool enableUARTs( void );

    // Disables bank UART ports
    void disableUARTs( void );

    // Flush UART on all ports
    void flushBankUarts( void );

    // Sends the break (space) character to all ports
    void sendIBPSBreaks( void );

    // Returns true if all ports are initialized to the banner menu offering hex output
    bool menusInitialized( void );

    // Returns true if ALL banks had valid data, but failed to parse it
    bool allBanksHaveDataError( void );

    // Returns the total number of batt sticks (from all banks)
    int numBattSticks( void );

    // Returns the total number of reserve batt sticks (from all banks)
    int numReserveSticks( void );

    // indicates whether things are ok to run
    bool ok_;

    // True if we have detected an under threshold value for capacity or voltage
    bool capacityFailed_;
    bool voltageFailed_;


};

#endif /*BPC1_H*/
