/** \file
 *
 *  Contains the Dynamic Docking Module (DDM) class declaration.
 *
 *  DDM.h should only be included by DDM.cpp
 *  Other classes should include DDMIF.h
 *
 *  Copyright (c) 2007,2008,2009-2019 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef DDM_H
#define DDM_H

#include "component/SyncComponent.h"
#include "io/LoadControl.h"
#include "io/UartStream.h"
#include "logger/Logger.h"

#include "dockModule/DockIF.h"
#include "DDMIF.h"

#include "data/Matrix3x3.h"

class UniversalDataReader;
class UniversalDataWriter;

/**
 *  Provides software interface to the Benthos DDM.
 *
 *  DDM.h should only be included by DDM.cpp
 *  Other classes should include DDMIF.h
 *
 *  \ingroup modules_sensor
 */
class DDM : public SyncSensorComponent
{
public:

    DDM( const Module* module );

    virtual ~DDM();

    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;

private:

    friend class DDM_Test;

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

    void readConfig();

    ConfigReader* verbosityCfgReader_;
    ConfigReader* PWMLimitCfgReader_;
    ConfigReader* currentLimitCfgReader_;

    // Slate inputs
    DataReader* DDMModeCmdReader_;
    DataReader* power24vConverterDataReader_;

    // Slate outputs
    DataWriter* whiskerStateWriter_;
    DataWriter* latchStateWriter_;
    DataWriter* cablePresentWriter_;
    DataWriter* cableValueWriter_;
    DataWriter* DDMModeWriter_;

    bool debug_;
    bool cablePresent_; // set to true when the IR emmitter shows an obstruction (and we just hope it's the dock cable)
    int cablePresentCounts_; // Keeps track of how many successive present readings there are
    int cableStatus_; // hold the actual value read from the sensor
    bool cableStatusFailed_; // set to true if there was a problem getting the state of the cable. Allows for another try before failing the component.
    int verbosityCfgSetting_;
    int PWMLimitCfgSetting_;
    int currentLimitCfgSetting_;
    int lastDDMMode_; // Store the last known commanded mode
    bool modeChanged_; // Lets us know if the mode has changed this cycle to allow command change mid transit
    int whiskerState_, latchState_, cableState_;// 1 is whiskers opened, 2 is whiskers closed, 0 is whiskers in the middle. 1 is latch closed, 2 is latch open, 0 is latch in the middle.

    char deviceResponse_[396]; // Stores the current response from the modem

    DockIF::DockingState DDMMode_, DDMModeCmd_; // ModeCmd_ is the commanded mode while Mode_ is what mode the DDM is actually in


    LoadControl loadControl_; // Instance of load controller
    Timestamp startTime_;
    Timestamp powerOffTimeStart_;
    Timespan poTimeout_, powerDownTimeout_, hardwareTimeout_;
    bool initRequested_; // Was initilization status requested

    UartStream uart_; // Holds the communications device

    void logVoltageAndCurrent();

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

    // functions for enabling and disabling the IR emitter in the cable detection board
    bool enableIREmitter();
    bool disableIREmitter();
    bool cableDetectorOccupied();

    void publishData( void );

    void logLatchStatus( void );
    void logWhiskerStatus( void );
    void logCableStatus( void );

    bool getSimulatedMeasurements( void ); // TODO fix simulator where appropriate so that this method just reads sim outputs and rewrites them to the slate in the appropriate places

};

#endif /*DDM_H*/
