/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2002/X/X - 2014/02/05
/// 
/// @brief  基本的なやつら。
/// 
/// ****************************************************************************

#pragma once


#include "CPL_Core_Exception.h"
#include "CPL_Core_Traits.h"
#include "CPL_Core_Cast.h"
#include "CPL_Core_BasicVector.h"
#include "CPL_Core_BasicColor.h"
#include "CPL_Core_Time.h"
#include "CPL_Core_Package.h"
#include "CPL_Core_Numbering.h"

namespace CPL {

/// CorePLiの基本となるデータ構造、アルゴリズム等が含まれます。 
namespace Core {


// _____________________________________________________________________________
/// @brief CorePLi基底オブジェクト
///
// *****************************************************************************
class BaseObject {
private:
  friend struct base_object_debug_counter;
  static void check_();

protected:
  //BaseObject( InitializeVT_ const& ivt ){}

#ifdef CPL_DEBUG
  BaseObject();
  ~BaseObject();
#else
  BaseObject(){}
  ~BaseObject(){}
#endif

public:
  // 現在の総オブジェクト数（デバッグモードのみ有効値を返す）
  static size_t GetBaseObjectCount();

  size_t GetBaseObjectID() const { return ((size_t)(this))>>2; }
};

// _____________________________________________________________________________
/// @brief 仮想明示化用基底クラス
///
// *****************************************************************************
class Virtualize_
{
protected:
  virtual ~Virtualize_(){}
};


// _____________________________________________________________________________
/// @brief コピー禁止化用基底クラス
///
// *****************************************************************************
struct NonCopyable_
{
  NonCopyable_() = default;

  NonCopyable_( NonCopyable_ const& ) = delete;
  NonCopyable_( NonCopyable_&& )      = delete;
  NonCopyable_&
    operator =( NonCopyable_ const& ) = delete;
};





// _____________________________________________________________________________
/// @brief 固定少数用クラス
///
// *****************************************************************************
template<class T_DEC, class T_INT, class T_INT2>
union IntFixedT {
protected:
  struct {
    T_DEC dec_;
    T_INT int_;
  };

public:
  T_INT2 data;

  void   Int( _in<T_INT > in_int_ ){ this->int_ = in_int_; }
  void   Dec( _in<float > in_dec_ ){ this->dec_ = T_DEC(in_dec_ * (1<<(sizeof(T_DEC)*8))); }
  void   Dec( _in<double> in_dec_ ){ this->dec_ = T_DEC(in_dec_ * (1<<(sizeof(T_DEC)*8))); }
  void   Set( _in<float > d ){ data = int(d * (1<<(sizeof(T_DEC)*8))); }
  void   Set( _in<double> d ){ data = int(d * (1<<(sizeof(T_DEC)*8))); }
  int    Int()      const { return int_; }
  int    Dec()      const { return dec_; }
  float  DecFloat() const { return (float)dec_ / (1<<(sizeof(T_DEC)*8)) * ((Int() < 0) ? -1 : 1 ); }
  float  Float()    const { return (float)data / (1<<(sizeof(T_DEC)*8)) * ((Int() < 0) ? -1 : 1 ); }
  double Double()   const { return (double)data / (1<<(sizeof(T_DEC)*8)) * ((Int() < 0) ? -1 : 1 ); }

  void      operator +=( cref<IntFixedT> d ){ data += d.data; }
  IntFixedT operator + ( cref<IntFixedT> d ){ return IntFixedT(static_cast<S16>(data + d.data)); }
  void      operator -=( cref<IntFixedT> d ){ data -= d.data; }
  IntFixedT operator - ( cref<IntFixedT> d ){ return IntFixedT(static_cast<S16>(data - d.data)); }
  void      operator *=( cref<IntFixedT> d ){ data = int(S64(data) * S64(d.data) >> 16); }
  IntFixedT operator * ( cref<IntFixedT> d ){ return IntFixedT(data * d.Float()); }
  void      operator /=( cref<IntFixedT> d ){ data = int((S64(data)<<16) / d.data); }
  IntFixedT operator / ( cref<IntFixedT> d ){ return IntFixedT(data / d.Float()); }

  IntFixedT& operator = ( const IntFixedT& d ){ data = d.data; return *this; }

  IntFixedT( T_INT  d ){ int_ = d; dec_ = 0; }
  IntFixedT( float  d ){ Set( d ); }
  IntFixedT( double d ){ Set( d ); }
  IntFixedT( IntFixedT const& d ){ data = d.data; }
  IntFixedT(){ data = 0; }
};



} // namespace Core



typedef CPL::Core::IntFixedT<U16,S16,S32> IntFixed4b16;
typedef CPL::Core::IntFixedT<U16,U16,U32> IntFixed4b16U;
typedef CPL::Core::IntFixedT<U8,S8,S16>   IntFixed2b08;
typedef CPL::Core::IntFixedT<U8,U8,U16>   IntFixed2b08U;

typedef IntFixed2b08     intfix2;
typedef IntFixed2b08U    intfix2u;
typedef IntFixed4b16     intfix4;
typedef IntFixed4b16U    intfix4u;


//typedef Color_A8R8G8B8   color32;
//typedef Color_R8G8B8     color24;
//typedef Color_R5G6B5     color16;
//typedef Color_R5G5B5     color15;
//typedef Color_A4R4G4B4   color16a;

// _____________________________________________________________________________
/// @brief ２の累乗（べき乗）サイズへの補正。
///
/// ※ １未満は１として扱う。
/// 
/// @param[in] in_value : 補正する値を指定します。
/// 
/// @return 補正後の値が返ります。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<class T>
T AdjustPowerd2( T in_value )
{
  if( in_value <= 1 )
    return (T)1;

  size_t value = 1;
  while( (size_t)in_value > value )
  {
    value <<= 1;
  }
  return (T)value;
}


} // namespace CPL
