/*
    Kopete Latex Plugin

    Copyright (c) 2004 by Duncan Mac-Vicar Prett   <duncan@kde.org>
    Copyright (c) 2004-2005 by Olivier Goffart  <ogoffart@kde. org>

    Kopete    (c) 2001-2004 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * 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 <tqregexp.h>
#include <tqimage.h>
#include <tqbuffer.h>
#include <tqcstring.h>
#include <tqstylesheet.h>
#include <kgenericfactory.h>
#include <kdebug.h>
#include <tdestandarddirs.h>
#include <tdeprocess.h>
#include <tdetempfile.h>
#include <kmdcodec.h>
#include <tdemessagebox.h>

#include "kopetechatsessionmanager.h"
#include "kopeteuiglobal.h"

#include "latexplugin.h"
#include "latexconfig.h"
#include "latexguiclient.h"

#define ENCODED_IMAGE_MODE 0

typedef KGenericFactory<LatexPlugin> LatexPluginFactory;
K_EXPORT_COMPONENT_FACTORY( kopete_latex, LatexPluginFactory( "kopete_latex" )  )

LatexPlugin::LatexPlugin( TQObject *parent, const char *name, const TQStringList &/*args*/ )
: Kopete::Plugin( LatexPluginFactory::instance(), parent, name )
{
//	kdDebug() << k_funcinfo << endl;
	if( !s_pluginStatic )
		s_pluginStatic = this;

	mMagickNotFoundShown = false;
	connect( Kopete::ChatSessionManager::self(), TQ_SIGNAL( aboutToDisplay( Kopete::Message & ) ), TQ_SLOT( slotMessageAboutToShow( Kopete::Message & ) ) );
	connect( Kopete::ChatSessionManager::self(), TQ_SIGNAL( aboutToSend(Kopete::Message& )  ), this,  TQ_SLOT(slotMessageAboutToSend(Kopete::Message& )  ) );
	connect ( this , TQ_SIGNAL( settingsChanged() ) , this , TQ_SLOT( slotSettingsChanged() ) );
	connect( Kopete::ChatSessionManager::self(), TQ_SIGNAL( chatSessionCreated( Kopete::ChatSession * ) ),
			 this, TQ_SLOT( slotNewChatSession( Kopete::ChatSession * ) ) );
	
	m_convScript = TDEStandardDirs::findExe("kopete_latexconvert.sh");
	slotSettingsChanged();

		//Add GUI action to all already existing kmm (if the plugin is launched when kopete already rining)
	TQValueList<Kopete::ChatSession*> sessions = Kopete::ChatSessionManager::self()->sessions();
	for (TQValueListIterator<Kopete::ChatSession*> it= sessions.begin(); it!=sessions.end() ; ++it)
		slotNewChatSession( *it );
}

LatexPlugin::~LatexPlugin()
{
	s_pluginStatic = 0L;
}

LatexPlugin* LatexPlugin::plugin()
{
	return s_pluginStatic ;
}

LatexPlugin* LatexPlugin::s_pluginStatic = 0L;

void LatexPlugin::slotNewChatSession( Kopete::ChatSession *KMM )
{
	new LatexGUIClient( KMM );
}


void LatexPlugin::slotMessageAboutToShow( Kopete::Message& msg )
{
	TQString mMagick = TDEStandardDirs::findExe("convert");
	if ( mMagick.isEmpty() )
	{
		// show just once
		if (  !mMagickNotFoundShown )
		{
			KMessageBox::queuedMessageBox(
			    Kopete::UI::Global::mainWidget(),
			    KMessageBox::Error, i18n("I cannot find the Magick convert program.\nconvert is required to render the Latex formulas.\nPlease go to www.imagemagick.org or to your distribution site and get the right package.")
			);
			mMagickNotFoundShown = true;
		}
		// dont try to parse if convert is not installed
		return;
	}
	
	TQString messageText = msg.plainBody();
	if( !messageText.contains("$$"))
		return;

	//kdDebug() << k_funcinfo << " Using converter: " << m_convScript << endl;

	// /\[([^]]).*?\[/$1\]/
	// \$\$.+?\$\$
	
	// this searches for $$formula$$ 
	TQRegExp rg("\\$\\$.+\\$\\$");
	rg.setMinimal(true);
	// this searches for [latex]formula[/latex]
	//TQRegExp rg("\\[([^]\]).*?\\[/$1\\]");
	
	int pos = 0;
	
	TQMap<TQString, TQString> replaceMap;
	while (pos >= 0 && (unsigned int)pos < messageText.length())
	{
//		kdDebug() << k_funcinfo  << " searching pos: " << pos << endl;
		pos = rg.search(messageText, pos);
		
		if (pos >= 0 )
		{
			TQString match = rg.cap(0);
			pos += rg.matchedLength();

			TQString formul=match;
			if(!securityCheck(formul))
				continue;
			
			TQString fileName=handleLatex(formul.replace("$$",""));
			
			// get the image and encode it with base64
			#if ENCODED_IMAGE_MODE
			TQImage renderedImage( fileName );
			imagePxWidth = renderedImage.width();
			imagePxHeight = renderedImage.height();
			if ( !renderedImage.isNull() )
			{
				TQByteArray ba;
				TQBuffer buffer( ba );
				buffer.open( IO_WriteOnly );
				renderedImage.save( &buffer, "PNG" );
				TQString imageURL = TQString::fromLatin1("data:image/png;base64,%1").arg( KCodecs::base64Encode( ba ) );
				replaceMap[match] = imageURL;
			}
			#else
			replaceMap[match] = fileName;
			#endif
		}
	}

	if(replaceMap.isEmpty()) //we haven't found any latex strings
		return;

	messageText= msg.escapedBody();

	int imagePxWidth,imagePxHeight;
	for (TQMap<TQString,TQString>::ConstIterator it = replaceMap.begin(); it != replaceMap.end(); ++it)
	{
		TQImage theImage(*it);
		if(theImage.isNull())
			continue;
		imagePxWidth = theImage.width();
		imagePxHeight = theImage.height();
		TQString escapedLATEX=TQStyleSheet::escape(it.key()).replace("\"","&quot;");  //we need  the escape quotes because that string will be in a title="" argument, but not the \n
		messageText.replace(Kopete::Message::escape(it.key()), " <img width=\"" + TQString::number(imagePxWidth) + "\" height=\"" + TQString::number(imagePxHeight) + "\" src=\"" + (*it) + "\"  alt=\"" + escapedLATEX +"\" title=\"" + escapedLATEX +"\"  /> ");
	}

	msg.setBody( messageText, Kopete::Message::RichText );
}


