#include <catch2/catch.hpp>

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

#include "automaton/FSM/DFA.h"
#include "automaton/xml/FSM/DFA.h"

#include "automaton/AutomatonException.h"

#include "factory/XmlDataFactory.hpp"

#include <primitive/xml/Integer.h>
#include <primitive/xml/Character.h>

#include <object/Object.h>

TEST_CASE ( "Automaton Templates", "[unit][data][automaton]" ) {
	SECTION ( "DFA Parser" ) {
		automaton::DFA < char, int > automaton ( 1 );

		automaton.addState ( 2 );
		automaton.addState ( 3 );
		automaton.addInputSymbol ( 'a' );
		automaton.addInputSymbol ( 'b' );

		automaton.addTransition ( 1, 'a', 2 );
		automaton.addTransition ( 2, 'b', 1 );

		automaton.addFinalState ( 3 );

		CHECK ( automaton == automaton );
		{
			ext::deque < sax::Token > tokens = factory::XmlDataFactory::toTokens ( automaton );
			std::string tmp = sax::SaxComposeInterface::composeMemory ( tokens );

			ext::deque < sax::Token > tokens2;
			sax::SaxParseInterface::parseMemory ( tmp, tokens2 );
			automaton::DFA < char, int > automaton2 = factory::XmlDataFactory::fromTokens ( std::move ( tokens2 ) );

			CHECK ( automaton == automaton2 );
		}
		{
			ext::deque < sax::Token > tokens = factory::XmlDataFactory::toTokens ( automaton );
			std::string tmp = sax::SaxComposeInterface::composeMemory ( tokens );

			ext::deque < sax::Token > tokens2;
			sax::SaxParseInterface::parseMemory ( tmp, tokens2 );
			automaton::DFA < object::Object, object::Object > automaton2 = factory::XmlDataFactory::fromTokens ( std::move ( tokens2 ) );

			automaton::DFA < object::Object, object::Object > automaton3 ( object::Object ( object::AnyObject < int > ( 1 ) ) );

			automaton3.addState ( object::Object ( object::AnyObject < int > ( 2 ) ) );
			automaton3.addState ( object::Object ( object::AnyObject < int > ( 3 ) ) );
			automaton3.addInputSymbol ( object::Object ( object::AnyObject < char > ( 'a' ) ) );
			automaton3.addInputSymbol ( object::Object ( object::AnyObject < char > ( 'b' ) ) );

			automaton3.addTransition ( object::Object ( object::AnyObject < int > ( 1 ) ), object::Object ( object::AnyObject < char > ( 'a' ) ), object::Object ( object::AnyObject < int > ( 2 ) ) );
			automaton3.addTransition ( object::Object ( object::AnyObject < int > ( 2 ) ), object::Object ( object::AnyObject < char > ( 'b' ) ), object::Object ( object::AnyObject < int > ( 1 ) ) );

			automaton3.addFinalState ( object::Object ( object::AnyObject < int > ( 3 ) ) );

			CHECK ( automaton2 == automaton3 );
		}
	}
}
