//  Copyright (c) 2001, Reson, Inc. All Rights Reserved.
//
//  Filename:   EdgeTechMessage.cpp
//
//  Project:    6046
//
//  Author(s):  W. Arcus
//
//  Purpose:    Implements the EdgeTech FS-AU message encoder/decoder class CEdgeTechMessage.
//
//  Notes:      Nil.
//

#include "StdAfx.h"
#include "EdgeTechMessage.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// CEdgeTechMessage class implementation.

CEdgeTechMessage::~CEdgeTechMessage( void )
{
    DestroyAutoPointer( m_pMessageBuffer );
}

//////////////////////////////////////////////////////////////////////
// Decoder services

CEdgeTechMessage::CEdgeTechMessage( SonarMessageHeaderType *pHeader )

                 :m_ulMessageHeaderSize( sizeof( SonarMessageHeaderType ) ),
                  m_ulMaxMessageLength( ulMaxEdgeTechDynamicDataSize_c )
{
    m_pMessageBuffer = std::auto_ptr<CBufferManager>( new CBufferManager() );
    ASSERT( m_pMessageBuffer.get() != NULL );

    SetHeader( pHeader );
}

bool CEdgeTechMessage::SetHeader( SonarMessageHeaderType *pHeader )
{
    bool bSuccess = false;

    ASSERT( pHeader != NULL );

    if ( pHeader != NULL )
    {
        ASSERT( m_pMessageBuffer.get() != NULL );

        if ( m_pMessageBuffer.get() != NULL )
        {
            bSuccess = m_pMessageBuffer->SetBuffer( (BYTE *) pHeader, m_ulMessageHeaderSize + pHeader->byteCount, false );
        }
    }

    return bSuccess;
}

//////////////////////////////////////////////////////////////////////
// Encoder services.

CEdgeTechMessage::CEdgeTechMessage( unsigned short  unMessage,
                                    unsigned char   ucCommand,
                                    unsigned char   ucSessionID,
                                    unsigned char   ucSubSystem,
                                    unsigned char   ucChannel )

                 :m_ulMessageHeaderSize( sizeof( SonarMessageHeaderType ) ),
                  m_ulMaxMessageLength( (unsigned long) ulMaxEdgeTechDynamicDataSize_c )

{
    m_pMessageBuffer = std::auto_ptr<CBufferManager>( new CBufferManager() );
    ASSERT( m_pMessageBuffer.get() != NULL );

    if ( ! SetHeader( unMessage, ucCommand, ucSessionID, ucSubSystem, ucChannel ) )
    {
        TRACE( _T( "CEdgeTechMessage::CEdgeTechMessage(), Can't set header\n" ) );
    }
}

bool CEdgeTechMessage::SetHeader(   unsigned short  unMessage,
                                    unsigned char   ucCommand,
                                    unsigned char   ucSessionID,
                                    unsigned char   ucSubSystem,
                                    unsigned char   ucChannel )
{
    if ( ( m_pMessageBuffer.get() != NULL ) &&
         ( m_pMessageBuffer->SetBuffer( NULL, m_ulMessageHeaderSize, true ) ) )
    {
        SonarMessageHeaderType *psHeader = (SonarMessageHeaderType *) m_pMessageBuffer->GetMessage();

        memset( psHeader, 0x00, m_ulMessageHeaderSize );

        psHeader->startOfMessage  = SONAR_MESSAGE_HEADER_START;
        psHeader->version         = 0;

        psHeader->sonarMessage    = unMessage;
        psHeader->sonarCommand    = ucCommand;
        psHeader->sessionID       = ucSessionID;
        psHeader->subSystem       = ucSubSystem;
        psHeader->channel         = ucChannel;
        psHeader->byteCount       = 0;

        return true;
    }

    return false;
}

