//
//  Copyright (c) 2001, Reson, Inc. All Rights Reserved.
//
//  Filename:   Component.cpp
//
//  Project:    6046.
//
//  Author(s):  W. Arcus
//
//  Purpose:    Implementation file for the CComponent class.
//
//  Notes:      According to MSDN (documentation on AfxFreeLibrary()):
//              "Both AfxFreeLibrary and AfxLoadLibrary maintain a reference count for 
//              each loaded library module. AfxFreeLibrary decrements the reference count 
//              of the loaded dynamic-link library (DLL) module. When the reference count 
//              reaches zero, the module is unmapped from the address space of the calling 
//              process and the handle is no longer valid. This reference count is 
//              incremented each time AfxLoadLibrary is called."
//
//              Therefore we don't need to explicitly handle reference counting ourselves
//              for multiple sensors that use the same DLL.
//

#include "StdAfx.h"
#include "Component.h"

#include <string.h>

#define MapProcedure_m( Type, Ptr, Name )   if ( ( Ptr = (Type) ::GetProcAddress( m_hInstLib, Name ) ) == NULL )                            \
                                            {                                                                                               \
                                                bSuccess = false;                                                                           \
                                                throw ( _T( "File: " __FILE__ ", Line: %d, Can't map procedure: " Name "\n" ), __LINE__ );  \
                                            }

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// CComponent class implementation.

CComponent::CComponent( void )
{
    m_bLoaded             = false;
    m_hInstLib            = NULL;

    m_pfnStartup          = NULL;
    m_pfnShutdown         = NULL;
    m_pfnIdentify         = NULL;
    m_pfnLoad             = NULL;
    m_pfnGetModuleVersion = NULL;
    m_pfnSendCommand      = NULL;
    m_pfnRetrieveStatus   = NULL;
    m_pfnRouteMessage     = NULL;
    m_pfnResetSensor      = NULL;
    m_pfnIsSensorHealthy  = NULL;
}

CComponent::CComponent( const CString &rLibraryName )
{
    m_bLoaded             = false;
    m_hInstLib            = NULL;

    m_pfnStartup          = NULL;
    m_pfnShutdown         = NULL;
    m_pfnIdentify         = NULL;
    m_pfnLoad             = NULL;
    m_pfnGetModuleVersion = NULL;
    m_pfnSendCommand      = NULL;
    m_pfnRetrieveStatus   = NULL;
    m_pfnRouteMessage     = NULL;
    m_pfnResetSensor      = NULL;
    m_pfnIsSensorHealthy  = NULL;

    if ( ! LoadDLL( rLibraryName ) )
    {
        TRACE( _T( "CComponent::CComponent(), LoadDLL failed\n" ) );
    }
}

CComponent::~CComponent( void )
{
    UnloadDLL();
}

bool CComponent::IsLoaded( void ) const
{
    return m_bLoaded;
}

bool CComponent::LoadDLL( const CString & rLibraryName )
{
    bool bSuccess = false;    // Assume failure for now.

    if ( m_bLoaded )
    {
        UnloadDLL();
    }

    ASSERT( ! rLibraryName.IsEmpty() );

    if ( ! rLibraryName.IsEmpty() )
    {
        // Dynamically load the DLL and assign the various pointers to the DLL entry points.

        if ( ( m_hInstLib = ::AfxLoadLibrary( rLibraryName ) ) != NULL )
        {
            // Load the interface services by name.

            try
            {
                MapProcedure_m( PFN_STARTUP,            m_pfnStartup,           "Startup"           );
                MapProcedure_m( PFN_SHUTDOWN,           m_pfnShutdown,          "Shutdown"          );
                MapProcedure_m( PFN_IDENTIFY,           m_pfnIdentify,          "Identify"          );
                MapProcedure_m( PFN_LOAD,               m_pfnLoad,              "Load"              );
                MapProcedure_m( PFN_GETMODULEVERSION,   m_pfnGetModuleVersion,  "GetModuleVersion"  );
                MapProcedure_m( PFN_SENDCOMMAND,        m_pfnSendCommand,       "SendCommand"       );
                MapProcedure_m( PFN_RETRIEVESTATUS,     m_pfnRetrieveStatus,    "RetrieveStatus"    );
                MapProcedure_m( PFN_ROUTEMESSAGE,       m_pfnRouteMessage,      "RouteMessage"      );
                MapProcedure_m( PFN_RESETSENSOR,        m_pfnResetSensor,       "ResetSensor"       );
                MapProcedure_m( PFN_ISSENSORHEALTHY,    m_pfnIsSensorHealthy,   "IsSensorHealthy"   );

                bSuccess = true;
            }
            catch ( LPCTSTR lpszMessage )
            {
                bSuccess = false;
                TRACE( "CComponent::LoadDLL(), %s\n", lpszMessage );
            }
            catch ( ... )
            {
                bSuccess = false;
                TRACE( "CComponent::LoadDLL(), unspecified exception caught\n" );
            }
        }
        else
        {
            TRACE( _T( "CComponent::CComponent(), AfxLoadLibrary() can't load library %s\n" ), (LPCTSTR) rLibraryName );
        }
    }

    m_bLoaded = bSuccess;

    return bSuccess;
}

