//
//  Copyright © 2001 - 2002, 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:   Sensor.cpp
//
//  Project:    6046
//
//  Author(s):  W. Arcus
//
//  Purpose:    
//
//  Notes:      
//

#include "StdAfx.h"
#include "EdgeTechFSDW.h"

#include "Sensor.h"
#include "CommandProcessor.h"
#include "DataProcessor.h"
#include "MessageProcessor.h"

#include "..\..\Include\Exports.h"
#include "..\..\Include\SurveyEventTypes.h"

#include <ctype.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// CSensor class implementation.

CSensor::CSensor(    CCommandProcessor *pSonarCommandProcessor,
                     CDataProcessor    *pSonarDataProcessor )

        :CSubsystem( pSonarCommandProcessor,
                     pSonarDataProcessor )
{
}

CSensor::~CSensor( void )
{
}

bool CSensor::Startup(  int             iSubsystemId,
                        int             iSensorIndex,
                        DWORD           dwThreadId,
                        unsigned int    uiDataReadyMessageId,
                        unsigned int    uiReplyReadyMessageId,
                        int             iActivateOnStartup )
{
    bool bSuccess = false;

    try
    {
        // Set the subsystems key parameters and load the previously stored state.

        if ( ! SetSystemParameters( iSubsystemId, iSensorIndex, dwThreadId, uiDataReadyMessageId, uiReplyReadyMessageId ) )
        {
            ThrowMessage_m( "SetSystemParameters() failed" );
        }

        // Initialize the subsystem.

        bool bActivateOnStart = ( iActivateOnStartup != 0 );

        if ( ! InitializeSubsystem( bActivateOnStart ) )
        {
            ThrowMessage_m( "InitializeSubsystem() failed" );
        }

        bSuccess = true;
    }
    catch ( LPCTSTR lpszMessage )
    {
        bSuccess = false;
        TRACE( _T( "CSensor::Startup(), %s\b" ), lpszMessage );
    }
    catch ( ... )
    {
        bSuccess = false;
        TRACE( _T( "CSensor::Startup(), unspecified exception caught\n" ) );
    }

    return bSuccess;
}

bool CSensor::Shutdown( int iSensorIndex )
{
    bool bSuccess = false;

    UNREFERENCED_PARAMETER( iSensorIndex );

    try
    {
        // Save current state.

        if ( ! CSubsystem::Shutdown() )
        {
            ThrowMessage_m( "Shutdown() failed" );
        }

        bSuccess = true;
    }
    catch ( LPCTSTR lpszMessage )
    {
        bSuccess = false;
        TRACE( _T( "CSensor::Shutdown(), %s\n" ), lpszMessage );
    }
    catch ( ... )
    {
        bSuccess = false;
        TRACE( _T( "CSensor::Shutdown(), unspecified exception caught\n" ) );
    }

    return bSuccess;
}

bool CSensor::Load( BYTE           *pbyData,
                    unsigned long  *pulSize,
                    unsigned long  *pulTimestamp )
{
    bool bRetrieved = false;

    UNREFERENCED_PARAMETER( pbyData );
    UNREFERENCED_PARAMETER( pulSize );
    UNREFERENCED_PARAMETER( pulTimestamp );

    // Load no redundant. See comments noted in ::Load()

//    bool bSuccess   = false;
//
//    try
//    {
//        m_DataGuard.Enter();
//        unsigned long ulQueuedRecords = m_DataRecordQueue.Items();
//        m_DataGuard.Leave();
//
//        //TRACE( _T( "CSensor::Load(), %lu items queued\n" ), ulQueuedRecords );
//
//        if ( ulQueuedRecords > 0UL )
//        {
//            m_DataGuard.Enter();
//
//            try
//            {
//                int iIndex = m_DataRecordQueue.Front();
//
//                if ( iIndex != m_DataRecordQueue.m_iInvalidIndex )
//                {
//                    QUEUEDMESSAGE        *psMessage = NULL;
//                    CDynamicBuffer<BYTE> *pBuffer   = NULL;
//
//                    if ( m_DataRecordQueue.Get( iIndex, psMessage, pBuffer ) )
//                    {
//                        *pulTimestamp = psMessage->m_ulTimeStamp;
//                        *pulSize      = pBuffer->Size() * sizeof( BYTE );
//
//                        ASSERT( *pulSize > 0UL );
//
//                        if ( *pulSize > 0UL )
//                        {
//                            ::memcpy( pbyData, pBuffer->GetAt( 0 ), *pulSize );
//                        }
//
//                        m_DataRecordQueue.Remove( iIndex );
//
//                        bRetrieved = true;
//                    }
//                }
//
//                bSuccess = true;
//            }
//            catch (...)
//            {
//                bSuccess = false;
//                TRACE( _T( "CSensor::Load(), unspecified exception caught\n" ) );
//            }
//
//            m_DataGuard.Leave();
//        }
//        else
//        {
//            bSuccess = true;
//        }
//    }
//    catch ( LPCTSTR lpszMessage )
//    {
//        bSuccess = false;
//        TRACE( _T( "CSensor::Load(), %s\n" ), lpszMessage );
//    }
//    catch ( ... )
//    {
//        bSuccess = false;
//        TRACE( _T( "CSensor::Load(), unspecified exception caught\n" ) );
//    }

    return bRetrieved;
}

