/*
 * TreeToXMLComposer.h
 *
 *  Created on: Nov 16, 2014
 *      Author: Stepan Plachy
 */

#pragma once

#include <alib/deque>
#include <alib/set>
#include <alib/vector>
#include <alib/tree>
#include <sax/Token.h>
#include <core/xmlApi.hpp>

namespace tree {

/**
 * This class contains methods to print XML representation of tree to the output stream.
 */
class TreeToXMLComposer {
public:
	template < class SymbolType >
	static void composeAlphabet ( ext::deque < sax::Token > & out, const ext::set < SymbolType > & symbols );

	template < class SymbolType >
	static void composeBar ( ext::deque < sax::Token > & out, const SymbolType & symbol );
	template < class SymbolType >
	static void composeBars ( ext::deque < sax::Token > & out, const ext::set < SymbolType > & symbols );
	template < class SymbolType >
	static void composeVariablesBar ( ext::deque < sax::Token > & out, const SymbolType & symbol );

	template < class SymbolType >
	static void composeSubtreeWildcard ( ext::deque < sax::Token > & out, const SymbolType & symbol );

	template < class SymbolType >
	static void composeContent ( ext::deque < sax::Token > & out, const ext::vector < SymbolType > & content );
	template < class SymbolType >
	static void composeContent ( ext::deque < sax::Token > & out, const ext::tree < SymbolType > & content );

	template < class SymbolType >
	static void composeNonlinearVariables ( ext::deque < sax::Token > & out, const ext::set < SymbolType > & symbols );
};

template < class SymbolType >
void TreeToXMLComposer::composeBar ( ext::deque < sax::Token > & out, const SymbolType & symbol ) {
	out.emplace_back ( sax::Token ( "bar", sax::Token::TokenType::START_ELEMENT ) );
	core::xmlApi < SymbolType >::compose ( out, symbol );
	out.emplace_back ( sax::Token ( "bar", sax::Token::TokenType::END_ELEMENT ) );
}

template < class SymbolType >
void TreeToXMLComposer::composeBars ( ext::deque < sax::Token > & out, const ext::set < SymbolType > & symbols ) {
	out.emplace_back ( sax::Token ( "bars", sax::Token::TokenType::START_ELEMENT ) );

	for ( const auto & symbol : symbols )
		core::xmlApi < SymbolType >::compose ( out, symbol );

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

template < class SymbolType >
void TreeToXMLComposer::composeVariablesBar ( ext::deque < sax::Token > & out, const SymbolType & symbol ) {
	out.emplace_back ( sax::Token ( "variablesBar", sax::Token::TokenType::START_ELEMENT ) );
	core::xmlApi < SymbolType >::compose ( out, symbol );
	out.emplace_back ( sax::Token ( "variablesBar", sax::Token::TokenType::END_ELEMENT ) );
}

template < class SymbolType >
void TreeToXMLComposer::composeSubtreeWildcard ( ext::deque < sax::Token > & out, const SymbolType & symbol ) {
	out.emplace_back ( sax::Token ( "subtreeWildcard", sax::Token::TokenType::START_ELEMENT ) );
	core::xmlApi < SymbolType >::compose ( out, symbol );
	out.emplace_back ( sax::Token ( "subtreeWildcard", sax::Token::TokenType::END_ELEMENT ) );
}

template < class SymbolType >
void TreeToXMLComposer::composeAlphabet ( ext::deque < sax::Token > & out, const ext::set < SymbolType > & symbols ) {
	out.emplace_back ( sax::Token ( "alphabet", sax::Token::TokenType::START_ELEMENT ) );

	for ( const auto & symbol : symbols )
		core::xmlApi < SymbolType >::compose ( out, symbol );

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

template < class SymbolType >
void TreeToXMLComposer::composeContent ( ext::deque < sax::Token > & out, const ext::vector < SymbolType > & content ) {
	out.emplace_back ( "content", sax::Token::TokenType::START_ELEMENT );

	for ( const auto & symbol : content )
		core::xmlApi < SymbolType >::compose ( out, symbol );

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

template < class SymbolType >
void TreeToXMLComposer::composeContent ( ext::deque < sax::Token > & out, const ext::tree < SymbolType > & content ) {
	out.emplace_back ( "content", sax::Token::TokenType::START_ELEMENT );

	unsigned level = 0;

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

		core::xmlApi < SymbolType >::compose ( out, * iter );
		++iter;

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

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

template < class SymbolType >
void TreeToXMLComposer::composeNonlinearVariables ( ext::deque < sax::Token > & out, const ext::set < SymbolType > & symbols ) {
	out.emplace_back ( sax::Token ( "nonlinearVariables", sax::Token::TokenType::START_ELEMENT ) );

	for ( const auto & symbol : symbols )
		core::xmlApi < SymbolType >::compose ( out, symbol );

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

} /* namespace tree */

