/***************************************************************************
 *   Copyright (C) 2004, 2005 Thomas Nagy                                  *
 *   tnagy2^8@yahoo.fr                                                     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License version 2        *
 *   as published by the Free Software Foundation (see COPYING)            *
 *                                                                         *
 *   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.                          *
 ***************************************************************************/

#include <qdir.h>
#include <qfile.h>
#include <qtextstream.h>
#include <qmap.h>
#include <qpixmap.h>
#include <qregexp.h>
#include <qxml.h>

#include <kglobal.h>
#include <kio/job.h>
#include <kio/netaccess.h>
#include <kzip.h>
#include <kurl.h>
#include <klocale.h>
#include <kdebug.h>
#include <ktempdir.h>
#include <kgenericfactory.h>

#include "aux.h"
#include "DItem.h"
#include "DDataControl.h"
#include "DDataItem.h"

#include "kdissOOOdoc.h"

class richtext2oodoc : public QXmlDefaultHandler
{
        public:
                richtext2oodoc() : QXmlDefaultHandler() {}
                ~richtext2oodoc() {}

                bool startDocument();
                bool startElement( const QString&, const QString&, const QString& , const QXmlAttributes& );
                bool endElement( const QString&, const QString&, const QString& );
                bool characters( const QString& s);
                const QString& stringRead() { return m_result; }


        private:
                int styleCode();

                QString m_result;
                bool m_inparagraph;
                bool m_inbullet;
                bool m_inspan;

                bool m_isbold;
                bool m_isitalic;
                bool m_isunderline;

                QString m_str;
};

bool richtext2oodoc::startDocument()
{
        m_inbullet = false;
        m_inparagraph = false;
        m_inspan = false;
        return true;
}

bool richtext2oodoc::startElement( const QString&, const QString&, const QString& qName, const QXmlAttributes& atts )
{
        if (qName == "ul")
        {
		m_result += "<text:unordered-list text:style-name=\"L2\">\n";
                m_inbullet = true;
        }
        else if (qName == "p")
        {
                m_result += "<text:p text:style-name=\"Standard\">";
                m_str = QString::null;
                m_inparagraph = true;
        }
	else if (qName == "li")
	{
		m_result += "<text:list-item>\n";
		m_result += "<text:p text:style-name=\"Standard\">";
		m_str = QString::null;
	}
        else if (qName == "span")
        {
                QString style = atts.value("style");

                m_isbold=false;
                m_isitalic=false;
                m_isunderline=false;

                QStringList styleatts = QStringList::split(";", style);
                for (unsigned int i=0; i<styleatts.count(); ++i)
                {
                        QStringList pair = QStringList::split(":", styleatts[i]);
                        if (pair.count() == 2)
                        {
                                QString key = pair[0];
                                QString val = pair[1];

                                if (key == "font-style")
                                {
                                        if (val == "italic") m_isitalic = true;
                                        // else kdWarning()<<"don't know how to handle font-style "<<val<<endl;
                                }
                                else if (key == "font-weight")
                                {
                                        m_isbold = true;
                                }
                                else if (key == "text-decoration")
                                {
                                        if (val == "underline") m_isunderline = true;
                                        // else kdWarning()<<"don't know how to handle text-decoration "<<val<<endl;
                                }
                        }
                }

                if (m_inparagraph)
                {
                        m_result += DDataItem::protectXML(m_str);
                        m_str = QString::null;
                        m_result += "<text:span text:style-name=\"T"+QString::number(styleCode())+"\">";
                }
                else if (m_inbullet)
                {
			m_result += DDataItem::protectXML(m_str);
			m_str = QString::null;
			m_result += "<text:span text:style-name=\"T"+QString::number(styleCode())+"\">";
                }
                m_inspan = true;
        }
        return true;
}

