/*
	ZRandomGeneratorBase.hpp
	Author: James Russell <jcrussell@762studios.com>

	Purpose: 
	
	This is an RAII wrapper class for the libsst-random pseudo-random number generators that
	also introduces some extra functionality.

	License:

	TODO
*/

#pragma once

#ifndef _ZRANDOMGENERATOR_H
#define _ZRANDOMGENERATOR_H

#include <ZUtil/ZUtilBuild.hpp>

#include <SST/SST_PRNG.h>

class ZRandomGenerator
{
private:
	DISABLE_COPY_AND_ASSIGN(ZRandomGenerator);

protected:
	//Our random generator type
	const SST_PRNG_TYPE Type;

	//Random Seed
	uint32_t Seed;

	//Random Sequence
	uint64_t Sequence;

	//Our SST RNG Instance
	SST_PRNG RNG;

public:
	/*
	Default Constructor.

	This constructor will create a random generator that uses type SST_PRNG_SMALLPRNG, 
	that is	seeded with the current time, and starts at sequence 0.
	*/
	ZRandomGenerator();

	/*
	Parameterized Constructor.

	@param _type - the type of random number generator to create
	@param _seed - the seed to create the generator with
	@param _sequence - the sequence number to start at
	*/
	ZRandomGenerator(SST_PRNG_TYPE _type, uint32_t _seed, uint64_t _sequence = 0);

	/*
	Destructor.
	*/
	~ZRandomGenerator();

	/*
	public ZRandomGenerator::GetFloat
	
	Gets next float from random generator in the range [0, 1).
	
	@return (float) - next float from the PRNG
	*/
	float GetFloat();

	/*
	public ZRandomGenerator::GetFloatArray
	
	Gets an array of floats from the random generator in the range [0, 1).

	@param _array - array to store floats into
	@param _count - number of elements in array
	@return (void)
	*/
	void GetFloatArray(float *_array, size_t _count);

	/*
	public ZRandomGenerator::GetFloatInRange
	
	Gets a float in the range [_min, _max)
	
	@param _min - inclusive lower bound of range.
	@param _max - exclusive upper bound of range.
	@return (float) - next float in range.
	*/
	float GetFloatInRange(float _min, float _max);

	/*
	public ZRandomGenerator::GetFloatArrayInRange
	
	Gets an array of floats in range [_min, _max).

	@param _array - array to store floats into
	@param _count - number of elements in array
	@param _min - inclusive lower bound of range
	@param _max - exclusive upper bound of range
	@return (void)
	*/
	void GetFloatArrayInRange(float *_array, size_t _count, float _min, float _max);

	/*
	public ZRandomGeneratorGenerator::GetInt
	 
	Gets an int in the range [STDINT_MIN, STDINT_MAX).
	 
	@return (int) - next int from generator
	*/
	int GetInt();

	/*
	public ZRandomGenerator::GetIntArray
	
	Gets an array of ints in the range [STDINT_MIN, STDINT_MAX).
	
	@param _array - array to store ints into
	@param _count - number of elements in 
	@return (void)
	*/
	void GetIntArray(int *_array, size_t _count);

	/*
	public ZRandomGenerator::GetIntInRange
	
	Gets an int in the range [_min, _max).
	
	@param _min - inclusive lower bound of range
	@param _max - exclusive upper bound of range
	@return (int) - next int from range
	*/
	int GetIntInRange(int _min, int _max);

	/*
	public ZRandomGenerator::GetIntArrayInRange
	
	Gets an array of ints in the range [_min, _max).

	@param _array - array to store floats into
	@param _count - number of elements in array
	@param _min - inclusive lower bound of range
	@param _max - exclusive upper bound of range
	@return (void)
	*/
	void GetIntArrayInRange( int *_array, size_t _count, int _min, int _max);

	/*
	public ZRandomGenerator::GetGaussianFloat
	
	Gets a gaussian-distributed float in the range [_min, _max).  This is expected to generate
	two random numbers to get the gaussian distributed number, which will increase sequence by two.
	
	@param _min - inclusive lower bound of range
	@param _max - exclusive upper bound of range
	@return (float) - floating point number in range
	*/
	float GetGaussianFloat(float _min, float _max);

	/*
	public ZRandomGenerator::GetGaussianFloatArray
	
	Gets an array of guassian-distributed floats in the range [_min, _max).  This is expected to generate
	two random numbers to get the gaussian distributed number, which will increase sequence by two.

	@param _array - array to store floats into
	@param _count - number of elements in array
	@param _min - inclusive lower bound of range
	@param _max - exclusive upper bound of range
	@return (void)
	*/
	void GetGaussianFloatArray(float *_array, size_t _count, float _min, float _max);

	/*
	public ZRandomGenerator::GetGaussianInt
	
	Gets a gaussian-distributed int in the range [_min, _max).  This is expected to generate
	two random numbers to get the gaussian distributed number, which will increase sequence by two.
	
	@param _min - inclusive lower bound of range
	@param _max - exclusive upper bound of range
	@return (int)
	*/
	int GetGaussianInt(int _min, int _max);

	/*
	public ZRandomGenerator::GetGaussianIntArray
	
	Gets an array of gaussian-distributed int in the range [_min, _max).  This is expected to generate
	two random numbers to get the gaussian distributed number, which will increase sequence by two.
	
	@param _array - array to store ints into
	@param _count - number of elements in array
	@param _min - inclusive lower bound of range
	@param _max - exclusive upper bound of range
	@return (void)
	*/
	void GetGaussianIntArray(int *_array, size_t _count, int _min, int _max);

	/*
	public ZRandomGenerator::GetSeed
	
	Gets the seed of this random generator.
	
	@return (uint32_t) - PRNG seed
	*/
	uint32_t GetSeed();

	/*
	public ZRandomGenerator::GetSequence
	
	Gets the sequence of this random number generator, which is the number of random
	numbers that have currently been generated.
	
	@return (uint64_t) - sequence of this random generator
	*/
	uint64_t GetSequence();

	/*
	public ZRandomGenerator::SetSequence
	
	Sets the sequence (amount of numbers generated) for this PRNG.
	
	@param _seq - sequence to set this generator to.
	@return (void)
	*/
	void SetSequence(uint64_t _seq);

	/*
	public ZRandomGenerator::SetSeed
	
	Sets the seed on this PRNG.
	
	@param _seed - 32 bit unsigned integer seed to use
	@return (void)
	*/
	void SetSeed(uint32_t _seed);
};

#endif
