#include <catch2/catch.hpp>

#include "automaton/simplify/SingleInitialState.h"
#include "automaton/determinize/Determinize.h"
#include "automaton/simplify/Normalize.h"
#include "automaton/simplify/Minimize.h"

#include "automaton/FSM/MultiInitialStateNFA.h"

TEST_CASE ( "FSM Single initial state", "[unit][algo][automaton][simplify]" ) {
	SECTION ( "MISNFA to single initial state NFA" ) {
		DefaultStateType q  = DefaultStateType ("q");
		DefaultStateType q0 = DefaultStateType ("q0");
		DefaultStateType q1 = DefaultStateType ("q1");
		DefaultStateType q2 = DefaultStateType ("q2");
		DefaultStateType q3 = DefaultStateType ("q3");

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

		automaton::MultiInitialStateNFA < > automaton1;
		automaton1.setStates({q0, q1, q2, q3});
		automaton1.setInitialStates({q0, q1, q2});
		automaton1.setFinalStates({q3});
		automaton1.setInputAlphabet({a, b});
		automaton1.addTransition(q0, a, q1);
		automaton1.addTransition(q1, b, q2);
		automaton1.addTransition(q2, a, q3);

		automaton::NFA < > automaton2 = automaton::simplify::SingleInitialState::convert(automaton1);

		automaton::NFA < > automaton3(q);
		automaton3.setStates({q, q1, q2, q3});
		automaton3.setFinalStates({q3});
		automaton3.setInputAlphabet({a, b});
		automaton3.addTransition(q, a, q3);
		automaton3.addTransition(q, b, q2);
		automaton3.addTransition(q, a, q1);
		automaton3.addTransition(q1, b, q2);
		automaton3.addTransition(q2, a, q3);

		automaton::DFA < DefaultSymbolType, ext::set < DefaultStateType > > dfa2 = automaton::simplify::Minimize::minimize(automaton::determinize::Determinize::determinize(automaton2));
		automaton::DFA < DefaultSymbolType, ext::set < DefaultStateType > > dfa3 = automaton::simplify::Minimize::minimize(automaton::determinize::Determinize::determinize(automaton3));

		CHECK (automaton::simplify::Normalize::normalize(dfa2) == automaton::simplify::Normalize::normalize(dfa3));
	}

	SECTION ( "MISNFA to single initial state NFA final state initial" ) {
		DefaultStateType q  = DefaultStateType ("q");
		DefaultStateType q0 = DefaultStateType ("q0");
		DefaultStateType q1 = DefaultStateType ("q1");
		DefaultStateType q2 = DefaultStateType ("q2");
		DefaultStateType q3 = DefaultStateType ("q3");

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

		automaton::MultiInitialStateNFA < > automaton1;
		automaton1.setStates({q0, q1, q2, q3});
		automaton1.setInitialStates({q0, q1, q3});
		automaton1.setFinalStates({q3});
		automaton1.setInputAlphabet({a, b});
		automaton1.addTransition(q0, a, q1);
		automaton1.addTransition(q1, b, q2);
		automaton1.addTransition(q2, a, q3);

		automaton::NFA < > automaton2 = automaton::simplify::SingleInitialState::convert(automaton1);

		automaton::DFA < DefaultSymbolType, ext::set < DefaultStateType > > dfa2 = automaton::simplify::Minimize::minimize(automaton::determinize::Determinize::determinize(automaton2));
		automaton::DFA < DefaultSymbolType, ext::set < DefaultStateType > > dfa3 = automaton::simplify::Minimize::minimize(automaton::determinize::Determinize::determinize(automaton1));

		CHECK (automaton::simplify::Normalize::normalize(dfa2) == automaton::simplify::Normalize::normalize(dfa3));
	}
}
