/**
 * @file
 * @version @$Id$
 * @author
 * ui-gxmlcpp: C++ wrapper for Gnome libxml2/libxsl.
 * Copyright (C) Schlund+Partner AG 2002-2004.
 * Licensed under the GNU Lesser General Public License (LGPL). See
 * @ref License, or the file COPYING in distribution.
 */

// Local configuration
#include "config.h"

// Implementation
#include "Conf.hpp"

// STDC++
#include <cstdarg>
#include <cstdio>
#include <iostream>

// STDC; do not necessarily be in cstdio so include it for vsnprintf
// Visual C++ compiler cannot compile otherwise
#include <stdio.h>

// C++ Libraries
#include <ui-utilcpp/Text.hpp>

// C libraries
#include <libxml/parser.h>
#include <libxslt/xsltutils.h>
#include <libexslt/exslt.h>

namespace UI {
namespace GXML {

Conf::Conf()
	:customLoggingEnabled_(true)
	,logPrefix_("")
{
	LIBXML_TEST_VERSION;
	// This is a reasonable default. It keeps DOM trees as compact as possible and make format dumps work as expected.
	setKeepBlanks(false);
}

Conf::~Conf()
{
	xsltCleanupGlobals();
	xmlCleanupParser();
}

Conf & Conf::setCustomLogging(bool on, std::string prefix)
{
	xmlSetGenericErrorFunc (on ? this : 0, on ? libxmlLog : 0);
	xsltSetGenericErrorFunc(on ? this : 0, on ? libxmlLog : 0);
	logPrefix_ = prefix;
	return *this;
}

Conf & Conf::setCustomLoggingEnable(bool on)
{
	customLoggingEnabled_ = on;
	return *this;
}

void Conf::setKeepBlanks(bool on)
{
	xmlKeepBlanksDefault(on ? 1 : 0);
}

Conf & Conf::setEXSLT()
{
	exsltRegisterAll();
	return *this;
}

void Conf::memberLog(std::string const & msg)
{
	if (customLoggingEnabled_)
	{
		customLog(msg);
	}
}

void Conf::customLog(std::string const & msg)
{
	std::clog << msg << std::flush;
}

void Conf::libxmlLog(void * ctx, const char * msg, ...)
{
	Conf * c((Conf *) ctx);

	va_list args;
	va_start(args, msg);

	int const maxChars(512);
	std::string log;
	log.resize(maxChars);

	if (::vsnprintf(&log[0], maxChars-1, msg, args) < 0)
	{
		std::cerr << "Internal error in ui-gxmlcpp copying error log line (no cure)." << std::endl;
		return;
	}
	va_end(args);

	// Add prefix where appropriate
	std::string line(log.c_str());
	if (!c->logPrefix_.empty())
	{
		static bool logTouched(false);
		if (!logTouched)
		{
			line = c->logPrefix_ + log.c_str();
			logTouched = true;
		}
		UI::Util::strrpl(line, "\n", "\n" + c->logPrefix_);
	}

	// Log
	(c->*&UI::GXML::Conf::memberLog)(line.c_str());
}

}}
