/***************************************************************************
 *   Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf             *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License                  *
 *   (version 3 or above) as published by the Free Software Foundation.    *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU GPL                        *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA               *
 ***************************************************************************/
#include <yf/random/random.hpp>
#include <ctime>
#include <cstdlib>

namespace yf
{
	namespace random
	{
		void rnd_init()
		{
			#ifdef YF_ENABLE_CHECKS
				try
				{
			#endif
					std::time_t tmp_time_struct;
					std::srand((unsigned)std::time(&tmp_time_struct));
			#ifdef YF_ENABLE_CHECKS
				}
				catch(...)
				{
					YF_FUNC_EXCEPTION( init )
				}
			#endif
		}
		//------------------------------------------------------------------------------------
		bool rnd_bool()
		{
			return (std::rand() & 1);
		}
		byte rnd_byte()
		{
			return std::rand() % yf::max_byte;
		}
		//--------------------------------------------------------------
		uint16 rnd_uint16(uint16 border)
		{
			#ifdef YF_ENABLE_CHECKS
				if (border == 0)
				{
					YF_FUNC_EXCEPTION(domain)
				}
			#endif
			return rnd_uint32(border);
		}
		sint16 rnd_sint16(uint16 border)
		{
			#ifdef YF_ENABLE_CHECKS
				if (border > (uint16)max_sint16)
				{
					YF_FUNC_EXCEPTION(domain)
				}
			#endif
			return (rnd_bool() ? 1l : -1l) * rnd_uint16(border) ;
		}
		uint32 rnd_uint32(uint32 border)
		{
			#ifdef YF_ENABLE_CHECKS
				if (border == 0)
				{
					YF_FUNC_EXCEPTION( domain )
				}
			#endif
			return static_cast<uint32>(rnd_0_1() * border);
		}
		sint32 rnd_sint32(uint32 border)
		{
			#ifdef YF_ENABLE_CHECKS
				if (border > (uint32)max_sint32)
				{
					YF_FUNC_EXCEPTION(domain)
				}
			#endif
			return (rnd_bool() ? 1l : -1l) * rnd_uint32(border) ;
		}
		//--------------------------------------------------------------
		uint16 rnd_uint16()
		{
			uint16 retv = rnd_byte();
			retv <<= 8;
			retv += rnd_byte();
			return retv;
		}
		sint16 rnd_sint16()
		{
			uint16 ush = rnd_uint16();
			return reinterpret_cast<sint16&>(ush);
		}
		uint32 rnd_uint32()
		{
			uint32 retv = rnd_uint16();
			retv <<= 16;
			retv += rnd_uint16();
			return retv;
		}
		sint32 rnd_sint32()
		{
			uint32 ul = rnd_uint32();
			return reinterpret_cast<sint32&>(ul);
		}
		uint64 rnd_uint64()
		{
			uint64 retv = rnd_uint32();
			retv <<= 32;
			retv += rnd_uint32();
			return retv;
		}
		//--------------------------------------------------------------
		sint32 rnd_in_range(sint32 start, sint32 stop)
		{
			#ifdef YF_ENABLE_CHECKS
				if (start > stop)
				{
					YF_FUNC_MESSAGE_EXCEPTION(domain, "range start is greater than range end")
				}
			#endif
			return start + rnd_uint32(stop-start+1);
		}
		//--------------------------------------------------------------
		double rnd_0_1()
		{
			double f_retv = static_cast<double>(rnd_uint32());
			f_retv /= max_uint32;
			return f_retv;
		}
		double rnd_double(double border)
		{
			#ifdef YF_ENABLE_CHECKS
				if (border < 0.0)
				{
					YF_FUNC_MESSAGE_EXCEPTION(domain, "border must be positive or 0")
				}
			#endif
			return rnd_0_1() * border;
		}
		//--------------------------------------------------------------
		void rnd_mem(void* ptr, size_t size)
		{
			byte* mov_ptr = static_cast<byte*>(ptr);
			for (size_t i = 0; i < size; ++i, ++mov_ptr)
			{
				*mov_ptr = rnd_byte();
			}
		}
		//--------------------------------------------------------------
		char rnd_decimal_digit()
		{
			return '0' + std::rand() % 10;
		}
		char rnd_small_latin_character()
		{
			return 'a' + std::rand() % 26;
		}
		char rnd_big_lation_character()
		{
			return 'A' + std::rand() % 26;
		}
		char rnd_latin_character()
		{
			return ( rnd_bool() ? rnd_big_lation_character() : rnd_small_latin_character() );
		}
		//--------------------------------------------------------------
	} // namespace random
} // namespace yf
//---------------------------------------------------------------------------

