/** @file */

// Local configuration
#include "config.h"

// Implementation
#include "RelaxNGTree.hpp"

namespace UI {
namespace GXML {

// Private helper function for constructors
void RelaxNGTree::init()
{
	parserCtxt_ = xmlRelaxNGNewDocParserCtxt(get());
	if (!parserCtxt_)
	{
		UI_THROW_CODE(Ctxt_, "Error creating new relaxng parser context");
	}

	relaxng_ = xmlRelaxNGParse(parserCtxt_);
	if (!relaxng_)
	{
		xmlRelaxNGFreeParserCtxt(parserCtxt_);
		UI_THROW_CODE(Parse_, "Could not parse relaxng");
	}
}

RelaxNGTree::RelaxNGTree(char const * xml, int len, std::string const & base, int const options)
	:ValidatorTree(xml, len, base, options)
{
	init();
}

RelaxNGTree::RelaxNGTree(std::string const & xml, std::string const & base, int const options)
	:ValidatorTree(xml, base, options)
{
	init();
}

RelaxNGTree::RelaxNGTree(std::istream & xml, std::string const & base, int const options)
	:ValidatorTree(xml, base, options)
{
	init();
}

RelaxNGTree::RelaxNGTree(FileConstructor const dummy, std::string const & file, int const options)
	:ValidatorTree(dummy, file, options)
{
	init();
}

RelaxNGTree::~RelaxNGTree()
{
	xmlRelaxNGFree(relaxng_);
	xmlRelaxNGFreeParserCtxt(parserCtxt_);
}

int RelaxNGTree::libxml2Validate(Tree const & tree) const
{
	// Sub class to encapsulate create/free: make it exception safe
	class ValidCtxt
	{
	public:
		ValidCtxt(xmlRelaxNG * relaxng)
			:value_(xmlRelaxNGNewValidCtxt(relaxng))
		{
			if (!value_)
			{
				UI_THROW_CODE(ValidCtxt_, "Could not generate valid relaxng context");
			}
		}
		~ValidCtxt()
		{
			xmlRelaxNGFreeValidCtxt(value_);
		}
		xmlRelaxNGValidCtxt * value_;
	};

	return xmlRelaxNGValidateDoc(ValidCtxt(relaxng_).value_, tree.get());
}

}}