bool CEdgeTechMessage::SetMessage(  unsigned short  unMessage,
                                    unsigned char   ucCommand,
                                    BYTE           *pbyMessage,
                                    unsigned long   ulBytesInMessage,
                                    unsigned char   ucSessionID,
                                    unsigned char   ucSubSystem,
                                    unsigned char   ucChannel )
{
    if ( ( m_pMessageBuffer.get() != NULL ) &&
         ( m_pMessageBuffer->SetBuffer( NULL, m_ulMessageHeaderSize + ulBytesInMessage, true ) ) )
    {
        SonarMessageHeaderType *psHeader = (SonarMessageHeaderType *) m_pMessageBuffer->GetMessage();

        ::memset( psHeader, 0x00, m_ulMessageHeaderSize );

        psHeader->startOfMessage  = SONAR_MESSAGE_HEADER_START;
        psHeader->version         = 0;

        psHeader->sonarMessage    = unMessage;
        psHeader->sonarCommand    = ucCommand;
        psHeader->sessionID       = ucSessionID;
        psHeader->subSystem       = ucSubSystem;
        psHeader->channel         = ucChannel;
        psHeader->byteCount       = 0;

        if ( ( ulBytesInMessage > 0UL ) && ( ulBytesInMessage < m_ulMaxMessageLength ) )
        {
            if ( pbyMessage != NULL )
            {
                BYTE *pbyDestination = ((BYTE *) psHeader) + m_ulMessageHeaderSize;

                memcpy( pbyDestination, pbyMessage, ulBytesInMessage );

                psHeader->byteCount = ulBytesInMessage;
            }
        }

        return true;
    }

    return false;
}

CEdgeTechMessage::CEdgeTechMessage( const CEdgeTechMessage &rRhs )

                 :m_ulMessageHeaderSize( sizeof( SonarMessageHeaderType ) ),
                  m_ulMaxMessageLength( ulMaxEdgeTechDynamicDataSize_c )
{
    m_pMessageBuffer = std::auto_ptr<CBufferManager>( new CBufferManager );
    ASSERT( m_pMessageBuffer.get() != NULL );

    *(m_pMessageBuffer.get()) = *(rRhs.m_pMessageBuffer.get());
}

CEdgeTechMessage & CEdgeTechMessage::operator = ( const CEdgeTechMessage &rRhs )
{
    *(m_pMessageBuffer.get()) = *(rRhs.m_pMessageBuffer.get());

    return *this;
}

BYTE * CEdgeTechMessage::Message( void ) const
{
    ASSERT( m_pMessageBuffer.get() != NULL );
    return ( ( m_pMessageBuffer.get() == NULL ) ? NULL : m_pMessageBuffer->GetMessage() );
}

unsigned short CEdgeTechMessage::SonarMessage( void ) const
{
    ASSERT( m_pMessageBuffer.get() != NULL );
    return ((SonarMessageHeaderType *) m_pMessageBuffer->GetMessage())->sonarMessage;
}

unsigned char CEdgeTechMessage::SonarCommand( void ) const
{
    ASSERT( m_pMessageBuffer.get() != NULL );
    return ((SonarMessageHeaderType *) m_pMessageBuffer->GetMessage())->sonarCommand;
}

unsigned char CEdgeTechMessage::Subsystem( void ) const
{
    ASSERT( m_pMessageBuffer.get() != NULL );
    return ((SonarMessageHeaderType *) m_pMessageBuffer->GetMessage())->subSystem;
}

unsigned long CEdgeTechMessage::MessageSize( void ) const
{
    unsigned long ulTotalBytes = 0UL;

    ASSERT( m_pMessageBuffer.get() != NULL );

    if ( m_pMessageBuffer.get() != NULL )
    {
        ulTotalBytes = m_pMessageBuffer->MessageSize();

#ifdef _DEBUG
        SonarMessageHeaderType *psHeader = (SonarMessageHeaderType *) m_pMessageBuffer->GetMessage();
        ASSERT( psHeader != NULL );
        ASSERT( ulTotalBytes == ( psHeader->byteCount + m_ulMessageHeaderSize ) );
#endif
    }

    return ulTotalBytes;
}

unsigned long CEdgeTechMessage::HeaderSize( void )
{
    return sizeof( SonarMessageHeaderType );
}

//////////////////////////////////////////////////////////////////////
// Conversion operators.

CEdgeTechMessage::operator SonarMessageHeaderType *() const
{
    ASSERT( m_pMessageBuffer.get() != NULL );
    return ( (::SonarMessageHeaderType *) m_pMessageBuffer->GetMessage() );
}

CEdgeTechMessage::operator long () const
{
    return ( (long) ( ( (::SonarMessageLongType *) OptionalData() )->value ) );
}

CEdgeTechMessage::operator unsigned long () const
{
    return ( (unsigned long) ( ( (::SonarMessageLongType *) OptionalData() )->value ) );
}

