//  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 "EdgeTechMessage.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// CEdgeTechMessage class implementation.

EdgeTechMessage::~EdgeTechMessage(void) {
	//DestroyAutoPointer( m_pMessageBuffer ); //deprecated call, autopoint should destroy itself.
}

//////////////////////////////////////////////////////////////////////
// Decoder services

EdgeTechMessage::EdgeTechMessage(SonarMessageHeaderType *pHeader)

:
		m_ulMessageHeaderSize(sizeof(SonarMessageHeaderType)), m_ulMaxMessageLength(ulMaxEdgeTechDynamicDataSize_c), m_ulDevHeaderSize(sizeof(DEVDataType)) {
	//m_pMessageBuffer = std::auto_ptr<CBufferManager>(new CBufferManager());
	m_pMessageBuffer = new CBufferManager();

//	assert( m_pMessageBuffer.get() != NULL);

	SetHeader(pHeader);
}

bool EdgeTechMessage::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((unsigned char *) pHeader, m_ulMessageHeaderSize + pHeader->byteCount, false);
//		}
	}

	return bSuccess;
}

//////////////////////////////////////////////////////////////////////
// Encoder services.

EdgeTechMessage::EdgeTechMessage(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_ulDevHeaderSize(sizeof(DEVDataType))

{
	m_pMessageBuffer = (new CBufferManager());
//	assert( m_pMessageBuffer.get() != NULL);

	if (!SetHeader(unMessage, ucCommand, ucSessionID, ucSubSystem, ucChannel)) {
		printf("%s", "EdgeTechMessage::EdgeTechMessage(), Can't set header\n");
	}
}

bool EdgeTechMessage::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))) {
	if ((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 EdgeTechMessage::SetMessage(unsigned short unMessage, unsigned char ucCommand, unsigned char *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))) {
	if ((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) {
				unsigned char *pbyDestination = ((unsigned char *) psHeader) + m_ulMessageHeaderSize;

				memcpy(pbyDestination, pbyMessage, ulBytesInMessage);

				psHeader->byteCount = ulBytesInMessage;
			}
		}

		return true;
	}

	return false;
}

