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

#ifndef TREE_FROM_XML_PARSER_H_
#define TREE_FROM_XML_PARSER_H_

#include <alib/set>
#include <alib/vector>
#include <alib/deque>
#include <alib/tree>

#include <sax/Token.h>
#include <sax/ParserException.h>
#include <core/xmlApi.hpp>

namespace tree {

/**
 * Parser used to get tree from XML parsed into list of Tokens.
 */
class TreeFromXMLParser {
	template < class SymbolType >
	static ext::tree < SymbolType > parseTreeChild ( ext::deque < sax::Token >::iterator & input );

public:
	template < class SymbolType >
	static ext::vector < SymbolType > parseLinearContent ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::tree < SymbolType > parseTreeContent ( ext::deque < sax::Token >::iterator & input );

	template < class SymbolType >
	static ext::set < SymbolType > parseAlphabet ( ext::deque < sax::Token >::iterator & input );

	template < class SymbolType >
	static SymbolType parseBar ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::set < SymbolType > parseBars ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static SymbolType parseVariablesBar ( ext::deque < sax::Token >::iterator & input );

	template < class SymbolType >
	static SymbolType parseWildcardSymbol ( ext::deque < sax::Token >::iterator & input );

	template < class SymbolType >
	static ext::set < SymbolType > parseNonlinearVariables ( ext::deque < sax::Token >::iterator & input );
};

template < class SymbolType >
SymbolType TreeFromXMLParser::parseBar ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "bar" );
	SymbolType bar ( core::xmlApi < SymbolType >::parse ( input ) );
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, "bar" );

	return bar;
}

template < class SymbolType >
ext::set < SymbolType > TreeFromXMLParser::parseBars ( ext::deque < sax::Token >::iterator & input ) {
	ext::set < SymbolType > bars;
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "bars" );

	while ( sax::FromXMLParserHelper::isTokenType ( input, sax::Token::TokenType::START_ELEMENT ) )
		bars.insert ( core::xmlApi < SymbolType >::parse ( input ) );

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

	return bars;
}

template < class SymbolType >
SymbolType TreeFromXMLParser::parseVariablesBar ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "variablesBar" );
	SymbolType variablesBar ( core::xmlApi < SymbolType >::parse ( input ) );
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, "variablesBar" );

	return variablesBar;
}

template < class SymbolType >
SymbolType TreeFromXMLParser::parseWildcardSymbol ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "subtreeWildcard" );
	SymbolType subtreeWildcard ( core::xmlApi < SymbolType >::parse ( input ) );
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, "subtreeWildcard" );

	return subtreeWildcard;
}

template < class SymbolType >
ext::set < SymbolType > TreeFromXMLParser::parseAlphabet ( ext::deque < sax::Token >::iterator & input ) {
	ext::set < SymbolType > symbols;
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "alphabet" );

	while ( sax::FromXMLParserHelper::isTokenType ( input, sax::Token::TokenType::START_ELEMENT ) )
		symbols.insert ( core::xmlApi < SymbolType >::parse ( input ) );

	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, "alphabet" );
	return symbols;
}

template < class SymbolType >
ext::vector < SymbolType > TreeFromXMLParser::parseLinearContent ( ext::deque < sax::Token >::iterator & input ) {
	ext::vector < SymbolType > data;
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "content" );

	while ( sax::FromXMLParserHelper::isTokenType ( input, sax::Token::TokenType::START_ELEMENT ) )
		data.push_back ( core::xmlApi < SymbolType >::parse ( input ) );

	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, "content" );
	return data;
}

template < class SymbolType >
ext::tree < SymbolType > TreeFromXMLParser::parseTreeChild ( ext::deque < sax::Token >::iterator & input ) {
	SymbolType symbol = core::xmlApi < SymbolType >::parse ( input );

	ext::vector < ext::tree < SymbolType > > children;

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

		while ( sax::FromXMLParserHelper::isTokenType ( input, sax::Token::TokenType::START_ELEMENT ) ) {
			children.push_back ( TreeFromXMLParser::parseTreeChild < SymbolType > ( input ) );
		}

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

	return ext::tree < SymbolType > ( symbol, std::move( children ) );
}

template < class SymbolType >
ext::tree < SymbolType > TreeFromXMLParser::parseTreeContent ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "content" );

	ext::tree < SymbolType > data = TreeFromXMLParser::parseTreeChild < SymbolType > ( input );

	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, "content" );
	return data;
}

template < class SymbolType >
ext::set < SymbolType > TreeFromXMLParser::parseNonlinearVariables ( ext::deque < sax::Token >::iterator & input ) {
	ext::set < SymbolType > symbols;
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "nonlinearVariables" );

	while ( sax::FromXMLParserHelper::isTokenType ( input, sax::Token::TokenType::START_ELEMENT ) )
		symbols.insert ( core::xmlApi < SymbolType >::parse ( input ) );

	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, "nonlinearVariables" );
	return symbols;
}

} /* namespace tree */

#endif /* TREE_FROM_XML_PARSER_H_ */
