#pragma once
/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2012/01/18 - 2015/11/11
/// 
/// @brief  パイプ基本制御関連
/// 
/// 2012/01/18 CEG(仮)への仮実装からCorePLiへの本実装のため一部移行。
/// ****************************************************************************


#include "../Base/CPL_Core_Transceiver.h"
#include "../Base/CPL_Core_SharedBuffer.h"
#include "../Base/CPL_Core_ThreadEx.h"
#include "../Stream/CPL_Core_MemoryStream.h"


namespace CPL {
namespace Core {

const std::chrono::milliseconds timeout_default_memory_pipe( 60 * 1000 );


// _____________________________________________________________________________
/// @brief メモリパイプのタイプ。
///
/// 共有メモリを作成した側をホスト。開いた側をゲストとする。
// *****************************************************************************
enum class ePipeType : U32
{ Invalid = 0
, Host    = BIT0
, Guest   = BIT1
};


// _____________________________________________________________________________
/// @brief メモリパイプの動作フラグ。
///
// *****************************************************************************
enum class ePipeMode : U32
{ Host_to_Guest = 0x01 ///< ホストからゲストへの転送専用。
, Guest_to_Host = 0x02 ///< ゲストからホストへの転送専用。
, Interactive   = 0x03 ///< 双方向（未対応）
, None          = 0xFFFF ///< モード取得時のエラーなど。
};

// _____________________________________________________________________________
/// @brief メモリパイプの状態フラグ。
///
// *****************************************************************************
enum class ePipeState : U32
{ Wait          = 0x0000
, Request       = 0x1000  ///< 送信またはモード変更の要求。
, Updating      = 0x1001  ///< 送信中（メモリ書き込み中）。
, Update        = 0x1002  ///< 送信完了（メモリ書き込み完了）。
//, SendTimeout   = 0x1100  ///< 送信側タイムアウト。
//, SendClose     = 0x1101  ///< 送信側クローズ。
, SendError     = 0x1102  ///< 送信中、何らかのエラー。
, Ready         = 0x2000  ///< 要求OK.（このフラグを設定したら、相手側で）
, Reading       = 0x2001  ///< 受信中。
, Readed        = 0x2002  ///< 受信完了。
//, RecvTimeout   = 0x2100  ///< 受信側タイムアウト。
//, RecvClose     = 0x2101  ///< 受信側クローズ。
, OverSize      = 0x2102  ///< 受信側のバッファサイズを超えた。
, RecvError     = 0x2103  ///< 受信中、上記以外の何らかのエラー。
, InvalidMemory = 0xF000  ///< パイプ用のメモリが設定されていない。
, InvalidType   = 0xF001  ///< メモリパイプタイプがInvalidのままである。
, Timeout       = 0xF002  ///< タイムアウト。
, Empty         = 0xFFFF  ///< 未使用またはクローズ。
};


// _____________________________________________________________________________
/// @brief バッファリード／ライトフラグ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
enum class eStatePipeAccess : U32
{ Readed  ///< データ読込完了＝送信側書き込み可。
, Updated ///< データ更新完了＝受信側読み込み可。
, Invalid ///< なんらかの理由で読み書き不可。
};


// _____________________________________________________________________________
/// @brief 転送パイプ返却値
///
// *****************************************************************************
enum class eResultPipe : U32
{ Success_Create_HostMode       ///< ホストモードで作成に成功。
, Success_Create_GuestMode      ///< ゲストモードで作成に成功。
, Success_ModeChange            ///< モード変更に成功。
, Success_StateChange           ///< ステート変更に成功。
, Success_WithoutChange         ///< 変更の必要なし。
, Successful                    ///< その他正常終了。
, Timeout_Myself     = 0x0100   ///< 自身がタイムアウト。
, Timeout_Partner               ///< 相手がタイムアウト。
, Error_Faild_Create = 0x1000   ///< 作成に失敗。
, Error_Faild_ModeChange        ///< モード変更に失敗。
, Error_Faild_StateChange       ///< ステート変更に失敗。
, Error_Empty_Partner           ///< パートナーが設定されていない。
, Error_Invalid_Parameter       ///< パラメータが無効。
, Error_Invalid_SharedBuffer    ///< 共有バッファが無効。
, Error_Invalid_Type            ///< 転送パイプのタイプが無効。
, Error_Invalid_State           ///< 状態が無効である。

, MaskTimeout    = Timeout_Myself
, MaskError      = Error_Faild_Create
, MaskNotSuccess = MaskTimeout | MaskError
};


// _____________________________________________________________________________
/// @brief 転送パイプの統括情報
///
// *****************************************************************************
struct PipeInfo
{
  ePipeMode   mode;   // 
  //StatePipeAccess access_buffer; // バッファの状態。
  ePipeState  state_host;    // ホスト側の状態。
  ePipeState  state_guest;   // ゲスト側の状態。
  //U64         total_size;    // 一度の転送要求に対する全体のデータサイズ。
  //U32         write_size;    // データ部の一回で転送するデータサイズ（毎回設定する）

