#include <catch2/catch.hpp>

#include "regexp/transform/RegExpDerivation.h"

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

#include <regexp/string/UnboundedRegExp.h>
#include <regexp/xml/UnboundedRegExp.h>

#include <string/string/LinearString.h>
#include <string/xml/LinearString.h>

TEST_CASE ( "Regexp Derivation", "[unit][algo][grammar][transform]" ) {
	SECTION ( "Derivation" ) {
		// https://edux.fit.cvut.cz/oppa/BI-AAG/cviceni/aag-cv04.pdf
		auto testcase = GENERATE (
				// Exc. 13
				std::make_tuple ( "0 1 0 + 1 0 1 + 0*1 + 1*0", "0", "#E 1 0+#0 0 1+#E 0* 1+#0+#0 1* 0+#E"),
				std::make_tuple ( "0 1 0 + 1 0 1 + 0*1 + 1*0", "0 0", "#0 1 0+#0 0+#0 0 1+(#0 0*+#E 0*) 1+#0+#0+#0 1* 0+#0"),

				// Exc. 14
				std::make_tuple ( "(0 1*0 + 1 0*)*", "1", "(#0 1* 0+#E 0*) (0 1* 0+1 0*)*"),
				std::make_tuple ( "(0 1*0 + 1 0*)*", "1 0", "(#0 1* 0+#0 0*+#E 0*) (0 1* 0+1 0*)*+(#E 1* 0+#0 0*) (0 1* 0+1 0*)*"),

				// Exc. 15
				std::make_tuple ( "1 0*1*0", "1 0 0", "#0 0* 1* 0+(#0 0*+#E 0*) 1* 0+#0 1* 0+#E+#0 1* 0+#0")
				);

		const std::string & regexp_str = std::get < 0 > ( testcase );
		const std::string & string_str = std::get < 1 > ( testcase );
		const std::string & result     = std::get < 2 > ( testcase );

		regexp::UnboundedRegExp < > regexp0 = factory::StringDataFactory::fromString (regexp_str);
		ext::deque<sax::Token> tokens = factory::XmlDataFactory::toTokens(regexp0);
		regexp::UnboundedRegExp < > regexp = factory::XmlDataFactory::fromTokens (std::move(tokens));

		string::LinearString < > string0 = factory::StringDataFactory::fromString ("\"" + string_str + "\"");
		ext::deque<sax::Token> tokens2 = factory::XmlDataFactory::toTokens(string0);
		string::LinearString < > string1 = factory::XmlDataFactory::fromTokens (std::move(tokens2));

		CHECK(factory::StringDataFactory::toString(regexp::transform::RegExpDerivation::derivation(regexp, string1)) == result);
	}
}
