#pragma once
/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2007/X/X - 2015/11/13
/// 
/// @par Note
/// ソケット管理クラスを提供。\n
/// @par
/// このソケットクラスを用いての受信(Recv)はソケットクラスの送信(Send)のみ対応する。\n
/// 使用者が独自にソケットクラスのSOCKETを用いて転送しても、ソケットクラスのRecv
/// では、正しく受け取ることができない。\n
/// 現在はTCPのみ対応。\n
/// @par
/// 転送単位は次の構造とする。\n
/// 転送要求ブロック{\n
/// 　フラグメント[N]{}\n
/// }\n
/// １つの転送要求では複数のバッファを一度に指定でき、１つの転送ブロック単位とし
/// て扱われる。\n
/// この転送ブロックはフラグメントブロックの集まりとして転送され、このフラグメン
/// トは転送要求時のバッファと１：１となることを保障しなければならない。\n
/// つまり、転送時に３つのバッファを渡すと、３つのフラグメントとしてデータが転送
/// されることになる。\n
/// そして、受け取り側ではその区切りを取得できる仕様としなければならない。
/// 
/// ****************************************************************************


#include "CPL_WIN_WS_SocketBase.h"


namespace CPL {
namespace WIN {


// _____________________________________________________________________________
/// @brief TCPソケット管理クラス
///
// *****************************************************************************
class SocketTCP
  : public SocketBase
{
  // _____________________________________________________________________________
  /// @brief 送信スレッド管理クラス ※ 現仕様では継承禁止
  ///
  /// １ソケットのデータ送信を担当する。
  ///
  // *****************************************************************************
  class ThreadSend
    //: public WIN::Thread
    : public Core::ThreadEx
  {
    friend class SocketTCP;
    friend CallPrivateConstructor<ThreadSend>;
    // VS2013CTP時点では必要(たぶん、アロケータの仕様を満たしていない)。
    template<class _Ty, class _Alloc>
	  friend class std::_Ref_count_obj_alloc;

    CPL_SCOPED_ENUM
      ( eThreadLockID, int
      , Cache
      , Buffer
      , Request
      , Push
      );
    //typedef Core::ExctionTLv<ThreadSend,TLId_REQUEST> AutoThreadLock_Request;
    //typedef Core::ExctionTLv<ThreadSend,TLId_BUFFER > AutoThreadLock_Buffer;
    //typedef Core::ExctionTLv<ThreadSend,TLId_CACHE  > AutoThreadLock_Cache;
    //typedef Core::ExctionTLv<ThreadSend,TLId_PUSH   > AutoThreadLock_Push;
    typedef std::atomic<int> atomic_int;

    CPL_SINGLETON_INIT( U32, id_counter, 0 )
    
    SocketTCP*                m_ptr_socket;
    mutable Core::Array::S_U8 m_cache_buffer;
    mutable RequestQueue      m_send_request_queue; // 送信リクエストキュー
    mutable Core::BufferQueue m_send_data_queue;    // 送信データキャッシュキュー
    mutable volatile S64      m_send_size;          // 転送済みサイズ保存用
    mutable atomic_int        m_flag_sending;       // true:転送中 false:待機中
    mutable atomic_int        m_complete_seg_num;   // 転送済みセグメントキャッシュサイズ
    mutable atomic_int        m_flag_life_thread;   // スレッドが実行中かどうか。
    Core::ThreadMutex<>       m_mutex_request;
    Core::ThreadMutex<>       m_mutex_data;
    Core::ThreadMutex<>       m_mutex_cache;

    int   zzf_Send( SendParam& io_send_param ) const;
    S64   zzf_SendEx( SendParam& io_send_param ) const;
    S64   zzf_SendQueue() const;
    S64   zzf_SendQueue_Push( SendParam& io_send_param ) const;
    SDEF  zzf_Refresh( volatile S64* out_ptr_size = nullptr ) const;

    //int   Call( void* arglist );
    size_t operator ()() override;
    U32   AddData
            ( SpByteBuffer const in_buffer_table[]
            , int                in_table_num
            );
    int   GetCompleteSegmentCacheNum() const;
    int   IsThread() const { return m_flag_life_thread.load(); }
    bool  WaitSendRequest
            ( _in<U32      > in_send_ID
            , _in<TimePoint> in_time_point_end = TimePoint::Max()
            ) const;

    ThreadSend
      ( SocketTCP*         in_ptr_socket
      , SpByteBuffer const in_buffer_table[]
      , int                in_table_num
      , U32*               out_ptr_ID = nullptr
      );
  public:
    ~ThreadSend(){}
  };

  // _____________________________________________________________________________
  /// @brief 受信スレッド管理クラス
  ///
  /// １ソケットのデータ送信を担当する。
  ///
  // *****************************************************************************
  class ThreadRecv
    //: public WIN::Thread
    : public Core::ThreadEx
  {
  public:
    CPL_SCOPED_ENUM
      ( eFlagComplete, int
      , NoneData
      , Receiving
      , ReceivedCache
      );
  private:
    friend class SocketTCP;
    friend CallPrivateConstructor<ThreadRecv>;
    // VS2013CTP時点では必要(たぶん、アロケータの仕様を満たしていない)。
    template<class _Ty, class _Alloc>
	  friend class std::_Ref_count_obj_alloc;

    CPL_SCOPED_ENUM
      ( eThreadLockID, int
      , RequestBuffer
      , RequestInfo
      );
    //typedef Core::ExctionTLv<ThreadRecv,TLId_REQ_INFO  > AutoThreadLock_Request;
    //typedef Core::ExctionTLv<ThreadRecv,TLId_REQ_BUFFER> AutoThreadLock_Buffer;

    SocketTCP*                m_ptr_socket;         // 呼び出し元のソケットのポインタを保持する。
    mutable U32               m_read_size;          // 現在読み込み中の読み込み済みサイズ（圧縮されている場合、展開後のサイズ）
    mutable U32               m_req_block_size;     // 現在読み込み中のリクエストブロックサイズ（非圧縮サイズ）。0の場合、現在読み込み中のブロックは無いということ。
    mutable RequestQueue      m_recv_request_queue; // 受信リクエストサイズキュー
    mutable Core::BufferQueue m_recv_buffer_queue;  // 受信バッファキュー
    mutable int               m_complete_seg_num;   // 受信済みセグメントキャッシュサイズ
    Core::ThreadMutex<>       m_mutex_request;
    Core::ThreadMutex<>       m_mutex_data;

    int   zzf_Recv( RecvParam& io_recv_param ) const;
    int   zzf_RecvEx( RecvParam& io_recv_param ) const;
    int   zzf_RecvRequestInfo( RequestInfoBuffer& out_req_info ) const;
    int   zzf_RecvCache() const;

    //int   Call( void* arglist );
    size_t operator ()() override;
    eFlagComplete
          IsCompleteRequest() const;
    int   GetCompleteSegmentCacheNum() const;

    ThreadRecv( SocketTCP* in_ptr_socket );
  };

public:
  //static const int FLAg_RECV_COMPLETE_NONE_DATA = ThreadRecv::FlagCompleteNoneData;
  //static const int FLAg_RECV_COMPLETE_RECEIVING = ThreadRecv::FlagCompleteReceiving;
  //static const int FLAg_RECV_COMPLETE_RECEIVED  = ThreadRecv::FlagCompleteReceivedCache;

protected:
  //Core::SmartPtr<ThreadRecv>::RefCntMT m_sp_thread_recv;
  //Core::SmartPtr<ThreadSend>::RefCntMT m_sp_thread_send;
  std::shared_ptr<ThreadRecv> m_sp_thread_recv;
  std::shared_ptr<ThreadSend> m_sp_thread_send;


  // ワーカースレッド
  //int Call( void* arglist );
  //
  bool zzf_IsRecvCache() const;
  bool zzf_IsSendCache() const;
  
  Core::eResultTransSend
    zzf_Send
      ( cptr<SpByteBuffer> in_buffer_table
      , _in <int         > in_buf_table_num
      , _in <TimePoint   > in_time_point_end
      , _in <bool        > in_flag_copy
      , pout<U32         > out_send_ID
      );

  U32 CreateThreadSend
    ( SpByteBuffer const in_buffer_table[]
    , int                in_table_num
    );

public:
  //SocketTCP( SocketTCP const& s ); // コピーコンストラクタは禁止。

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  SocketTCP( SOCKET s, _in<SpSocket> in_sp_socket = nullptr );
  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  SocketTCP
  ( _in<int     > in_AF        = AF_INET
  , _in<int     > in_type      = SOCK_STREAM
  , _in<int     > in_protocol  = 0
  , _in<SpSocket> in_sp_socket = nullptr
  );
  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  SocketTCP
  ( pin<char    > in_hostname
  , pin<char    > in_service
  , _in<SpSocket> in_sp_socket = nullptr
  );
  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  SocketTCP
  ( _in<SOCKET  > in_socket
  , pin<sockaddr> in_ptr_sockaddr
  , _in<int     > in_sockaddr_len
  , _in<SpSocket> in_sp_socket = nullptr
  );
  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ~SocketTCP();

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  int Close() override;

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  void CreateThreadRecv();

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  using Receiver::Recv;
  using Sender::Send;

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Core::eResultTransRecv
    Recv( rout<ByteBuffer> out_buffer
        , _in <TimePoint > in_time_point_end
        ) override;

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  int   GetRecvReport( rout<ReportInfoBufferTable> out_report_table ) const override;

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Core::eResultTransSend
    Send
      ( pin <void     > in_ptr_buf
      , _in <size_t   > in_size_send
      , _in <TimePoint> in_time_out
      , pout<U32      > out_send_ID = nullptr
      ) override;
  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Core::eResultTransSend
    Send
      ( cref<ByteBuffer> in_buffer
      , _in <TimePoint > in_time_out
      , pout<U32       > out_send_ID = nullptr
      ) override;
  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Core::eResultTransSend
    Send
      ( rvref<ByteBuffer> in_buffer
      , _in  <TimePoint > in_time_out
      , pout <U32       > out_send_ID = nullptr
      ) override;

  //// _____________________________________________________________________________
  //// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //Core::ResultTransSend
  //  Send
  //    ( _in <SpByteBuffer> in_sp_buffer
  //    , _in <TimePoint   > in_time_out
  //    , _in <bool        > in_flag_copy
  //    , pout<U32         > out_send_ID = nullptr
  //    ) override;
  //// _____________________________________________________________________________
  //// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //Core::ResultTransSend
  //  Send
  //    ( cptr<SpByteBuffer> in_buffer_table
  //    , _in <int         > in_buf_table_num
  //    , _in <TimePoint   > in_time_out
  //    , _in <bool        > in_flag_copy
  //    , pout<U32         > out_send_ID = nullptr
  //    ) override;
  
  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  int   GetSendReport( rout<ReportInfoBufferTable> out_report_table ) const override;
};



} // namespace WIN
} // namespace CPL
