//  Copyright © 2003, RESON Inc. All Rights Reserved.
//
//  No part of this file may be reproduced or transmitted in any form or by
//  any means, electronic or mechanical, including photocopy, recording, or
//  information storage or retrieval system, without permission in writing
//  from RESON Inc.
//
//  Filename:   7kTriggerController.cpp
//
//  Project:    6046
//
//  Author(s):  W. Arcus
//
//  Purpose:    Implements the logical trigger controller C7kTriggerController class.
//
//
//  Notes:      
//

#include "StdAfx.h"
#include "7kTriggerController.h"
#include "TriggerTableManager.h"

///////////////////////////////////////////////////////////////////////////////
// Internal definitions etc.

namespace                                                                                                   // Begin anonymous namespace.
{
#pragma pack( push, C7KTRIGGERCONTROLLER_CPP_PACK, 1 )

#pragma CompileMessage_m( "TODO: 7K TRIGGER RELATED MESSAGE HEADERS TO BE DEFINED HERE" )

#pragma pack( pop,  C7KTRIGGERCONTROLLER_CPP_PACK )

    class CTriggerException
    {
    public:

        /////////////////////
        // Definitions.

        enum EERRORCODE                                                                                     // Cause of last error if false returned from method.
        {
            errorCodeNone                   = 0,
            errorCodeInternalError,
            errorCodeConstruction,
            errorCodeDestruction,
            errorCodeConnectionFailed,
            errorCodeDisconnectionFailed,
            errorCodeEnableFailed,
            errorCodeDisableFailed,

            // Insert new error codes before this item to maintain an accurate count.

            errorCodeMaxCodes                                                                                // Counter thus always keep as last item.
        };

        /////////////////////
        // Services.

                                CTriggerException           (   void );
        virtual                ~CTriggerException           (   void );

        void                    Set                         (   const EERRORCODE   &reErrorCode,
                                                                const int          &riLine      = __LINE__,
                                                                LPCTSTR             lpszFile    = __FILE__ );

        EERRORCODE              ErrorCode                   (   void ) const;
        LPCTSTR                 ErrorMessage                (   void ) const;

        static bool             IsErrorCodeValid            (   const EERRORCODE   &reErrorCode );
        static LPCTSTR          ErrorMessageFromCode        (   const EERRORCODE   &reErrorCode );
        static void             GenerateError               (   const EERRORCODE   &reErrorCode,
                                                                const int          &riLine      = __LINE__,
                                                                LPCTSTR             lpszFile    = __FILE__ );
    private:

        EERRORCODE              m_eErrorCode;
        CString                 m_sErrorMsg;
        const static LPCTSTR    m_szErrorMessages[];

    };

    const LPCTSTR CTriggerException::m_szErrorMessages[] =
    {
        _T( "No error" ),                                                                                   // errorCodeNone
        _T( "Internal error" ),                                                                             // errorCodeInternalError
        _T( "Construction error" ),                                                                         // errorCodeConstruction
        _T( "Destruction error" ),                                                                          // errorCodeDestruction
        _T( "Connection to 7k trigger controller failed" ),                                                 // errorCodeConnectionFailed
        _T( "Disconnection to 7k trigger controller failed" )                                               // errorCodeDisconnectionFailed
        _T( "Enable failed" ),                                                                              // errorCodeEnableFailed
        _T( "Disable failed" )                                                                              // errorCodeDisableFailed
    };

}                                                                                                           // End anonymous namespace.

// Macros.

#define GenerateError_m( code )     CTriggerException::GenerateError( CTriggerException::code, __LINE__, __FILE__ )
#define TriggerTable_m()            static_cast<CTriggerTableManager *>( m_pvTriggerTable )

///////////////////////////////////////////////////////////////////////////////
// C7kTriggerController class implementation, starting with the public services.

C7kTriggerController::C7kTriggerController( void )
{
    ManageDllState_m();

    m_bInitialized  = false;

    try
    {
        m_bConnected    = false;
        m_bEnabled      = false;

        m_iLastError    = CTriggerException::errorCodeNone;
        m_LastErrorMsg.Empty();

        CTriggerTableManager *pTriggerTableManager = new CTriggerTableManager();
        ASSERT( pTriggerTableManager != NULL );

        if ( pTriggerTableManager != NULL )
        {
            pTriggerTableManager->Clear();
            m_pvTriggerTable = pTriggerTableManager;
        }
        
        m_bInitialized  = true;
    }
    catch ( CTriggerException Exception )
    {
        m_bInitialized  = false;

        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
    }
    catch ( ... )
    {
        m_bInitialized = false;
        SetError( CTriggerException::errorCodeConstruction );
    }
}

