/** SGX

The   sss    gggg x   x   
     s      g      x x    Engine
      sss   g  gg   x
         s  g   g  x x          Copyright 1995-2009.
     ssss    gggg x   x         Steven Goodwin. All Rights Reserved.
    
This version has been released under the GNU Public License v2.0.

Please see the license files for details.

File: sgx/src/sgx/core/sgxlib/random.cpp

*/

#include "sgx/core/types/types.hpp"
#include "sgx/core/sgxlib/random.hpp"

/*
This file contains a pruned version of George Marsaglia's post 
from http://www.ciphersbyritter.com/NEWS4/RANDC.HTM 

Minor alterations have been made to fit in with the sgx naming scheme.
*/


/* Random seeds must be used to reset z,w,jsr,jco
*/
namespace {
	tUINT32 z=362436069, w=521288629, jsr=123456789, jcong=380116160;
}

#define znew  ((z=36969*(z&65535)+(z>>16))<<16)
#define wnew  ((w=18000*(w&65535)+(w>>16))&65535)
#define MWC   (znew+wnew)
#define SHR3  (jsr=(jsr=(jsr=jsr^(jsr<<17))^(jsr>>13))^(jsr<<5))
#define CONG  (jcong=69069*jcong+1234567)
#define KISS  ((MWC^CONG)+SHR3)
#define UNI   (KISS*2.328306e-10f)

/**
The four arguments values indicate the seeds which allow you to
replicate the stream of pseudo-random numbers. The defaults are
362436069, 521288629, 123456789, and 380116160, but need not be used.
*/
void 
sgxSetRandSeed(tUINT32 nz, tUINT32 nw, tUINT32 njsr, tUINT32 njcong)
{
	z = nz;
	w = nw;
	jsr = njsr;
	jcong = njcong;
}

/**
Returns a random number between 0 and 1.
*/
tREAL32 
sgxRand()
{
	return UNI;
}

/**
Returns a random number between 0 and @n.
*/
tUINT32 
sgxRand(int n)
{
	return tUINT32(UNI*n);
}

/**
Returns a random number between @from and @to inclusive.
*/
tUINT32 
sgxRand(const int from, const int to)
{
	return tUINT32(UNI*(to-from) + from);
}

void 
sgxRandList(tINT32 *pList, const tINT32 listSize, const tINT32 from, const tINT32 to)
{
	tINT32 unused = from-1;	// BUGWARN
	tINT32 available = (to-from)+1;
	for(tINT32 i=0;i<listSize;++i) {
		pList[i] = unused;
	}
	//
	for(tINT32 i=0;i<listSize;++i) {
		tINT32 num = sgxRand(from, to);
		for(tINT32 check=0;check<i;++check) {
			if (pList[check] == num) {
				// aready got it :( so find another
				num = ((num+1)%available) + from;
				// Restart the search...
				check = -1;		// because check will get ++'d at end of loop. Otherwise 1st number in array could get repeated
			}
		}

		pList[i] = num;
	}
}

