/** @file */

// Local configuration
#include "config.h"

// Implementation
#include "SchemaTree.hpp"

namespace UI {
namespace GXML {

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

	schema_ = xmlSchemaParse(parserCtxt_);
	if (!schema_)
	{
		xmlSchemaFreeParserCtxt(parserCtxt_);
		UI_THROW_CODE(Parse_, "Could not parse schema");
	}
}

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

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

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

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

SchemaTree::~SchemaTree()
{
	xmlSchemaFree(schema_);
	xmlSchemaFreeParserCtxt(parserCtxt_);
}

int SchemaTree::libxml2Validate(Tree const & tree) const
{
	// Sub class to encapsulate create/free: make it exception safe
	class ValidCtxt
	{
	public:
		ValidCtxt(xmlSchema * schema)
			:value_(xmlSchemaNewValidCtxt(schema))
		{
			if (!value_)
			{
				UI_THROW_CODE(ValidCtxt_, "Could not generate valid schema context");
			}
		}
		~ValidCtxt()
		{
			xmlSchemaFreeValidCtxt(value_);
		}
		xmlSchemaValidCtxt * value_;
	};

	return xmlSchemaValidateDoc(ValidCtxt(schema_).value_, tree.get());
}

}}
