#include <catch2/catch.hpp>

#include "sax/SaxParseInterface.h"
#include "sax/SaxComposeInterface.h"

#include "automaton/string/FSM/DFA.h"
#include "automaton/string/FSM/NFA.h"
#include "automaton/string/FSM/EpsilonNFA.h"
#include "automaton/string/FSM/MultiInitialStateNFA.h"
#include "automaton/string/FSM/MultiInitialStateEpsilonNFA.h"

#include "automaton/AutomatonException.h"

#include "factory/XmlDataFactory.hpp"
#include "factory/StringDataFactory.hpp"

#include "alphabet/BottomOfTheStackSymbol.h"

TEST_CASE ( "Automaton String Parser", "[unit][str][automaton]" ) {
	SECTION ("ENFA" ) {
		std::string input = 	"\r\n"
					"ENFA a b c d #E\n\r"
					"\r"
					">0 3|4 5 1|3|4 - 2\r"
					"\r\n"
					"1 2 - - - -\n"
					"\n\r"
					"2 3 - - - -\n"
					"3 - - 4 - -\n"
					"\n"
					"<4 - 5 - - 5\n"
					"\r"
					"<5 - - - - 3"
					"\r";
		std::string input2 = 	"ENFA a b c d #E\n"
					">0 3|4 5 1|3|4 - 2\n"
					"1 2 - - - -\n"
					"2 3 - - - -\n"
					"3 - - 4 - -\n"
					"<4 - 5 - - 5\n"
					"<5 - - - - 3\n";
		automaton::EpsilonNFA < > automaton = factory::StringDataFactory::fromString (input);
		std::string output = factory::StringDataFactory::toString(automaton);
		CHECK( input2 == output );

		automaton::EpsilonNFA < > automaton2 = factory::StringDataFactory::fromString (output);
		CHECK( automaton == automaton2 );
	}

	SECTION ( "MISNFA" ) {
		std::string input = 	"MISNFA a b c d\n"
					">0 3|4 5 1|3|4 -\n"
					"1 2 - - -\n"
					"2 3 - - -\n"
					">3 - - 4 -\n"
					"4 - 5 - -\n"
					"<5 - - - 3\n";
		automaton::MultiInitialStateNFA < > automaton = factory::StringDataFactory::fromString (input);
		std::string output = factory::StringDataFactory::toString(automaton);
		CHECK( input == output );

		automaton::MultiInitialStateNFA < > automaton2 = factory::StringDataFactory::fromString (output);
		CHECK( automaton == automaton2 );
	}

	SECTION ( "MISENFA" ) {
		std::string input = 	"MISENFA a b c #E\n"
					">0 3|4 5 1|3|4 -\n"
					">1 2 - - -\n"
					">2 3 - - -\n"
					"><3 - - 4 -\n"
					"<4 - 5 - -\n"
					"<5 - - - 3\n";
		automaton::MultiInitialStateEpsilonNFA < > automaton = factory::StringDataFactory::fromString ( input );
		std::string output = factory::StringDataFactory::toString ( automaton );
		CHECK( input == output );

		automaton::MultiInitialStateEpsilonNFA < > automaton2 = factory::StringDataFactory::fromString ( output );
		CHECK( automaton == automaton2 );
	}

	SECTION ( "NFA" ) {
		std::string input = 	"NFA a b c d\n"
					">0 3|4 5 1|3|4 -\n"
					"1 2 - - -\n"
					"2 3 - - -\n"
					"3 - - 4 -\n"
					"4 - 5 - -\n"
					"<5 - - - 3\n";
		automaton::NFA < > automaton = factory::StringDataFactory::fromString (input);
		std::string output = factory::StringDataFactory::toString(automaton);
		CHECK( input == output );

		automaton::NFA < > automaton2 = factory::StringDataFactory::fromString (output);
		CHECK( automaton == automaton2 );
	}

	SECTION ( "DFA" ) {
		std::string input = 	"DFA a b c d\n"
					">0 3 5 1 -\n"
					"1 2 - - -\n"
					"2 3 - - -\n"
					"3 - - 4 -\n"
					"4 - 5 - -\n"
					"<5 - - - 3\n";
		automaton::DFA < > automaton = factory::StringDataFactory::fromString (input);
		std::string output = factory::StringDataFactory::toString(automaton);
		CAPTURE ( output );
		CHECK( input == output );

		automaton::DFA < > automaton2 = factory::StringDataFactory::fromString (output);
		CHECK( automaton == automaton2 );
	}
}

