/** \file
 *
 *  Contains the CommandExec class declaration.
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef COMMANDEXEC_H_
#define COMMANDEXEC_H_

#include <stdio.h>
#include <deque>

#include "component/AsyncComponent.h"
#include "component/SyncComponent.h"
#include "data/StrValue.h"
#include "dockModule/DockIF.h"
#include "io/OutStream.h"
#include "supervisor/Command.h"
#include "supervisor/CommandLine.h"
#include "supervisor/Scheduler.h"
#include "utils/FastMap.h"
#include "utils/Mutex.h"
#include "utils/Timestamp.h"

#define MAX_CMDS 20

class Supervisor;
class UniversalDataReader;
class UniversalDataWriter;

/**
 *  Provides a simple command line interface
 *  to the LRAUV.  The command line is available from the
 *  console while the application runs, and is intended
 *  to take commands sent over the satellite radio.
 *
 *  \ingroup supervisor
 */
class CommandExec : public AsyncComponent
{
public:
    CommandExec( Supervisor& supervisor );

    virtual ~CommandExec();

    void initialize();

    void run();

    void uninitialize();

    static void QueueCommand( const char* command );

    static void ListCommandQueue( void );

    static void DoCommand( const char* command, bool forceRun = false );

    static void DoScheduled( void );

    static void DoScheduleList( void );

    static void DoScheduleResume( void );

    static void DoSchedulePause( Syslog::Severity schedulePauseSeverity, Timestamp pauseTime );

    static const char* GetCommandHistory( size_t index );

    static unsigned int GetCommandHistorySize( void );

    static FlexArray<Command*>& KnownCommands( void );

    virtual bool isWritable( void );

protected:

    friend class CommandExec_Test;
    friend class CommandLine;

    static const Timespan PERIOD;

    static FlexArray<Command*> commands_;

    ParsedCommand parsedCommands_[MAX_CMDS];
    int parsedCommandCount_;

    Command& addCommand( const char* keyword, const char* description, bool advanced = false )
    {
        Command* command = new Command( keyword, description, advanced );
        commands_.push( command );
        return *command;
    }

    enum BurnMode
    {
        BURN_OFF,
        BURN_ON,
        BURN_SECONDS,
    };

    enum StrobeMode
    {
        STROBE_OFF,
        STROBE_ON,
    };

    enum ConversationMode
    {
        CONVERSATION_SHOW,
        CONVERSATION_START,
        CONVERSATION_STOP,
    };

    enum ConfigSetMode
    {
        CONFIG_SET_LIST,
        CONFIG_SET_RELOAD,
        CONFIG_SET_CONFIG,
        CONFIG_SET_LOGGING,
    };

    enum FailComponentMode
    {
        FAIL_COMPONENT_LIST,
        FAIL_COMPONENT_SHOW,
        FAIL_COMPONENT_NONE,
        FAIL_COMPONENT_HARD,
        FAIL_COMPONENT_SOFT,
        FAIL_COMPONENT_SEGFAULT,
    };

    enum FailVariableMode
    {
        FAIL_VARIABLE_LIST,
        FAIL_VARIABLE_SHOW,
        FAIL_VARIABLE_UNAVAILABLE,
        FAIL_VARIABLE_AVAILABLE,
        FAIL_VARIABLE_INVALID,
        FAIL_VARIABLE_VALID,
    };

    enum QuickMode
    {
        QUICK_SHOW,
        QUICK_ON,
        QUICK_OFF,
    };

    enum ReportAddMode
    {
        REPORT_ADD_MOD,
        REPORT_ADD_TOUCH,
        REPORT_ADD_PERIODIC,
    };

    enum RestartType
    {
        RESTART_APPLICATION,
        RESTART_HARDWARE,
        RESTART_LOGS,
        RESTART_SYSTEM,
    };

    enum RetransmitType
    {
        RETRANSMIT_SBD,
    };

    enum ScheduleType
    {
        SCHEDULE_ASAP,
        SCHEDULE_CLEAR,
        SCHEDULE_LIST,
        SCHEDULE_NEXT,
        SCHEDULE_PAUSE,
        SCHEDULE_REMOVE,
        SCHEDULE_RESUME,
        SCHEDULE_TIME,
    };

    enum SendType
    {
        SEND_VALUE,
        SEND_COMMAND,
    };

    enum UbatMode
    {
        UBAT_ON,
        UBAT_OFF
    };

public:

