//
// C++ Implementation: xslthandler
//
// Description: 
//
//
// Author: Thach Nguyen <thach.nguyen@rmit.edu.au>, (C) 2006
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include <config.h>
#if HAVE_XSLT
#include "xslthandler.h"

#include <qtextcodec.h>

extern "C" {
#include <libxslt/xslt.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
#include <libxslt/extensions.h>

#include <libexslt/exslt.h>
}

#include <iostream>


static const int xml_options = XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_NOCDATA;
static const int xslt_options = xml_options;

static int writeToQString(void* context, const char* buffer, int len) {
	QString* t = static_cast<QString*>(context);
	*t += QString::fromUtf8(buffer, len);
	return len;
}

static void closeQString(void* context) {
	QString* t = static_cast<QString*>(context);
	*t += QString::fromLatin1("\n");
}


XSLTHandler::XMLOutputBuffer::XMLOutputBuffer() : m_res(QString::null) {
	m_buf = xmlOutputBufferCreateIO((xmlOutputWriteCallback)writeToQString,
									 (xmlOutputCloseCallback)closeQString,
									 &m_res, 0);
	if(m_buf) {
		m_buf->written = 0;
	} else {
		std::cerr << "XMLOutputBuffer::XMLOutputBuffer() - error writing output buffer!\n";
	}
}

XSLTHandler::XMLOutputBuffer::~XMLOutputBuffer() {
	if(m_buf) {
		xmlOutputBufferClose(m_buf); //also flushes
		m_buf = 0;
	}
}

int XSLTHandler::s_initCount = 0;

XSLTHandler::XSLTHandler(const KURL& xsltURL_) :
		m_stylesheet(0),
    m_docIn(0),
	m_docOut(0) {
		init();
		if(xsltURL_.isValid() && xsltURL_.isLocalFile()) {
			xmlDocPtr xsltDoc = xmlReadFile(xsltURL_.encodedPathAndQuery().utf8(), NULL, xslt_options);
			m_stylesheet = xsltParseStylesheetDoc(xsltDoc);
			if(!m_stylesheet) {
				std::cerr << "XSLTHandler::XSLTHandler() - null stylesheet pointer for " << xsltURL_.path() << "\n";
			}
		}
}


XSLTHandler::~XSLTHandler() {
	if(m_stylesheet) {
		xsltFreeStylesheet(m_stylesheet);
	}

	if(m_docIn) {
		xmlFreeDoc(m_docIn);
	}

	if(m_docOut) {
		xmlFreeDoc(m_docOut);
	}

	--s_initCount;
	if(s_initCount == 0) {
		xsltUnregisterExtModule(EXSLT_STRINGS_NAMESPACE);
		xsltUnregisterExtModule(EXSLT_DYNAMIC_NAMESPACE);
		xsltCleanupGlobals();
		xmlCleanupParser();
	}
}


void XSLTHandler::init() {
	if(s_initCount == 0) {
		xmlSubstituteEntitiesDefault(1);
		xmlLoadExtDtdDefaultValue = 0;

    // register all exslt extensions
		exsltRegisterAll();
	}
	++s_initCount;

	m_params.clear();
}

QString XSLTHandler::applyStylesheet(const QString& text_) {
	if(!m_stylesheet) {
		std::cerr << "XSLTHandler::applyStylesheet() - null stylesheet pointer!\n";
		return QString::null;
	}
	
	m_docIn = xmlReadDoc(reinterpret_cast<xmlChar*>(text_.utf8().data()), NULL, NULL, xml_options);

	return process();
}

QString XSLTHandler::process() {
	if(!m_docIn) {
		std::cerr  << "XSLTHandler::process() - error parsing input string!\n";
		return QString::null;
	}
	/*
	const char* params[2*m_params.count() + 1];
	params[0] = NULL;
	QMap<QCString, QCString>::ConstIterator it = m_params.constBegin();
	QMap<QCString, QCString>::ConstIterator end = m_params.constEnd();
	for(uint i = 0; it != end; ++it) {
		params[i  ] = qstrdup(it.key());
		params[i+1] = qstrdup(it.data());
		params[i+2] = NULL;
		i += 2;
	}
	*/
  // returns NULL on error
	//m_docOut = xsltApplyStylesheet(m_stylesheet, m_docIn, params);
	m_docOut = xsltApplyStylesheet(m_stylesheet, m_docIn, NULL);
/*	for(uint i = 0; i < 2*m_params.count(); ++i) {
		delete[] params[i];
	}
*/
	if(!m_docOut) {
		std::cerr  << "XSLTHandler::applyStylesheet() - error applying stylesheet!\n";
		return QString::null;
	}

	XMLOutputBuffer output;
	if(output.isValid()) {
		int num_bytes = xsltSaveResultTo(output.buffer(), m_docOut, m_stylesheet);
		if(num_bytes == -1) {
			std::cerr  << "XSLTHandler::applyStylesheet() - error saving output buffer!\n";
		}
	}
	return output.result();
}

#endif