#include "ModemMessage.h"
#include "Exception.h"
#include <time.h>

int iNumModemMessages = 0;
int iMessageTotal = 0;

//////////////////////////////////////
// ModemMessage implementation

ModemMessage::ModemMessage(const char* buffer)
{
    ++iNumModemMessages;
    ++iMessageTotal;

    // We have a message to parse
    pcParse(buffer);
}

ModemMessage::ModemMessage(const ModemMessage* pMM)
{
    ++iNumModemMessages;
    ++iMessageTotal;
   
    char *buffer = new char[pMM->nBinaryBytes()];
    // perhaps a little inefficient, but hey, you shouldn't be doing this often
    pMM->pcUnparse(buffer);
    pcParse(buffer);
    delete[] buffer;
}

ModemMessage::ModemMessage(const MMConvertible* pMMC)
{
    ++iNumModemMessages;
    ++iMessageTotal;
  
    // use subclassed pcWrite
    char buffer[iMAX_MESSAGE_SIZE];
    char * pcEnd = pMMC->pcWrite(buffer);
    
    // use subclassed tGetMessageType
    _type = pMMC->tGetMessageType();
    _iBufferLength = pcEnd - buffer;
    
    Assert(pcEnd - buffer < iMAX_MESSAGE_SIZE);
    // Everything is done, now copy in the data.
    _pcBuffer = new char[pcEnd - buffer];
    memcpy(_pcBuffer, buffer, pcEnd - buffer);
}



ModemMessage::~ModemMessage()
{
    iNumModemMessages--;
    Assert(iNumModemMessages >= 0);

    //    fprintf(stderr,"destroying mm, num outstanding %d\n",iNumModemMessages);

    if (_pcBuffer)
	{
	    delete[] _pcBuffer;
	    //	    char* pc = _pcBuffer;
	    //	    _pcBuffer = 0;
	    //	    delete[] pc;
	}
}


void ModemMessage::pcParse(const char *buffer) {
    char c;

    // _type
    buffer = pcRead(buffer, &c);
    _type = Type(c);
    
	// _iBufferLength
    buffer = pcRead(buffer, &_iBufferLength);
    
    // Is our size valid?
    Assert(_iBufferLength > 0 && _iBufferLength < iMAX_MESSAGE_SIZE);
    
    // _pcBuffer
    _pcBuffer = new char[_iBufferLength];
    Assert(_pcBuffer);
    
    // Everything is done, now copy in the data.
    memcpy(_pcBuffer, buffer, _iBufferLength);
}


char* ModemMessage::pcUnparse(char* buffer) const
{
    // _type
    char c = getType();
    buffer = ::pcWrite(buffer, c);
    
    // _iBufferLength
    buffer = ::pcWrite(buffer, _iBufferLength);
    
    // _pcBuffer
    memcpy(buffer, _pcBuffer, _iBufferLength);
    return buffer + getBufferSize();
}


int ModemMessage::nBinaryBytes() const
{
    // ACK? byte plus size int plus data
    int iRet =  sizeof(char)        //  type
	+ sizeof(int) // buffer size data
	+ getBufferSize(); // actual data
    
    
    Assert(iRet < iMAX_MESSAGE_SIZE);
    //printf("This message is %d bytes\n", iRet);
    return iRet;
}