C7kTriggerController::~C7kTriggerController( void )
{
    ManageDllState_m();

    m_bInitialized  = false;

    try
    {
        if ( ! Reset( true ) )
        {
            TRACE( _T( "C7kTriggerController::~C7kTriggerController::(), Disable() failed\n" ) );
        }

        if ( m_pvTriggerTable == NULL )
        {
            delete TriggerTable_m();
            m_pvTriggerTable = NULL;
        }
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
    }
    catch ( ... )
    {
        SetError( CTriggerException::errorCodeDestruction );
    }
}

bool C7kTriggerController::IsInitialized( void ) const
{
    ManageDllState_m();

    return m_bInitialized;
}

bool C7kTriggerController::Reset( const bool &rbClear )
{
    ManageDllState_m();

    bool bSuccess = false;

    try
    {
        ResetError();

        CTriggerTableManager *pTriggerTable = TriggerTable_m();
        if ( pTriggerTable == NULL )
        {
            GenerateError_m( errorCodeInternalError );
        }

        if ( ! Disable() )
        {
            TRACE( _T( "C7kTriggerController::Reset(), Disable() failed\n" ) );
        }

        if ( ! Disconnect() )
        {
            TRACE( _T( "C7kTriggerController::Reset(), Disconnect() failed\n" ) );
        }

        if ( rbClear )
        {
            pTriggerTable->Clear();
        }

        bSuccess = true;
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
        bSuccess = false;
    }
    catch ( ... )
    {
        SetError( -1, "Unspecified exception caught" );
        bSuccess = false;
    }

    return bSuccess;
}

bool C7kTriggerController::IsConnected( void ) const
{
    ManageDllState_m();

    return m_bConnected;
}

bool C7kTriggerController::IsEnabled( void ) const
{
    ManageDllState_m();

    return m_bEnabled;
}

int C7kTriggerController::ErrorCode( void ) const
{
    ManageDllState_m();

    return m_iLastError;
}

LPCTSTR C7kTriggerController::ErrorMsg( void ) const
{
    ManageDllState_m();

    return static_cast<LPCTSTR>( m_LastErrorMsg );
}

bool C7kTriggerController::Connect( const bool             &rbLocal,        // Local (true), or remote (false ).
                                    LPCTSTR                 lpszAddress,    // Address of sonar, if remote.
                                    const unsigned long    &rulPortIn,      // Input to 7k sonar, if remote.
                                    const unsigned long    &rulPortOut,     // Output from sonar, if remote.
                                    const unsigned long    &rulType )       // 0 - UDP, 1 - TCP.
{
    ManageDllState_m();

    bool bSuccess = false;

    try
    {
        ResetError();

        if ( ! IsConnected() )
        {
#pragma CompileMessage_m( "TODO: CONNECT TO SONAR AND INSTALL CALLBACK ETC WHEN RELEVANT MESSAGES ARE RECEIVED ETC." )

            //if ( ! Connect( rbLocal, lpszAddress, rulPortIn, rulPortOut, rulType ) )
            //{
            //    GenerateError_m( errorCodeConnectionFailed );
            //}
        }

        bSuccess = IsConnected();
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
        bSuccess = false;
    }
    catch ( ... )
    {
        SetError( -1, "Unspecified exception caught" );
        bSuccess = false;
    }

    return bSuccess;
}

bool C7kTriggerController::Disconnect( void )
{
    ManageDllState_m();

    bool bSuccess = false;

    try
    {
        ResetError();

        if ( IsConnected() )
        {
#pragma CompileMessage_m( "TODO: DISCONNECT FROM SONAR AND REVOKE CALLBACK HANDLERS ETC" )
            //if ( ! Disconnect() )
            //{
            //    GenerateError_m( errorCodeDisconnectionFailed );
            //}

            bSuccess = ! IsConnected();
        }
        else
        {
            bSuccess = true;
        }
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
        bSuccess = false;
    }
    catch ( ... )
    {
        SetError( -1, "Unspecified exception caught" );
        bSuccess = false;
    }

    return bSuccess;
}

bool C7kTriggerController::Enable( void )
{
    ManageDllState_m();

    bool bSuccess = false;

    try
    {
        ResetError();

        if ( ! IsEnabled() )
        {

#pragma CompileMessage_m( "TODO: DISABLE TRIGGER CONTROLLER (STOP ALL TRIGGERING ETC???)" )

//            if ( ! Enable() )
//            {
//                GenerateError_m( errorCodeEnableFailed );
//            }

            bSuccess = IsEnabled();
        }
        else
        {
            bSuccess = true;
        }
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
        bSuccess = false;
    }
    catch ( ... )
    {
        SetError( -1, "Unspecified exception caught" );
        bSuccess = false;
    }

    return bSuccess;
}

