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

#ifndef GOBYMODEM_H
#define GOBYMODEM_H

#include "component/SyncComponent.h"
#include "data/StrValue.h"
#include "io/UartStream.h"
#include "io/LoadControl.h"
#include "logger/Logger.h"
#include "utils/Timestamp.h"
#include "utils/FlexArray.h"
#include "GobyModemIF.h"

class UniversalDataReader;
class UniversalDataWriter;
namespace goby
{
namespace acomms
{
class ModemDriverBase;
class DCCLCodec;
class QueueManager;
class MACManager;
namespace protobuf
{
class ModemTransmission;
}
}
}

/**
 *  Provides software interface to the GobySoft-supported underwater modems
= *
 *  GobyModem.h should only be included by GobyModem.cpp
 *  Other classes should include GobyModemIF.h
 *
 *  \ingroup modules_sensor
 */
class GobyModem: public SyncSensorComponent
{
public:

    GobyModem( const Module* module );

    virtual ~GobyModem();

    virtual bool readConfig();

    virtual void initialize();

    virtual void run();

    virtual void uninitialize();

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

    int getVehicleId()
    {
        return vehicleId_;
    }

    static GobyModem* Instance()
    {
        return Instance_;
    }

protected:

    UartStream uart_;
    LoadControl loadControl_;

    bool ok_, initialized_;
    Timestamp powerOnTimeStart_, powerOnTimeout_;

    ConfigReader* vehicleIdReader_;
    ConfigReader* modemTypeReader_;
    ConfigReader* networkIdsReader_;
    ConfigReader* maxDistanceReader_;
    ConfigReader* transBaudReader_;
    int vehicleId_;
    Str modemType_;
    Str networkIds_;
    float maxDistanceCfg_;
    float transBaudCfg_;
    bool networkIdsChanged_;
    bool pinging_;

    goby::acomms::ModemDriverBase* mm_driver_;
    goby::acomms::QueueManager* q_manager_;
    goby::acomms::MACManager* mac_;
    goby::acomms::DCCLCodec* dccl_;

    UniversalDataWriter* platformConversationWriter_;

    DataReader* dusblPingCodeReader_;

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

    bool isDataRequested();

    bool isCommanded();

private:
    // This is OK, since the class is basically a singleton.
    static GobyModem* Instance_;
};

#endif /*GOBYMODEM_H*/
