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

#ifndef _XML_OBJECTS_TREE_H_
#define _XML_OBJECTS_TREE_H_

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

namespace core {

template < typename T >
struct xmlApi < ext::tree < T > > {
	static ext::tree < T > 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::tree < T > & input );
};

template < typename T >
ext::tree < T > xmlApi < ext::tree < T > >::parse ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, xmlTagName ( ) );
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "Root" );

	ext::tree < T > tree ( core::xmlApi < T >::parse ( input ) );

	ext::tree < T > * under = & tree;

	unsigned level = 0;

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

			if ( level > 0 )
				under = & * std::prev ( under->end ( ) );

			++level;
		}

		under->push_back ( core::xmlApi < T >::parse ( input ) );

		while ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::END_ELEMENT, "Children" ) ) {
			sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, "Children" );

			under = under->getParent ( );
			--level;
		}
	}

	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, "Root" );
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, xmlTagName ( ) );
	return tree;
}

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

template < typename T >
std::string xmlApi < ext::tree < T > >::xmlTagName ( ) {
	return "Tree";
}

template < typename T >
void xmlApi < ext::tree < T > >::compose ( ext::deque < sax::Token > & output, const ext::tree < T > & input ) {
	output.emplace_back ( xmlTagName ( ), sax::Token::TokenType::START_ELEMENT );
	output.emplace_back ( "Root", sax::Token::TokenType::START_ELEMENT );

	unsigned level = 0;

	for ( typename ext::tree < T >::const_prefix_iterator iter = input.prefix_begin ( ); iter != input.prefix_end ( ); ) {
		while ( iter.getLevel ( ) > level ) {
			output.emplace_back ( "Children", sax::Token::TokenType::START_ELEMENT );
			++level;
		}

		core::xmlApi < T >::compose ( output, * iter );
		++iter;

		while ( iter.getLevel ( ) < level ) {
			output.emplace_back ( "Children", sax::Token::TokenType::END_ELEMENT );
			--level;
		}
	}

	output.emplace_back ( "Root", sax::Token::TokenType::END_ELEMENT );
	output.emplace_back ( xmlTagName ( ), sax::Token::TokenType::END_ELEMENT );
}

} /* namespace core */

#endif /* _XML_OBJECTS_TREE_H_ */
