/*******************************************************************************
 * Copyright (c) 2005, 2009 IBM, Intel Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Guru Nagarajan, Intel - initial API and implementation
 *    IBM - Initial Java API and implementation
 *
 * $Id: Message.cpp,v 1.12 2009/08/26 14:59:51 jwest Exp $
 *
 *******************************************************************************/ 

#include <string>
#include <string.h>
#include <stdlib.h>
#include "tptp/client/Message.h"
#include "tptp/client/Constants.h"
#include "tptp/NoLog.h"


using namespace std;


Message::Message()
{
	this->_magicNumber = 0;
	/* The protocol version number */
	this->_version=Constants::RA_VERSION;

	/* Length of the message */
	this->_type=1;

	/* The ticket number of the message */
	this->_ticket=0;

	/* For New AC Message - Flags */
	this->_flags = 0;

	/* Message Type */
	this->_messageType = Constants::NEW_AC_MESSAGE;//Old RAC Format- OLD_RAC_MESSAGE(1), New RAC Format - NEW_AC_MESSAGE(2)

	/* MD5 Flag */
	this->_md5Flag = NULL;

	TPTP_LOG_DEBUG_MSG1("The Message Type - %ld", this->_messageType);
}


Message::~Message()
{

}

unsigned int Message::getSize()
{
	if(this->_messageType == Constants::OLD_RAC_MESSAGE)
		return 4*Constants::sizeofLong;
	else if (this->_messageType == Constants::NEW_AC_MESSAGE)
		return 3*Constants::sizeofLong;
	else return 0;
}

unsigned long Message::getTicket()
{	
	return this->_ticket;
}

unsigned long Message::getType()  
{	
	return this->_type;
}

unsigned long Message::getVersion()
{
	return this->_version;
}

unsigned long Message::getMessageType()
{
	return this->_messageType;
}

unsigned long Message::getFlags()
{
	return this->_flags;
}

void Message::setMagicNumber(unsigned long magicNumber)
{
	this->_magicNumber = magicNumber;
}

void Message::setTicket(unsigned long ticket)
{
	this->_ticket = ticket;
}

void Message::setVersion(unsigned long version)
{
	this->_version = version;
}

void Message::setMessageType(unsigned int messageType)
{
	this->_messageType = messageType;
}

void Message::setFlags(unsigned long flags)
{
	this->_flags = flags;
}


unsigned char* Message::readFromBuffer(unsigned char *buffer,unsigned int data)
{
	//unsigned int current = data;
	unsigned char *currentdata;
	currentdata = buffer;
	unsigned int intt = 0;

	#if (defined(__linux__) && defined(__s390__)) || defined(_SOLARIS) || defined(_AIX) || defined(MVS)
		currentdata = Message::readTPTPUINTFromBuffer(currentdata, (unsigned int*)&intt);
		_magicNumber  = intt;
	#else
		currentdata = Message::readTPTPUINTFromBuffer(currentdata, (unsigned int*)&_magicNumber);
	#endif

	TPTP_LOG_DEBUG_MSG1("Currentdata - %s", currentdata);
	
	if (this->_magicNumber == Constants::AC_MAGIC_NUMBER)
	{
		this->_messageType = Constants::NEW_AC_MESSAGE;
		
	}
	else if (this->_magicNumber == Constants::RA_MAGIC)
	{
		this->_messageType = Constants::OLD_RAC_MESSAGE;
	}

	/* version */
	if (this->_messageType == Constants::OLD_RAC_MESSAGE)
	{
		#if (defined(__linux__) && defined(__s390__)) || defined(_SOLARIS) || defined(_AIX) || defined(MVS)
			currentdata = Message::readTPTPUINTFromBuffer(currentdata, (unsigned int*)&intt);
			_version = intt;
		#else
			currentdata = Message::readTPTPUINTFromBuffer(currentdata, (unsigned int*)&_version);
		#endif
		//currentdata +=4;
	}

	if (this->_messageType == Constants::NEW_AC_MESSAGE)
	{		
		#if (defined(__linux__) && defined(__s390__)) || defined(_SOLARIS) || defined(_AIX) || defined(MVS)
			currentdata = Message::readTPTPUINTFromBuffer(currentdata, (unsigned int*)&intt);
			_flags = intt;
		#else
			currentdata = Message::readTPTPUINTFromBuffer(currentdata, (unsigned int*)&_flags);
		#endif
		//current +=4;
	}


	if (this->_messageType == Constants::OLD_RAC_MESSAGE)
	{
		#if (defined(__linux__) && defined(__s390__)) || defined(_SOLARIS) || defined(_AIX) || defined(MVS)
			currentdata=Message::readTPTPUINTFromBuffer(currentdata,(unsigned int*)&intt);
			_type = intt;
		#else
			currentdata=Message::readTPTPUINTFromBuffer(currentdata,(unsigned int*)&_type);
		#endif
		
		#if (defined(__linux__) && defined(__s390__)) || defined(_SOLARIS) || defined(_AIX) || defined(MVS)
			currentdata=Message::readTPTPUINTFromBuffer(currentdata,(unsigned int*)&intt);
			_ticket = intt;
		#else
			currentdata=Message::readTPTPUINTFromBuffer(currentdata,(unsigned int*)&_ticket);
		#endif
	}

	return currentdata;
}
 

