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

#ifndef REG_EXP_TO_XML_COMPOSER_H_
#define REG_EXP_TO_XML_COMPOSER_H_

#include <alib/deque>
#include <regexp/unbounded/UnboundedRegExpElement.h>
#include <regexp/formal/FormalRegExpElement.h>
#include <sax/Token.h>

#include <core/xmlApi.hpp>

namespace regexp {

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

	class Unbounded {
	public:
		template < class SymbolType >
		static void visit( const UnboundedRegExpAlternation < SymbolType > & alternation, ext::deque < sax::Token > & output);
		template < class SymbolType >
		static void visit( const UnboundedRegExpConcatenation < SymbolType > & concatenation, ext::deque < sax::Token > & output);
		template < class SymbolType >
		static void visit( const UnboundedRegExpIteration < SymbolType > & iteration, ext::deque < sax::Token > & output);
		template < class SymbolType >
		static void visit( const UnboundedRegExpSymbol < SymbolType > & symbol, ext::deque < sax::Token > & output);
		template < class SymbolType >
		static void visit( const UnboundedRegExpEpsilon < SymbolType > & epsilon, ext::deque < sax::Token > & output);
		template < class SymbolType >
		static void visit( const UnboundedRegExpEmpty < SymbolType > & empty, ext::deque < sax::Token > & output);
	};

	class Formal {
	public:
		template < class SymbolType >
		static void visit( const FormalRegExpAlternation < SymbolType > & alternation, ext::deque < sax::Token > & output);
		template < class SymbolType >
		static void visit( const FormalRegExpConcatenation < SymbolType > & concatenation, ext::deque < sax::Token > & output);
		template < class SymbolType >
		static void visit( const FormalRegExpIteration < SymbolType > & iteration, ext::deque < sax::Token > & output);
		template < class SymbolType >
		static void visit( const FormalRegExpSymbol < SymbolType > & symbol, ext::deque < sax::Token > & output);
		template < class SymbolType >
		static void visit( const FormalRegExpEpsilon < SymbolType > & epsilon, ext::deque < sax::Token > & output);
		template < class SymbolType >
		static void visit( const FormalRegExpEmpty < SymbolType > & empty, ext::deque < sax::Token > & output);
	};
};

template < class SymbolType >
void RegExpToXmlComposer::Unbounded::visit(const UnboundedRegExpAlternation < SymbolType > & alternation, ext::deque<sax::Token>& output) {
	output.emplace_back("alternation", sax::Token::TokenType::START_ELEMENT);
	for (const UnboundedRegExpElement < SymbolType > & element : alternation.getElements()) {
		element.template accept < void, RegExpToXmlComposer::Unbounded > ( output );
	}
	output.emplace_back("alternation", sax::Token::TokenType::END_ELEMENT);
}

template < class SymbolType >
void RegExpToXmlComposer::Unbounded::visit(const UnboundedRegExpConcatenation < SymbolType > & concatenation, ext::deque<sax::Token>& output) {
	output.emplace_back("concatenation", sax::Token::TokenType::START_ELEMENT);
	for (const UnboundedRegExpElement < SymbolType > & element : concatenation.getElements()) {
		element.template accept < void, RegExpToXmlComposer::Unbounded > ( output );
	}
	output.emplace_back("concatenation", sax::Token::TokenType::END_ELEMENT);
}

template < class SymbolType >
void RegExpToXmlComposer::Unbounded::visit(const UnboundedRegExpIteration < SymbolType > & iteration, ext::deque<sax::Token>& output) {
	output.emplace_back("iteration", sax::Token::TokenType::START_ELEMENT);
	iteration.getElement().template accept < void, RegExpToXmlComposer::Unbounded > ( output );
	output.emplace_back("iteration", sax::Token::TokenType::END_ELEMENT);
}

template < class SymbolType >
void RegExpToXmlComposer::Unbounded::visit(const UnboundedRegExpSymbol < SymbolType > & symbol, ext::deque<sax::Token>& output) {
	core::xmlApi<SymbolType>::compose(output, symbol.getSymbol());
}

template < class SymbolType >
void RegExpToXmlComposer::Unbounded::visit(const UnboundedRegExpEpsilon < SymbolType > &, ext::deque<sax::Token>& output) {
	output.emplace_back("epsilon", sax::Token::TokenType::START_ELEMENT);
	output.emplace_back("epsilon", sax::Token::TokenType::END_ELEMENT);
}

template < class SymbolType >
void RegExpToXmlComposer::Unbounded::visit(const UnboundedRegExpEmpty < 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 RegExpToXmlComposer::Formal::visit(const FormalRegExpAlternation < SymbolType > & alternation, ext::deque<sax::Token>& output) {
	output.emplace_back("alternation", sax::Token::TokenType::START_ELEMENT);
	alternation.getLeftElement().template accept < void, RegExpToXmlComposer::Formal > ( output );
	alternation.getRightElement().template accept < void, RegExpToXmlComposer::Formal > ( output );
	output.emplace_back("alternation", sax::Token::TokenType::END_ELEMENT);
}

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

template < class SymbolType >
void RegExpToXmlComposer::Formal::visit(const FormalRegExpIteration < SymbolType > & iteration, ext::deque<sax::Token>& output) {
	output.emplace_back("iteration", sax::Token::TokenType::START_ELEMENT);
	iteration.getElement().template accept < void, RegExpToXmlComposer::Formal > ( output );
	output.emplace_back("iteration", sax::Token::TokenType::END_ELEMENT);
}

template < class SymbolType >
void RegExpToXmlComposer::Formal::visit(const FormalRegExpSymbol < SymbolType > & symbol, ext::deque<sax::Token>& output) {
	core::xmlApi<SymbolType>::compose(output, symbol.getSymbol());
}

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

template < class SymbolType >
void RegExpToXmlComposer::Formal::visit(const FormalRegExpEmpty < 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 RegExpToXmlComposer::composeAlphabet(ext::deque<sax::Token>& output, const ext::set<SymbolType>& alphabet) {
	output.emplace_back("alphabet", sax::Token::TokenType::START_ELEMENT);
	for (const SymbolType & symbol : alphabet) {
		core::xmlApi<SymbolType>::compose(output, symbol);
	}
	output.emplace_back("alphabet", sax::Token::TokenType::END_ELEMENT);
}

} /* namespace regexp */

#endif /* REG_EXP_TO_XML_COMPOSER_H_ */
