/*
 * LG.h
 *
 * This file is part of Algorithms library toolkit.
 * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)

 * Algorithms library toolkit is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * Algorithms library toolkit is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with Algorithms library toolkit.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  Created on: Nov 17, 2013
 *      Author: Jan Travnicek
 */

#pragma once

#include <sstream>

#include <alib/map>
#include <alib/set>
#include <alib/tuple>
#include <alib/vector>
#include <alib/variant>
#include <alib/algorithm>

#include <core/components.hpp>

#include <common/DefaultSymbolType.h>

#include <grammar/GrammarException.h>

#include <core/normalize.hpp>
#include <alphabet/common/SymbolNormalize.h>
#include <grammar/common/GrammarNormalize.h>

namespace grammar {

class TerminalAlphabet;
class NonterminalAlphabet;
class InitialSymbol;

/**
 * \brief
 * Context free grammar in Chomsky hierarchy or type 2 in Chomsky hierarchy. Generates context free languages.

 * \details
 * Definition is similar to all common definitions of context free grammars.
 * G = (N, T, P, S),
 * N (NonterminalAlphabet) = nonempty finite set of nonterminal symbols,
 * T (TerminalAlphabet) = finite set of terminal symbols - having this empty won't let grammar do much though,
 * P = set of production rules of the form A -> B, where A \in N and B \in ( N \cup T )*,
 * S (InitialSymbol) = initial nonterminal symbol,
 *
 * \tparam TerminalSymbolType used for the terminal alphabet of the grammar.
 * \tparam NonterminalSymbolType used for the nonterminal alphabet, and the initial symbol of the grammar.
 */
template < class TerminalSymbolType = DefaultSymbolType, class NonterminalSymbolType = DefaultSymbolType >
class LG final : public core::Components < LG < TerminalSymbolType, NonterminalSymbolType >, ext::set < TerminalSymbolType >, component::Set, TerminalAlphabet, ext::set < NonterminalSymbolType >, component::Set, NonterminalAlphabet, NonterminalSymbolType, component::Value, InitialSymbol > {
	/**
	 * Rules function as mapping from nonterminal symbol on the left hand side to a set of sequences of terminal and nonterminal symbols.
	 */
	ext::map < NonterminalSymbolType, ext::set < ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > > > rules;

public:
	/**
	 * \brief Creates a new instance of the grammar with a concrete initial symbol.
	 *
	 * \param initialSymbol the initial symbol of the grammar
	 */
	explicit LG ( NonterminalSymbolType initialSymbol );

	/**
	 * \brief Creates a new instance of the grammar with a concrete nonterminal alphabet, terminal alphabet and initial symbol.
	 *
	 * \param nonTerminalSymbols the initial nonterminal alphabet
	 * \param terminalSymbols the initial terminal alphabet
	 * \param initialSymbol the initial symbol of the grammar
	 */
	explicit LG ( ext::set < NonterminalSymbolType > nonterminalAlphabet, ext::set < TerminalSymbolType > terminalAlphabet, NonterminalSymbolType initialSymbol );

	/**
	 * \brief Add a new rule of a grammar.
	 *
	 * \details The rule is in a form of A -> aBb or A -> a, where A, B, \in N and a, b \in T*.
	 *
	 * \param leftHandSide the left hand side of the rule
	 * \param rightHandSide the right hand side of the rule
	 *
	 * \returns true if the rule was indeed added, false othervise
	 */
	bool addRule ( NonterminalSymbolType leftHandSide, ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > rightHandSide );

	/**
	 * \brief Add new rules of a grammar.
	 *
	 * \details The rules are in form of A -> aBb | cCd | ... | e | f | ..., where A, B, C \in N and a, b, c, d, e, f ... \in T*.
	 *
	 * \param leftHandSide the left hand side of the rule
	 * \param rightHandSide a set of right hand sides of the rule
	 */
	void addRules ( NonterminalSymbolType leftHandSide, ext::set < ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > > rightHandSide );

	/**
	 * Get rules of the grammar.
	 *
	 * \returns rules of the grammar
	 */
	const ext::map < NonterminalSymbolType, ext::set < ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > > > & getRules ( ) const &;

	/**
	 * Get rules of the grammar.
	 *
	 * \returns rules of the grammar
	 */
	ext::map < NonterminalSymbolType, ext::set < ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > > > && getRules ( ) &&;

