/*
 * RandomAutomatonFactory.cpp
 *
 *  Created on: 5. 11. 2017
 *	  Author: Jan Travnicek
 */

#include "RandomAutomatonFactory3.h"
#include <registration/AlgoRegistration.hpp>

namespace automaton {

namespace generate {

automaton::MultiInitialStateNFA < std::string, unsigned > RandomAutomatonFactory3::generate ( size_t statesMinimal, size_t statesDuplicates, size_t statesUnreachable, size_t statesUseless, size_t initialStates, size_t finalStates, size_t alphabetSize, bool randomizedAlphabet, double density, bool deterministic ) {
	if ( alphabetSize > 26 )
		throw exception::CommonException("Too big alphabet.");

	if ( initialStates > statesUseless + statesMinimal )
		throw exception::CommonException("Too many initial states.");

	if ( finalStates > statesUnreachable + statesMinimal )
		throw exception::CommonException("Too many final states.");

	if ( deterministic && initialStates != 1 )
		throw exception::CommonException("Deterministic automaton has to have a single initial state.");

	if ( initialStates == 0 )
		throw exception::CommonException("There has to be at least one initial state.");

	ext::vector < std::string > symbols;
	for ( char i = 'a'; i <= 'z'; i++ )
		symbols.push_back ( std::string ( 1, i ) );

	if ( randomizedAlphabet )
		shuffle ( symbols.begin ( ), symbols.end ( ), ext::random_devices::semirandom );

	ext::deque < std::string > alphabet ( symbols.begin ( ), symbols.begin ( ) + alphabetSize );

	return RandomAutomatonFactory3::run ( makeVector ( 0									, statesMinimal ),
										  statesDuplicates,
										  makeVector ( statesMinimal						, statesMinimal + statesUnreachable ),
										  makeVector ( statesMinimal + statesUnreachable	, statesMinimal + statesUnreachable + statesUseless ),
										  initialStates, finalStates, alphabet, density, deterministic );
}

ext::vector < unsigned > RandomAutomatonFactory3::makeVector ( size_t begin, size_t end ) {
	ext::vector < unsigned > res;
	for ( ; begin < end; ++ begin )
		res.push_back ( begin );
	return res;
}

} /* namespace generate */

} /* namespace automaton */

namespace {

auto Generate = registration::AbstractRegister < automaton::generate::RandomAutomatonFactory3, automaton::MultiInitialStateNFA < std::string, unsigned >, size_t, size_t, size_t, size_t, size_t, size_t, size_t, bool, double, bool > ( automaton::generate::RandomAutomatonFactory3::generate, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "statesMinimal", "statesDuplicates", "statesUnreachable", "statesUseless", "initialStates", "finalStates", "alphabetSize", "randomizedAlphabet", "density", "deterministic" );

} /* namespace */

