/*
 * RandomStringFactory.cpp
 *
 *  Created on: 27. 3. 2014
 *	  Author: Jan Travnicek
 */

#include "RandomStringFactory.h"

#include <alib/algorithm>

#include <registration/AlgoRegistration.hpp>

namespace string {

namespace generate {

string::LinearString < std::string > string::generate::RandomStringFactory::generateLinearString ( size_t size, size_t alphabetSize, bool randomizedAlphabet, bool integerSymbols ) {
	if ( !integerSymbols ) return generateLinearString ( size, alphabetSize, randomizedAlphabet );

	if ( alphabetSize <= 0 )
		throw exception::CommonException ( "Alphabet size must be greater than 0." );

	ext::vector < std::string > elems;

	for ( size_t i = 0; i < size; i++ )
		elems.push_back ( ext::to_string ( static_cast < int > ( ext::random_devices::semirandom ( ) % alphabetSize ) ) );

	return string::LinearString < std::string > ( elems );
}

auto GenerateLinearString1 = registration::AbstractRegister < string::generate::RandomStringFactory, string::LinearString < std::string >, size_t, size_t, bool, bool > ( string::generate::RandomStringFactory::generateLinearString, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "size", "alphabetSize", "randomizedAlphabet", "integerSymbols" ).setDocumentation (
"Generates a random string of given size.\n\
\n\
@param size the length of the generated string\n\
@param alphabetSize size of the alphabet (1-26 for characters and 0-INT_MAX for integers)\n\
@param randomizedAlphabet selects random symbols from a-z range if true\n\
@param integerSymbols use integers as symbols in the generated string is true, randomize alphabet is not used if integer alphabet is requested\n\
@return random string" );

string::LinearString < std::string > string::generate::RandomStringFactory::generateLinearString ( size_t size, size_t alphabetSize, bool randomizedAlphabet ) {
	if ( alphabetSize > 26 )
		throw exception::CommonException ( "Too big alphabet." );

	if ( alphabetSize <= 0 )
		throw exception::CommonException ( "Alphabet size must be greater than 0." );

	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::set < std::string > alphabet ( symbols.begin ( ), symbols.begin ( ) + alphabetSize );

	return string::generate::RandomStringFactory::generateLinearString ( size, alphabet );
}

} /* namespace generate */

} /* namespace string */

namespace {

auto GenerateLinearString2 = registration::AbstractRegister < string::generate::RandomStringFactory, string::LinearString < std::string >, size_t, size_t, bool > ( string::generate::RandomStringFactory::generateLinearString, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "size", "alphabetSize", "randomizedAlphabet" ).setDocumentation (
"Generates a random string of given size.\n\
\n\
@param size the length of the generated string\n\
@param alphabetSize size of the alphabet (1-26 for characters)\n\
@param randomizedAlphabet selects random symbols from a-z range if true\n\
@return random string" );

auto GenerateLinearString3 = registration::AbstractRegister < string::generate::RandomStringFactory, string::LinearString < >, size_t, ext::set < DefaultSymbolType > > ( string::generate::RandomStringFactory::generateLinearString, abstraction::AlgorithmCategories::AlgorithmCategory::DEFAULT, "size", "alphabet" ).setDocumentation (
"Generates a random string of given size\n\
\n\
@param size the length of the generated string\n\
@param alphabet alphabet of the generated string\n\
@return random string" );

} /* namespace */