	/**
	 * Remove a rule of a grammar in form of A -> aBb or A -> a, where A, B \in N and a, b \in T*.
	 *
	 * \param leftHandSide the left hand side of the rule
	 * \param rightHandSide the right hand side of the rule
	 *
	 * \returns true if the rule was indeed removed, false othervise
	 */
	bool removeRule ( const NonterminalSymbolType & leftHandSide, const ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > & rightHandSide );

	/**
	 * Remove a rule of a grammar in form of A -> a, where A \in N and a \in T*.
	 *
	 * \param leftHandSide the left hand side of the rule
	 * \param rightHandSide the right hand side of the rule
	 *
	 * \returns true if the rule was indeed removed, false othervise
	 */
	bool removeRule ( const NonterminalSymbolType & leftHandSide, const ext::vector < TerminalSymbolType > & rightHandSide );

	/**
	 * Remove a rule of a grammar in form of A -> aBb, where A, B \in N and a, b \in T*.
	 *
	 * \param leftHandSide the left hand side of the rule
	 * \param rightHandSide the right hand side of the rule
	 *
	 * \returns true if the rule was indeed removed, false othervise
	 */
	bool removeRule ( const NonterminalSymbolType & leftHandSide, const ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > & rightHandSide );

	/**
	 * Getter of initial symbol.
	 *
	 * \returns the initial symbol of the grammar
	 */
	const NonterminalSymbolType & getInitialSymbol ( ) const & {
		return this->template accessComponent < InitialSymbol > ( ).get ( );
	}

	/**
	 * Getter of initial symbol.
	 *
	 * \returns the initial symbol of the grammar
	 */
	NonterminalSymbolType && getInitialSymbol ( ) && {
		return std::move ( this->template accessComponent < InitialSymbol > ( ).get ( ) );
	}

	/**
	 * Setter of initial symbol.
	 *
	 * \param symbol new initial symbol of the grammar
	 *
	 * \returns true if the initial symbol was indeed changed
	 */
	bool setInitialSymbol ( NonterminalSymbolType symbol ) {
		return this->template accessComponent < InitialSymbol > ( ).set ( std::move ( symbol ) );
	}

	/**
	 * Getter of nonterminal alphabet.
	 *
	 * \returns the nonterminal alphabet of the grammar
	 */
	const ext::set < NonterminalSymbolType > & getNonterminalAlphabet ( ) const & {
		return this->template accessComponent < NonterminalAlphabet > ( ).get ( );
	}

	/**
	 * Getter of nonterminal alphabet.
	 *
	 * \returns the nonterminal alphabet of the grammar
	 */
	ext::set < NonterminalSymbolType > && getNonterminalAlphabet ( ) && {
		return std::move ( this->template accessComponent < NonterminalAlphabet > ( ).get ( ) );
	}

	/**
	 * Adder of nonterminal symbol.
	 *
	 * \param symbol the new symbol to be added to nonterminal alphabet
	 *
	 * \returns true if the symbol was indeed added
	 */
	bool addNonterminalSymbol ( NonterminalSymbolType symbol ) {
		return this->template accessComponent < NonterminalAlphabet > ( ).add ( std::move ( symbol ) );
	}

	/**
	 * Setter of nonterminal alphabet.
	 *
	 * \param symbols completely new nonterminal alphabet
	 */
	void setNonterminalAlphabet ( ext::set < NonterminalSymbolType > symbols ) {
		this->template accessComponent < NonterminalAlphabet > ( ).set ( std::move ( symbols ) );
	}

	/**
	 * Getter of terminal alphabet.
	 *
	 * \returns the terminal alphabet of the grammar
	 */
	const ext::set < TerminalSymbolType > & getTerminalAlphabet ( ) const & {
		return this->template accessComponent < TerminalAlphabet > ( ).get ( );
	}

	/**
	 * Getter of terminal alphabet.
	 *
	 * \returns the terminal alphabet of the grammar
	 */
	ext::set < TerminalSymbolType > && getTerminalAlphabet ( ) && {
		return std::move ( this->template accessComponent < TerminalAlphabet > ( ).get ( ) );
	}

	/**
	 * Adder of terminal symbol.
	 *
	 * \param symbol the new symbol tuo be added to nonterminal alphabet
	 *
	 * \returns true if the symbol was indeed added
	 */
	bool addTerminalSymbol ( TerminalSymbolType symbol ) {
		return this->template accessComponent < TerminalAlphabet > ( ).add ( std::move ( symbol ) );
	}

