#include <catch2/catch.hpp>

#include "grammar/convert/ToGrammarLeftRG.h"
#include "grammar/convert/ToGrammarRightRG.h"

TEST_CASE ( "Left <-> Right Regular Grammar", "[unit][algo][grammar][convert]" ) {
	SECTION ( "Right to left" ) {
		grammar::RightRG < > rrGrammar(DefaultSymbolType(1));

		rrGrammar.addNonterminalSymbol(DefaultSymbolType(1));
		rrGrammar.addNonterminalSymbol(DefaultSymbolType(2));
		rrGrammar.addNonterminalSymbol(DefaultSymbolType(3));
		rrGrammar.addTerminalSymbol(DefaultSymbolType("a"));
		rrGrammar.addTerminalSymbol(DefaultSymbolType("b"));

		rrGrammar.addRule(DefaultSymbolType(1), ext::make_pair(DefaultSymbolType("a"), DefaultSymbolType(2)));
		rrGrammar.addRule(DefaultSymbolType(2), ext::make_pair(DefaultSymbolType("b"), DefaultSymbolType(3)));
		rrGrammar.addRule(DefaultSymbolType(3), DefaultSymbolType("a"));

		grammar::LeftRG < > lrGrammar = grammar::convert::ToGrammarLeftRG::convert(rrGrammar);

		DefaultSymbolType four ( object::AnyObject < int > ( 1, 1 ) );
		grammar::LeftRG < > lrGrammarRef ( four );

		lrGrammarRef.addNonterminalSymbol(DefaultSymbolType(1));
		lrGrammarRef.addNonterminalSymbol(DefaultSymbolType(2));
		lrGrammarRef.addNonterminalSymbol(DefaultSymbolType(3));
		lrGrammarRef.addTerminalSymbol(DefaultSymbolType("a"));
		lrGrammarRef.addTerminalSymbol(DefaultSymbolType("b"));

		lrGrammarRef.addRule(DefaultSymbolType(2), ext::make_pair(DefaultSymbolType(1), DefaultSymbolType("a")));
		lrGrammarRef.addRule(DefaultSymbolType(2), DefaultSymbolType("a"));
		lrGrammarRef.addRule(DefaultSymbolType(3), ext::make_pair(DefaultSymbolType(2), DefaultSymbolType("b")));
		lrGrammarRef.addRule(four, ext::make_pair(DefaultSymbolType(3), DefaultSymbolType("a")));

		CHECK(lrGrammarRef == lrGrammar);
	}
	SECTION ( "Left to right" ) {
		grammar::LeftRG < > lrGrammar(DefaultSymbolType(4));

		lrGrammar.addNonterminalSymbol(DefaultSymbolType(2));
		lrGrammar.addNonterminalSymbol(DefaultSymbolType(3));
		lrGrammar.addNonterminalSymbol(DefaultSymbolType(4));
		lrGrammar.addTerminalSymbol(DefaultSymbolType("a"));
		lrGrammar.addTerminalSymbol(DefaultSymbolType("b"));

		lrGrammar.addRule(DefaultSymbolType(2), DefaultSymbolType("a"));
		lrGrammar.addRule(DefaultSymbolType(3), ext::make_pair(DefaultSymbolType(2), DefaultSymbolType("b")));
		lrGrammar.addRule(DefaultSymbolType(4), ext::make_pair(DefaultSymbolType(3), DefaultSymbolType("a")));

		grammar::RightRG < > rrGrammar = grammar::convert::ToGrammarRightRG::convert(lrGrammar);

		DefaultSymbolType five ( object::AnyObject < int > ( 4, 1 ) );
		grammar::RightRG < > rrGrammarRef ( five );

		rrGrammarRef.addNonterminalSymbol(DefaultSymbolType(2));
		rrGrammarRef.addNonterminalSymbol(DefaultSymbolType(3));
		rrGrammarRef.addNonterminalSymbol(DefaultSymbolType(4));
		rrGrammarRef.addTerminalSymbol(DefaultSymbolType("a"));
		rrGrammarRef.addTerminalSymbol(DefaultSymbolType("b"));

		rrGrammarRef.addRule(five, ext::make_pair(DefaultSymbolType("a"), DefaultSymbolType(2)));
		rrGrammarRef.addRule(DefaultSymbolType(2), ext::make_pair(DefaultSymbolType("b"), DefaultSymbolType(3)));
		rrGrammarRef.addRule(DefaultSymbolType(3), DefaultSymbolType("a"));
		rrGrammarRef.addRule(DefaultSymbolType(3), ext::make_pair(DefaultSymbolType("a"), DefaultSymbolType(4)));

		CHECK(rrGrammarRef == rrGrammar);
	}
}