bool CSensor::SendCommand(  int     iClientIndex,
                            char   *pszCommand )
{
    bool bSuccess = false;

    typedef enum tagECOMMANDID
    {
        commandRange,
        commandPulse,
        commandPing,
        commandTxPower,
        commandRxGain,
        commandDuration,
        commandPulseFiles,
        commandDefaultState
    }
    ECOMMANDID;

    typedef struct tagCOMMAND
    {
        char        m_szPneumonic[ _MAX_PATH ];
        ECOMMANDID  m_eId;
    }
    COMMAND;

    try
    {
        CString Command( pszCommand );

        if ( ! Command.IsEmpty() )
        {
            static COMMAND asCommands[] =   {
                                                { "Range",          commandRange        },

                                                // Note: order is significant here since pulse will be found
                                                // in PulseFiles too. So by having the full name, "PulseFiles" first,
                                                // guarantees it'll be located first.

                                                { "PulseFiles",     commandPulseFiles   },
                                                { "Pulse",          commandPulse        },

                                                { "Ping"    ,       commandPing         },
                                                { "TxPower",        commandTxPower      },
                                                { "RxGain",         commandRxGain       },
                                                { "Duration",       commandDuration     },
                                                { "DefaultState",   commandDefaultState }
                                            };

            for ( int iCommand = 0; iCommand < DimOf_m( asCommands ); iCommand++ )
            {
                if ( Command.Find( asCommands[ iCommand ].m_szPneumonic, 0 ) != -1 )
                {
                    CString Parameter;
                    int     iParamPos;
                    
                    if ( ( iParamPos = Command.Find( "=", 0 ) ) != -1 )
                    {
                        // Point just past the '=' and then trim off white space before assigning the parameter.

                        int iLength = Command.GetLength();

                        iParamPos++;

                        while ( ( iParamPos < iLength ) && isspace( Command[ iParamPos ] ) )
                        {
                            iParamPos++;
                        }

                        // Assign parameter string.

                        if ( iParamPos < iLength )
                        {
                            Parameter = Command.Right( Command.GetLength() - iParamPos );
                        }
                    }

                    switch ( asCommands[ iCommand ].m_eId )
                    {
                        case commandRange:

                            ASSERT( ! Parameter.IsEmpty() );

                            if ( ! Parameter.IsEmpty() )
                            {
                                SetRange( static_cast<float>( ::atof( (LPCTSTR) Parameter ) ), true );
                            }

                            break;

                        case commandPing:

                            ASSERT( ! Parameter.IsEmpty() );

                            if ( ! Parameter.IsEmpty() )
                            {
                                PingEnable( static_cast<bool>( ::atoi( (LPCTSTR) Parameter ) != 0 ), true );
                            }

                            break;

                        case commandTxPower:

                            ASSERT( ! Parameter.IsEmpty() );

                            if ( ! Parameter.IsEmpty() )
                            {
                                SetTxPower( static_cast<float>( ::atof( (LPCTSTR) Parameter ) ), true );
                            }

                            break;

                        case commandRxGain:

                            ASSERT( ! Parameter.IsEmpty() );

                            if ( ! Parameter.IsEmpty() )
                            {
                                SetRxGain( ::atoi( (LPCTSTR) Parameter ), true );
                            }

                            break;

                        case commandDuration:

                            ASSERT( ! Parameter.IsEmpty() );

                            if ( ! Parameter.IsEmpty() )
                            {
                                SetPingDuration( static_cast<float>( ::atof( (LPCTSTR) Parameter ) ), true );
                            }

                            break;

                        case commandPulse:

                            ASSERT( ! Parameter.IsEmpty() );

                            if ( ! Parameter.IsEmpty() )
                            {
                                SetPulseFile( Parameter, true );
                            }

                            break;

                        case commandPulseFiles:

                            RetrievePulseFileListQuery( iClientIndex );
                            break;

                        case commandDefaultState:

                            SetDefaultState();
                            break;

                        default:

                            TRACE( _T( "CSensor::SendCommand(), Unhandled command: %s\n" ), (LPCTSTR) Command );
                            break;
                    }

                    break;
                }
            }
        }

        bSuccess = true;
    }
    catch ( LPCTSTR lpszMessage )
    {
        bSuccess = false;
        TRACE( _T( "CSensor::SendCommand(), %s\n" ), lpszMessage );
    }
    catch ( ... )
    {
        bSuccess = false;
        TRACE( _T( "CSensor::SendCommand(), unspecified exception caught\n" ) );
    }

    return bSuccess;
}