	/**
	 * Setter of terminal alphabet.
	 *
	 * \param symbol completely new nontemrinal alphabet
	 */
	void setTerminalAlphabet ( ext::set < TerminalSymbolType > symbols ) {
		this->template accessComponent < TerminalAlphabet > ( ).set ( std::move ( symbols ) );
	}

	/**
	 * The three way comparison implementation
	 *
	 * \param other the other instance
	 *
	 * \returns the ordering between this object and the @p other.
	 */
	auto operator <=> ( const LG & other ) const {
		return std::tie ( getTerminalAlphabet ( ), getNonterminalAlphabet ( ), getInitialSymbol ( ), rules ) <=> std::tie ( other.getTerminalAlphabet ( ), other.getNonterminalAlphabet ( ), other.getInitialSymbol ( ), other.rules );
	}

	/**
	 * The equality comparison implementation.
	 *
	 * \param other the other object to compare with.
	 *
	 * \returns true if this and other objects are equal, false othervise
	 */
	bool operator == ( const LG & other ) const {
		return std::tie ( getTerminalAlphabet ( ), getNonterminalAlphabet ( ), getInitialSymbol ( ), rules ) == std::tie ( other.getTerminalAlphabet ( ), other.getNonterminalAlphabet ( ), other.getInitialSymbol ( ), other.rules );
	}

	/**
	 * Print this object as raw representation to ostream.
	 *
	 * \param out ostream where to print
	 * \param instance object to print
	 *
	 * \returns modified output stream
	 */
	friend std::ostream & operator << ( std::ostream & out, const LG & instance ) {
		return out << "(LG "
			   << "nonterminalAlphabet = " << instance.getNonterminalAlphabet ( )
			   << "terminalAlphabet = " << instance.getTerminalAlphabet ( )
			   << "initialSymbol = " << instance.getInitialSymbol ( )
			   << "rules = " << instance.getRules ( )
			   << ")";
	}

