#if !defined( _IOAKEYARRAY_H )
#define _IOAKEYARRAY_H

#pragma warning( push )
#pragma warning( disable: 4996 )

class IoAKey
{
public:
    IoAKey( ) : m_pName( NULL ), m_pValue( NULL ) { }
    IoAKey( char *pName, char *pValue ) : m_pName( pName ), m_pValue( pValue ) { }

    void Define( char *pName, char *pValue ) { m_pName = pName; m_pValue = pValue; }

    int IsDefined( ) const { return m_pName != NULL && m_pValue != NULL; }

    const char *Name ( ) const { return m_pName;  }
    const char *Value( ) const { return m_pValue; }

    int IsCalled( const char *Name ) const
    {
        return Name != NULL && m_pName != NULL && ::stricmp( m_pName, Name ) == 0;
    }

    int IsEqualTo( const char *Value ) const
    {
        return Value != NULL && m_pValue != NULL && ::stricmp( m_pValue, Value ) == 0;
    }

    int IsYes( ) const { return IsEqualTo( "yes" ); }
    int IsNo ( ) const { return IsEqualTo( "no"  ); }

    int IsTrue ( ) const { return IsEqualTo( "true"  ); }
    int IsFalse( ) const { return IsEqualTo( "false" ); }

    int IsOn ( ) const { return IsEqualTo( "on"  ); }
    int IsOff( ) const { return IsEqualTo( "off" ); }

    int Scan( const char *Format, void *Arg1 ) const
    {
        return m_pValue != NULL && ::sscanf( m_pValue, Format, Arg1 ) == 1;
    }

    int Scan( const char *Format, void *Arg1, void *Arg2 ) const
    {
        return m_pValue != NULL && ::sscanf( m_pValue, Format, Arg1, Arg2 ) == 2;
    }

    int Scan( const char *Format, void *Arg1, void *Arg2, void *Arg3 ) const
    {
        return m_pValue != NULL && ::sscanf( m_pValue, Format, Arg1, Arg2, Arg3 ) == 3;
    }

    int Scan( const char *Format, void *Arg1, void *Arg2, void *Arg3, void *Arg4 ) const
    {
        return m_pValue != NULL && ::sscanf( m_pValue, Format, Arg1, Arg2, Arg3, Arg4 ) == 4;
    }

    int Scan( const char *Format, void *Arg1, void *Arg2, void *Arg3, void *Arg4, void *Arg5 ) const
    {
        return m_pValue != NULL && ::sscanf( m_pValue, Format, Arg1, Arg2, Arg3, Arg4, Arg5 ) == 5;
    }

    int Scan( const char *Format, void *Arg1, void *Arg2, void *Arg3, void *Arg4, void *Arg5, void *Arg6 ) const
    {
        return m_pValue != NULL && ::sscanf( m_pValue, Format, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6 ) == 6;
    }

private:
    char *m_pName;
    char *m_pValue;
};

#pragma warning( pop )

class IoAKeyArray
{
public:
    IoAKeyArray( ) : m_pKeys( NULL ), m_nKeys( 0 ), m_pData( NULL ) { }
    ~IoAKeyArray( ) { Free( ); }

    int Allocate( int nKeys, int nData );

    int IsAllocated( ) const { return m_pKeys != NULL && m_pData != NULL; }

    void Free( );

    int Read( const char *KeyFile );
	int Load( int argc, char* argv[ ] );
    int Load( const char *KeyString );

    int KeyCount( ) const { return m_nKeys; }

    const IoAKey& Key( int Index ) const { return 0 <= Index && Index < m_nKeys ? m_pKeys[ Index ] : m_NullKey; }
    const IoAKey& operator[ ]( int Index ) const { return Key( Index ); }

    int KeyCount( const char *Name ) const;

    const IoAKey& Key( const char *Name, int Index = -1 ) const;
    const IoAKey& operator[ ]( const char *Name ) const { return Key( Name ); }

	static const IoAKey& NullKey( ) { return m_NullKey; }

private:
    static int IsWhiteSpace( char cha )
    {
        return cha == ' ' || cha == '\n' || cha == '\r' || cha == '\t' || cha == '\v' || cha == '\f';
    }
    static int IsStartOfComment( char cha )
    {
//        return cha == '/' || cha == '#' || cha == '!' || cha == ';' || cha == '\'';
        return cha == '#' || cha == '!' || cha == ';';
    }
    static int IsEqualsSign( char cha ) { return cha == '='; }
    static int IsNewLine( char cha ) { return cha == '\n'; }
    static int IsNull( char cha ) { return cha == '\0'; }

    IoAKey *m_pKeys;  // key array
    int     m_nKeys;

    char *m_pData;  // character data
    int   m_nData;

    static IoAKey m_NullKey;
};

#endif
