/*
    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"

// Qt includes
#include <qdatastream.h>
#include <qregexp.h>
#include <QByteArray>

// Kde includes
#include <kdebug.h>

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

MessageFormatter::MessageFormatter(QObject *parent) : QObject(parent)
{}

MessageFormatter::~MessageFormatter()
{}

Message MessageFormatter::readMessage(const QByteArray& stream, bool compact)
{
	Message inbound;
	
	qint32 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.
		QString messageHeader = QByteArray(stream.data(), index);

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

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

//		kDebug(14140) ;
	
		regex = QRegExp("MIME-Version: (\\d.\\d)");
		regex.indexIn(messageHeader);
		inbound.mimeVersion = regex.cap(1);
		inbound.contentType = contentType;
		regex = QRegExp("P2P-Dest: ([^\r\n]*)");
		regex.indexIn(messageHeader);
		QString destination = regex.cap(1);
	}
	
	QByteArray tempStream = stream;
	QDataStream reader( &tempStream,QIODevice::ReadOnly);
	reader.setVersion(QDataStream::Qt_3_3);
	reader.setByteOrder(QDataStream::LittleEndian);
	// Seek to the start position of the message
	// transport header.
	reader.device()->seek(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;

	/*kDebug(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.readRawData(inbound.body.data(), inbound.header.dataSize);
	}

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

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

void MessageFormatter::writeMessage(const Message& message, QByteArray& stream, bool compact)
{
//	kDebug(14140) ;

	QDataStream writer( &stream,QIODevice::WriteOnly);
	writer.setVersion(QDataStream::Qt_3_3);
	writer.setByteOrder(QDataStream::LittleEndian);

	if(compact == false)
	{
		const QByteArray messageHeader = QString("MIME-Version: 1.0\r\n"
			"Content-Type: application/x-msnmsgrp2p\r\n"
			"P2P-Dest: " + message.destination + "\r\n"
			"\r\n").toUtf8();
		// Set the capacity of the message buffer.
		stream.resize(messageHeader.length() + 48 + message.body.size() + 4);
		// Write the message header to the stream
		writer.writeRawData(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 << (qint32)(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;

/*	kDebug(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.writeRawData(message.body.data(), message.body.size());
	}

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

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

#include "messageformatter.moc"
