/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2012/X/X - 2013/10/09
/// 
/// @brief  ランダム関数
/// 
/// ****************************************************************************

#pragma once

#include <time.h>
#include <random>
#include "CPL_Core_Define.h"


namespace CPL {
namespace Core {


/// @cond
namespace zzz_ {
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // 基本乱数生成関数
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  U32 random32_();
}
/// @endcond


// _____________________________________________________________________________
/// @brief 乱数を取得。
/// 
/// @param[out] out_value    : 取得する値を格納する変数への参照。
/// @param[in]  in_value_of_minimum : 乱数の最小値。
/// @param[in]  in_value_of_maximum : 乱数の最大値。
/// 
/// @return 乱数値。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T> inline
void GetRandomValue( T& out_value, T in_value_of_minimum, T in_value_of_maximum )
{
  static T old_value = 0;
  old_value =
  out_value = old_value + (T)zzz_::random32_();
  if( in_value_of_maximum != (T)-1 )
  {
    out_value = out_value % (in_value_of_maximum - in_value_of_minimum + 1) + in_value_of_minimum;
  }
}

/// @copydoc CPL::Core::GetRandomValue
template<class T> inline
void GetRandomValue( U64& out_value, U64 in_value_of_minimum, U64 in_value_of_maximum )
{
  ((U32*)&out_value)[0] = zzz_::random32_();
  ((U32*)&out_value)[1] = zzz_::random32_();
  if( in_value_of_maximum != (U64)-1 )
  {
    out_value = out_value % (in_value_of_maximum - in_value_of_minimum + 1) + in_value_of_minimum;
  }
}

/// @copydoc CPL::Core::GetRandomValue
template<class T> inline
void GetRandomValue( S64& out_value, S64 in_value_of_minimum, S64 in_value_of_maximum )
{
  ((U32*)&out_value)[0] = zzz_::random32_();
  ((U32*)&out_value)[1] = zzz_::random32_();
  if( in_value_of_maximum != (((U64)-1)>>1) )
  {
    out_value = out_value % (in_value_of_maximum - in_value_of_minimum + 1) + in_value_of_minimum;
  }
}

/// @copydoc CPL::Core::GetRandomValue
template<> inline
void GetRandomValue( float& out_value, float in_value_of_minimum, float in_value_of_maximum )
{
  out_value =
    (float)zzz_::random32_() / (float)0xffffffff
    * (in_value_of_maximum - in_value_of_minimum) + in_value_of_minimum;
}

/// @copydoc CPL::Core::GetRandomValue
template<> inline
void GetRandomValue( double& out_value, double in_value_of_minimum, double in_value_of_maximum )
{
  out_value =
    (double)zzz_::random32_() / (double)0xffffffff
    * (in_value_of_maximum - in_value_of_minimum) + in_value_of_minimum;
}


// _____________________________________________________________________________
/// @brief ランダム文字列生成（マルチバイト仕様）
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void GetRandomStringA( char* out_string, U32 in_buf_size, U32 in_flags );

// _____________________________________________________________________________
/// @brief ランダム文字列生成（UNICODE仕様）
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void GetRandomStringW( wchar_t* out_string, U32 in_buf_size, U32 in_flags );

#ifdef CPL_UNICODE
inline void GetRandomString( wchar_t* out_string, U32 in_buf_size, U32 in_flags )
{
  GetRandomStringW( out_string, in_buf_size, in_flags );
}
#else
inline void GetRandomString( char* out_string, U32 in_buf_size, U32 in_flags )
{
  GetRandomStringA( out_string, in_buf_size, in_flags );
}
#endif



//// _____________________________________________________________________________
///// @brief 重み付きランダム生成用オブジェクト
///// 
///// ※ 今のところ整数値のみ実装。
//// *****************************************************************************
//class WeightRandom
//{
//  using td_Element = std::pair<size_t,size_t>;
//  using td_Table   = std::vector<td_Element>;
//
//public:
//  WeightRandom( _in<std::vector<size_t>> in_weight_table, _in<bool> in_is_sort );
//
//  size_t Get() const
//  {
//    static std::random_device rd;
//	  static std::mt19937 mt( rd() );
//    std::uniform_int_distribution<U32> dist( 0, m_weight_sum-1 );
//    U32 val = dist( mt );
//    return val;
//  }
//protected:
//private:
//  td_Table m_weight_table;
//  size_t   m_weight_sum;
//};



} // namespace Core
} // namespace CPL
