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

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

namespace automaton {

namespace generate {

size_t RandomAutomatonFactory2::randomSourceState ( size_t statesMinimal, size_t visited, size_t depleted, const ext::deque < bool > & VStates, const ext::deque < bool > & DStates ) {
	size_t y = ext::random_devices::semirandom() % ( visited - depleted ) + 1; // select y-th accessible state

	for( size_t i = 0, cnt = 0; i < statesMinimal; i++ ) {
		if( VStates [ i ] && ! DStates [ i ] )
			cnt ++;

		if( cnt == y )
			return i;
	}

	return -1;
}

size_t RandomAutomatonFactory2::randomTargetState ( size_t statesMinimal, size_t visited, const ext::deque < bool > & VStates ) {
	size_t z = ext::random_devices::semirandom() % ( statesMinimal - visited ) + 1; // select z-th inaccessible state

	for( size_t i = 0, cnt = 0; i < statesMinimal; i++ ) {
		if( ! VStates[ i ] )
			cnt ++;

		if( cnt == z )
			return i;
	}

	return -1;
}

automaton::DFA < std::string, unsigned > RandomAutomatonFactory2::generateDFA( size_t statesMinimal, size_t statesDuplicates, size_t statesUnreachable, size_t statesUseless, size_t alphabetSize, bool randomizedAlphabet, double density ) {
	if ( alphabetSize > 26 )
		throw exception::CommonException("Too big alphabet.");

	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 RandomAutomatonFactory2::NonminimalDFA ( statesMinimal, statesDuplicates, statesUnreachable, statesUseless, alphabet, density );
}

} /* namespace generate */

} /* namespace automaton */

namespace {

auto GenerateDFA = registration::AbstractRegister < automaton::generate::RandomAutomatonFactory2, automaton::DFA < std::string, unsigned >, size_t, size_t, size_t, size_t, size_t, bool, double > ( automaton::generate::RandomAutomatonFactory2::generateDFA, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "statesMinimal", "statesDuplicates", "statesUnreachable", "statesUseless", "alphabetSize", "randomizedAlphabet", "density" );

} /* namespace */

