/*
 * RegExpFromXmlParser.h
 *
 *  Created on: Nov 23, 2013
 *      Author: Martin Zak
 */

#pragma once

#include <alib/set>
#include <alib/deque>
#include <sax/Token.h>

#include <sax/FromXMLParserHelper.h>

#include <regexp/unbounded/UnboundedRegExpElements.h>
#include <regexp/formal/FormalRegExpElements.h>
#include <core/xmlApi.hpp>

namespace regexp {

/**
 * Parser used to get RegExp from XML parsed into list of tokens.
 */
class RegExpFromXmlParser {
public:
	template < class SymbolType >
	static ext::set < SymbolType > parseAlphabet ( ext::deque < sax::Token >::iterator & input );

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

	template < class SymbolType >
	static ext::ptr_value < UnboundedRegExpElement < SymbolType > > parseUnboundedRegExpEpsilon ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::ptr_value < UnboundedRegExpElement < SymbolType > > parseUnboundedRegExpEmpty ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::ptr_value < UnboundedRegExpElement < SymbolType > > parseUnboundedRegExpIteration ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::ptr_value < UnboundedRegExpElement < SymbolType > > parseUnboundedRegExpAlternation ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::ptr_value < UnboundedRegExpElement < SymbolType > > parseUnboundedRegExpConcatenation ( ext::deque < sax::Token >::iterator & input );

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

	template < class SymbolType >
	static ext::ptr_value < FormalRegExpElement < SymbolType > > parseFormalRegExpEpsilon ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::ptr_value < FormalRegExpElement < SymbolType > > parseFormalRegExpEmpty ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::ptr_value < FormalRegExpElement < SymbolType > > parseFormalRegExpIteration ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::ptr_value < FormalRegExpElement < SymbolType > > parseFormalRegExpAlternation ( ext::deque < sax::Token >::iterator & input );
	template < class SymbolType >
	static ext::ptr_value < FormalRegExpElement < SymbolType > > parseFormalRegExpConcatenation ( ext::deque < sax::Token >::iterator & input );
};

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

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

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

template < class SymbolType >
ext::ptr_value < UnboundedRegExpElement < SymbolType > > RegExpFromXmlParser::parseUnboundedRegExpElement ( ext::deque < sax::Token >::iterator & input ) {
	if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "empty" ) )
		return parseUnboundedRegExpEmpty < SymbolType > ( input );
	else if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "epsilon" ) )
		return parseUnboundedRegExpEpsilon < SymbolType > ( input );
	else if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "iteration" ) )
		return parseUnboundedRegExpIteration < SymbolType > ( input );
	else if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "alternation" ) )
		return parseUnboundedRegExpAlternation < SymbolType > ( input );
	else if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "concatenation" ) )
		return parseUnboundedRegExpConcatenation < SymbolType > ( input );
	else
		return ext::ptr_value < UnboundedRegExpElement < SymbolType > > ( UnboundedRegExpSymbol < SymbolType > ( core::xmlApi < SymbolType >::parse ( input ) ) );
}

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

	UnboundedRegExpAlternation < SymbolType > alternation;

	while ( sax::FromXMLParserHelper::isTokenType ( input, sax::Token::TokenType::START_ELEMENT ) )
		alternation.appendElement ( parseUnboundedRegExpElement < SymbolType > ( input ) );

	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, "alternation" );
	return ext::ptr_value < UnboundedRegExpElement < SymbolType > > ( std::move ( alternation ) );
}

template < class SymbolType >
ext::ptr_value < UnboundedRegExpElement < SymbolType > > RegExpFromXmlParser::parseUnboundedRegExpConcatenation ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "concatenation" );

	UnboundedRegExpConcatenation < SymbolType > concatenation;

	while ( sax::FromXMLParserHelper::isTokenType ( input, sax::Token::TokenType::START_ELEMENT ) )
		concatenation.appendElement ( parseUnboundedRegExpElement < SymbolType > ( input ) );

	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, "concatenation" );
	return ext::ptr_value < UnboundedRegExpElement < SymbolType > > ( std::move ( concatenation ) );
}

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

	ext::ptr_value < UnboundedRegExpElement < SymbolType > > iteration ( UnboundedRegExpIteration < SymbolType > ( parseUnboundedRegExpElement < SymbolType > ( input ) ) );

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

	return iteration;
}

template < class SymbolType >
ext::ptr_value < UnboundedRegExpElement < SymbolType > > RegExpFromXmlParser::parseUnboundedRegExpEpsilon ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "epsilon" );

	ext::ptr_value < UnboundedRegExpElement < SymbolType > > epsilon { UnboundedRegExpEpsilon < SymbolType > ( ) };

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

	return epsilon;
}

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

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

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

	return empty;
}

template < class SymbolType >
ext::ptr_value < FormalRegExpElement < SymbolType > > RegExpFromXmlParser::parseFormalRegExpElement ( ext::deque < sax::Token >::iterator & input ) {
	if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "empty" ) )
		return parseFormalRegExpEmpty < SymbolType > ( input );
	else if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "epsilon" ) )
		return parseFormalRegExpEpsilon < SymbolType > ( input );
	else if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "iteration" ) )
		return parseFormalRegExpIteration < SymbolType > ( input );
	else if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "alternation" ) )
		return parseFormalRegExpAlternation < SymbolType > ( input );
	else if ( sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, "concatenation" ) )
		return parseFormalRegExpConcatenation < SymbolType > ( input );
	else
		return ext::ptr_value < FormalRegExpElement < SymbolType > > ( FormalRegExpSymbol < SymbolType > ( core::xmlApi < SymbolType >::parse ( input ) ) );
}

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

	ext::ptr_value < FormalRegExpElement < SymbolType > > element1 = parseFormalRegExpElement < SymbolType > ( input );
	ext::ptr_value < FormalRegExpElement < SymbolType > > element2 = parseFormalRegExpElement < SymbolType > ( input );

	ext::ptr_value < FormalRegExpElement < SymbolType > > alternation ( FormalRegExpAlternation < 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 < FormalRegExpElement < SymbolType > > RegExpFromXmlParser::parseFormalRegExpConcatenation ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "concatenation" );

	ext::ptr_value < FormalRegExpElement < SymbolType > > element1 = parseFormalRegExpElement < SymbolType > ( input );
	ext::ptr_value < FormalRegExpElement < SymbolType > > element2 = parseFormalRegExpElement < SymbolType > ( input );

	ext::ptr_value < FormalRegExpElement < SymbolType > > concatenation ( FormalRegExpConcatenation < SymbolType > ( std::move ( element1 ), std::move ( element2 ) ) );

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

	return concatenation;
}

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

	ext::ptr_value < FormalRegExpElement < SymbolType > > iteration ( FormalRegExpIteration < SymbolType > ( parseFormalRegExpElement < SymbolType > ( input ) ) );

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

	return iteration;
}

template < class SymbolType >
ext::ptr_value < FormalRegExpElement < SymbolType > > RegExpFromXmlParser::parseFormalRegExpEpsilon ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, "epsilon" );

	ext::ptr_value < FormalRegExpElement < SymbolType > > epsilon { FormalRegExpEpsilon < SymbolType > ( ) };

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

	return epsilon;
}

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

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

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

	return empty;
}

} /* namespace regexp */

