//
// Created by dolan on 4/3/2020.
//

#include <string/LinearString.h>
#include <catch2/catch.hpp>
#include <stringology/seed/DeterministicApproximateSuffixAutomatonForHammingDistanceFactory.h>
#include <automaton/FSM/NFA.h>

TEST_CASE ( "DeterministicApproximateSuffixAutomatonForHammingDistanceFactory", "[unit][stringology][seed]" ) {
	string::LinearString < char > pattern;
	ext::set < ext::set < ext::pair < unsigned, unsigned > > > nodes;
	size_t k;
	ext::set < char > inputAlphabet;
	ext::set < ext::pair < unsigned, unsigned > > initialState;
	ext::set < ext::set < ext::pair < unsigned, unsigned > > > finalNodes;
	ext::map < ext::pair < ext::set < ext::pair < unsigned, unsigned > >, char>, ext::set < ext::pair < unsigned, unsigned > > > transitions;

    SECTION ( "create automaton for abab for Hamming distance = 0" ) {
        pattern = string::LinearString < char > ( "abab" );
        k = 0;
        nodes = {
			{ { 0, 0 } },
			{ { 1, 0 }, { 3, 0 } },
			{ { 2, 0 }, { 4, 0 } },
			{ { 3, 0 } },
			{ { 4, 0 } },
        };

		inputAlphabet = { 'a', 'b' };
		initialState = { { 0, 0 } };
        finalNodes = { { { 0, 0 } }, { { 4, 0 } }, { { 2, 0 }, { 4, 0 } } };

        transitions = {
			{ { { { 0, 0 } },           'a' }, { { 1, 0 }, { 3, 0 } } },
			{ { { { 0, 0 } },           'a' }, { { 1, 0 }, { 3, 0 } } },
			{ { { { 0, 0 } },           'b' }, { { 2, 0 }, { 4, 0 } } },
			{ { { { 1, 0 }, { 3, 0 } }, 'b' }, { { 2, 0 }, { 4, 0 } } },
			{ { { { 2, 0 }, { 4, 0 } }, 'a' }, { { 3, 0 } } },
			{ { { { 3, 0 } },           'b' }, { { 4, 0 } } },
        };
    }

    SECTION ( "create automaton for empty string with Hamming distance = 2" ) {
        pattern = string::LinearString < char > ( "" );
        k = 2;
		nodes = { { { 0, 0 } } };
		inputAlphabet = { };
		initialState = { { 0, 0 } };
		finalNodes = { { { 0, 0 } } };
    }

	auto automaton = stringology::seed::DeterministicApproximateSuffixAutomatonForHammingDistanceFactory::construct ( pattern, k );

	CHECK ( nodes == automaton.getStates ( ) ) ;
	CHECK ( inputAlphabet == automaton.getInputAlphabet ( ) );
	CHECK ( initialState == automaton.getInitialState ( ) );
	CHECK ( finalNodes == automaton.getFinalStates() );
	CHECK ( transitions == automaton.getTransitions() );
}
