#include <catch2/catch.hpp>

#include "grammar/simplify/SimpleRulesRemover.h"

#include "grammar/ContextFree/CFG.h"
#include "grammar/ContextFree/EpsilonFreeCFG.h"

TEST_CASE ( "Simple rules remover", "[unit][algo][grammar][simplify]" ) {
	SECTION ( "Test CFG" ) {
		{
			DefaultSymbolType S = DefaultSymbolType("S");
			DefaultSymbolType A = DefaultSymbolType("A");
			DefaultSymbolType B = DefaultSymbolType("B");
			DefaultSymbolType C = DefaultSymbolType("C");
			DefaultSymbolType D = DefaultSymbolType("D");

			DefaultSymbolType a = DefaultSymbolType('a');
			DefaultSymbolType b = DefaultSymbolType('b');

			grammar::CFG < > grammar1(S);
			grammar1.setNonterminalAlphabet({S, A, B, C, D});
			grammar1.setTerminalAlphabet({a, b});

			grammar::CFG < > grammar2 = grammar::simplify::SimpleRulesRemover::remove(grammar1);

			grammar::CFG < > grammar3(S);
			grammar3.setNonterminalAlphabet({S, A, B, C, D});
			grammar3.setTerminalAlphabet({a, b});

			CHECK(grammar2 == grammar3);
		}
		{
			DefaultSymbolType S = DefaultSymbolType("S");
			DefaultSymbolType A = DefaultSymbolType("A");
			DefaultSymbolType B = DefaultSymbolType("B");
			DefaultSymbolType C = DefaultSymbolType("C");
			DefaultSymbolType D = DefaultSymbolType("D");

			DefaultSymbolType a = DefaultSymbolType('a');
			DefaultSymbolType b = DefaultSymbolType('b');
			DefaultSymbolType c = DefaultSymbolType('c');
			DefaultSymbolType d = DefaultSymbolType('d');

			grammar::CFG < > grammar1(S);
			grammar1.setNonterminalAlphabet({S, A, B, C, D});
			grammar1.setTerminalAlphabet({a, b, c, d});
			grammar1.addRule(S, {A});
			grammar1.addRule(A, {a, A, d, D});
			grammar1.addRule(A, {B});
			grammar1.addRule(B, {b, B, c, C});
			grammar1.addRule(B, {});
			grammar1.addRule(C, {c, C});
			grammar1.addRule(C, {});
			grammar1.addRule(D, {d, D});
			grammar1.addRule(D, {});

			grammar::CFG < > grammar2 = grammar::simplify::SimpleRulesRemover::remove(grammar1);

			grammar::CFG < > grammar3(S);
			grammar3.setNonterminalAlphabet({S, A, B, C, D});
			grammar3.setTerminalAlphabet({a, b, c, d});
			grammar3.addRule(S, {a, A, d, D});
			grammar3.addRule(S, {b, B, c, C});
			grammar3.addRule(S, {});
			grammar3.addRule(A, {a, A, d, D});
			grammar3.addRule(A, {b, B, c, C});
			grammar3.addRule(A, {});
			grammar3.addRule(B, {b, B, c, C});
			grammar3.addRule(B, {});
			grammar3.addRule(C, {c, C});
			grammar3.addRule(C, {});
			grammar3.addRule(D, {d, D});
			grammar3.addRule(D, {});

			CHECK(grammar2 == grammar3);
		}
		{
			DefaultSymbolType S = DefaultSymbolType("S");
			DefaultSymbolType A = DefaultSymbolType("A");
			DefaultSymbolType B = DefaultSymbolType("B");
			DefaultSymbolType C = DefaultSymbolType("C");
			DefaultSymbolType D = DefaultSymbolType("D");

			DefaultSymbolType a = DefaultSymbolType('a');
			DefaultSymbolType b = DefaultSymbolType('b');
			DefaultSymbolType c = DefaultSymbolType('c');
			DefaultSymbolType d = DefaultSymbolType('d');

			grammar::EpsilonFreeCFG < > grammar1(S);
			grammar1.setNonterminalAlphabet({S, A, B, C, D});
			grammar1.setTerminalAlphabet({a, b, c, d});
			grammar1.addRule(S, {A});
			grammar1.addRule(A, {a, A, d, D});
			grammar1.addRule(A, {B});
			grammar1.addRule(B, {b, B, c, C});
			grammar1.addRule(B, {c});
			grammar1.addRule(C, {c, C});
			grammar1.addRule(C, {b});
			grammar1.addRule(D, {d, D});
			grammar1.addRule(D, {a});

			grammar::EpsilonFreeCFG < > grammar2 = grammar::simplify::SimpleRulesRemover::remove(grammar1);

			grammar::EpsilonFreeCFG < > grammar3(S);
			grammar3.setNonterminalAlphabet({S, A, B, C, D});
			grammar3.setTerminalAlphabet({a, b, c, d});
			grammar3.addRule(S, {a, A, d, D});
			grammar3.addRule(S, {b, B, c, C});
			grammar3.addRule(S, {c});
			grammar3.addRule(A, {a, A, d, D});
			grammar3.addRule(A, {b, B, c, C});
			grammar3.addRule(A, {c});
			grammar3.addRule(B, {b, B, c, C});
			grammar3.addRule(B, {c});
			grammar3.addRule(C, {c, C});
			grammar3.addRule(C, {b});
			grammar3.addRule(D, {d, D});
			grammar3.addRule(D, {a});

			CHECK(grammar2 == grammar3);
		}
	}
}