CEdgeTechMessage::operator char * () const
{
    return ( (char *) ( ( (::SonarMessageStringType *) OptionalData() )->name ) );
}

CEdgeTechMessage::operator SonarMessageStatusType * () const
{
    return ( (::SonarMessageStatusType *) OptionalData() );
}

CEdgeTechMessage::operator TimestampType * () const
{
    return ( (::TimestampType *) OptionalData() );
}

CEdgeTechMessage::operator SonarMessagePingType * () const
{
    return ( (::SonarMessagePingType *) OptionalData());
}

CEdgeTechMessage::operator SonarMessageWindowType * () const
{
    return ( (::SonarMessageWindowType *) OptionalData());
}

CEdgeTechMessage::operator SonarMessageFishType * () const
{
    return ( (::SonarMessageFishType *) OptionalData());
}

CEdgeTechMessage::operator SegyDataType * () const
{
    return ( (::SegyDataType *) OptionalData());
}

CEdgeTechMessage::operator SidescanHeaderType * () const
{
    return ( (::SidescanHeaderType *) OptionalData());
}

CEdgeTechMessage::operator SonarMessageCouplingParametersType * ( void ) const
{
    return ( (::SonarMessageCouplingParametersType *) OptionalData());
}

inline
BYTE * CEdgeTechMessage::OptionalData( void ) const
{
    ASSERT( m_pMessageBuffer.get() != NULL );
    return ( ((BYTE *)(m_pMessageBuffer->GetMessage())) + sizeof( SonarMessageHeaderType ));
}

//////////////////////////////////////////////////////////////////////
// Internal helper class CEdgeTechMessage::CBufferManager implementation.

inline
CEdgeTechMessage::CBufferManager::CBufferManager( void )
{
    m_pbyBuffer    = NULL;
    m_ulBufferSize = 0UL;
    m_bIsOwner     = false;
}

inline
CEdgeTechMessage::CBufferManager::CBufferManager( const CEdgeTechMessage::CBufferManager &rRhs )
{
    m_pbyBuffer    = NULL;
    m_ulBufferSize = 0UL;
    m_bIsOwner     = false;

    SetBuffer( rRhs.m_pbyBuffer, rRhs.m_ulBufferSize, rRhs.m_bIsOwner );
}

inline
CEdgeTechMessage::CBufferManager &
CEdgeTechMessage::CBufferManager::operator = ( const CEdgeTechMessage::CBufferManager &rRhs )
{
    m_pbyBuffer    = NULL;
    m_ulBufferSize = 0UL;
    m_bIsOwner     = false;

    SetBuffer( rRhs.m_pbyBuffer, rRhs.m_ulBufferSize, rRhs.m_bIsOwner );

    return *this;
}

inline
CEdgeTechMessage::CBufferManager::~CBufferManager( void )
{
    Release();
}

inline
bool CEdgeTechMessage::CBufferManager::SetBuffer(   BYTE                *pbyBuffer,
                                                    const unsigned long &rulMaxSize,
                                                    const bool          &rbAllocate )
{
    Release();                  // Ensure any previously used buffer is released.

    ASSERT( rulMaxSize > 0UL );

    m_ulBufferSize = rulMaxSize;
    m_bIsOwner     = rbAllocate;

    if ( rbAllocate )
    {
        m_pbyBuffer = new BYTE [ rulMaxSize ];

        if ( pbyBuffer != NULL )
        {
            ::memcpy( m_pbyBuffer, pbyBuffer, rulMaxSize );
        }
    }
    else
    {
        ASSERT( pbyBuffer != NULL );
        m_pbyBuffer = pbyBuffer;
    }

    return ( ( m_pbyBuffer != NULL ) && ( m_ulBufferSize > 0UL ) );
}

inline
void CEdgeTechMessage::CBufferManager::Release( void )
{
    if ( ( m_pbyBuffer != NULL ) && m_bIsOwner )
    {
        delete [] m_pbyBuffer;
    }

    m_pbyBuffer    = NULL;
    m_ulBufferSize = 0UL;
    m_bIsOwner     = false;
}

inline
BYTE * CEdgeTechMessage::CBufferManager::GetMessage( void )
{
    return m_pbyBuffer;
}

inline
unsigned long CEdgeTechMessage::CBufferManager::MessageSize( void ) const
{
    return m_ulBufferSize;
}
