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

#ifndef COMMANDLINE_H_
#define COMMANDLINE_H_

#include <stdio.h>
#include <termios.h>

#include "component/AsyncComponent.h"
#include "data/StrValue.h"
#include "io/OutStream.h"
#include "supervisor/Command.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 CommandLine : public AsyncComponent, public OutStream
{
public:
    CommandLine( Supervisor& supervisor );
    virtual ~CommandLine();

    void initialize();

    void run();

    void uninitialize();

    virtual bool isWritable();

    /// writes num bytes from buffer to the output buffer/stream
    virtual OutStream& write( const char* buffer, size_t num );

    void setChar( const char theChar );

    void flush();

    static FILE* getOutFile()
    {
        return out_;
    }

protected:

    friend class CommandLine_Test;
    friend class CommandExec;

    ParsedCommand parsedCommands_[MAX_CMDS];
    int parsedCommandCount_;

    void clearParsed();

    /// Return true if a unique arg matches the supplied arg.
    bool findUniqueArg( char *buffer, int len );

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

    /// Normally called in response to a tab keypress.
    /// If there's a parsedCommand_, expand it.
    /// Otherwise expand all options and start a new line.
    void completeArg( char* buffer, int len );

    /// Return unique syntax that buffer matches unique keyword.
    CommandSyntax* findUniqueSyntax( char *buffer, int len, bool& anyMatch );

    /// If the buffer equals a unique syntax keyword, set parsedSyntax_ to that syntax.
    /// Return true if buffer equals start of any syntax keyword.
    bool findSyntax( char* buffer, int len );

    /// Normally called in response to a tab keypress.
    /// If there's a parsedSyntax_, expand it.
    /// Otherwise expand all options and start a new line.
    void completeSyntax( char* buffer, int len );

public:

protected:

    static const int BUFF_SIZE = 1024;

    static char ConsoleBuffer_[BUFF_SIZE];
    static int InputIndex_;

    static char OutputBuffer_[BUFF_SIZE];
    static int OutputIndex_;

    static bool AtMode_;

    bool haveTermios_;
    struct termios originalTermios_;
    struct termios newTermios_;
    Supervisor& supervisor_;

    static FILE* out_;
    static FILE* in_;
    const char* prompt_;
    static const size_t MAX_HOST_NAME_SIZE = 128;
    char hostname_[MAX_HOST_NAME_SIZE];

    size_t cmdHistoryIndex_;

    bool gettingLines_;

    StrValue keyText_;

    void clearLine();
    void backspace();
    void setLine( const char* line, bool allowExec );
    void execLine();

    void getLines();
    unsigned char kbGetc();
    char* nextWord( char** line );

    static Mutex QueueCommandMutex_;
    static CommandLine* Instance_;

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

};

#endif /*COMMANDLINE_H_*/