	/**
	 * Casts this instance to as compact as possible string representation.
	 *
	 * \returns string representation of the object
	 */
	explicit operator std::string ( ) const;
};

template < class TerminalSymbolType, class NonterminalSymbolType >
LG < TerminalSymbolType, NonterminalSymbolType >::LG ( NonterminalSymbolType initialSymbol ) : LG ( ext::set < NonterminalSymbolType > { initialSymbol }, ext::set < TerminalSymbolType > ( ), initialSymbol ) {
}

template < class TerminalSymbolType, class NonterminalSymbolType >
LG < TerminalSymbolType, NonterminalSymbolType >::LG ( ext::set < NonterminalSymbolType > nonterminalAlphabet, ext::set < TerminalSymbolType > terminalAlphabet, NonterminalSymbolType initialSymbol ) : core::Components < LG, ext::set < TerminalSymbolType >, component::Set, TerminalAlphabet, ext::set < NonterminalSymbolType >, component::Set, NonterminalAlphabet, NonterminalSymbolType, component::Value, InitialSymbol > ( std::move ( terminalAlphabet), std::move ( nonterminalAlphabet ), std::move ( initialSymbol ) ) {
}

template < class TerminalSymbolType, class NonterminalSymbolType >
bool LG < TerminalSymbolType, NonterminalSymbolType >::addRule ( NonterminalSymbolType leftHandSide, ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > rightHandSide ) {
	if ( !getNonterminalAlphabet ( ).count ( leftHandSide ) )
		throw GrammarException ( "Rule must rewrite nonterminal symbol" );

	if ( rightHandSide.template is < ext::vector < TerminalSymbolType > > ( ) ) {
		const ext::vector < TerminalSymbolType > & rhs = rightHandSide.template get < ext::vector < TerminalSymbolType > > ( );

		for ( const TerminalSymbolType & symbol : rhs )
			if ( !getTerminalAlphabet ( ).count ( symbol ) )
				throw GrammarException ( "Symbol " + ext::to_string ( symbol ) + " is not a terminal symbol" );
	} else {
		const ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > & rhs = rightHandSide.template get < ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > ( );

		for ( const TerminalSymbolType & symbol : std::get < 0 > ( rhs ) )
			if ( !getTerminalAlphabet ( ).count ( symbol ) )
				throw GrammarException ( "Symbol " + ext::to_string ( symbol ) + " is not a terminal symbol" );

		if ( !getNonterminalAlphabet ( ).count ( std::get < 1 > ( rhs ) ) )
			throw GrammarException ( "Symbol " + ext::to_string ( std::get < 1 > ( rhs ) ) + " is not a nonterminal symbol" );

		for ( const TerminalSymbolType & symbol : std::get < 2 > ( rhs ) )
			if ( !getTerminalAlphabet ( ).count ( symbol ) )
				throw GrammarException ( "Symbol " + ext::to_string ( symbol ) + " is not a terminal symbol" );
	}

	return rules[std::move ( leftHandSide )].insert ( std::move ( rightHandSide ) ).second;
}

template < class TerminalSymbolType, class NonterminalSymbolType >
void LG < TerminalSymbolType, NonterminalSymbolType >::addRules ( NonterminalSymbolType leftHandSide, ext::set < ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > > rightHandSide ) {
	if ( !getNonterminalAlphabet ( ).count ( leftHandSide ) )
		throw GrammarException ( "Rule must rewrite nonterminal symbol" );

	for ( const ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > & element : rightHandSide ) {
		if ( element.template is < ext::vector < TerminalSymbolType > > ( ) ) {
			const ext::vector < TerminalSymbolType > & rhs = element.template get < ext::vector < TerminalSymbolType > > ( );

			for ( const TerminalSymbolType & symbol : rhs )
				if ( !getTerminalAlphabet ( ).count ( symbol ) )
					throw GrammarException ( "Symbol " + ext::to_string ( symbol ) + " is not a terminal symbol" );
		} else {
			const ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > & rhs = element.template get < ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > ( );

			for ( const TerminalSymbolType & symbol : std::get < 0 > ( rhs ) )
				if ( !getTerminalAlphabet ( ).count ( symbol ) )
					throw GrammarException ( "Symbol " + ext::to_string ( symbol ) + " is not a terminal symbol" );

			if ( !getNonterminalAlphabet ( ).count ( std::get < 1 > ( rhs ) ) )
				throw GrammarException ( "Symbol " + ext::to_string ( std::get < 1 > ( rhs ) ) + " is not a nonterminal symbol" );

			for ( const TerminalSymbolType & symbol : std::get < 2 > ( rhs ) )
				if ( !getTerminalAlphabet ( ).count ( symbol ) )
					throw GrammarException ( "Symbol " + ext::to_string ( symbol ) + " is not a terminal symbol" );
		}
	}

	rules [ std::move ( leftHandSide ) ].insert ( ext::make_mover ( rightHandSide ).begin ( ), ext::make_mover ( rightHandSide ).end ( ) );
}

template < class TerminalSymbolType, class NonterminalSymbolType >
const ext::map < NonterminalSymbolType, ext::set < ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > > > & LG < TerminalSymbolType, NonterminalSymbolType >::getRules ( ) const & {
	return rules;
}

template < class TerminalSymbolType, class NonterminalSymbolType >
ext::map < NonterminalSymbolType, ext::set < ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > > > && LG < TerminalSymbolType, NonterminalSymbolType >::getRules ( ) && {
	return std::move ( rules );
}

template < class TerminalSymbolType, class NonterminalSymbolType >
bool LG < TerminalSymbolType, NonterminalSymbolType >::removeRule ( const NonterminalSymbolType & leftHandSide, const ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > & rightHandSide ) {
	return rules[leftHandSide].erase ( rightHandSide );
}

template < class TerminalSymbolType, class NonterminalSymbolType >
bool LG < TerminalSymbolType, NonterminalSymbolType >::removeRule ( const NonterminalSymbolType & leftHandSide, const ext::vector < TerminalSymbolType > & rightHandSide ) {
	ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > rhs ( rightHandSide );

	return removeRule ( leftHandSide, rhs );
}

template < class TerminalSymbolType, class NonterminalSymbolType >
bool LG < TerminalSymbolType, NonterminalSymbolType >::removeRule ( const NonterminalSymbolType & leftHandSide, const ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > & rightHandSide ) {
	ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > rhs ( rightHandSide );

	return removeRule ( leftHandSide, rhs );
}

template < class TerminalSymbolType, class NonterminalSymbolType >
LG < TerminalSymbolType, NonterminalSymbolType >::operator std::string ( ) const {
	std::stringstream ss;
	ss << * this;
	return ss.str ( );
}

} /* namespace grammar */

