/*
    messageformatter.cpp - msn p2p protocol

    Copyright (c) 2005      by Gregg Edghill          <gregg.edghill@gmail.com>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "messageformatter.h"
#include "p2p.h"

// TQt includes
#include <tqdatastream.h>
#include <tqregexp.h>

// Kde includes
#include <kdebug.h>

using P2P::MessageFormatter;
using P2P::Message;

MessageFormatter::MessageFormatter(TQObject *parent, const char *name) : TQObject(parent, name)
{}

MessageFormatter::~MessageFormatter()
{}

Message MessageFormatter::readMessage(const TQByteArray& stream, bool compact)
{
	Message inbound;
	
	TQ_UINT32 index = 0;
	if(compact == false)
	{
		// Determine the end position of the message header.
		while(index < stream.size())
		{
			if(stream[index++] == '\n'){
				if(stream[index - 3] == '\n')
					break;
			}
		}

		// Retrieve the message header.
		TQString messageHeader = TQCString(stream.data(), index);

		// Retrieve the message mime version, content type,
		// and p2p destination.
		TQRegExp regex("Content-Type: ([A-Za-z0-9$!*/\\-]*)");
		regex.search(messageHeader);
		TQString contentType = regex.cap(1);

		if(contentType != "application/x-msnmsgrp2p")
			return inbound;

//		kdDebug(14140) << k_funcinfo << endl;
	
		regex = TQRegExp("MIME-Version: (\\d.\\d)");
		regex.search(messageHeader);
		inbound.mimeVersion = regex.cap(1);
		inbound.contentType = contentType;
		regex = TQRegExp("P2P-Dest: ([^\r\n]*)");
		regex.search(messageHeader);
		TQString destination = regex.cap(1);
	}
	
	TQDataStream reader(stream, IO_ReadOnly);
	reader.setByteOrder(TQDataStream::LittleEndian);
	// Seek to the start position of the message
	// transport header.
	reader.device()->at(index);

	// Read the message transport headers from the stream.
	reader >> inbound.header.sessionId;
	reader >> inbound.header.identifier;
	reader >> inbound.header.dataOffset;
	reader >> inbound.header.totalDataSize;
	reader >> inbound.header.dataSize;
	reader >> inbound.header.flag;
	reader >> inbound.header.ackSessionIdentifier;
	reader >> inbound.header.ackUniqueIdentifier;
	reader >> inbound.header.ackDataSize;

	/*kdDebug(14140)
		<< "session id, "             << inbound.header.sessionId << endl
		<< "identifier, "             << inbound.header.identifier << endl
		<< "data offset, "            << inbound.header.dataOffset << endl
		<< "total size, "             << inbound.header.totalDataSize << endl
		<< "data size, "              << inbound.header.dataSize << endl
		<< "flag, "                   << inbound.header.flag << endl
		<< "ack session identifier, " << inbound.header.ackSessionIdentifier << endl
		<< "ack unique identifier, "  << inbound.header.ackUniqueIdentifier << endl
		<< "ack data size, "          << inbound.header.ackDataSize
	<< endl;*/

	// Read the message body from the stream.
	if(inbound.header.dataSize > 0){
		inbound.body.resize(inbound.header.dataSize);
		reader.readRawBytes(inbound.body.data(), inbound.header.dataSize);
	}

	if(compact == false)
	{
		reader.setByteOrder(TQDataStream::BigEndian);
		// Read the message application identifier from the stream.
		reader >> inbound.applicationIdentifier;

/*		kdDebug(14140)
			<< "application identifier, " << inbound.applicationIdentifier
		<< endl;*/
	}
		
	return inbound;
}

void MessageFormatter::writeMessage(const Message& message, TQByteArray& stream, bool compact)
{
//	kdDebug(14140) << k_funcinfo << endl;

	TQDataStream writer(stream, IO_WriteOnly);
	writer.setByteOrder(TQDataStream::LittleEndian);

	if(compact == false)
	{
		const TQCString messageHeader = TQString("MIME-Version: 1.0\r\n"
			"Content-Type: application/x-msnmsgrp2p\r\n"
			"P2P-Dest: " + message.destination + "\r\n"
			"\r\n").utf8();
		// Set the capacity of the message buffer.
		stream.resize(messageHeader.length() + 48 + message.body.size() + 4);
		// Write the message header to the stream
		writer.writeRawBytes(messageHeader.data(), messageHeader.length());
	}
	else
	{
		// Set the capacity of the message buffer.
		stream.resize(4 + 48 + message.body.size());
		// Write the message size to the stream.
		writer << (TQ_INT32)(48+message.body.size());
	}

	
	// Write the transport headers to the stream.
	writer << message.header.sessionId;
	writer << message.header.identifier;
	writer << message.header.dataOffset;
	writer << message.header.totalDataSize;
	writer << message.header.dataSize;
	writer << message.header.flag;
	writer << message.header.ackSessionIdentifier;
	writer << message.header.ackUniqueIdentifier;
	writer << message.header.ackDataSize;

/*	kdDebug(14140)
		<< "session id, "             << message.header.sessionId << endl
		<< "identifier, "             << message.header.identifier << endl
		<< "data offset, "            << message.header.dataOffset << endl
		<< "total size, "             << message.header.totalDataSize << endl
		<< "data size, "              << message.header.dataSize << endl
		<< "flag, "                   << message.header.flag << endl
		<< "ack session identifier, " << message.header.ackSessionIdentifier << endl
		<< "ack unique identifier, "  << message.header.ackUniqueIdentifier << endl
		<< "ack data size, "          << message.header.ackDataSize
		<< endl;
*/
	if(message.body.size() > 0){
		// Write the messge body to the stream.
		writer.writeRawBytes(message.body.data(), message.body.size());
	}

	if(compact == false)
	{
		// Seek to the message application identifier section.
		writer.setByteOrder(TQDataStream::BigEndian);
		// Write the message application identifier to the stream.
		writer << message.applicationIdentifier;

/*		kdDebug(14140)
			<< "application identifier, " << message.applicationIdentifier
			<< endl;
		*/
	}
}

#include "messageformatter.moc"
