/*
 * GrammarFromXMLParser.h
 *
 *  Created on: Oct 12, 2013
 *      Author: Martin Zak
 */

#ifndef GRAMMAR_FROM_XML_PARSER_H_
#define GRAMMAR_FROM_XML_PARSER_H_

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

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

namespace grammar {

/**
 * Parser used to get general FSM or EpsilonNFA, NFA, DFA from XML parsed into list of Tokens.
 */
class GrammarFromXMLParser {
public:
	template < class SymbolType >
	static ext::set<SymbolType> parseNonterminalAlphabet(ext::deque<sax::Token>::iterator& input);
	template < class SymbolType >
	static ext::set<SymbolType> parseTerminalAlphabet(ext::deque<sax::Token>::iterator& input);
	template < class SymbolType >
	static SymbolType parseInitialSymbol(ext::deque<sax::Token>::iterator& input);

	static bool parseGeneratesEpsilon(ext::deque<sax::Token>::iterator& input) {
		bool generatesEpsilon;
		sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::START_ELEMENT, "generatesEpsilon");
		if(sax::FromXMLParserHelper::isToken(input, sax::Token::TokenType::START_ELEMENT, "true")) {
			++input;
			sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "true");
			generatesEpsilon = true;
		} else {
			sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::START_ELEMENT, "false");
			sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "false");
			generatesEpsilon = false;
		}
		sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "generatesEpsilon");
		return generatesEpsilon;
	}

	template < class SymbolType >
	static ext::vector<SymbolType> parseRuleLContext(ext::deque<sax::Token>::iterator& input);
	template < class SymbolType >
	static ext::vector<SymbolType> parseRuleLHS(ext::deque<sax::Token>::iterator& input);
	template < class SymbolType >
	static ext::vector<SymbolType> parseRuleRContext(ext::deque<sax::Token>::iterator& input);
	template < class SymbolType >
	static SymbolType parseRuleSingleSymbolLHS(ext::deque<sax::Token>::iterator& input);
	template < class SymbolType >
	static ext::vector<SymbolType> parseRuleRHS(ext::deque<sax::Token>::iterator& input);

	template<class T>
	static void parseRules(ext::deque<sax::Token>::iterator& input, T& grammar);
};

template < class SymbolType >
ext::set<SymbolType> GrammarFromXMLParser::parseNonterminalAlphabet(ext::deque<sax::Token>::iterator& input) {
	ext::set<SymbolType> inputSymbols;
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::START_ELEMENT, "nonterminalAlphabet");
	while (sax::FromXMLParserHelper::isTokenType(input, sax::Token::TokenType::START_ELEMENT)) {
		inputSymbols.insert(core::xmlApi<SymbolType>::parse(input));
	}
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "nonterminalAlphabet");
	return inputSymbols;
}

template < class SymbolType >
ext::set<SymbolType> GrammarFromXMLParser::parseTerminalAlphabet(ext::deque<sax::Token>::iterator& input) {
	ext::set<SymbolType> inputSymbols;
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::START_ELEMENT, "terminalAlphabet");
	while (sax::FromXMLParserHelper::isTokenType(input, sax::Token::TokenType::START_ELEMENT)) {
		inputSymbols.insert(core::xmlApi<SymbolType>::parse(input));
	}
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "terminalAlphabet");
	return inputSymbols;
}

template < class SymbolType >
SymbolType GrammarFromXMLParser::parseInitialSymbol(ext::deque<sax::Token>::iterator& input) {
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::START_ELEMENT, "initialSymbol");
	SymbolType blank(core::xmlApi<SymbolType>::parse(input));
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "initialSymbol");
	return blank;
}

template < class SymbolType >
ext::vector<SymbolType> GrammarFromXMLParser::parseRuleLContext(ext::deque<sax::Token>::iterator& input) {
	ext::vector<SymbolType> lContext;
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::START_ELEMENT, "lContext");
	if(sax::FromXMLParserHelper::isToken(input, sax::Token::TokenType::START_ELEMENT, "epsilon")) {
		++input;
		sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "epsilon");
	} else while (sax::FromXMLParserHelper::isTokenType(input, sax::Token::TokenType::START_ELEMENT)) {
		lContext.push_back(core::xmlApi<SymbolType>::parse(input));
	}
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "lContext");
	return lContext;
}

template < class SymbolType >
ext::vector<SymbolType> GrammarFromXMLParser::parseRuleLHS(ext::deque<sax::Token>::iterator& input) {
	ext::vector<SymbolType> lhs;
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::START_ELEMENT, "lhs");
	if(sax::FromXMLParserHelper::isToken(input, sax::Token::TokenType::START_ELEMENT, "epsilon")) {
		++input;
		sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "epsilon");
	} else while (sax::FromXMLParserHelper::isTokenType(input, sax::Token::TokenType::START_ELEMENT)) {
		lhs.push_back(core::xmlApi<SymbolType>::parse(input));
	}
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "lhs");
	return lhs;
}

template < class SymbolType >
SymbolType GrammarFromXMLParser::parseRuleSingleSymbolLHS(ext::deque<sax::Token>::iterator& input) {
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::START_ELEMENT, "lhs");
	SymbolType lhs = core::xmlApi<SymbolType>::parse(input);
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "lhs");
	return lhs;
}

template < class SymbolType >
ext::vector<SymbolType> GrammarFromXMLParser::parseRuleRContext(ext::deque<sax::Token>::iterator& input) {
	ext::vector<SymbolType> rContext;
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::START_ELEMENT, "rContext");
	if(sax::FromXMLParserHelper::isToken(input, sax::Token::TokenType::START_ELEMENT, "epsilon")) {
		++input;
		sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "epsilon");
	} else while (sax::FromXMLParserHelper::isTokenType(input, sax::Token::TokenType::START_ELEMENT)) {
		rContext.push_back(core::xmlApi<SymbolType>::parse(input));
	}
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "rContext");
	return rContext;
}

template < class SymbolType >
ext::vector<SymbolType> GrammarFromXMLParser::parseRuleRHS(ext::deque<sax::Token>::iterator& input) {
	ext::vector<SymbolType> rhs;
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::START_ELEMENT, "rhs");
	if(sax::FromXMLParserHelper::isToken(input, sax::Token::TokenType::START_ELEMENT, "epsilon")) {
		++input;
		sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "epsilon");
	} else while (sax::FromXMLParserHelper::isTokenType(input, sax::Token::TokenType::START_ELEMENT)) {
		rhs.push_back(core::xmlApi<SymbolType>::parse(input));
	}
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "rhs");
	return rhs;
}

template<class T>
void GrammarFromXMLParser::parseRules(ext::deque<sax::Token>::iterator& input, T& grammar) {
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::START_ELEMENT, "rules");
	while (sax::FromXMLParserHelper::isTokenType(input, sax::Token::TokenType::START_ELEMENT)) {
		sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::START_ELEMENT, "rule");
		core::xmlApi < T >::parseRule(input, grammar);
		sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "rule");
	}
	sax::FromXMLParserHelper::popToken(input, sax::Token::TokenType::END_ELEMENT, "rules");
}

} /* namespace grammar */

#endif /* GRAMMAR_FROM_XML_PARSER_H_ */
