#pragma once
/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2015/03/24 - 2015/03/25
/// 
/// @brief  共有フラグ
/// 
/// ****************************************************************************

#include "CPL_Core_Mutex.h"
#include "CPL_Core_Time.h"
#include "../String/CPL_Core_String.h"
#include "../Memory/CPL_Core_BlockPool.h"

namespace CPL {
namespace Core {

// _____________________________________________________________________________
/// @brief 共有フラグ基本クラス
///
// *****************************************************************************
class SharedFlagBase
{
public:
  // _____________________________________________________________________________
  /// @brief フラグの取得。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual bool GetFlag() const = 0;

  // _____________________________________________________________________________
  /// @brief フラグの設定。
  /// 
  /// @param[in] in_flag     : 設定するbool値を指定。
  /// @param[in] in_time_point_end
  ///   : タイムアウト時間を時点または時間で指定。\n
  ///   : この値はネットワーク共有フラグでのみ有効。\n
  ///   : それ以外の共有フラグオブジェクトでは無視される。
  /// 
  /// @retval true  : フラグを更新。
  /// @retval false : タイムアウト。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual bool
    SetFlag
      ( _in<bool     > in_flag
      , _in<TimePoint> in_time_point_end = TimePoint::Max()
      ) = 0;

  // _____________________________________________________________________________
  /// @brief 設定されている識別名を取得。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual td_tstring GetName() const = 0;

  // _____________________________________________________________________________
  /// @brief フラグがONになるまで待機。
  /// 
  /// @param[in] in_time_point_end : タイムアウト時間を時点または時間で指定。
  /// 
  /// @retval true  : フラグがONになっている。
  /// @retval false : フラグがONになる前にタイムアウトになった。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual bool WaitOn( _in<TimePoint> in_time_point_end ) = 0;

  // _____________________________________________________________________________
  /// @brief フラグがOFFになるまで待機。
  /// 
  /// @param[in] in_time_point_end : タイムアウト時間を時点または時間で指定。
  /// 
  /// @retval true  : フラグがOFFになっている。
  /// @retval false : フラグがOFFになる前にタイムアウトになった。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual bool WaitOff( _in<TimePoint> in_time_point_end ) = 0;

protected:
};


// _____________________________________________________________________________
/// @brief スレッド用共有フラグオブジェクト
///
// *****************************************************************************
class ThreadSharedFlag
  : public SharedFlagBase
{
public:
  ThreadSharedFlag()
    : m_sp_flag( nullptr )
  {}

  ThreadSharedFlag
  ( _in<bool      > in_flag_init
  , _in<td_tstring> in_name
  );

  /// @brief SharedFlagBase::GetFlag
  bool GetFlag() const override
  {
    return flag_();
  }

  /// @brief SharedFlagBase::SetFlag
  bool
    SetFlag
      ( _in<bool     > in_flag
      , _in<TimePoint> in_time_point_end = TimePoint::Max()
      ) override
  {
    flag_() = in_flag;
    return true;
  }

  /// @brief SharedFlagBase::GetName
  td_tstring GetName() const override
  {
    return m_name;
  }

  bool WaitOn ( _in<TimePoint> in_time_point_end ) override;
  bool WaitOff( _in<TimePoint> in_time_point_end ) override;

protected:
  using td_spBool_ = sdptr< std::atomic_bool >;
  using td_Map_    = std::map< td_tstring, td_spBool_ >;

  std::atomic_bool&       flag_()       { return *m_sp_flag; }
  std::atomic_bool const& flag_() const { return *m_sp_flag; }

  td_spBool_ zzf_open_  ( _in<td_tstring> in_name );
  td_spBool_ zzf_create_( _in<td_tstring> in_name );

private:
  td_tstring m_name;
  td_spBool_ m_sp_flag;

  CPL_SINGLETON( td_Map_, sm_pool_flag )
};


// _____________________________________________________________________________
/// @brief プロセス用共有フラグ
///
// *****************************************************************************
class ProcessSharedFlag
  : public SharedFlagBase
{
public:
  ProcessSharedFlag
    ( _in<bool      > in_flag = false
    , _in<td_tstring> in_name = SwS("")
    );

  bool GetFlag() const override;

  bool
    SetFlag
      ( _in<bool     > in_flag
      , _in<TimePoint> in_time_point_end = TimePoint::Max()
      ) override;

  td_tstring GetName() const override;

  bool WaitOn ( _in<TimePoint> in_time_point_end ) override;
  bool WaitOff( _in<TimePoint> in_time_point_end ) override;

protected:
  class Entity;
  sdptr<Entity> m_sp_entity;
};


// _____________________________________________________________________________
/// @brief ネットワーク用共有フラグ
///
// *****************************************************************************
class NetworkSharedFlag
  : public SharedFlagBase
{
public:
  NetworkSharedFlag
    ( _in<bool      > in_flag = false
    , _in<td_tstring> in_name = SwS("")
    );

  bool GetFlag() const override;

  bool
    SetFlag
      ( _in<bool     > in_flag
      , _in<TimePoint> in_time_point_end = TimePoint::Max()
      ) override;

  td_tstring GetName() const override;

  bool WaitOn ( _in<TimePoint> in_time_point_end ) override;
  bool WaitOff( _in<TimePoint> in_time_point_end ) override;
protected:
  class Entity;
  sdptr<Entity> m_sp_entity;
};



} // namespace Core
} // namespace CPL