namespace core {

/**
 * Helper class specifying constraints for the grammar's internal terminal alphabet component.
 *
 * \tparam TerminalSymbolType used for the terminal alphabet of the grammar.
 * \tparam NonterminalSymbolType used for the nonterminal alphabet, and the initial symbol of the grammar.
 */
template < class TerminalSymbolType, class NonterminalSymbolType >
class SetConstraint< grammar::LG < TerminalSymbolType, NonterminalSymbolType >, TerminalSymbolType, grammar::TerminalAlphabet > {
public:
	/**
	 * Returns true if the terminal symbol is still used in some rule of the grammar.
	 *
	 * \param grammar the tested grammar
	 * \param symbol the tested symbol
	 *
	 * \returns true if the symbol is used, false othervise
	 */
	static bool used ( const grammar::LG < TerminalSymbolType, NonterminalSymbolType > & grammar, const TerminalSymbolType & symbol ) {
		for ( const std::pair < const NonterminalSymbolType, ext::set < ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > > > & rule : grammar.getRules ( ) ) {
			for ( const ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > & rhsTmp : rule.second )
				if ( rhsTmp.template is < ext::vector < TerminalSymbolType > > ( ) ) {
					const ext::vector < TerminalSymbolType > & rhs = rhsTmp.template get < ext::vector < TerminalSymbolType > > ( );

					if ( std::find ( rhs.begin ( ), rhs.end ( ), symbol ) != rhs.end ( ) )
						return true;
				} else {
					const ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > & rhs = rhsTmp.template get < ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > ( );

					const ext::vector < TerminalSymbolType > & lPart = std::get < 0 > ( rhs );

					if ( std::find ( lPart.begin ( ), lPart.end ( ), symbol ) != lPart.end ( ) )
						return true;

					const ext::vector < TerminalSymbolType > & rPart = std::get < 2 > ( rhs );

					if ( std::find ( rPart.begin ( ), rPart.end ( ), symbol ) != rPart.end ( ) )
						return true;
				}

		}

		return false;
	}

	/**
	 * Returns true as all terminal symbols are possibly available to be terminal symbols.
	 *
	 * \param grammar the tested grammar
	 * \param symbol the tested symbol
	 *
	 * \returns true
	 */
	static bool available ( const grammar::LG < TerminalSymbolType, NonterminalSymbolType > &, const TerminalSymbolType & ) {
		return true;
	}

	/**
	 * Throws runtime exception if the symbol requested to be terminal symbol is already in nonterminal alphabet.
	 *
	 * \param grammar the tested grammar
	 * \param symbol the tested symbol
	 *
	 * \throws grammar::GrammarException of the tested symbol is in nonterminal alphabet
	 */
	static void valid ( const grammar::LG < TerminalSymbolType, NonterminalSymbolType > & grammar, const TerminalSymbolType & symbol ) {
		if ( grammar.template accessComponent < grammar::NonterminalAlphabet > ( ).get ( ).count ( ext::poly_comp ( symbol ) ) )
			throw grammar::GrammarException ( "Symbol " + ext::to_string ( symbol ) + " cannot be in the terminal alphabet since it is already in the nonterminal alphabet." );
	}
};

/**
 * Helper class specifying constraints for the grammar's internal nonterminal alphabet component.
 *
 * \tparam TerminalSymbolType used for the terminal alphabet of the grammar.
 * \tparam NonterminalSymbolType used for the nonterminal alphabet, and the initial symbol of the grammar.
 */
template < class TerminalSymbolType, class NonterminalSymbolType >
class SetConstraint< grammar::LG < TerminalSymbolType, NonterminalSymbolType >, NonterminalSymbolType, grammar::NonterminalAlphabet > {
public:
	/**
	 * Returns true if the nonterminal symbol is still used in some rule of the grammar or if it is the initial symbol of the grammar.
	 *
	 * \param grammar the tested grammar
	 * \param symbol the tested symbol
	 *
	 * \returns true if the symbol is used, false othervise
	 */
	static bool used ( const grammar::LG < TerminalSymbolType, NonterminalSymbolType > & grammar, const NonterminalSymbolType & symbol ) {
		for ( const std::pair < const NonterminalSymbolType, ext::set < ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > > > & rule : grammar.getRules ( ) ) {
			if ( rule.first == symbol )
				return true;

			for ( const ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > & rhsTmp : rule.second )
				if ( rhsTmp.template is < ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > ( ) ) {
					const ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > & rhs = rhsTmp.template get < ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > ( );

					if ( std::get < 1 > ( rhs ) == symbol )
						return true;
				}

		}

		return grammar.template accessComponent < grammar::InitialSymbol > ( ).get ( ) == symbol;
	}

