#include <catch2/catch.hpp>

#include "automaton/transform/AutomatonIteration.h"

TEST_CASE ( "Automata Iteration", "[unit][algo][automaton][transform]" ) {
	SECTION ( "AAG slides lecture 3 (fixed example from Melichar 2.83)" ) {
		DefaultStateType q0('0'), q1('1'), q2('2');
		DefaultSymbolType a('a'), b('b');

		automaton::DFA < > m1(q0);
		m1.setStates({q0, q1, q2});
		m1.setFinalStates({q2});
		m1.setInputAlphabet({a, b});
		m1.addTransition(q0, a, q1);
		m1.addTransition(q1, b, q1);
		m1.addTransition(q1, a, q2);

		DefaultStateType S = common::createUnique(q0, m1.getStates());

		automaton::NFA< > expected(S);
		expected.setStates({S, q0, q1, q2});
		expected.setInputAlphabet({a, b});
		expected.setFinalStates({S, q2});
		expected.addTransition(S, a, q1);
		expected.addTransition(q0, a, q1);
		expected.addTransition(q1, b, q1);
		expected.addTransition(q1, a, q0);
		expected.addTransition(q1, a, q2);

		REQUIRE(automaton::transform::AutomatonIteration::iteration(m1) == expected);
	}

	SECTION ( "Transition from initial to final state in the original automaton" ) {
		DefaultStateType q0('0'), q1('1'), q2('2'), q3('3'), q4('4');
		DefaultSymbolType a('a'), b('b'), c('c');

		automaton::NFA < > m1(q0);
		m1.setStates({q0, q1, q2, q3, q4});
		m1.setFinalStates({q1, q4});
		m1.setInputAlphabet({a, b, c});
		m1.addTransition(q0, a, q1);
		m1.addTransition(q0, b, q2);
		m1.addTransition(q0, b, q3);
		m1.addTransition(q1, a, q1);
		m1.addTransition(q1, b, q3);
		m1.addTransition(q2, a, q4);
		m1.addTransition(q2, c, q0);
		m1.addTransition(q3, c, q2);
		m1.addTransition(q4, c, q3);
		m1.addTransition(q4, c, q4);

		DefaultStateType S = common::createUnique(q0, m1.getStates());

		automaton::NFA< > expected(S);
		expected.setStates({S, q0, q1, q2, q3, q4});
		expected.setInputAlphabet({a, b, c});
		expected.setFinalStates({S, q1, q4});
		expected.addTransition(q0, a, q1);
		expected.addTransition(q0, b, q2);
		expected.addTransition(q0, b, q3);
		expected.addTransition(q1, a, q1);
		expected.addTransition(q1, b, q3);
		expected.addTransition(q2, a, q4);
		expected.addTransition(q2, c, q0);
		expected.addTransition(q3, c, q2);
		expected.addTransition(q4, c, q3);
		expected.addTransition(q4, c, q4);

		expected.addTransition(S, a, q0);
		expected.addTransition(S, a, q1);
		expected.addTransition(S, b, q2);
		expected.addTransition(S, b, q3);
		expected.addTransition(q0, a, q0);
		expected.addTransition(q0, b, q2);
		expected.addTransition(q1, a, q0);
		expected.addTransition(q2, a, q0);
		expected.addTransition(q4, c, q0);

		REQUIRE(automaton::transform::AutomatonIteration::iteration(m1) == expected);
	}
}
