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

#ifndef _COMMANDEXEC_TEST_H_
#define _COMMANDEXEC_TEST_H_

#include "CommandExec.h"
#include "Supervisor.h"
#include "data/ConfigDataElement.h"
#include "data/Slate.h"

#include <cxxtest/TestSuite.h>

/**
 *  Unit tests for CommandExec class
 *
 *  \ingroup supervisor
 */
class CommandExec_Test : public CxxTest::TestSuite
{
public:

    // test parser
    void testParse( void )
    {
        // Configure the slate for Unit testing
        Slate::SimulateDirectoryWrites();

        // Create a test component with a name & elements that can be used later
        TestAsyncComponent testComponent( "CommandExec_TestComponent" );

        // When creating a ConfigURI with no config file, have to initialize element
        ConfigURI pauseCfg( testComponent.getName(), "pauseCfg", Units::SECOND );
        ConfigDataElement* pauseCfgElement = new ConfigDataElement( pauseCfg, pauseCfg.getUnit().dataValue( pauseCfg.getBinaryType() ) );
        Slate::MapDataElement( ( ConfigURI* )&pauseCfg, pauseCfgElement );

        DataURI waterTemp( testComponent.getName(), "waterTemp", Units::FAHRENHEIT );
        Slate::CodifyElementURI( ( ElementURI& )UniversalURI::TIME );
        Slate::CodifyElementURI( ( ElementURI& )waterTemp );
        testComponent.newConfigReader( pauseCfg );

        int argc = 0;
        char **argv = NULL;
        Str dataDir;
        Supervisor supervisor( argc, argv, dataDir );
        CommandExec commandExec( supervisor );
        for( unsigned int i = 0; i < commandExec.commands_.size(); ++i )
        {
            Command* command = commandExec.commands_[i];
            for( int j = 0; j < command->getSyntaxCount(); ++j )
            {
                CommandSyntax* syntax = command->getSyntax( j );
                int optional = 0;
                // Loop through the syntax once, counting optional parts, then repeat omitting each optional part
                for( int jj = -1; jj < optional; ++jj )
                {
                    int jOptional = -1;
                    int kOptional = -1;
                    Str str = Str( command->getKeyword(), command->getKeywordLen() ) + " ";
                    for( int k = 0; k < syntax->getArgCount(); ++k )
                    {
                        CommandArg* arg = syntax->getArg( k );
                        if( jj < 0 )
                        {
                            if( arg->getRequired() == NOT_REQUIRED )
                            {
                                ++optional;
                            }
                        }
                        else
                        {
                            if( arg->getRequired() == NOT_REQUIRED )
                            {
                                ++jOptional;
                                if( jOptional == jj )
                                {
                                    kOptional = k;
                                    continue;
                                }
                            }
                            if( arg->getRequired() == REQUIRED_AFTER_PREVIOUS && kOptional == k - 1 )
                            {
                                ++kOptional;
                                continue;
                            }
                        }
                        switch( arg->getArgType() )
                        {
                        case ARG_NONE:
                            break;
                        case ARG_COMMAND:
                            str += "help ";
                            break;
                        case ARG_COMPONENT:
                            str += testComponent.getName() + " ";
                            break;
                        case ARG_CONFIG_DIR:
                            str += "sim ";
                            break;
                        case ARG_CONFIG_VARIABLE:
                            str += pauseCfg + " ";
                            break;
                        case ARG_LIST:
                            str += "12.3,4.5e6,-7.8e-9 ";
                            break;
                        case ARG_DECIMATION_TYPE:
                            str += "NONE ";
                            break;
                        case ARG_FLOAT:
                            str += "12.34 ";
                            break;
                        case ARG_INT:
                            str += "1234 ";
                            break;
                        case ARG_KEYWORD:
                            str += Str( arg->getKeyword(), arg->getKeywordLen() ) + " ";
                            break;
                        case ARG_MISSION:
                            str += "Demo/NoMission.xml ";
                            break;
                        case ARG_QUOTED_STRING:
                            str += "\"quoted string\" ";
                            break;
                        case ARG_REGEX:
                            str += "[dD]epth ";
                            break;
                        case ARG_SECONDS:
                            str += "30 ";
                            break;
                        case ARG_SERVICE_TYPE:
                            str += "EXPRESS ";
                            break;
                        case ARG_STRING:
                            str += "a random string";
                            break;
                        case ARG_TIMESTAMP:
                            str += "19991231T1159 ";
                            break;
                        case ARG_TOKEN:
                            str += "token ";
                            break;
                        case ARG_UNIT:
                            str += "meter ";
                            break;
                        case ARG_UNIVERSAL:
                            str += "time ";
                            break;
                        case ARG_VARIABLE:
                            str += waterTemp + " ";
                            break;
                        }
                    }
                    printf( "parse: %s\n", str.cStr() );
                    CommandExec::InputIndex_ = 0;
                    CommandExec::Instance_->clearParsed();
                    bool ok = true;
                    for( size_t k = 0; ok && k + 1 < str.length(); ++k )
                    {
                        char theChar = str.cStr()[k];
                        CommandExec::CommandBuffer_[ CommandExec::InputIndex_ ] = theChar;
                        CommandExec::CommandBuffer_[ CommandExec::InputIndex_ + 1 ] = 0;
                        ok = CommandExec::Instance_->parseBufferEnd();
                        //printf("CommandExec::CommandBuffer_[ %d ] = '%c', ok=%d\n",CommandExec::InputIndex_, theChar, ok );
                        if( ok )
                        {
                            ++CommandExec::InputIndex_;
                        }
                    }
                    TSM_ASSERT( str.cStr(), ok );
                }
            }
            CommandExec::InputIndex_ = 0;
            CommandExec::Instance_->clearParsed();
        }
    }

};

#endif // _COMMANDEXEC_TEST_H