bool richtext2oodoc::endElement( const QString&, const QString&, const QString& qName )
{
        if (qName == "ul")
        {
		m_result += "</text:unordered-list>\n";
                m_inbullet = false;
        }
	else if (qName == "li")
	{
		m_result += DDataItem::protectXML( m_str );
		m_result += "</text:p>\n";
		m_result += "</text:list-item>\n";
		m_str = QString::null;
	}
        else if (qName == "p")
        {
                m_inparagraph = false;
                m_result += DDataItem::protectXML( m_str );
                m_str = QString::null;
                m_result += "</text:p>\n";
        }
        else if (qName == "span")
        {
		m_inspan = false;
                if (m_inparagraph)
                {
                        m_result += DDataItem::protectXML( m_str );
                        m_str=QString::null;
                        m_result += "</text:span>\n";
                }
                else if (m_inbullet)
                {
			m_result += DDataItem::protectXML( m_str );
			m_str=QString::null;
			m_result += "</text:span>\n";
                }
        }
        else if (qName == "br")
        {
                if (m_inparagraph)
                {
                        if (m_inspan)
                        {
                                m_result += DDataItem::protectXML(m_str);
                                m_str=QString::null;
                                m_result += "</text:span>";
                                m_result += "</text:p>\n";
                                m_result += "<text:p text:style-name=\"Standard\">";
                                m_result += "<text:span text:style-name=\"T"+QString::number(styleCode())+"\">";
                        }
			else
			{
				m_result += DDataItem::protectXML(m_str);
				m_result += "</text:p>\n";
				m_result += "<text:p text:style-name=\"Standard\">";
				m_str=QString::null;
			}
		}
		else if (m_inbullet)
		{
			// TODO : nothing to do here ?
			/*m_result += DDataItem::protectXML(m_str);
			  m_str=QString::null;
			  m_result += "</text:span>";
			  m_result += "</text:p>\n";
			  m_result += "<text:p text:style-name=\"Standard\">";
			  m_result += "<text:span text:style-name=\"T"+QString::number(styleCode())+"\">";*/
		}
        }

        return true;
}

bool richtext2oodoc::characters( const QString& s)
{
        m_str += s;
        return true;
}

int richtext2oodoc::styleCode()
{
        int style = 2;
        if (m_isbold)
        {
                if (m_isitalic)
                {
                        if (m_isunderline) style = 8;
                        else style = 5;
                }
                else if (m_isunderline)
                {
                        style = 6;
                }
                else
                {
                        style = 2;
                }
        }
        else if (m_isitalic)
        {
                if (m_isunderline) style = 7;
                else style = 3;
        }
        else if (m_isunderline)
        {
                style = 4;
        }
        return style;
}

K_EXPORT_COMPONENT_FACTORY(libkdissOOOdoc, kdissOOOdocFactory) 
	QObject *kdissOOOdocFactory::createObject(QObject *, const char *, const char *, const QStringList &) { return new kdissOOOdoc; }

	static const int maxpicsize = 700;

const QString kdissOOOdoc::identifikation()
{
	return "kdissOOOdoc";
}

const QString kdissOOOdoc::fullName()
{
	return i18n("Text document");
}

const QString kdissOOOdoc::group()
{
	return i18n("OpenOffice.org");
}

const QString kdissOOOdoc::description()
{
	return i18n("This template generates a simple OpenOffice.org document that can be viewed using any OpenOffice.org file format reader like OpenOffice.org writer or kword");
}

const QString kdissOOOdoc::quickstart()
{
	return i18n("Go into the directory created and open the .sxw file generated with oowriter or kword\n");
}

void kdissOOOdoc::outputData(DDataItem* item, QTextStream & s, int level)
{
	// links
	for (unsigned int i=0; i<item->m_urllist.count(); i++)
	{
		QString url = DDataItem::protectXML(item->m_urllist[i].m_url);
		QString caption = DDataItem::protectXML(item->m_urllist[i].m_caption);

		if (!caption.length()) caption = url;

		s<<"<text:p text:style-name=\"Standard\">";
		s<<"<text:a xlink:type=\"simple\" xlink:href=\"";
		s<<url;
		s<<"\">"<<caption<<"</text:a>\n";
		s<<"</text:p>\n";
	}

	// print the comment
	if (item->m_comment.length()>0)
	{
		s<<"<text:p text:style-name=\"P11\">";
		s<<DDataItem::protectXML(item->m_comment);
		s<<"</text:p>\n";
	}

	// process the picture
	if (!item->m_pix.isNull())
	{
		//s<<"<text:p text:style-name=\"P"<<level<<"\">\n";
		s<<"<text:p text:style-name=\"P8\">\n";
		s<<"<draw:text-box draw:style-name=\"fr1\" draw:name=\"Cadre1\" text:anchor-type=\"paragraph\" svg:x=\"1.48cm\" svg:y=\"0.226cm\" svg:width=\"5.606cm\" fo:min-height=\"3.605cm\" draw:z-index=\"0\">\n";

		s<<"<text:p text:style-name=\"Illustration\">\n";

		// TODO: set the size of the picture ..
		s<<"<draw:image draw:style-name=\"fr2\" draw:name=\"Image1\" text:anchor-type=\"paragraph\" svg:x=\"0.004cm\" svg:y=\"0.002cm\" svg:width=\"5.606cm\" style:rel-width=\"100%\" svg:height=\"3.605cm\" style:rel-height=\"scale\" draw:z-index=\"1\" xlink:href=\""<<"#Pictures/"<<item->m_picfilename<<"\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\"/>Illustration <text:sequence text:ref-name=\"refIllustration0\" text:name=\"Illustration\" text:formula=\"Illustration+1\" style:num-format=\"1\">1</text:sequence>: "<<DDataItem::protectXML(item->m_piccaption)<<"</text:p>";

		s<<"</draw:text-box>\n";
		s<<"</text:p>\n";
	}	
}

