// -*- Mode: c++-mode; c-basic-offset: 2; indent-tabs-mode: t; tab-width: 2; -*-
//
// Copyright (C) 2004 Grzegorz Jaskiewicz <gj at pointblue.com.pl>
//
// gadurichtextformat.cpp
//
// 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.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
// 02110-1301, USA.

#include <knotifyclient.h>
#include <kdebug.h>
#include <kopetemessage.h>

#include "gadurichtextformat.h"
#include "gadusession.h"

#include <tqstring.h>
#include <tqregexp.h>

GaduRichTextFormat::GaduRichTextFormat()
{
}

GaduRichTextFormat::~GaduRichTextFormat()
{
}

TQString
GaduRichTextFormat::convertToHtml( const TQString& msg, unsigned int formats, void* formatStructure)
{
	TQString tmp, nb;
	gg_msg_richtext_format *format;
	char *pointer = (char*) formatStructure;

	unsigned int i,j;
	int r, g, b;
	r = g = b = 0;
	bool opened = false;

	if ( formatStructure == NULL || formats == 0 ) {
		tmp = msg;
		escapeBody( tmp );
		return tmp;
	}

	for ( i = 0, j = 0 ; i < formats ; ) {
		format = (gg_msg_richtext_format*) pointer;
		unsigned int position = format->position;
		char font = format->font;
		TQString style;

		if ( position < j || position > msg.length() ) {
			break;
		}

		if ( font & GG_FONT_IMAGE ) {
			i += sizeof( gg_msg_richtext_image );
			pointer += sizeof( gg_msg_richtext_image );
			tmp += "<b>[this should be a picture, not yet implemented]</b>";
		}
		else {
			nb = msg.mid( j, position - j );
			tmp += escapeBody( nb );

			j = position;

			// add message bit between formating
			if ( opened ) {
				tmp += formatClosingTag("span");
				opened = false;
			}
			// set font attributes
			if ( font & GG_FONT_BOLD ) {
				style += (" font-weight:bold; ");
			}
			if ( font & GG_FONT_ITALIC ) {
				style += (" font-style:italic; ");
			}
			if ( font & GG_FONT_UNDERLINE ) {
				style += (" text-decoration:underline; ");
			}
			// add color
			if ( font & GG_FONT_COLOR ) {
				pointer += sizeof( gg_msg_richtext_format );
				i += sizeof( gg_msg_richtext_format );
				gg_msg_richtext_color *color = (gg_msg_richtext_color*)( pointer );
				r = (int)color->red;
				g = (int)color->green;
				b = (int)color->blue;
			}
			style += TQString(" color: rgb( %1, %2, %3 ); ").arg( r ).arg( g ).arg( b );

			tmp += formatOpeningTag( TQString::fromLatin1("span"), TQString::fromLatin1("style=\"%1\"").arg( style ) );
			opened = true;

		}

		// advance to next structure in row
		pointer += sizeof( gg_msg_richtext_format );
		i += sizeof( gg_msg_richtext_format );
	}

	nb = msg.mid( j, msg.length() );
	tmp += escapeBody( nb );
	if ( opened ) {
		tmp += formatClosingTag("span");
	}

	return tmp;
}

TQString
GaduRichTextFormat::formatOpeningTag( const TQString& tag, const TQString& attributes )
{
	TQString res = "<" + tag;
	if(!attributes.isEmpty())
		res.append(" " + attributes);
	return res + ">";
}

TQString
GaduRichTextFormat::formatClosingTag( const TQString& tag )
{
	return "</" + tag + ">";
}