bool C7kTriggerController::Disable( void )
{
    ManageDllState_m();

    bool bSuccess = false;

    try
    {
        ResetError();

        if ( IsEnabled() )
        {
#pragma CompileMessage_m( "TODO: ENABLE THE TRIGGER CONTROLLER PER THE CONFIGURATION" )
        }

        bSuccess = ! IsEnabled();
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
        bSuccess = false;
    }
    catch ( ... )
    {
        SetError( -1, "Unspecified exception caught" );
        bSuccess = false;
    }

    return bSuccess;
}

bool C7kTriggerController::AddPort( C7kPort &rPort )
{
    ManageDllState_m();

    bool bSuccess = false;

    try
    {
        ResetError();

        CTriggerTableManager *pTriggerTable = TriggerTable_m();
        if ( pTriggerTable == NULL )
        {
            GenerateError_m( errorCodeInternalError );
        }

        bSuccess = pTriggerTable->AddPort( rPort );
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
        bSuccess = false;
    }
    catch ( ... )
    {
        SetError( -1, "Unspecified exception caught" );
        bSuccess = false;
    }

    return bSuccess;
}

bool C7kTriggerController::RemovePort( const unsigned long &rulPortIndex )
{
    ManageDllState_m();

    bool bSuccess = false;

    try
    {
        ResetError();

        CTriggerTableManager *pTriggerTable = TriggerTable_m();
        if ( pTriggerTable == NULL )
        {
            GenerateError_m( errorCodeInternalError );
        }

        bSuccess = pTriggerTable->RemovePort( rulPortIndex );
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
        bSuccess = false;
    }
    catch ( ... )
    {
        SetError( -1, "Unspecified exception caught" );
        bSuccess = false;
    }

    return bSuccess;
}

C7kPort * C7kTriggerController::Port ( const unsigned long &rulPortIndex )
{
    ManageDllState_m();

    C7kPort *pPort = NULL;

    try
    {
        ResetError();

        CTriggerTableManager *pTriggerTable = TriggerTable_m();
        if ( pTriggerTable == NULL )
        {
            GenerateError_m( errorCodeInternalError );
        }

        pPort = pTriggerTable->Port( rulPortIndex );
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
        pPort = NULL;
    }
    catch ( ... )
    {
        SetError( -1, "Unspecified exception caught" );
        pPort = NULL;
    }

    return pPort;
}

bool C7kTriggerController::AddTrigger( C7kTrigger &rTrigger )
{
    ManageDllState_m();

    bool bSuccess = false;

    try
    {
        ResetError();

        CTriggerTableManager *pTriggerTable = TriggerTable_m();
        if ( pTriggerTable == NULL )
        {
            GenerateError_m( errorCodeInternalError );
        }

        bSuccess = pTriggerTable->AddTrigger( rTrigger );
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
        bSuccess = false;
    }
    catch ( ... )
    {
        SetError( -1, "Unspecified exception caught" );
        bSuccess = false;
    }

    return bSuccess;
}

bool C7kTriggerController::RemoveTrigger( const unsigned long &rulTrigger )
{
    ManageDllState_m();

    bool bSuccess = false;

    try
    {
        ResetError();

        CTriggerTableManager *pTriggerTable = TriggerTable_m();
        if ( pTriggerTable == NULL )
        {
            GenerateError_m( errorCodeInternalError );
        }

        bSuccess = pTriggerTable->RemoveTrigger( rulTrigger );
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
        bSuccess = false;
    }
    catch ( ... )
    {
        SetError( -1, "Unspecified exception caught" );
        bSuccess = false;
    }

    return bSuccess;
}

C7kTrigger * C7kTriggerController::Trigger( const unsigned long &rulTrigger )
{
    ManageDllState_m();

    C7kTrigger *pTrigger = NULL;

    try
    {
        ResetError();

        CTriggerTableManager *pTriggerTable = TriggerTable_m();
        if ( pTriggerTable == NULL )
        {
            GenerateError_m( errorCodeInternalError );
        }

        pTrigger = pTriggerTable->Trigger( rulTrigger );
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
        pTrigger = NULL;
    }
    catch ( ... )
    {
        SetError( -1, "Unspecified exception caught" );
        pTrigger = NULL;
    }

    return pTrigger;
}

bool C7kTriggerController::AddSequence( C7kTriggerSequence &rSequence )
{
    ManageDllState_m();

    bool bSuccess = false;

    try
    {
        ResetError();

        CTriggerTableManager *pTriggerTable = TriggerTable_m();
        if ( pTriggerTable == NULL )
        {
            GenerateError_m( errorCodeInternalError );
        }

        bSuccess = pTriggerTable->AddSequence( rSequence );
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
        bSuccess = false;
    }
    catch ( ... )
    {
        SetError( -1, "Unspecified exception caught" );
        bSuccess = false;
    }

    return bSuccess;
}