QString convertToOOOdoc(const QString & str)
{
	QString thing = str;

	richtext2oodoc handler;
	QXmlInputSource source;
	source.setData( str );
	QXmlSimpleReader reader;
	reader.setContentHandler( &handler );
	bool result = reader.parse( source );

	if (result) return handler.stringRead();
	else return QString::null;
}

void printlevel_listitem( QTextStream & s, int level, bool begin )
{
	for (int i=0; i<level; i++)
	{
		if (begin)
		{
			s<<"<text:ordered-list text:style-name=\"L1\" text:continue-numbering=\"true\">";
			s<<"<text:list-item>";
			
		}
		else
		{
			s<<"</text:list-item>\n";
			s<<"</text:ordered-list>\n";
		}
	}
}


void kdissOOOdoc::writeItem(DDataItem* item, QTextStream & s, int level)
{
	DGenerator::writeItem(item, s, level);

	// printitem ?
	if (level == 0)
	{
		///TODO
		///s<<"<text:p text:style-name=\"Standard\"/>\n";
		
		s<<"<text:p text:style-name=\"P1\">";
		s<<DDataItem::protectXML(item->m_summary);
		s<<"</text:p>\n";

		s<<"<text:p text:style-name=\"Standard\">";
		s<<i18n("Abstract:")<<"</text:p>\n";
		s<<convertToOOOdoc(item->m_text);

		s<<"<text:p text:style-name=\"Standard\"/>\n";
		outputData(item, s, level);
		s<<"<text:p text:style-name=\"Standard\"/>\n";

		///TODO
		//s<<"</text:p>\n";
		
		//s<<"<text:table-of-content text:style-name=\"Sect1\" text:protected=\"true\" text:name=\"";
		//s<<i18n("Table of contents")<<"1\">\n";
		/*s<<"<text:table-of-content-source text:outline-level=\"10\">\n";
		  s<<"<text:index-title-template text:style-name=\"Contents Heading\">";
		  s<<i18n("Table of contents")<<"</text:index-title-template>\n";
		  s<<"</text:table-of-content>\n";
		  */

		//s<<"<text:p text:style-name=\"Standard\"/>\n";
		
		if (item->countChildren() > 0)
		{
			for (unsigned int i = 0; i<item->countChildren(); i++)
				writeItem((DDataItem*) m_data->Item(item->childNum(i)), s, level+1);
		}
	}
	else if (level <= 10)
	{
		// The title
		for (int i=0; i<level; i++)
		{
			s<<"<text:ordered-list text:style-name=\"L1\" text:continue-numbering=\"true\">";
			s<<"<text:list-item>\n";
		}
		
		s<<"<text:h text:style-name=\"P"<<level+100<<"\" text:level=\""<<level<<"\">";
		s<<DDataItem::protectXML(item->m_summary);
		s<<"</text:h>\n";

		for (int i=0; i<level; i++)
		{
			s<<"</text:list-item>\n";
			s<<"</text:ordered-list>\n";
		}

		// The text
		s<<convertToOOOdoc( item->m_text );

		// The data
		outputData(item, s, level);

		// And now the children
		if (item->countChildren() > 0)
		{
			for (unsigned int i = 0; i<item->countChildren(); i++)
				writeItem((DDataItem*) m_data->Item(item->childNum(i)), s, level+1);
		}
	}
	else
	{
		// insane, a document shouldn't grow *that* big
		s<<"<text:p text:style-name=\"Standard\">";
		s<<DDataItem::protectXML(item->m_summary);
		s<<"</text:p>\n";

		//s<<"<text:p text:style-name=\"Standard\">";
		s<<convertToOOOdoc( item->m_text );

		outputData(item, s, level);
	}
}

