#include <catch2/catch.hpp>
#include <alib/vector>
#include <extensions/container/string.hpp>

#include "testing/TimeoutAqlTest.hpp"
#include "testing/TestFiles.hpp"

double RAND_DENSITY = 50;
size_t RAND_NONTERMINALS = 2;
size_t RAND_TERMINALS = 4;
size_t STRING_LENGTHS = 6;
size_t RANDOM_ITERATIONS = 50;


std::string qGenerateCfg ( const std::string & var ) {
	std::ostringstream oss;
	oss << "execute grammar::generate::RandomGrammarFactory" << " ";
	oss << "(int) " << rand ( ) % RAND_NONTERMINALS + 1 << " ";
	oss << "(int) " << rand ( ) % RAND_TERMINALS + 1 << " ";
	oss << "(bool) true ";
	oss << "(double) " << RAND_DENSITY << " | ";
	oss << "grammar::simplify::EpsilonRemover - | ";
	oss << "grammar::simplify::SimpleRulesRemover - > $" << var;
	return oss.str();
}

TEST_CASE ( "Normalize test", "[integration]" ) {
	auto algorithm = GENERATE ( as < std::string > ( ), "grammar::simplify::ToCNF", "grammar::simplify::ToGNF" );

	SECTION ( "Test Files" ) {
		for ( const std::string & file : TestFiles::Get ( "/grammar/anormalization.test.*.xml$" ) ) {
			ext::vector < std::string > qs = {
				"execute < " + file + " > $cfg",
				"execute " + algorithm + " $cfg > $cfg2",
				"execute grammar::generate::GenerateUpToLength $cfg "  + ext::to_string ( STRING_LENGTHS ) + " > $str",
				"execute grammar::generate::GenerateUpToLength $cfg2 " + ext::to_string ( STRING_LENGTHS ) + " > $str2",
				"quit compare::TrieCompare $str $str2",
			};

			TimeoutAqlTest ( 1s, qs );
		}
	}

	SECTION ( "Random tests" ) {
		for ( size_t i = 0; i < RANDOM_ITERATIONS; i++ ) {
			ext::vector < std::string > qs = {
				qGenerateCfg ( "cfg" ),
				"execute " + algorithm + " $cfg > $cfg2",
				"execute grammar::generate::GenerateUpToLength $cfg "  + ext::to_string ( STRING_LENGTHS ) + " > $str",
				"execute grammar::generate::GenerateUpToLength $cfg2 " + ext::to_string ( STRING_LENGTHS ) + " > $str2",
				"quit compare::TrieCompare $str $str2",
			};

			TimeoutAqlTest ( 1s, qs );
		}
	}
}