bool EdgeTechMessage::SetDevMessage(unsigned short unMessage, unsigned char ucCommand, unsigned char* pbyMessage, unsigned long ulBytesInMessage, unsigned char ucSessionID, unsigned char ucSubSystem, unsigned char ucChannel) {

//	if ((m_pMessageBuffer.get() != NULL) && (m_pMessageBuffer->SetBuffer(NULL, m_ulMessageHeaderSize + m_ulDevHeaderSize + ulBytesInMessage, true))) {
	if ((m_pMessageBuffer->SetBuffer(NULL, m_ulMessageHeaderSize + m_ulDevHeaderSize + 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;

		DEVDataType * psDevHeader = (DEVDataType *) ((unsigned char*) psHeader + m_ulMessageHeaderSize);
		memset(psDevHeader, 0x00, m_ulDevHeaderSize);

		TimestampType * tstemp = &(psDevHeader->timestamp);
		tstemp->time = time(NULL);
		tstemp->milliseconds = 0;
		//psDevHeader->timestamp.milliseconds = 0L;
		psDevHeader->messageSource = 4;

//			fprintf(stdout,"DEVHEADERSIZE: %li\n",(unsigned long)(m_ulDevHeaderSize+m_ulMessageHeaderSize));

		if ((ulBytesInMessage > 0UL) && (ulBytesInMessage < m_ulMaxMessageLength)) {
			if (pbyMessage != NULL) {
				unsigned char *pbyDestination = ((unsigned char *) psHeader) + m_ulMessageHeaderSize + m_ulDevHeaderSize;

				memcpy(pbyDestination, pbyMessage, ulBytesInMessage);

				psHeader->byteCount = ulBytesInMessage + m_ulDevHeaderSize;
			}
		}

		return true;
	}

	return false;
}

EdgeTechMessage::EdgeTechMessage(const EdgeTechMessage &rRhs)

:
		m_ulMessageHeaderSize(sizeof(SonarMessageHeaderType)), m_ulMaxMessageLength(ulMaxEdgeTechDynamicDataSize_c), m_ulDevHeaderSize(sizeof(DEVDataType)) {

//	m_pMessageBuffer = std::auto_ptr<CBufferManager>(new CBufferManager);
	m_pMessageBuffer = (new CBufferManager);
//	assert( m_pMessageBuffer.get() != NULL);

//	*(m_pMessageBuffer.get()) = *(rRhs.m_pMessageBuffer.get());
	m_pMessageBuffer = rRhs.m_pMessageBuffer;
}

EdgeTechMessage & EdgeTechMessage::operator =(const EdgeTechMessage &rRhs) {
//	*(m_pMessageBuffer.get()) = *(rRhs.m_pMessageBuffer.get());
	m_pMessageBuffer = rRhs.m_pMessageBuffer;

	return *this;
}

unsigned char * EdgeTechMessage::Message(void) const {
//	assert( m_pMessageBuffer.get() != NULL);
//	return ((m_pMessageBuffer.get() == NULL) ?
//			NULL : m_pMessageBuffer->GetMessage());
	return m_pMessageBuffer->GetMessage();
}

unsigned short EdgeTechMessage::SonarMessage(void) const {
//	assert( m_pMessageBuffer.get() != NULL);
	return ((SonarMessageHeaderType *) m_pMessageBuffer->GetMessage())->sonarMessage;
}

unsigned char EdgeTechMessage::SonarCommand(void) const {
//	assert( m_pMessageBuffer.get() != NULL);
	return ((SonarMessageHeaderType *) m_pMessageBuffer->GetMessage())->sonarCommand;
}

unsigned char EdgeTechMessage::Subsystem(void) const {
//	assert( m_pMessageBuffer.get() != NULL);
	return ((SonarMessageHeaderType *) m_pMessageBuffer->GetMessage())->subSystem;
}

unsigned long EdgeTechMessage::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 EdgeTechMessage::HeaderSize(void) {
	return sizeof(SonarMessageHeaderType);
}

//////////////////////////////////////////////////////////////////////
// Conversion operators.

EdgeTechMessage::operator SonarMessageHeaderType *() const {
//	assert( m_pMessageBuffer.get() != NULL);
	return ((::SonarMessageHeaderType *) m_pMessageBuffer->GetMessage());
}

EdgeTechMessage::operator long() const {
	return ((long) (((::SonarMessageLongType *) OptionalData())->value));
}

EdgeTechMessage::operator unsigned long() const {
	return ((unsigned long) (((::SonarMessageLongType *) OptionalData())->value));
}

EdgeTechMessage::operator char *() const {
	return ((char *) (((::SonarMessageStringType *) OptionalData())->name));
}

EdgeTechMessage::operator SonarMessageStatusType *() const {
	return ((::SonarMessageStatusType *) OptionalData());
}

EdgeTechMessage::operator TimestampType *() const {
	return ((::TimestampType *) OptionalData());
}

EdgeTechMessage::operator SonarMessagePingType *() const {
	return ((::SonarMessagePingType *) OptionalData());
}

EdgeTechMessage::operator SonarMessageWindowType *() const {
	return ((::SonarMessageWindowType *) OptionalData());
}

EdgeTechMessage::operator SonarMessageFishType *() const {
	return ((::SonarMessageFishType *) OptionalData());
}

EdgeTechMessage::operator SegyDataType *() const {
	return ((::SegyDataType *) OptionalData());
}

EdgeTechMessage::operator SidescanHeaderType *() const {
	return ((::SidescanHeaderType *) OptionalData());
}

EdgeTechMessage::operator SonarMessageCouplingParametersType *(void) const {
	return ((::SonarMessageCouplingParametersType *) OptionalData());
}

EdgeTechMessage::operator DEVPressureType *(void) const {
	return ((::DEVPressureType *) OptionalDEVData());
}

EdgeTechMessage::operator DEVDataType*(void) const {
	return ((::DEVDataType *) OptionalData());

}

EdgeTechMessage::operator DataLoggingStatusType *(void) const {
	return ((::DataLoggingStatusType *) OptionalData());
}

inline
unsigned char * EdgeTechMessage::OptionalData(void) const {
//	assert( m_pMessageBuffer.get() != NULL);
	return (((unsigned char *) (m_pMessageBuffer->GetMessage())) + sizeof(SonarMessageHeaderType));
}

inline
unsigned char* EdgeTechMessage::OptionalDEVData(void) const {
//	assert( m_pMessageBuffer.get() != NULL);
	return (((unsigned char *) (m_pMessageBuffer->GetMessage())) + sizeof(SonarMessageHeaderType) + sizeof(DEVDataType));
}

//////////////////////////////////////////////////////////////////////
// Internal helper class EdgeTechMessage::CBufferManager implementation.

inline EdgeTechMessage::CBufferManager::CBufferManager(void) {
	m_pbyBuffer = NULL;
	m_ulBufferSize = 0UL;
	m_bIsOwner = false;
}

inline EdgeTechMessage::CBufferManager::CBufferManager(const EdgeTechMessage::CBufferManager &rRhs) {
	m_pbyBuffer = NULL;
	m_ulBufferSize = 0UL;
	m_bIsOwner = false;

	SetBuffer(rRhs.m_pbyBuffer, rRhs.m_ulBufferSize, rRhs.m_bIsOwner);
}

inline EdgeTechMessage::CBufferManager &
EdgeTechMessage::CBufferManager::operator =(const EdgeTechMessage::CBufferManager &rRhs) {
	m_pbyBuffer = NULL;
	m_ulBufferSize = 0UL;
	m_bIsOwner = false;

	SetBuffer(rRhs.m_pbyBuffer, rRhs.m_ulBufferSize, rRhs.m_bIsOwner);

	return *this;
}

inline EdgeTechMessage::CBufferManager::~CBufferManager(void) {
	Release();
}

inline
bool EdgeTechMessage::CBufferManager::SetBuffer(unsigned char *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 unsigned char[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 EdgeTechMessage::CBufferManager::Release(void) {
	if ((m_pbyBuffer != NULL) && m_bIsOwner) {
		delete[] m_pbyBuffer;
	}

	m_pbyBuffer = NULL;
	m_ulBufferSize = 0UL;
	m_bIsOwner = false;
}

inline
unsigned char * EdgeTechMessage::CBufferManager::GetMessage(void) {
	return m_pbyBuffer;
}

inline
unsigned long EdgeTechMessage::CBufferManager::MessageSize(void) const {
	return m_ulBufferSize;
}