void kdissOOOdoc::writeItemPic(DDataControl * data, DDataItem *item, QTextStream &m)
{
	if (!item) return;

	if (! item->m_pix.isNull())
	{
		if (item->m_picfilename.endsWith(".png", false))
		{
			m<<"<manifest:file-entry manifest:media-type=\"image/png\" manifest:full-path=\"";
			m<<"Pictures/"+item->m_picfilename;
			m<<"\"/>\n";
		}
		else if (item->m_picfilename.endsWith(".jpeg", false) || item->m_picfilename.endsWith(".jpg", false))
		{
			m<<"<manifest:file-entry manifest:media-type=\"image/jpeg\" manifest:full-path=\"";
			m<<"Pictures/"+item->m_picfilename;
			m<<"\"/>\n";
		}
		// FIXME: can't remember why ?
		//item->m_pix.save(path+"/Pictures/"+"pic-"+QString::number(data->idNum(i))+".png", "PNG");
	}

	for (unsigned int i=0; i<item->countChildren(); i++)
	{
		writeItemPic( data, (DDataItem*) data->Item(item->childNum(i)), m );
	}
}

void kdissOOOdoc::writePics(DDataControl * data, QString path)
{
	// write the pics and process the META-INF directory
	DDataItem *root = (DDataItem*) data->Item( data->rootID() );

	// copy the pictures
	KIO::NetAccess::dircopy( KURL(data->getTmpDir()->absPath()), KURL(path+"/Pictures"), NULL );

	// proces the manifest file
	QFile manifestfile(path+"/META-INF/manifest.xml");
	if (!manifestfile.open(IO_WriteOnly | IO_Append) )
	{
		kdError()<<"could not open the manifest xml file for append :-/"<<endl;
		return;
	}

	QTextStream m(&manifestfile);
	m.setEncoding(QTextStream::UnicodeUTF8);

	// write the pictures contained in the subtree considered
	writeItemPic( data, root, m );

	// close the manifest file
	m<<"</manifest:manifest>";
	manifestfile.close();
}

