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

#ifndef BUOYANCYSERVO_H_
#define BUOYANCYSERVO_H_

#include "EZServoServo.h"
#include "io/LoadControl.h"
#include "io/UartStream.h"

class UniversalDataWriter;

/**
 *  This is the device driver for the EZServo that controls the vehicle's
 *  buoyancy engine. Since it shares the same RS-485 bus with the other EZServos,
 *  it is a child class of EZServoServo, which has a static instance of
 *  the StdUart class to interact with the bus.
 *
 *  BuoyancyServo.h should only be included by BuoyancyServo.cpp
 *  Other classes should include BuoyancyServoIF.h
 *
 *  \ingroup modules_controller
 */
class BuoyancyServo : public EZServoServo
{
public:
    BuoyancyServo( const Module* module );
    virtual ~BuoyancyServo();

    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 follow a Pause request
    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();

    // Shuts down motor controllers
    void uninitialize( void );

    /// 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.
    BuoyancyServo( const BuoyancyServo& old ); // disallow copy constructor

    // Instance of load controller
    LoadControl loadControl_;

    // The outputs themselves
    UniversalDataWriter* buoyancyPosWriter_;

    // The inputs
    DataReader* buoyancyPosReader_;

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

    // returns true if a new position has been commanded
    bool isNeeded();

    typedef enum
    {
        INITIALIZE,   // Program basic initialization into EEPROM
        WAIT,         // Wait for EEPROM write to finish
        HOME,         // Do any centering/homing, etc if needed
        EXECUTE,      // Execute any stored programs
        VERIFY,       // Confirm operable and no errors
        DONE,         // Ready to run
    } StartupSequence;

    StartupSequence startup_;

    // indicates whether component is initialized
    bool initialized_;

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

    float cmdBuoyancyPos_, actualBuoyancyPos_, lastCmdPos_, lastActPos_;

    // Timeouts for checking buoyancy position when we're "OFF"
    Timespan checkingTimeout_;

    // Debugging outputs
    bool debug_;

    bool valveOpen_;

    // Indicates speed has been initialized to fast
    bool fastPumpInit_;


    //------------------- vehicle parameters --------------------------*/
    // Buoyancy Engine
    float deviationVolumeCfg_;
    float checkingTimeoutCfg_;
    float countsPerCCCfg_;
    float buoyancyDefaultCfg_;
    float offsetVolumeCfg_;
    float buoyancyPumpDepth_;
    float fastPumpDepthCfg_;
    float fastPumpCoeffCfg_;
    //-----------------------------------------------------------------*/

    ConfigReader* countsPerCCCfgReader_;         // counts on the A/D per ml of fluid pumped
    ConfigReader* deviationVolumeCfgReader_;     // Number of ml deviation allowed between expected and actual
    ConfigReader* checkingTimeoutCfgReader_;     // If the buoyancy is idling, this is how often to check for actual position. If there's a leak. This is when we'll find it.
    ConfigReader* offsetVolumeCfgReader_;        // Offset of position of motor controller
    ConfigReader* buoyancyDefaultCfgReader_;     // Full bladder volume
    ConfigReader* buoyancyPumpDepthCfgReader_;   // How deep we can pump
    ConfigReader* fastPumpDepthCfgReader_;       // Dpeth definition to inform pumping rate
    ConfigReader* fastPumpCoefficientCfgReader_; // Specifies how many times faster than normal the pump should operate in fast mode

    /// Universal Readers
    UniversalDataReader *depthReader_;

    // Read configuration
    bool readConfig();

    // Are we above the depth at which we can pump?
    bool abovePumpDepth();

    // Are we above the depth at which we can pump fast?
    bool aboveFastPumpDepth();

    // the given motor controller is ready to receive commands
    bool buoyancyRdy_;

    // Initialization routines. Returns true if initialization completed without error
    bool initBuoyancy( void );

};

#endif /*BUOYANCYSERVO_H_*/