bool CComponent::UnloadDLL( void )
{
    bool bSuccess = true;

    m_pfnStartup          = NULL;
    m_pfnShutdown         = NULL;
    m_pfnIdentify         = NULL;
    m_pfnLoad             = NULL;
    m_pfnGetModuleVersion = NULL;
    m_pfnSendCommand      = NULL;
    m_pfnRetrieveStatus   = NULL;
    m_pfnRouteMessage     = NULL;
    m_pfnResetSensor      = NULL;
    m_pfnIsSensorHealthy  = NULL;

    if ( m_hInstLib != NULL )
    {
        if ( ! ::AfxFreeLibrary( m_hInstLib ) )
        {
            bSuccess = false;
            TRACE( _T( "CComponent::~CComponent(), AfxFreeLibrary() can't free specified DLL\n" ) );
        }

        m_hInstLib = NULL;
    }

    m_bLoaded = false;

    return bSuccess;
}

int CComponent::Startup(    SENSORINFO     *pSensorInfo,
                            DWORD           dwThreadId,
                            UINT            uiDataReadyMessageId,
                            UINT            uiReplyReadyMessageId,
                            void           *vpfnLog,
                            void           *vpCriticalParameters )
{
    int iReturnCode = 0;

    ASSERT( m_pfnStartup != NULL );

    try
    {
        if ( m_pfnStartup != NULL )
        {
            iReturnCode = ( m_pfnStartup )( pSensorInfo, dwThreadId, uiDataReadyMessageId, uiReplyReadyMessageId, vpfnLog, vpCriticalParameters );
        }
    }
    catch ( ... )
    {
        iReturnCode = 0;
        TRACE( "CComponent::Startup(), exception caught\n" );
    }

    return iReturnCode;
}

int CComponent::Shutdown( int iSensorIndex )
{
    int iReturnCode = 0;

    ASSERT( m_pfnShutdown != NULL );

    try
    {
        if ( m_pfnShutdown != NULL )
        {
            iReturnCode = ( m_pfnShutdown ) ( iSensorIndex );
        }
    }
    catch ( ... )
    {
        iReturnCode = 0;
        TRACE( "CComponent::Shutdown(), exception caught\n" );
    }

    return iReturnCode;
}

int CComponent::Identify( SENSORINFO     *pSensorInfo,
                          int             iSensorIndex )
{
    int iReturnCode = 0;

    ASSERT( m_pfnIdentify != NULL );

    try
    {
        if ( m_pfnIdentify != NULL )
        {
            iReturnCode = ( m_pfnIdentify ) ( pSensorInfo, iSensorIndex );
        }
    }
    catch ( ... )
    {
        iReturnCode = 0;
        TRACE( "CComponent::Identify(), exception caught\n" );
    }

    return iReturnCode;
}

