/*
 * ObjectsTrie.h
 *
 * Created on: Apr 1, 2013
 * Author: Jan Travnicek
 */

#pragma once

#include <alib/trie>
#include <core/xmlApi.hpp>

namespace core {

template < typename T, typename R >
struct xmlApi < ext::trie < T, R > > {
	static ext::trie < T, R > parse ( ext::deque < sax::Token >::iterator & input );
	static bool first ( const ext::deque < sax::Token >::const_iterator & input );
	static std::string xmlTagName ( );
	static void compose ( ext::deque < sax::Token > & output, const ext::trie < T, R > & input );

private:
	static ext::map < T, ext::trie < T, R > > parseChildren ( ext::deque < sax::Token >::iterator & input );
	static void composeChildren ( ext::deque < sax::Token > & out, const ext::map < T, ext::trie < T, R > > & children );
};

template < typename T, typename R >
ext::map < T, ext::trie < T, R > > xmlApi < ext::trie < T, R > >::parseChildren ( ext::deque < sax::Token >::iterator & input ) {
	ext::map < T, ext::trie < T, R > > children;

	while ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "Child" ) ) {
		sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "Child" );

		T key = core::xmlApi < T >::parse ( input );
		R value = core::xmlApi < R >::parse ( input );
		ext::map < T, ext::trie < T, R > > innerChildren = parseChildren ( input );

		children.insert ( std::make_pair ( std::move ( key ), ext::trie < T, R > ( std::move ( value ), std::move ( innerChildren ) ) ) );

		sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, "Child" );
	}

	return children;
}

template < typename T, typename R >
ext::trie < T, R > xmlApi < ext::trie < T, R > >::parse ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, xmlTagName ( ) );
	R value = core::xmlApi < R >::parse ( input );
	ext::map < T, ext::trie < T, R > > children = parseChildren ( input );

	ext::trie < T, R > trie ( std::move ( value ), std::move ( children ) );

	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, xmlTagName ( ) );
	return trie;
}

template < typename T, typename R >
bool xmlApi < ext::trie < T, R > >::first ( const ext::deque < sax::Token >::const_iterator & input ) {
	return sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, xmlTagName ( ) );
}

template < typename T, typename R >
std::string xmlApi < ext::trie < T, R > >::xmlTagName ( ) {
	return "Trie";
}

template < typename T, typename R >
void xmlApi < ext::trie < T, R > >::composeChildren ( ext::deque < sax::Token > & out, const ext::map < T, ext::trie < T, R > > & children ) {
	for ( const std::pair < const T, ext::trie < T, R > > & child : children ) {
		out.emplace_back ( "Child", sax::Token::TokenType::START_ELEMENT );

		core::xmlApi < T >::compose ( out, child.first );
		core::xmlApi < R >::compose ( out, child.second.getData ( ) );
		composeChildren ( out, child.second.getChildren ( ) );

		out.emplace_back ( "Child", sax::Token::TokenType::END_ELEMENT );
	}
}

template < typename T, typename R >
void xmlApi < ext::trie < T, R > >::compose ( ext::deque < sax::Token > & output, const ext::trie < T, R > & input ) {
	output.emplace_back ( xmlTagName ( ), sax::Token::TokenType::START_ELEMENT );
	core::xmlApi < R >::compose ( output, input.getData ( ) );
	composeChildren ( output, input.getChildren ( ) );
	output.emplace_back ( xmlTagName ( ), sax::Token::TokenType::END_ELEMENT );
}

} /* namespace core */