  PipeInfo()
    : mode( ePipeMode::Interactive )
    , state_host( ePipeState::Wait )
    , state_guest( ePipeState::Empty )
//    , write_size( 0 )
  {
  }
};

// _____________________________________________________________________________
/// @brief パイプライン情報(version 0)
///
// *****************************************************************************
struct PipeBufferHeader
{
  union {
  U8  version[8];
  U64 version_n;
  };

  // パイプ用共有バッファのデータ用領域のサイズ(バッファサイズ−ヘッダサイズ)
  U64 size_data_buffer;

  // １度の書き込みサイズ。
  U32 size_write;

  PipeBufferHeader()
  {}
  PipeBufferHeader( U64 in_size_data_area, U32 in_size_write )
    : version_n( 0 )
    , size_data_buffer( in_size_data_area )
    , size_write( in_size_write )
  {}
};


// _____________________________________________________________________________
/// @brief パケットヘッダー
///
// *****************************************************************************
struct PipePacketHeader
{
  U64 size;

  PipePacketHeader( U64 in_size )
    : size( in_size )
  {}
  PipePacketHeader()
    : size( 0 )
  {}
};


// _____________________________________________________________________________
/// @brief 転送パイプキャッシュのパケットフォーマット
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//struct PipeCachePacketHeader
//{
//  //U32 size_packet_prev; // 前のパケットのサイズ（前のヘッダの更新に使用）。先頭は0.
//  size_t size_packet_data; // 自身のパケットデータサイズ。
//
//  static size_t ComputeSize( size_t in_data_size )
//  {
//    return sizeof(PipeCachePacketHeader) + in_data_size;
//  }
//
//  cptr<void> GetDataAddr() const { return reinterpret_cast<cptr<void>>(this+1); }
//   ptr<void> GetDataAddr()       { return reinterpret_cast< ptr<void>>(this+1); }
//  ptr<void> GetNextPacketAddr()
//  {
//    return
//      reinterpret_cast<char*>(this + 1) +
//      AlignHigh(size_packet_data,sizeof(size_t));
//  }
//};

//// _____________________________________________________________________________
///// @brief 転送パイプキャッシュのパケットヘッダフォーマット
/////
///// 転送パイプ効率化のための、キャッシュおよびグループ化のデータ形式。
//// *****************************************************************************
//struct PipeCachePacketPackegeHeader
//{
//  U32                   packet_num;
//  PipeCachePacketHeader packet_first;
//};


// _____________________________________________________________________________
/// @brief 転送パイプの送信キャッシュ用のキュー要素
///
// *****************************************************************************
//struct PipeSendCacheQueueElement
//{
//  using td_self = PipeSendCacheQueueElement;
//
//  //SpByteBuffer sp_buffer;
//  sdptr<MemoryStream> sp_bufstream;
//  bool                is_packing;
//
//  PipeSendCacheQueueElement(){}
//  PipeSendCacheQueueElement( cref<td_self> pscqe )
//    : sp_bufstream( pscqe.sp_bufstream )
//    , is_packing  ( pscqe.is_packing )
//  {}
//};
//using PipeSendCacheQueue = std::queue<PipeSendCacheQueueElement>;


// _____________________________________________________________________________
/// @brief 転送パイプのバッファ書き込みパラメタ
///
// *****************************************************************************
struct PipeWriteParam
{
  U64       size_packet; // これはパケットヘッダも含んだ値。
                         // addr_srcがデータの途中を指す場合、0を設定する。
  char_cptr addr_src;
  U64       size_write;

  PipeWriteParam(){}
  PipeWriteParam( U64 in_size_packet, void_cptr in_addr_src, U64 in_size_write )
    : size_packet( in_size_packet )
    , addr_src( static_cast<char_cptr>(in_addr_src) )
    , size_write( in_size_write )
  {}
};



} // namespace Core
} // namespace CPL
