/*
 * RTEFromXmlParser.h
 *
 *  Created on: Feb 20, 2016
 *      Author: Tomas Pecka
 */

#pragma once

#include <alib/set>
#include <alib/deque>
#include <sax/Token.h>
#include <common/ranked_symbol.hpp>
#include <core/xmlApi.hpp>

#include <exception/CommonException.h>

#include <rte/formal/FormalRTEElements.h>


namespace rte {

/**
 * Parser used to get RTE from XML parsed into list of tokens.
 */
class RTEFromXmlParser {
public:
	template < class SymbolType >
	static std::pair < ext::set < common::ranked_symbol < SymbolType > >, ext::set < common::ranked_symbol < SymbolType > > > parseAlphabet ( ext::deque < sax::Token >::iterator & input );

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

	template < class SymbolType >
	static ext::ptr_value < FormalRTEEmpty < SymbolType > > parseFormalRTEEmpty ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::ptr_value < FormalRTEIteration < SymbolType > > parseFormalRTEIteration ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::ptr_value < FormalRTEAlternation < SymbolType > > parseFormalRTEAlternation ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::ptr_value < FormalRTESubstitution < SymbolType > > parseFormalRTESubstitution ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::ptr_value < FormalRTESymbolAlphabet < SymbolType > > parseFormalRTESymbolAlphabet ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::ptr_value < FormalRTESymbolSubst < SymbolType > > parseFormalRTESymbolSubst ( ext::deque < sax::Token >::iterator & input );
};

template < class SymbolType >
std::pair < ext::set < common::ranked_symbol < SymbolType > >, ext::set < common::ranked_symbol < SymbolType > > > RTEFromXmlParser::parseAlphabet ( ext::deque < sax::Token >::iterator & input ) {
	ext::set < common::ranked_symbol < SymbolType > > alphabetF;
	ext::set < common::ranked_symbol < SymbolType > > alphabetK;

	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "alphabet" );

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

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

	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "substSymbolAlphabet" );

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

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

	return std::make_pair ( alphabetF, alphabetK );
}

template < class SymbolType >
ext::ptr_value < FormalRTEElement < SymbolType > > RTEFromXmlParser::parseFormalRTEElement ( ext::deque < sax::Token >::iterator & input ) {
	if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "empty" ) )
		return parseFormalRTEEmpty < SymbolType > ( input );
	else if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "iteration" ) )
		return parseFormalRTEIteration < SymbolType > ( input );
	else if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "alternation" ) )
		return parseFormalRTEAlternation < SymbolType > ( input );
	else if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "substitution" ) )
		return parseFormalRTESubstitution < SymbolType > ( input );
	else if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "symbol" ) )
		return parseFormalRTESymbolAlphabet < SymbolType > ( input );
	else
		return parseFormalRTESymbolSubst < SymbolType > ( input );
}

template < class SymbolType >
ext::ptr_value < FormalRTEAlternation < SymbolType > > RTEFromXmlParser::parseFormalRTEAlternation ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "alternation" );

	ext::ptr_value < FormalRTEElement < SymbolType > > element1 = parseFormalRTEElement < SymbolType > ( input );
	ext::ptr_value < FormalRTEElement < SymbolType > > element2 = parseFormalRTEElement < SymbolType > ( input );

	ext::ptr_value < FormalRTEAlternation < SymbolType > > alternation ( FormalRTEAlternation < SymbolType > ( std::move ( element1 ), std::move ( element2 ) ) );

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

template < class SymbolType >
ext::ptr_value < FormalRTESubstitution < SymbolType > > RTEFromXmlParser::parseFormalRTESubstitution ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "substitution" );

	FormalRTESymbolSubst < SymbolType > ssymb ( core::xmlApi < common::ranked_symbol < SymbolType > >::parse ( input ) );
	ext::ptr_value < FormalRTEElement < SymbolType > > element1 = parseFormalRTEElement < SymbolType > ( input );
	ext::ptr_value < FormalRTEElement < SymbolType > > element2 = parseFormalRTEElement < SymbolType > ( input );

	ext::ptr_value < FormalRTESubstitution < SymbolType > > substitution ( FormalRTESubstitution < SymbolType > ( std::move ( element1 ), std::move ( element2 ), std::move ( ssymb ) ) );

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

template < class SymbolType >
ext::ptr_value < FormalRTEIteration < SymbolType > > RTEFromXmlParser::parseFormalRTEIteration ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "iteration" );

	FormalRTESymbolSubst < SymbolType > ssymb ( core::xmlApi < common::ranked_symbol < SymbolType > >::parse ( input ) );
	ext::ptr_value < FormalRTEElement < SymbolType > > element = parseFormalRTEElement < SymbolType > ( input );
	ext::ptr_value < FormalRTEIteration < SymbolType > > iteration ( FormalRTEIteration < SymbolType > ( std::move ( element ), std::move ( ssymb ) ) );

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

template < class SymbolType >
ext::ptr_value < FormalRTEEmpty < SymbolType > > RTEFromXmlParser::parseFormalRTEEmpty ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "empty" );

	ext::ptr_value < FormalRTEEmpty < SymbolType > > empty { FormalRTEEmpty < SymbolType > ( ) };

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

	return empty;
}

template < class SymbolType >
ext::ptr_value < FormalRTESymbolAlphabet < SymbolType > > RTEFromXmlParser::parseFormalRTESymbolAlphabet ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "symbol" );
	common::ranked_symbol < SymbolType > symbol = core::xmlApi < common::ranked_symbol < SymbolType > >::parse ( input );
	ext::ptr_vector < FormalRTEElement < SymbolType > > elements;

	while ( sax::FromXMLParserHelper::isTokenType ( input, sax::Token::TokenType::START_ELEMENT ) )
		elements.push_back ( ( FormalRTEElement < SymbolType > && ) parseFormalRTEElement < SymbolType > ( input ) );

	ext::ptr_value < FormalRTESymbolAlphabet < SymbolType > > ret ( FormalRTESymbolAlphabet < SymbolType > ( std::move ( symbol ), std::move ( elements ) ) );

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

	return ret;
}

template < class SymbolType >
ext::ptr_value < FormalRTESymbolSubst < SymbolType > > RTEFromXmlParser::parseFormalRTESymbolSubst ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "substSymbol" );
	common::ranked_symbol < SymbolType > symbol = core::xmlApi < common::ranked_symbol < SymbolType > >::parse ( input );

	ext::ptr_value < FormalRTESymbolSubst < SymbolType > > ret { FormalRTESymbolSubst < SymbolType > ( symbol ) };

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

	return ret;
}

} /* namespace rte */

