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

#ifndef RTE_TO_XML_COMPOSER_H_
#define RTE_TO_XML_COMPOSER_H_

#include <alib/deque>
#include <rte/formal/FormalRTEElement.h>
#include <sax/Token.h>
#include <core/xmlApi.hpp>

#include <alphabet/xml/RankedSymbol.h>

namespace rte {

/**
 * This class contains methods to print XML representation of regular tree expression to the output stream.
 */
class RTEToXmlComposer {
public:
	template < class SymbolType >
	static void composeAlphabet ( ext::deque < sax::Token > & output, const ext::set < common::ranked_symbol < SymbolType > > & alphabetF, const ext::set < common::ranked_symbol < SymbolType > > & alphabetK );

	class Formal {
	public:
		template < class SymbolType >
		static void visit ( const FormalRTEAlternation < SymbolType > & alternation, ext::deque < sax::Token > & output );
		template < class SymbolType >
		static void visit ( const FormalRTEIteration < SymbolType > & iteration, ext::deque < sax::Token > & output );
		template < class SymbolType >
		static void visit ( const FormalRTESubstitution < SymbolType > & substitution, ext::deque < sax::Token > & output );
		template < class SymbolType >
		static void visit ( const FormalRTESymbolAlphabet < SymbolType > & symbol, ext::deque < sax::Token > & output );
		template < class SymbolType >
		static void visit ( const FormalRTESymbolSubst < SymbolType > & symbol, ext::deque < sax::Token > & output );
		template < class SymbolType >
		static void visit ( const FormalRTEEmpty < SymbolType > & empty, ext::deque < sax::Token > & output );
	};
};

template < class SymbolType >
void RTEToXmlComposer::Formal::visit ( const FormalRTEAlternation < SymbolType > & alternation, ext::deque < sax::Token > & output ) {
	output.emplace_back ( "alternation", sax::Token::TokenType::START_ELEMENT );
	alternation.getLeftElement ( ).template accept < void, RTEToXmlComposer::Formal > ( output );
	alternation.getRightElement ( ).template accept < void, RTEToXmlComposer::Formal > ( output );
	output.emplace_back ( "alternation", sax::Token::TokenType::END_ELEMENT );
}

template < class SymbolType >
void RTEToXmlComposer::Formal::visit ( const FormalRTESubstitution < SymbolType > & substitution, ext::deque < sax::Token > & output ) {
	output.emplace_back ( "substitution", sax::Token::TokenType::START_ELEMENT );

	core::xmlApi < common::ranked_symbol < SymbolType > >::compose ( output, substitution.getSubstitutionSymbol ( ).getSymbol ( ) );
	substitution.getLeftElement ( ).template accept < void, RTEToXmlComposer::Formal > ( output );
	substitution.getRightElement ( ).template accept < void, RTEToXmlComposer::Formal > ( output );

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

template < class SymbolType >
void RTEToXmlComposer::Formal::visit ( const FormalRTEIteration < SymbolType > & iteration, ext::deque < sax::Token > & output ) {
	output.emplace_back ( "iteration", sax::Token::TokenType::START_ELEMENT );

	core::xmlApi < common::ranked_symbol < SymbolType > >::compose ( output, iteration.getSubstitutionSymbol ( ).getSymbol ( ) );
	iteration.getElement ( ).template accept < void, RTEToXmlComposer::Formal > ( output );

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

template < class SymbolType >
void RTEToXmlComposer::Formal::visit ( const FormalRTESymbolAlphabet < SymbolType > & symbol, ext::deque < sax::Token > & output ) {
	output.emplace_back ( sax::Token ( "symbol", sax::Token::TokenType::START_ELEMENT ) );
	core::xmlApi < common::ranked_symbol < SymbolType > >::compose ( output, symbol.getSymbol ( ) );

	for ( const FormalRTEElement < SymbolType > & element : symbol.getElements ( ) )
		element.template accept < void, RTEToXmlComposer::Formal > ( output );

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

template < class SymbolType >
void RTEToXmlComposer::Formal::visit ( const FormalRTESymbolSubst < SymbolType > & symbol, ext::deque < sax::Token > & output ) {
	output.emplace_back ( sax::Token ( "substSymbol", sax::Token::TokenType::START_ELEMENT ) );
	core::xmlApi < common::ranked_symbol < SymbolType > >::compose ( output, symbol.getSymbol ( ) );

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

template < class SymbolType >
void RTEToXmlComposer::Formal::visit ( const FormalRTEEmpty < SymbolType > &, ext::deque < sax::Token > & output ) {
	output.emplace_back ( "empty", sax::Token::TokenType::START_ELEMENT );
	output.emplace_back ( "empty", sax::Token::TokenType::END_ELEMENT );
}

template < class SymbolType >
void RTEToXmlComposer::composeAlphabet ( ext::deque < sax::Token > & output, const ext::set < common::ranked_symbol < SymbolType > > & alphabetF, const ext::set < common::ranked_symbol < SymbolType > > & alphabetK ) {
	output.emplace_back ( "alphabet", sax::Token::TokenType::START_ELEMENT );

	for ( const auto & symbol : alphabetF )
		core::xmlApi < common::ranked_symbol < SymbolType > >::compose ( output, symbol );

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

	output.emplace_back ( "substSymbolAlphabet", sax::Token::TokenType::START_ELEMENT );

	for ( const auto & symbol : alphabetK )
		core::xmlApi < common::ranked_symbol < SymbolType > >::compose ( output, symbol );

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

} /* namespace rte */

#endif /* RTE_TO_XML_COMPOSER_H_ */
