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

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

#include <alib/deque>
#include <alib/algorithm>
#include <alib/random>

namespace automaton::generate {

automaton::NFA < std::string, unsigned > NumberOfSymbolsAutomaton::generateNFA ( size_t modulo, size_t alphabetSize, bool randomizedAlphabet, char symbol, size_t final_modulo ) {
	if ( alphabetSize > 26 )
		throw exception::CommonException("Too big alphabet.");

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

	if ( symbol < 'a' || symbol > 'z' )
		throw exception::CommonException("Invalid symbol " + ext::to_string ( symbol ) + ".");

	ext::deque < std::string > alphabet;
	alphabet.push_back ( std::string ( 1, symbol ) );

	for ( char i = 'a'; i <= 'z'; ++ i )
		if ( i != symbol )
			alphabet.push_back ( std::string ( 1, i ) );

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

	alphabet.resize ( alphabetSize );

	return automaton::generate::NumberOfSymbolsAutomaton::generateNFA ( modulo, ext::set < std::string > ( alphabet.begin ( ), alphabet.end ( ) ), std::string ( 1, symbol ), final_modulo );
}

} /* namespace automaton::generate */

namespace {

auto GenerateNFA1 = registration::AbstractRegister < automaton::generate::NumberOfSymbolsAutomaton, automaton::NFA < DefaultSymbolType, unsigned >, size_t, const ext::set < DefaultSymbolType > &, DefaultSymbolType, size_t > ( automaton::generate::NumberOfSymbolsAutomaton::generateNFA, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "modulo", "alphabet", "symbol", "final_modulo" ).setDocumentation (
"Generates automaton accepting strings over alphabet where the number of symbol given by @p symbol is modulo @p modulo equal to @p final_modulo.\n\
\n\
@param modulo number of symbols to modulo by\n\
@param alphabet Input alphabet of the automaton\n\
@param symbol the counted symbol\n\
@param final_modulo number of symbols to recognise mod modulo\n\
@return random nondeterministic finite automaton" );

auto GenerateNFA2 = registration::AbstractRegister < automaton::generate::NumberOfSymbolsAutomaton, automaton::NFA < std::string, unsigned >, size_t, size_t, bool, char, size_t > ( automaton::generate::NumberOfSymbolsAutomaton::generateNFA, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "statesCount", "alphabetSize", "randomizedAlphabet", "symbol", "final_modulo" ).setDocumentation (
"Generates automaton accepting strings over alphabet where the number of symbol given by @p symbol is modulo @p modulo equal to @p final_modulo.\n\
\n\
@param modulo number of symbols to modulo by\n\
@param alphabetSize size of the alphabet (1-26)\n\
@param randomizedAlphabet selects random symbols from a-z range if true\n\
@param symbol the counted symbol\n\
@param final_modulo number of symbols to recognise mod modulo\n\
@return random nondeterministic finite automaton" );

} /* namespace */
