#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <time.h>
#include <iostream>

#include "params.h"
#include "rnd_generators.h"

/*
 * Based on Pierrre L'Ecuyer, http://www.iro.umontreal.ca/~lecuyer/,
 * well performing random number generators also available in the GSL are:
 *
 * gsl_rng_mt19937
 * gsl_rng_taus2
 *
 * In case, one would like to give them a try, change lines
 *
 *		randState = gsl_rng_alloc(gsl_rng_default);
 * to, for example,
 *		randState = gsl_rng_alloc(gsl_rng_mt19937);
 *
 * Both "super generator", probably, need no extra seeding.
 * They should do seed themselves somehow...
 * http://www.gnu.org/software/gsl/manual/html_node/Random-number-generator-algorithms.html
 */

float GetRandomGauss(const float mean, const float sigma, const bool reseed)
{
	static gsl_rng *randState=NULL;
	static unsigned long seed=1;

	//do we need to init random generator?
	if (randState == NULL || reseed == true)
	{
		//yes, we do:
		//create instance of the generator and seed it
		if (randState == NULL) randState = gsl_rng_alloc(gsl_rng_default);
		if (seed == 1) seed=(unsigned long)-1 * (unsigned long) time(NULL);
		else ++seed;
		DEBUG_REPORT("GetRandomGauss(): randomness started with seed " << seed);
		gsl_rng_set(randState,seed);
	}

	return ( (float)gsl_ran_gaussian(randState, sigma) + mean );
}


float GetRandomUniform(const float A, const float B, const bool reseed)
{
	static gsl_rng *randState=NULL;
	static unsigned long seed=1;

	//do we need to init random generator?
	if (randState == NULL || reseed == true)
	{
		//yes, we do:
		//create instance of the generator and seed it
		if (randState == NULL) randState = gsl_rng_alloc(gsl_rng_default);
		if (seed == 1) seed=(unsigned long)-1 * (unsigned long) time(NULL);
		else ++seed;
		DEBUG_REPORT("GetRandomUniform(): randomness started with seed " << seed);
		gsl_rng_set(randState,seed);
	}

	return ( (float)gsl_ran_flat(randState, A,B) );
}


unsigned int GetRandomPoisson(const float mean, const bool reseed)
{
	static gsl_rng *randState=NULL;
	static unsigned long seed=1;

	//do we need to init random generator?
	if (randState == NULL || reseed == true)
	{
		//yes, we do:
		//create instance of the generator and seed it
		if (randState == NULL) randState = gsl_rng_alloc(gsl_rng_default);
		if (seed == 1) seed=(unsigned long)-1 * (unsigned long) time(NULL);
		else ++seed;
		DEBUG_REPORT("GetRandomPoisson(): randomness started with seed " << seed);
		gsl_rng_set(randState,seed);
	}

	return ( gsl_ran_poisson(randState, mean) );
}