bool CSensor::RetrieveStatus(   BYTE           *pbyData,
                                unsigned long  *pulSize,
                                unsigned long  *pulTimestamp,
                                int            *piClientIndex )
{
    bool bRetrieved = false;
    bool bSuccess   = false;

    *piClientIndex = -1;

    try
    {
        m_StatusQueueGuard.Enter();
        bool bRecordAvailable = ( m_StatusQueue.Items() > 0UL );
        m_StatusQueueGuard.Leave();

        if ( bRecordAvailable )
        {
            m_StatusQueueGuard.Enter();

            try
            {
                int iIndex = m_StatusQueue.Front();

                if ( iIndex != m_StatusQueue.m_iInvalidIndex )
                {
                    QUEUEDMESSAGE        *psMessage = NULL;
                    CDynamicBuffer<BYTE> *pBuffer   = NULL;

                    if ( m_StatusQueue.Get( iIndex, psMessage, pBuffer ) )
                    {
                        *pulTimestamp = psMessage->m_ulTimeStamp;
                        *pulSize      = pBuffer->Size() * sizeof( BYTE );

                        ASSERT( *pulSize > 0UL );

                        if ( *pulSize > 0UL )
                        {
                            ::memcpy( pbyData, pBuffer->GetAt( 0 ), *pulSize );
                        }

                        m_StatusQueue.Remove( iIndex );

                        bRetrieved = true;
                    }
                }

                bSuccess = true;
            }
            catch (...)
            {
                bSuccess = false;
            }

            m_StatusQueueGuard.Leave();
        }
        else
        {
            bSuccess = true;
        }
    }
    catch ( LPCTSTR lpszMessage )
    {
        bSuccess = false;
        TRACE( _T( "CSensor::RetrieveStatus(), %s\n" ), lpszMessage );
    }
    catch ( ... )
    {
        bSuccess = false;
        TRACE( _T( "CSensor::RetrieveStatus(), unspecified exception caught\n" ) );
    }

    return bRetrieved;
}

bool CSensor::RouteMessage( const BYTE          *pbyMessage,
                            const unsigned long &rulSize,
                            const unsigned long &rulTimeStamp )
{
    UNREFERENCED_PARAMETER( pbyMessage );
    UNREFERENCED_PARAMETER( rulSize );
    UNREFERENCED_PARAMETER( rulTimeStamp );

    // Nothing to do.

    return true;
}

bool CSensor::Identify( SENSORINFO *psSensorInfo )
{
    UNREFERENCED_PARAMETER( psSensorInfo );

    // Not implemented.

    return false;
}

///////////////////////////////////////////////////////////////////////////////
// Extended public methods.

bool CSensor::SetSystemTime( void )
{
    return CSubsystem::SetSystemTime();
}



