/*
 * RandomAutomatonFactory.cpp
 *
 *  Created on: 27. 3. 2014
 *	  Author: Tomas Pecka
 */

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

namespace automaton {

namespace generate {

automaton::NFTA < std::string, unsigned > RandomTreeAutomatonFactory::generateNFTA( size_t statesCount, size_t alphabetSize, size_t maxRank, bool randomizedAlphabet, double density ) {
	if(alphabetSize > 26)
		throw exception::CommonException("Too big alphabet.");

	if(alphabetSize < 1)
		throw exception::CommonException("Too small alphabet.");

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

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

	alphabet.resize ( alphabetSize );

	ext::deque < common::ranked_symbol < std::string > > rankedAlphabet;

	for ( std::string && symbol : ext::make_mover ( alphabet ) ) {
		rankedAlphabet.push_back ( common::ranked_symbol < std::string > ( std::move ( symbol ), ext::random_devices::semirandom() % ( maxRank + 1 ) ) );
	}

	bool containsNullary = false;
	for ( common::ranked_symbol < std::string > & rankedSymbol : rankedAlphabet ) {
		containsNullary |= rankedSymbol.getRank ( ) == 0;
	}

	if ( ! containsNullary ) {
		int c = ext::random_devices::semirandom() % rankedAlphabet.size ( );
		rankedAlphabet [ c ] = common::ranked_symbol ( rankedAlphabet [ c ].getSymbol ( ), 0u );
	}

	return automaton::generate::RandomTreeAutomatonFactory::LeslieConnectedNFTA( statesCount, rankedAlphabet, density );
}

unsigned RandomTreeAutomatonFactory::ithAccessibleState ( const ext::deque < bool > & VStates, size_t i ) {
	i ++;
	for( size_t j = 0; j < VStates.size ( ); j++ ) {
		if( VStates[ j ] )
			i --;

		if( i == 0 )
			return i;
	}
	throw std::logic_error ( "Not enough states in deque of visited states" );
}

unsigned RandomTreeAutomatonFactory::ithInaccessibleState ( const ext::deque < bool > & VStates, size_t i ) {
	i ++;
	for( size_t j = 0; j < VStates.size ( ); j++ ) {
		if( ! VStates[ j ] )
			i --;

		if( i == 0 )
			return j;
	}
	throw std::logic_error ( "Not enough states in deque of visited states" );
}

} /* namespace generate */

} /* namespace automaton */

namespace {

auto GenerateNFTA1 = registration::AbstractRegister < automaton::generate::RandomTreeAutomatonFactory, automaton::NFTA < DefaultSymbolType, unsigned >, size_t, const ext::set < common::ranked_symbol < DefaultSymbolType > > &, double > ( automaton::generate::RandomTreeAutomatonFactory::generateNFTA, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "statesCount", "alphabet", "density" ).setDocumentation (
"Generates a random finite automaton.\n\
@param statesCount number of states in the generated automaton\n\
@param alphabet Input alphabet of the automaton\n\
@param density density of the transition function\n\
@return random nondeterministic finite automaton" );

auto GenerateNFTA2 = registration::AbstractRegister < automaton::generate::RandomTreeAutomatonFactory, automaton::NFTA < std::string, unsigned >, size_t, size_t, size_t, bool, double > ( automaton::generate::RandomTreeAutomatonFactory::generateNFTA, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "statesCount", "alphabetSize", "maxRank", "randomizedAlphabet", "density" ).setDocumentation (
"Generates a random finite automaton.\n\
\n\
@param statesCount number of states in the generated automaton\n\
@param alphabetSize size of the alphabet (1-26)\n\
@param maxRank the maximum rank in the randomly generated alphabet\n\
@param randomizedAlphabet selects random symbols from a-z range if true\n\
@param density density of the transition function (0-100). 100 means every possible transition is created\n\
@return random nondeterministic finite automaton" );

} /* namespace */
