/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2013/11/29 - 2016/12/30
/// 
/// @brief  ファクトリー関連。
///
/// ※ 2014/04/03 GUCからCoreへ移行。
/// 
/// 
/// ****************************************************************************

#pragma once

#include "../../CPL_Setup.h"


namespace CPL {
// _____________________________________________________________________________
/// @brief ファクトリ構築専用クラスの自身ポインタ管理明示用クラス
/// 
/// 継承することでファクトリに対象を指すスマートポインタの管理を、
/// 対象のオブジェクトが行うことを示します。\n
/// また自身を指すスマートポインタを返す関数GetSelfPointer<type>()を必ず
/// 定義しなければならない。
// *****************************************************************************
struct UseFactorySelfPointer { UseFactorySelfPointer(){} };

// _____________________________________________________________________________
/// @brief ファクトリ構築用クラスの初期化用コールバック関数明示用クラス
/// 
/// 継承することでファクトリに初期化関数を呼ぶことを明示します。\n
/// 派生クラスでは初期化関数を定義する必要があります。\n
/// 初期化関数は次の使用になります。\n
/// bool On_Initialize( std::shared_ptr<T> self [, コンストラクタ引数リスト] )
// *****************************************************************************
struct UseFactoryCallInitialize { UseFactoryCallInitialize(){} };

// _____________________________________________________________________________
/// @brief ファクトリ構築用クラスの生成イベント用コールバック関数明示用クラス
/// 
/// 継承することでファクトリに生成イベントを呼ぶことを明示します。\n
/// 派生クラスではOn_Create()をオーバーライドしなければいけません。\n
/// UseFactoryCallInitializeとUseFactoryCallCreateの両方継承している場合、
/// On_Initialize(...)が先に呼ばれます。
// *****************************************************************************
struct UseFactoryCallCreate
{
  UseFactoryCallCreate(){}

  virtual bool On_Create() = 0;
};


namespace Core {

// _____________________________________________________________________________
/// @brief 基底ファクトリクラス
///
// *****************************************************************************
class BaseFactory
{
protected:
  CPL_SINGLETON_INIT( int, creating, 0 )

public:
  static int GetCreating(){ return creating(); }
};


// _____________________________________________________________________________
/// @brief ファクトリ
///
// *****************************************************************************
template< class T_Type >
class Factory : public BaseFactory
{
  static constexpr int is_self_pointer =
    std::is_convertible<T_Type,UseFactorySelfPointer>::value;
  static constexpr int is_call_init =
    std::is_convertible<T_Type,UseFactoryCallInitialize>::value;
  static constexpr int is_call_create =
    std::is_convertible<T_Type,UseFactoryCallCreate>::value;

  // スマートポインタ化関数
  template<class T>
  static sdptr<T> toPointer( T* p, ValueType<0> not_self_pointer )
  {
    return sdptr<T>(p);
  }
  template<class T>
  static sdptr<T> toPointer( T* p, ValueType<1> self_pointer )
  {
    return p->template GetSelfPointer<T>();
  }

  // 初期化呼び出し
  template<class T, class... T_Params>
  static bool
    CallInitialize
      ( ValueType<false> not_call_initialize
      , sdptr<T>& in_sp_self
      , T_Params&&... args
      )
  {
    return true;
  }
  template<class T, class... T_Params>
  static bool
    CallInitialize
      ( ValueType<true> not_call_initialize
      , sdptr<T_Type>& in_sp_self
      , T_Params&&... args
      )
  {
    return in_sp_self->On_Initialize( in_sp_self, std::forward<T_Params>(args)... );
  }

  // 作成時イベント
  static bool
    CallCreate( ValueType<false> not_call_create, sdptr<T_Type>& in_sp_self )
  {
    return true;
  }
  static bool
    CallCreate( ValueType<true> not_call_create, sdptr<T_Type>& in_sp_self )
  {
    return in_sp_self->On_Create();
  }

public:
  template<class... T_Params>
  static std::shared_ptr<T_Type>
    Create( T_Params&&... args )
  {
    //try {
      ++creating();

      // 作成。
      T_Type* ptr = CPL_NEW(T_Type)( std::forward<T_Params>(args)... );
      // スマートポインタ化
      auto sp_object = toPointer( ptr, ValueType<is_self_pointer>() );
      if( !sp_object )
      {
        --creating();
        return nullptr;
      }

      // 初期化関数呼び出し。
      auto res_init =
        CallInitialize
          ( ValueType<is_call_init>()
          , sp_object
          , std::forward<T_Params>(args)...
          );
      if( !res_init )
      {
        --creating();
        return nullptr;
      }

      // 作成時イベント呼び出し。
      auto res_create =
        CallCreate
          ( ValueType<is_call_create>()
          , sp_object
          );
      if( !res_create )
      {
        --creating();
        return nullptr;
      }

      --creating();

      return sp_object;
    //}
    //catch(...)
    //{
    //  return nullptr;
    //}
  }
  
};



} // namespace Core

template<class T> using Factory = Core::Factory<T>;

} // namespace CPL
