/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2015/02/10 - 2016/03/14
/// 
/// @brief  スレッド共有バッファ関連
/// 
/// ****************************************************************************

#include "CPL_Core_SharedBuffer.h"

namespace CPL {
namespace Core {


// _____________________________________________________________________________
/// @brief バッファ生成付きコンストラクタ
/// 
/// @param[in] in_shared_buffer_name
///   : バッファ名を指定します。
/// @param[in] in_size_max
///   : バッファサイズを指定します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ThreadSharedBuffer::ThreadSharedBuffer
( _in<td_tstring> in_shared_buffer_name
, _in<U64       > in_size_max
) : SharedBufferBase( in_shared_buffer_name, in_size_max )
{
  if( !Open() )
  {
    Create( in_size_max );
  }
}

// _____________________________________________________________________________
/// @brief コンストラクタ（バッファ生成なし）
/// 
/// @param[in] in_shared_buffer_name
///   : バッファ名を指定します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ThreadSharedBuffer::ThreadSharedBuffer
( _in<td_tstring> in_shared_buffer_name
) : SharedBufferBase( in_shared_buffer_name )
{
}


// _____________________________________________________________________________
/// @brief 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ThreadSharedBuffer::~ThreadSharedBuffer()
{
}


// _____________________________________________________________________________
/// @brief 共有バッファの作成。
/// 
/// @param[in] in_size_max     : バッファサイズを指定します。
/// @param[in] in_flag_protect : 使用しません。
/// 
/// @retval true  : バッファの作成に成功。
/// @retval false : バッファの作成に失敗。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

bool
  ThreadSharedBuffer::Create
    ( _in<U64               > in_size_max
    , _in<eFlagSharedProtect> in_flag_protect
    )
{
  try {
    auto res = sm_buffer_map().find( m_shared_buffer_name );
    if( res == sm_buffer_map().end()  ||
        res->second.lock() == nullptr
      ) // 該当なし、もしくはオブジェクトが無い場合。
    {
      m_sp_buffer =
        CPL_MAKE_SHARED( DefaultBuffer, static_cast<size_t>(in_size_max) );
      sm_buffer_map()[ m_shared_buffer_name ] = m_sp_buffer;
      m_size_max = in_size_max;
    }
    else
    {
      m_sp_buffer = res->second.lock();
      m_size_max = m_sp_buffer->GetSize();
    }
    return true;
  }
  catch( ... )
  {
    return false;
  }
}


// _____________________________________________________________________________
/// @brief 共有バッファを開く。
/// 
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  ThreadSharedBuffer::Open
    ( _in<eFlagSharedAccess> in_desired_access
    )
{
  try
  {
    auto res = sm_buffer_map().find( m_shared_buffer_name );
    if( res == sm_buffer_map().end() ) // 該当なし。
    {
      //m_sp_buffer =
      //  CPL_MAKE_SHARED( DefaultBuffer, static_cast<size_t>(m_size_max) );
      //sm_buffer_map()[ m_shared_buffer_name ] = m_sp_buffer;
      return false;
    }
    else
    if( auto sp_buf = res->second.lock() )
    {
      m_sp_buffer = sp_buf;
      m_size_max = m_sp_buffer->GetSize();
    }
    else // バッファが閉じられている。
    {
      sm_buffer_map().erase( res );
      return false;
    }
    return true;
  }
  catch(...)
  {
    return false;
  }
}


// _____________________________________________________________________________
/// @brief バッファを閉じる。
/// 
/// @retval 0 : 正常終了。
/// @retval -1 : 内部で何らかのエラーが発生。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int ThreadSharedBuffer::Close()
{
  try
  {
    m_sp_buffer.reset();

    auto res = sm_buffer_map().find( m_shared_buffer_name );
    if( res != sm_buffer_map().end() )
    {
      if( res->second.lock() == nullptr )
      {
        sm_buffer_map().erase( res );
      }
    }
    return 0;
  }
  catch(...)
  {
    return -1;
  }
}


// _____________________________________________________________________________
/// @brief スレッド間共有バッファからの読み込み。
/// 
/// @param[in]  in_pos      : 読み込み開始位置をバイト単位で指定します。
/// @param[out] out_ptr_buf : 読み出し先のアドレスを指定します。
/// @param[in]  in_size     : 読み込むサイズをバイト単位で指定します。
/// @param[in] in_type_access : ThreadSharedBufferクラスでは使用しません。省略可。
/// 
/// @return 実際に読み込まれたサイズを返します。\n失敗した場合、全ビットON(-1)を返します。
/// 
/// @note
/// この関数では排他制御は行いません。\n
/// 必要に応じて上位のモジュールで排他制御を行ってください。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
U64
  ThreadSharedBuffer::Read
    ( _in <U64 > in_pos
    , pout<void> out_ptr_buf
    , _in <U64 > in_size
    , _in <U32 > in_type_access
    ) const
{
  if( !IsEmpty() )
  {
    return m_sp_buffer->Read( in_pos, out_ptr_buf, in_size, in_type_access );
  }
  return 0;
}
  
// _____________________________________________________________________________
/// @brief スレッド間共有バッファへの書き込み。
/// 
/// @param[in] in_pos     : 書き込む位置をバイト単位で指定します。
/// @param[in] in_ptr_buf : 書き込まれるデータを指すアドレスを指定します。
/// @param[in] in_size    : 書き込むサイズをバイト単位で指定します。
/// @param[in] in_type_access : ThreadSharedBufferクラスでは使用しません。省略可。
/// 
/// @return 実際に書き込まれたサイズを返します。\n失敗した場合、全ビットON(-1)を返します。
/// 
/// @note
/// この関数では排他制御は行いません。\n
/// 必要に応じて上位のモジュールで排他制御を行ってください。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
U64
  ThreadSharedBuffer::Write
    ( _in<U64 > in_pos
    , pin<void> in_ptr_buf
    , _in<U64 > in_size
    , _in<U32 > in_type_access
    )
{
  if( !IsEmpty() )
  {
    return m_sp_buffer->Write( in_pos, in_ptr_buf, in_size, in_type_access );
  }
  return 0;
}


// _____________________________________________________________________________
/// @brief スレッド間共有バッファへのバッファリストの書き込み。
/// 
/// @param[in]  in_ptr_param_write
///   : 書き込みパラメータ配列の先頭ポインタを指定します。\n
///   : パラメータはstd::tuple<U64,void_cptr,U64>の構成とし、それぞれpos,address,sizeを表します。\n
/// @param[in]  in_num_param
///   : 書き込みパラメータ配列の要素数を指定します。
/// @param[out] out_ptr_result
///   : 各要素の実際に書き込まれたサイズを格納する配列へのポインタを指定します。\n
///   : 必要ない場合、nullptr指定できます。
/// @param[in] in_type_access : ThreadSharedBufferクラスでは使用しません。省略可。
/// 
/// @return 実際に読み込まれたサイズ。失敗した場合、全ビットON(-1)を返す。
/// 
/// @note
/// この関数では排他制御は行いません。\n
/// 必要に応じて上位のモジュールで排他制御を行ってください。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
std::pair<U64,U64>
  ThreadSharedBuffer::Write
    ( pin <std::tuple<U64,void_cptr,U64>> in_ptr_param_write
    , _in <size_t                       > in_num_param
    , pout<std::vector<U64>             > out_ptr_result
    , _in <U32                          > in_type_access
    )
{
  if( !IsEmpty() )
  {
    return
      m_sp_buffer->Write
        ( in_ptr_param_write
        , in_num_param
        , out_ptr_result
        , in_type_access
        );
  }
  return std::pair<U64,U64>(0,0);
}


} // namespace Core
} // namespace CPL