unsigned char* Message::writeToBuffer(unsigned char* buffer,unsigned int data)
{
	//unsigned int current = data;
	unsigned char *currentdata = buffer;
	
	currentdata = Message::copyTPTPUINTToBuffer(currentdata, Message::_magicNumber);
	
	if (this->_messageType == Constants::OLD_RAC_MESSAGE)
	{
		currentdata = Message::copyTPTPUINTToBuffer(currentdata, Constants::RA_VERSION);
	}

	if (this->_messageType == Constants::NEW_AC_MESSAGE)
	{
		currentdata = Message::copyTPTPUINTToBuffer(currentdata,this->_flags);
	}

	if (this->_messageType == Constants::OLD_RAC_MESSAGE)
	{
		currentdata=Message::copyTPTPUINTToBuffer(currentdata, this->_type);
		currentdata=Message::copyTPTPUINTToBuffer(currentdata, this->_ticket);
	}

	return currentdata;
}


unsigned char* Message::copyTPTPUINTToBuffer(unsigned char *buffer, unsigned int input) 
{
	buffer[0]=(unsigned char)(input>>24 & 0x000000ff);
	buffer[1]=(unsigned char)(input>>16 & 0x000000ff);
	buffer[2]=(unsigned char)(input>>8  & 0x000000ff);
	buffer[3]=(unsigned char)input;
	
	return &buffer[4];
}

unsigned char* Message::readTPTPUINTFromBuffer(unsigned char *buffer, unsigned int* input)
{
	*input=((unsigned int)(buffer[0]<<24)
		   |(unsigned int)(buffer[1]<<16)
		   |(unsigned int)(buffer[2]<<8 )
		   | buffer[3]);

	return &buffer[sizeof(unsigned int)];
}

unsigned char* Message::copyTPTPSTRINGToBuffer(unsigned char *buffer, string stringData) 
{
	
	int length = 0;
	if(stringData.empty())
	{ 
		length = 0;
	}
	else 
	{ 
		length = stringData.length();
	}
	/*
	unsigned int padding= 4 - (length)%4;
	if(padding==4) {padding=0;}
	*/

	//Message::copyTPTPUINTToBuffer(buffer,length);
		
	memcpy(buffer, stringData.c_str(), length);
	return buffer;
}

unsigned char* Message::readTPTPSTRINGFromBuffer(unsigned char *buffer, string newString)
{
	unsigned int padding = 0;
	int length = 0;
	if ( newString.empty())
	{
		length = 0;
	}
	else 
	{ 
		length = newString.length();
	}
	
	Message::readTPTPUINTFromBuffer(buffer, (unsigned int*)&length);

	char *tempbuf;
	tempbuf =(char *)malloc(length + 1);
	memcpy(tempbuf, &buffer[4], length);
	newString = tempbuf;
	TPTP_LOG_DEBUG_MSG1("Copy temp %s", tempbuf);
	padding=4-(length)%4;
	if(padding==4){ padding=0; }
	
	free(tempbuf);
    //cout<<"TPTPStringFromBuffer"<<&buffer[sizeof(unsigned int)+length+padding]<<endl;
	return &buffer[sizeof(unsigned int)+length+padding];
}

	
unsigned char* Message::copyTPTPBinaryArrayToBuffer(unsigned char *buffer, string binaryData)
{
	unsigned int padding=4-(binaryData.length())%4;
	if(padding==4) 
	{
		padding=0;
	}
	int length = 0;
	if(binaryData.empty())
	{ 
		length = 0;
	}
	else 
	{ 
		length = binaryData.length();
	}
	
	Message::copyTPTPUINTToBuffer(buffer, length);
	memcpy(&buffer[4], binaryData.c_str(), length);

	return &buffer[sizeof(unsigned int)+ length+padding];
}

unsigned char* Message::readTPTPBinaryArrayFromBuffer(unsigned char *buffer,string newArray)
{
	unsigned int padding = 0;
	int length = 0;
	if(newArray.empty())
	{ 
		length = 0;
	}
	else 
	{ 
		length = newArray.length();
	}
	
	Message::readTPTPUINTFromBuffer(buffer, (unsigned int*)&length);
		
	char *temp;
	temp = (char *)malloc(length +1);
	memcpy(temp, &buffer[4], length);

	newArray = temp;
	free(temp);
	
	padding=4-(0)%4;
	if(padding==4) 
	{
		padding=0;
	}
	
	return &buffer[sizeof(unsigned int)+ length + padding];
}


unsigned char* Message::writeTPTPInetAddressToBuffer()
{
	return (unsigned char *)"a";
}


unsigned char* Message::readTPTPInetAddressToBuffer()
{
	return (unsigned char*)"a";
}


