/******************************************************************************
 * $Id: gfx_random.cc,v 1.26 2006/11/19 20:31:20 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Random number functions.
 * @remarks	ANSI C rand() functions are used.  Avoid mixing BSD random() functions.
 *//*
 * LEGAL:	COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 ******************************************************************************/

#define GFX_RANDOM_CC 1
#include "gfx.hh"
#include "gfx_stream.hh"
#include "gfx_random.hh"
namespace gfx {

/*****************************************************************************
 * Seed the sequence of psuedo-random numbers.
 *****************************************************************************/
void
randomize( uint seed )
{
	srand( seed );
}
void
randomize( void )
{
	randomize( random_true() );
}

/*****************************************************************************
 * @return A psuedo-random unsigned int in range {0,..,RAND_MAX}.
 *****************************************************************************/
uint
random_ui( void )
{
	return rand();
}

/*****************************************************************************
 * @return A psuedo-random unsigned int in range {0,..,end-1}.
 * end-1 is for picking a random-but-valid index within a container
 * by passing size of container as end.
 * random_ui(100) will return {0,..,99} (never 100).
 *****************************************************************************/
uint
random_ui( uint end )
{
	// Prevent divide error exception.  Extreme compiler optimize flags skips such checks.
	if ( EX( end ) )
		return rand() % end;
	else
		return 0;
}

/*****************************************************************************
 * @return A psuedo-random float in range {0,..,1} or {0,..,range}.
 *****************************************************************************/
float
random_f( void )
{
	//return float(rand()) / float(RAND_MAX);			// float division is slow
	return float(rand()) * float(1.0 / RAND_MAX);
}
float
random_f( float range )
{
	//return float(rand()) / float(RAND_MAX) * range;	// float division is slow
	return float(rand()) * float(1.0 / RAND_MAX) * range;
}

/*****************************************************************************
 * @return A true random unsigned integer.
 * @remarks This function is slow.
 * An alternative is to call randomize( random_true() ) once and thereafter
 * call the pseudo random function.s
 *****************************************************************************/
uint
random_true( void )
{
#if ! __linux__
	srand( uint( time(NULL) ) );
	return rand();
#else
	static int fd = -1;
	uint val32 = 0;
	if ( fd == -1 ) fd = open( "/dev/random", O_RDONLY|O_NONBLOCK );
	if ( fd == -1 || read( fd, &val32, sizeof(val32) ) != sizeof(val32) )
	{
		// Failed to open /dev/random.  Try an alternative.
		DEBUG_CODE( *gStreamDebug << "can't open or read /dev/random (" << strerror(errno) << ")" << endl; )
		srand( uint( time(NULL) ) );
		val32 = rand();
	}
	return val32;
#endif
}

} // namespace gfx