// the initial idea stolen from IRC plugin
KGaduMessage*
GaduRichTextFormat::convertToGaduMessage( const Kopete::Message& message )
{
	TQString htmlString = message.escapedBody();
	KGaduMessage* output = new KGaduMessage;
	rtcs.blue  = rtcs.green = rtcs.red = 0;
	color = TQColor();
	int position = 0;

	rtf.resize( sizeof( gg_msg_richtext) );
	output->rtf.resize(0);

	// test first if there is any HTML formating in it
	if( htmlString.find( TQString::fromLatin1("</span") ) > -1 ) {
		TQRegExp findTags( TQString::fromLatin1("<span style=\"(.*)\">(.*)</span>") );
		findTags.setMinimal( true );
		int pos = 0;
		int lastpos = 0;

		while ( pos >= 0 ){
			pos = findTags.search( htmlString );
			rtfs.font = 0;
			if ( pos != lastpos ) {
				TQString tmp;
				if ( pos < 0 ) {
					tmp = htmlString.mid( lastpos );
				}
				else {
					tmp = htmlString.mid( lastpos, pos - lastpos );
				}
				if ( !tmp.isEmpty() ) {
					color.setRgb( 0, 0, 0 );
					if ( insertRtf( position ) == false ) {
						delete output;
						return NULL;
					}
					tmp = unescapeGaduMessage( tmp );
					output->message += tmp;
					position += tmp.length();
				}
			}

			if ( pos > -1 ) {
				TQString styleHTML = findTags.cap(1);
				TQString replacement = findTags.cap(2);
				TQStringList styleAttrs = TQStringList::split( ';', styleHTML );
				rtfs.font = 0;

				lastpos = pos + replacement.length();

				for( TQStringList::Iterator attrPair = styleAttrs.begin(); attrPair != styleAttrs.end(); ++attrPair ) {
					TQString attribute = (*attrPair).section(':',0,0);
					TQString value = (*attrPair).section(':',1);
					parseAttributes( attribute, value );
				}

				if ( insertRtf( position ) == false ) {
					delete output;
					return NULL;
				}

				TQString rep = TQString("<span style=\"%1\">%2</span>" ).arg( styleHTML ).arg( replacement );
				htmlString.replace( findTags.pos( 0 ), rep.length(), replacement );

				replacement = unescapeGaduMessage( replacement );
				output->message += replacement;
				position += replacement.length();
			}

		}
		output->rtf = rtf;
		// this is sick, but that's the way libgadu is designed
		// here I am adding network header !, should sit in libgadu IMO
		header = (gg_msg_richtext*) output->rtf.data();
		header->length = output->rtf.size() - sizeof( gg_msg_richtext );
		header->flag = 2;
	}
	else {
		output->message = message.escapedBody();
		output->message = unescapeGaduMessage( output->message );
	}

	return output;

}

void
GaduRichTextFormat::parseAttributes( const TQString attribute, const TQString value )
{
	if( attribute == TQString::fromLatin1("color") ) {
		color.setNamedColor( value );
	}
	if( attribute == TQString::fromLatin1("font-weight") && value == TQString::fromLatin1("600") ) {
		rtfs.font |= GG_FONT_BOLD;
	}
	if( attribute == TQString::fromLatin1("text-decoration")  && value == TQString::fromLatin1("underline") ) {
		rtfs.font |= GG_FONT_UNDERLINE ;
	}
	if( attribute == TQString::fromLatin1("font-style")  && value == TQString::fromLatin1("italic") ) {
		rtfs.font |= GG_FONT_ITALIC;
	}
}

TQString
GaduRichTextFormat::unescapeGaduMessage( TQString& ns )
{
	TQString s;
	s = Kopete::Message::unescape( ns );
	s.replace( TQString::fromAscii( "\n" ), TQString::fromAscii( "\r\n" ) );
	return s;
}

bool
GaduRichTextFormat::insertRtf( uint position)
{
	if ( color != TQColor( rtcs.red, rtcs.green, rtcs.blue ) ) {
		rtcs.red   = color.red();
		rtcs.green = color.green();
		rtcs.blue  = color.blue();
		rtfs.font |= GG_FONT_COLOR;
	}

	if ( rtfs.font ) {
		// append font description
		rtfs.position = position;
		uint csize = rtf.size();
		if ( rtf.resize( csize + sizeof( gg_msg_richtext_format ) ) == FALSE ) {
			return false;
		};
		memcpy( rtf.data()  + csize, &rtfs, sizeof( rtfs ) );
		// append color description, if color has changed
		if ( rtfs.font & GG_FONT_COLOR ) {
			csize = rtf.size();
			if ( rtf.resize( csize + sizeof( gg_msg_richtext_color ) ) == FALSE ) {
				return false;
			};
			memcpy( rtf.data() + csize, &rtcs, sizeof( rtcs ) );
		}
	}
	return true;
}

TQString
GaduRichTextFormat::escapeBody( TQString& input )
{
	input.replace( '<', TQString::fromLatin1("&lt;") );
	input.replace( '>', TQString::fromLatin1("&gt;") );
	input.replace( '\n', TQString::fromLatin1( "<br />" ) );
	input.replace( '\t', TQString::fromLatin1( "&nbsp;&nbsp;&nbsp;&nbsp;" ) );
	input.replace( TQRegExp( TQString::fromLatin1( "\\s\\s" ) ), TQString::fromLatin1( " &nbsp;" ) );
	return input;
}