bool kdissOOOdoc::writeMaindoc(DDataItem *root, const QString & path)
{
	// process the content

	QFile textfile(path+"/content.xml");
	if (!textfile.open(IO_WriteOnly | IO_Append) )
	{
		kdWarning()<<"could not open the main xml file for append :-/"<<endl;
		return false;
	}

	QTextStream u(&textfile);
	u.setEncoding(QTextStream::UnicodeUTF8);

	u<<"<office:body>\n";

	u<<"<text:sequence-decls>\n";
	u<<"<text:sequence-decl text:display-outline-level=\"0\" text:name=\"Illustration\"/>\n";
	u<<"<text:sequence-decl text:display-outline-level=\"0\" text:name=\"Table\"/>\n";
	u<<"<text:sequence-decl text:display-outline-level=\"0\" text:name=\"Text\"/>\n";
	u<<"<text:sequence-decl text:display-outline-level=\"0\" text:name=\"Drawing\"/>\n";
	u<<"</text:sequence-decls>\n";

	// now the central part, with text, pictures, etc ..
	writeItem(root, u, 0);

	// write the end of document
	u<<"</office:body>\n";
	u<<"</office:document-content>";

	// close the content document
	textfile.close();

	// styles
	QFile stylefile(path+"/styles.xml");
	if (!stylefile.open(IO_WriteOnly | IO_Append) )
	{
		kdWarning()<<"could not open the styles xml file for append :-/"<<endl;
		return false;
	}
	QTextStream v(&stylefile);

	//v<<"<text:author-name text:fixed=\"false\">";
	v<<DDataItem::protectXML(m_data->m_fname)<<" "<<DDataItem::protectXML(m_data->m_sname);
        if (!m_data->m_email.isEmpty())
        {
          v<<"<text:tab-stop/><text:tab-stop/>"<<DDataItem::protectXML(m_data->m_email);
        }
	//v<<"</text:author-name>";
	v<<"</text:p></style:header><style:footer><text:p text:style-name=\"Footer\"><text:date style:data-style-name=\"N37\" text:date-value=\"\" text:fixed=\"false\"></text:date><text:tab-stop/><text:page-number text:select-page=\"current\">1</text:page-number>/<text:page-count>3</text:page-count>";
        if (!m_data->m_company.isEmpty())
        {
          v<<"<text:tab-stop/>"<<DDataItem::protectXML(m_data->m_company);
        }
        v<<"</text:p></style:footer></style:master-page></office:master-styles></office:document-styles>";
	stylefile.close();

	// TODO process the meta-data section
	// title: DDataItem::protectXML(root->m_summary)
	QFile metafile(path+"/meta.xml");
	if (!metafile.open(IO_WriteOnly | IO_Append) )
	{
		kdWarning()<<"could not open the main xml file for append :-/"<<endl;
		return false;
	}

	QTextStream m(&metafile);
	m.setEncoding(QTextStream::UnicodeUTF8);

	m<<"<meta:initial-creator>"<<DDataItem::protectXML(m_data->m_fname)<<" "<<DDataItem::protectXML(m_data->m_sname)<<"</meta:initial-creator>\n";
	m<<"<dc:creator>"<<DDataItem::protectXML(m_data->m_fname)<<" "<<DDataItem::protectXML(m_data->m_sname)<<"</dc:creator>\n";

	m<<"<dc:language>";
	m<<Settings::countrycode();
	m<<"</dc:language>\n";

	m<<"<meta:editing-cycles>3</meta:editing-cycles>\n";
	m<<"<meta:editing-duration>PT8S</meta:editing-duration>\n";

	m<<"<meta:user-defined meta:name=\"Info 1\"/>";
	m<<"<meta:user-defined meta:name=\"Info 2\"/>";
	m<<"<meta:user-defined meta:name=\"Info 3\"/>";
	m<<"<meta:user-defined meta:name=\"Info 4\"/>";
	m<<"<meta:document-statistic meta:table-count=\"0\" meta:image-count=\"0\" meta:object-count=\"0\" meta:page-count=\"1\" meta:paragraph-count=\"1\" meta:word-count=\"1\" meta:character-count=\"0\"/>\n";
	m<<"</office:meta>\n</office:document-meta>";

	metafile.close();

	// create the archive
	KZip zip(path+"/newdoc.sxw");
	zip.setCompression( KZip::DeflateCompression );
	zip.open( IO_WriteOnly );

	zip.addLocalFile(path+"/content.xml", "content.xml");
	zip.addLocalFile(path+"/meta.xml", "meta.xml");
	zip.addLocalFile(path+"/mimetype", "mimetype");
	zip.addLocalFile(path+"/settings.xml", "settings.xml");
	zip.addLocalFile(path+"/styles.xml", "styles.xml");
	zip.addLocalDirectory(path+"/Pictures", "Pictures");
	zip.addLocalDirectory(path+"/META-INF", "META-INF");

	zip.close();

	// remove the (now useless) temporary files
	// do not show the progressdialog

	if (cli)
	{
		KIO::del(KURL(path+"/META-INF"), false, false );
		KIO::del(KURL(path+"/Pictures"), false, false );
		QFile(path+"/mimetype").remove();
		QFile(path+"/content.xml").remove();
		QFile(path+"/meta.xml").remove();
		QFile(path+"/settings.xml").remove();
		QFile(path+"/styles.xml").remove();
	}
	else
	{
		KIO::del(KURL(path+"/content.xml"), false, false );
		KIO::del(KURL(path+"/meta.xml"), false, false );
		KIO::del(KURL(path+"/mimetype"), false, false );
		KIO::del(KURL(path+"/settings.xml"), false, false );
		KIO::del(KURL(path+"/styles.xml"), false, false );
		KIO::del(KURL(path+"/META-INF"), false, false );
		KIO::del(KURL(path+"/Pictures"), false, false );
	}

	notifyDocGenerated( path+"/newdoc.sxw" );

	return true;
}

#include "kdissOOOdoc.moc"