void LatexPlugin::slotMessageAboutToSend( Kopete::Message& msg)
{
	Q_UNUSED(msg)
	//disabled because to work correctly, we need to find what special has the gif we can send over MSN
#if 0
	TDEConfig *config = TDEGlobal::config();
	config->setGroup("Latex Plugin");

	if(!config->readBoolEntry("ParseOutgoing", false))
		return;

	TQString messageText = msg.plainBody();
	if( !messageText.contains("$$"))
		return;
/*	if( msg.from()->protocol()->pluginId()!="MSNProtocol" )
	return;*/

	// this searches for $$formula$$
	TQRegExp rg("^\\s*\\$\\$([^$]+)\\$\\$\\s*$");

	if( rg.search(messageText) != -1 )
	{
		TQString latexFormula = rg.cap(1);
		if(!securityCheck( latexFormula ))
			return;

		TQString url = handleLatex(latexFormula);


		if(!url.isNull())
		{
			TQString escapedLATEX= TQStyleSheet::escape(messageText).replace("\"","&quot;");
			TQString messageText="<img src=\"" + url + "\" alt=\"" + escapedLATEX + "\" title=\"" + escapedLATEX +"\"  />";
			msg.setBody( messageText, Kopete::Message::RichText );
		}
	}
#endif
}

TQString LatexPlugin::handleLatex(const TQString &latexFormula)
{
	KTempFile *tempFile=new KTempFile( locateLocal( "tmp", "kopetelatex-" ), ".png" );
	tempFile->setAutoDelete(true);
	m_tempFiles.append(tempFile);
	m_tempFiles.setAutoDelete(true);
	TQString fileName = tempFile->name();

	TDEProcess p;
			
	TQString argumentRes = "-r %1x%2";
	TQString argumentOut = "-o %1";
	//TQString argumentFormat = "-fgif";  //we uses gif format because MSN only handle gif
	int hDPI, vDPI;
	hDPI = LatexConfig::self()->horizontalDPI();
	vDPI = LatexConfig::self()->verticalDPI();
	p << m_convScript <<  argumentRes.arg(TQString::number(hDPI), TQString::number(vDPI)) << argumentOut.arg(fileName) /*<< argumentFormat*/ << latexFormula  ;
			
	kdDebug() << k_funcinfo  << " Rendering " << m_convScript << " " <<  argumentRes.arg(TQString::number(hDPI), TQString::number(vDPI)) << " " << argumentOut.arg(fileName) << endl;
			
	// FIXME our sucky sync filter API limitations :-)
	p.start(TDEProcess::Block);
	return fileName;
}

bool LatexPlugin::securityCheck(const TQString &latexFormula)
{
	return !latexFormula.contains(TQRegExp("\\\\(def|let|futurelet|newcommand|renewcomment|else|fi|write|input|include"
			"|chardef|catcode|makeatletter|noexpand|toksdef|every|errhelp|errorstopmode|scrollmode|nonstopmode|batchmode"
			"|read|csname|newhelp|relax|afterground|afterassignment|expandafter|noexpand|special|command|loop|repeat|toks"
			"|output|line|mathcode|name|item|section|mbox|DeclareRobustCommand)[^a-zA-Z]"));

}

void LatexPlugin::slotSettingsChanged()
{
	LatexConfig::self()->readConfig();
}

#include "latexplugin.moc"