bool C7kTriggerController::RemoveSequence( const unsigned long &rulSequence )
{
    ManageDllState_m();

    bool bSuccess = false;

    try
    {
        ResetError();

        CTriggerTableManager *pTriggerTable = TriggerTable_m();
        if ( pTriggerTable == NULL )
        {
            GenerateError_m( errorCodeInternalError );
        }

        bSuccess = pTriggerTable->RemoveSequence( rulSequence );
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
        bSuccess = false;
    }
    catch ( ... )
    {
        SetError( -1, "Unspecified exception caught" );
        bSuccess = false;
    }

    return bSuccess;
}

bool C7kTriggerController::Configure( void )
{
    ManageDllState_m();

    bool bSuccess = false;

    try
    {
        ResetError();

        CTriggerTableManager *pTriggerTable = TriggerTable_m();
        if ( pTriggerTable == NULL )
        {
            GenerateError_m( errorCodeInternalError );
        }

#pragma CompileMessage_m( "TODO: FORMAT AND SEND 7K MESSAGES TO SONAR TO CONFIGURE TRIGGER CONTROLLER BASED ON THE TRIGGER TABLE" )

//        bSuccess = pTriggerTable->Get
    }
    catch ( CTriggerException Exception )
    {
        SetError( Exception.ErrorCode(), Exception.ErrorMessage() );
        bSuccess = false;
    }
    catch ( ... )
    {
        SetError( -1, "Unspecified exception caught" );
        bSuccess = false;
    }

    return bSuccess;
}

///////////////////////////////////////////////////////////////////////////////
// Private services.

inline
void C7kTriggerController::ResetError( void )
{
    SetError( CTriggerException::errorCodeNone );
}

inline
void C7kTriggerController::SetError(    const int  &riErrorCode,
                                        LPCTSTR     lpszMessage )
{
    try
    {
        m_iLastError = riErrorCode;

        if ( lpszMessage == NULL )
        {
            m_LastErrorMsg = CTriggerException::ErrorMessageFromCode( static_cast<CTriggerException::EERRORCODE>( riErrorCode ) );
        }
        else
        {
            m_LastErrorMsg = lpszMessage;
        }
    }
    catch ( ... )
    {
        TRACE( _T( "C7kTriggerController::SetError(), Unspecified exception caught\n" ) );
    }
}

///////////////////////////////////////////////////////////////////////////////
// CTriggerException class implementation -- an internal helper.

inline
CTriggerException::CTriggerException( void )
{
    m_eErrorCode = errorCodeNone;
    m_sErrorMsg.Empty();
}

inline
CTriggerException::~CTriggerException( void )
{
    m_eErrorCode = errorCodeNone;
    m_sErrorMsg.Empty();
}

inline
void CTriggerException::Set(  const EERRORCODE   &reErrorCode,
                                        const int          &riLine,
                                        LPCTSTR             lpszFile )
{
    m_eErrorCode = reErrorCode;

    if ( IsErrorCodeValid( reErrorCode ) )
    {
        m_sErrorMsg = m_szErrorMessages[ m_eErrorCode ];
    }
    else
    {
        m_sErrorMsg = _T( "Unknown error" );
        ASSERT( false );
    }

    TRACE( _T( "Exception generated from file \"%s\" @ line %d. Error # %d, %s\n" ),    lpszFile,
                                                                                        riLine,
                                                                                        reErrorCode,
                                                                                        static_cast<LPCTSTR>( m_sErrorMsg ) );
}

inline
CTriggerException::EERRORCODE CTriggerException::ErrorCode( void ) const
{
    return m_eErrorCode;
}

inline
LPCTSTR CTriggerException::ErrorMessage( void ) const
{
    return static_cast<LPCTSTR>( m_sErrorMsg );
}

inline
bool CTriggerException::IsErrorCodeValid( const EERRORCODE &reErrorCode )
{
    return ( ( reErrorCode >= CTriggerException::errorCodeNone ) && ( reErrorCode < CTriggerException::errorCodeMaxCodes ) );
}

inline
LPCTSTR CTriggerException::ErrorMessageFromCode( const EERRORCODE &reErrorCode )
{
    return ( ( IsErrorCodeValid( reErrorCode ) ) ? m_szErrorMessages[ reErrorCode ] : NULL );
}

inline
void CTriggerException::GenerateError(  const EERRORCODE   &reErrorCode,
                                        const int          &riLine,
                                        LPCTSTR             lpszFile )
{
    CTriggerException Exception;
    Exception.Set( reErrorCode, riLine, lpszFile );
    throw Exception;
}