    static void CommandBang( ParsedCommand* parsedCommand, int mode );
    void commandBang( ParsedCommand* parsedCommand );
    static void CommandBurn( ParsedCommand* parsedCommand, int mode );
    void commandBurn( ParsedCommand* parsedCommand, BurnMode mode );
    static void CommandStrobe( ParsedCommand* parsedCommand, int mode );
    void commandStrobe( ParsedCommand* parsedCommand, StrobeMode mode );
    static void CommandConfigSet( ParsedCommand* parsedCommand, int mode );
    void commandConfigSet( ParsedCommand* parsedCommand, ConfigSetMode mode );
    static void CommandConversation( ParsedCommand* parsedCommand, int mode );
    void commandConversation( ParsedCommand* parsedCommand, ConversationMode mode );
    static void CommandDDM( ParsedCommand* parsedCommand, int mode );
    void commandDDM( ParsedCommand* parsedCommand, DockIF::DockingState mode );
    static void CommandDockingServo( ParsedCommand* parsedCommand, int mode );
    void commandDockingServo( ParsedCommand* parsedCommand, DockIF::DockingState mode );
    static void CommandFailComponent( ParsedCommand* parsedCommand, int mode );
    void commandFailComponent( ParsedCommand* parsedCommand, FailComponentMode mode );
    static void CommandFailVariable( ParsedCommand* parsedCommand, int mode );
    void commandFailVariable( ParsedCommand* parsedCommand, FailVariableMode mode );
    static void CommandFileExec( ParsedCommand* parsedCommand, int mode );
    void commandFileExec( ParsedCommand* parsedCommand );
    static void CommandGet( ParsedCommand* parsedCommand, int mode );
    void commandGet( ParsedCommand* parsedCommand );
    static void CommandGFscan( ParsedCommand* parsedCommand, int mode );
    void commandGFscan( ParsedCommand* parsedCommand );
    static void CommandHelp( ParsedCommand* parsedCommand, int mode );
    void commandHelp( ParsedCommand* parsedCommand );
    static void CommandIbit( ParsedCommand* parsedCommand, int mode );
    void commandIbit( ParsedCommand* parsedCommand );
    static void CommandIbitMcp3553( ParsedCommand* parsedCommand, int mode );
    void commandIbitMcp3553( ParsedCommand* parsedCommand );
    static void CommandLoad( ParsedCommand* parsedCommand, int mode );
    void commandLoad( ParsedCommand* parsedCommand );
    static void CommandMaintainAdd( ParsedCommand* parsedCommand, int mode );
    void commandMaintainAdd( ParsedCommand* parsedCommand, SyncComponent::CycleOrder cycleOrder );
    static void CommandMaintainClear( ParsedCommand* parsedCommand, int mode );
    void commandMaintainClear( ParsedCommand* parsedCommand );
    static void CommandMaintainUnavailable( ParsedCommand* parsedCommand, int mode );
    void commandMaintainUnavailable( ParsedCommand* parsedCommand, SyncComponent::CycleOrder cycleOrder );
    static void CommandMaintainInvalid( ParsedCommand* parsedCommand, int mode );
    void commandMaintainInvalid( ParsedCommand* parsedCommand, SyncComponent::CycleOrder cycleOrder );
    static void CommandMaintainList( ParsedCommand* parsedCommand, int mode );
    void commandMaintainList( ParsedCommand* parsedCommand );
    static void CommandMaintainRemove( ParsedCommand* parsedCommand, int mode );
    void commandMaintainRemove( ParsedCommand* parsedCommand );
    static void CommandQuick( ParsedCommand* parsedCommand, int mode );
    void commandQuick( ParsedCommand* parsedCommand, QuickMode mode );
    static void CommandQuit( ParsedCommand* parsedCommand, int mode );
    void commandQuit( ParsedCommand* parsedCommand );
    static void CommandReportAdd( ParsedCommand* parsedCommand, int mode );
    void commandReportAdd( ParsedCommand* parsedCommand, ReportAddMode mode );
    static void CommandReportClear( ParsedCommand* parsedCommand, int mode );
    void commandReportClear( ParsedCommand* parsedCommand );
    static void CommandReportList( ParsedCommand* parsedCommand, int mode );
    void commandReportList( ParsedCommand* parsedCommand );
    static void CommandReportRemove( ParsedCommand* parsedCommand, int mode );
    void commandReportRemove( ParsedCommand* parsedCommand );
    static void CommandRestart( ParsedCommand* parsedCommand, int mode );
    void commandRestart( ParsedCommand* parsedCommand, RestartType mode );
    void commandRestartApplication( ParsedCommand* parsedCommand );
    void commandRestartHardware( ParsedCommand* parsedCommand );
    void commandRestartLogs( ParsedCommand* parsedCommand );
    void commandRestartSystem( ParsedCommand* parsedCommand );
    static void CommandResume( ParsedCommand* parsedCommand, int mode );
    void commandResume( ParsedCommand* parsedCommand );
    static void CommandRetransmit( ParsedCommand* parsedCommand, int mode );
    void commandRetransmit( ParsedCommand* parsedCommand, RetransmitType retransmitType );
    static void CommandRun( ParsedCommand* parsedCommand, int mode );
    void commandRun( ParsedCommand* parsedCommand );
    static void CommandSend( ParsedCommand* parsedCommand, int mode );
    void commandSend( ParsedCommand* parsedCommand, SendType mode );
    static void CommandSet( ParsedCommand* parsedCommand, int mode );
    void commandSet( ParsedCommand* parsedCommand );
    static void CommandSchedule( ParsedCommand* parsedCommand, int mode );
    void commandSchedule( ParsedCommand* parsedCommand, ScheduleType scheduleType );
    void commandSchedulePause( Syslog::Severity schedulePauseSeverity, Timestamp pauseTime );
    void commandScheduleShowPaused();
    void commandScheduleResume();
    static void CommandShowBest( ParsedCommand* parsedCommand, int mode );
    void commandShowBest( ParsedCommand* parsedCommand );
    static void CommandShowComponent( ParsedCommand* parsedCommand, int mode );
    void commandShowComponent( ParsedCommand* parsedCommand );
    static void CommandShowDependencies( ParsedCommand* parsedCommand, int mode );
    void commandShowDependencies( ParsedCommand* parsedCommand );
    static void CommandShowStack( ParsedCommand* parsedCommand, int mode );
    void commandShowStack( ParsedCommand* parsedCommand );
    static void CommandShowState( ParsedCommand* parsedCommand, int mode );
    void commandShowState( ParsedCommand* parsedCommand );
    static void CommandShowVariable( ParsedCommand* parsedCommand, int mode );
    void commandShowVariable( ParsedCommand* parsedCommand );
    static void CommandStop( ParsedCommand* parsedCommand, int mode );
    void commandStop( ParsedCommand* parsedCommand );
    static void CommandUbat( ParsedCommand* parsedCommand, int mode );
    void commandUbat( ParsedCommand* parsedCommand, UbatMode mode );

protected:

    /// Process any commands in the queue.
    void processCommandQueue( const Timespan& timeout );

    Supervisor& supervisor_;

    static const int BUFF_SIZE = 1024;

    static const int HISTORY_SIZE = 50;

    static bool AtMode_;

    static const Timespan BANG_TIMEOUT;

    static Mutex QueueCommandMutex_;
    static FlexArray<Str*> cmdQueue_;

    static Mutex CommandHistoryMutex_;
    static FlexArray<Str*> cmdHistory_;
    size_t cmdHistoryIndex_;

    static Mutex scheduleMutex_;
    static Scheduler* Scheduler_;

    StrValue keyText_;

    Timestamp burnStopTime_;
    char doBuffer_[1024];
    size_t doBytes_;
    Str doSbd_;

    static CommandExec* Instance_;

    DataWriter* strobeModeWriter_;
    DataWriter* dockingModuleStateWriter_;
    DataReader* dockingModuleStateReader_;
    DataWriter* enableUbatWriter_;
    DataReader* ibitRunningReader_;
    DataReader* scanRunningReader_;
    UniversalDataReader* platformConversationReader_;
    UniversalDataWriter* platformConversationWriter_;

private:

    Mutex setCommandMutex_;
    static char CommandBuffer_[BUFF_SIZE];
    static int InputIndex_;

    /// Returns the next command from the command queue.
    Str* getNextCommand( void );

    /// Mutex protected interface to the command buffer.
    void setLine( const char* line, bool allowExec );

    /// Inserts chars to the command buffer.
    void setChar( const char theChar );

    /// If the last word in buffer is a valid arg, deal with it.
    /// Return false if the end of the buffer is invalid.
    bool parseBufferEnd();

    /// Execute the parsed command.
    void execLine();

    void clearParsed( void );

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

};

#endif /*COMMANDEXEC_H_*/