	/**
	 * Returns true as all terminal symbols are possibly available to be nonterminal symbols.
	 *
	 * \param grammar the tested grammar
	 * \param symbol the tested symbol
	 *
	 * \returns true
	 */
	static bool available ( const grammar::LG < TerminalSymbolType, NonterminalSymbolType > &, const NonterminalSymbolType & ) {
		return true;
	}

	/**
	 * Throws runtime exception if the symbol requested to be nonterminal symbol is already in terminal alphabet.
	 *
	 * \param grammar the tested grammar
	 * \param symbol the tested symbol
	 *
	 * \throws grammar::GrammarException of the tested symbol is in nonterminal alphabet
	 */
	static void valid ( const grammar::LG < TerminalSymbolType, NonterminalSymbolType > & grammar, const NonterminalSymbolType & symbol ) {
		if ( grammar.template accessComponent < grammar::TerminalAlphabet > ( ).get ( ).count ( ext::poly_comp ( symbol ) ) )
			throw grammar::GrammarException ( "Symbol " + ext::to_string ( symbol ) + " cannot be in the nonterminal alphabet since it is already in the terminal alphabet." );
	}
};

/**
 * Helper class specifying constraints for the grammar's internal initial symbol element.
 *
 * \tparam TerminalSymbolType used for the terminal alphabet of the grammar.
 * \tparam NonterminalSymbolType used for the nonterminal alphabet, and the initial symbol of the grammar.
 */
template < class TerminalSymbolType, class NonterminalSymbolType >
class ElementConstraint< grammar::LG < TerminalSymbolType, NonterminalSymbolType >, NonterminalSymbolType, grammar::InitialSymbol > {
public:
	/**
	 * Returns true if the symbol requested to be initial is available in nonterminal alphabet.
	 *
	 * \param grammar the tested grammar
	 * \param symbol the tested symbol
	 *
	 * \returns true if the tested symbol is in nonterminal alphabet
	 */
	static bool available ( const grammar::LG < TerminalSymbolType, NonterminalSymbolType > & grammar, const NonterminalSymbolType & symbol ) {
		return grammar.template accessComponent < grammar::NonterminalAlphabet > ( ).get ( ).count ( symbol );
	}

	/**
	 * All symbols are valid as initial symbols.
	 *
	 * \param grammar the tested grammar
	 * \param symbol the tested symbol
	 */
	static void valid ( const grammar::LG < TerminalSymbolType, NonterminalSymbolType > &, const NonterminalSymbolType & ) {
	}
};

/**
 * Helper for normalisation of types specified by templates used as internal datatypes of symbols.
 *
 * \returns new instance of the grammar with default template parameters or unmodified instance if the template parameters were already default ones
 */
template < class TerminalSymbolType, class NonterminalSymbolType >
struct normalize < grammar::LG < TerminalSymbolType, NonterminalSymbolType > > {
	static grammar::LG < > eval ( grammar::LG < TerminalSymbolType, NonterminalSymbolType > && value ) {
		ext::set < DefaultSymbolType > nonterminals = alphabet::SymbolNormalize::normalizeAlphabet ( std::move ( value ).getNonterminalAlphabet ( ) );
		ext::set < DefaultSymbolType > terminals = alphabet::SymbolNormalize::normalizeAlphabet ( std::move ( value ).getTerminalAlphabet ( ) );
		DefaultSymbolType initialSymbol = alphabet::SymbolNormalize::normalizeSymbol ( std::move ( value ).getInitialSymbol ( ) );

		grammar::LG < > res ( std::move ( nonterminals ), std::move ( terminals ), std::move ( initialSymbol ) );

		for ( std::pair < NonterminalSymbolType, ext::set < ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > > > && rule : ext::make_mover ( std::move ( value ).getRules ( ) ) ) {

			ext::set < ext::variant < ext::vector < DefaultSymbolType >, ext::tuple < ext::vector < DefaultSymbolType >, DefaultSymbolType, ext::vector < DefaultSymbolType > > > > rhs;
			for ( ext::variant < ext::vector < TerminalSymbolType >, ext::tuple < ext::vector < TerminalSymbolType >, NonterminalSymbolType, ext::vector < TerminalSymbolType > > > && target : ext::make_mover ( rule.second ) )
				rhs.insert ( grammar::GrammarNormalize::normalizeRHS ( std::move ( target ) ) );

			DefaultSymbolType lhs = alphabet::SymbolNormalize::normalizeSymbol ( std::move ( rule.first ) );

			res.addRules ( std::move ( lhs ), std::move ( rhs ) );
		}

		return res;
	}
};

} /* namespace core */

extern template class grammar::LG < >;