int CComponent::Load( BYTE          *pbyData,
                      unsigned long *pulSize,
                      unsigned long *pulTimestamp,
                      int           iSensorIndex )
{
    int iReturnCode = 0;

    ASSERT( m_pfnLoad != NULL );

    try
    {
        if ( m_pfnLoad != NULL )
        {
            iReturnCode = ( m_pfnLoad )( pbyData, pulSize, pulTimestamp, iSensorIndex );
        }
    }
    catch ( ... )
    {
        iReturnCode = 0;
        TRACE( "CComponent::Load(), exception caught\n" );
    }

    return iReturnCode;
}

double CComponent::GetModuleVersion( void )
{
    double dReturnCode = 0.0;

    ASSERT( m_pfnGetModuleVersion != NULL );

    try
    {
        if ( m_pfnGetModuleVersion != NULL )
        {
            dReturnCode = ( m_pfnGetModuleVersion )();
        }
    }
    catch ( ... )
    {
        dReturnCode = 0.0;
        TRACE( "CComponent::GetModuleVersion(), exception caught\n" );
    }

    return dReturnCode;
}

int CComponent::SendCommand( int             iSensorIndex,
                             int             iClientIndex,
                             char           *pszCommand )
{
    int iReturnCode = 0;

    ASSERT( m_pfnSendCommand != NULL );

    try
    {
        if ( m_pfnSendCommand != NULL )
        {
            iReturnCode = ( m_pfnSendCommand )( iSensorIndex, iClientIndex, pszCommand );
        }
    }
    catch ( ... )
    {
        iReturnCode = 0;
        TRACE( "CComponent::SendCommand(), unspecified exception caught\n" );
    }

    return iReturnCode;
}

int CComponent::RetrieveStatus( BYTE           *pbyData,
                                unsigned long  *pulSize,
                                unsigned long  *pulTimestamp,
                                int            *piClientIndex,
                                int             iSensorIndex )
{
    int iReturnCode = 0;

    ASSERT( m_pfnRetrieveStatus != NULL );

    try
    {
        if ( m_pfnRetrieveStatus != NULL )
        {
            iReturnCode = ( m_pfnRetrieveStatus )( pbyData, pulSize, pulTimestamp, piClientIndex, iSensorIndex );
        }
    }
    catch ( ... )
    {
        iReturnCode = 0;
        TRACE( "CComponent::RetrieveStatus(), unspecified exception caught\n" );
    }

    return iReturnCode;
}

int CComponent::RouteMessage(   BYTE           *pbyMessage,
                                unsigned long   ulSize,
                                unsigned long   ulTimeStamp,
                                int             iSocketIndex,
                                int             iSensorIndex )
{
    int iReturnCode = 0;

    ASSERT( m_pfnRouteMessage != NULL );

    try
    {
        if ( m_pfnRouteMessage != NULL )
        {
            iReturnCode = ( m_pfnRouteMessage )( pbyMessage, ulSize, ulTimeStamp, iSocketIndex, iSensorIndex );
        }
    }
    catch ( ... )
    {
        iReturnCode = 0;
        TRACE( "CComponent::RouteMessage(), unspecified exception caught\n" );
    }

    return iReturnCode;
}

int CComponent::ResetSensor( int iSensorIndex )
{
    int iReturnCode = 0;

    ASSERT( m_pfnResetSensor != NULL );

    try
    {
        if ( m_pfnResetSensor != NULL )
        {
            iReturnCode = ( m_pfnResetSensor )( iSensorIndex );
        }
    }
    catch ( ... )
    {
        iReturnCode = 0;
        TRACE( "CComponent::ResetSensor(), unspecified exception caught\n" );
    }

    return iReturnCode;
}

int CComponent::IsSensorHealthy( int iSensorIndex )
{
    int iReturnCode = 0;

    ASSERT( m_pfnIsSensorHealthy != NULL );

    try
    {
        if ( m_pfnIsSensorHealthy != NULL )
        {
            iReturnCode = ( m_pfnIsSensorHealthy )( iSensorIndex );
        }
    }
    catch ( ... )
    {
        iReturnCode = 0;
        TRACE( "CComponent::IsSensorHealthy(), unspecified exception caught\n" );
    }

    return iReturnCode;
}


