/*!
	CConnectionControlは、以下の機能を持つ
	・リクエスト、レスポンスボディのサイズ管理
	・レスポンスボディのバッファリング
		・CGI出力や、gzip圧縮など、ボディサイズが完了まで分からない場合に、処理完了までバッファリングし、ContentLengthを設定する
	・KeepAliveの有効・無効の管理。ただし、ヘッダの操作は行わない
	・通信状態の管理
		・エラーなど、サーバレスポンスをどのタイミングでも送信可能とする
*/

#pragma once
#include "IServerTool.h"
#include "IClientConnection.h"
#include "IConnectionControl.h"
#include "BinaryData.h"
#include "Settings.h"


/*!
	接続制御クラス

	データストリームのバッファリングなどを行う
*/
class CConnectionControl : public IConnectionControl
{
public:
	CConnectionControl(void);
	virtual ~CConnectionControl(void);

	//!	開始
	void AttacheConnection(IServerToolPtr serverTool, IConnectionThreadStatusPtr threadStatus, IClientConnectionTempPtr connection, CContext context);

	//!	終了
	void DetacheConnection();

	//////////////////////////////////////////////////////////////////////////////
	//	IConnectionControl
	//////////////////////////////////////////////////////////////////////////////
	//!	IConnectionControl
	IConnectionControlPtr GetIConnectionControl() { return IConnectionControlRet(this, FALSE); };

	//!	接続中か取得する
	virtual int IsConnecting();

	//!	通信ブロックサイズを取得
	virtual int GetBlockSize() { return m_workingBufSize; };

	//!	帯域幅制御を有効にする
	virtual void EnableBandWidthLimit(int sendLimit = -1, int recvLimit = -1)
	{
		m_sendLimit = sendLimit;
		m_recvLimit = recvLimit;
	};

	//!	送信済みサイズを取得する
	virtual __int64 GetSendedSize() { return m_receivedSize; };

	//!	受信済みサイズを取得する
	virtual __int64 GetReceivedSize() { return m_sendedSize; };

	//!	バッファリングモードへ移行する
	virtual int ChangeBufferingMode(int mode);

	//!	現在のモードを取得する
	virtual int GetCurrentMode();

	//!	最大バッファリングサイズ取得
	virtual int GetMaxBufferingSize() { return m_maxBufferingSize; };

	//!	KeepAliveを無効に
	virtual void DisableReuseConnection();

	//!	KeepAlive状態をセット(DisableReuseConnectionが優先される)
	virtual void SetReuseConnection(int reuse);

	//!	KeepAliveは現在有効か？￥
	virtual int CanReuseConnection();

	//!	最大KeepAlive時間を指定
	virtual void SetWaitNextRequestTime(int time);

	//!	最大KeepAlive時間を取得
	virtual int GetWaitNextRequestTime() { return m_waitNextRequestTime; };

	//////////////////////////////////////////////////////////////////////////////////////////////
	//	リクエスト受信
	//////////////////////////////////////////////////////////////////////////////////////////////
	//!	ヘッダを受信(throw)
	void RecvRequestHeader();

	//!	ボディを受信、繰り返し(throw)
	int RecvRequestBody(CBinaryData &body);

	//!	受信処理完了
	void EndRecvRequest();

	//////////////////////////////////////////////////////////////////////////////////////////////
	//	レスポンス送信
	//////////////////////////////////////////////////////////////////////////////////////////////
	//!	ヘッダを送信(throw)
	void SendResponseHeader();

	//!	ボディを送信、繰り返し(throw)
	void SendResponseBody(CBinaryData &body);

	//!	送信処理完了
	void EndSendResponse();

	//////////////////////////////////////////////////////////////////////////////////////////////
	//	サーバレスポンス送信
	//////////////////////////////////////////////////////////////////////////////////////////////
	//!	サーバレスポンス送信(どの処理段階でも適切に処理される)
	void SendServerResponse(CBinaryData &body);

protected:
	//////////////////////////////////////////////////////////////////////////////
	//	ツール関数
	//////////////////////////////////////////////////////////////////////////////
	//!	バッファへ追加
	void AddToBodyBuffer(CBinaryData &body);

	//!	バッファサイズ取得
	__int64 GetBufferingSize() { return m_responseBody.GetSize(); };

	//!	バッファリングモードへ移行する
	int EnterBufferingMode();

	//!	ストリーミングモードへ移行する
	int EnterStreamingMode();

	//!	バッファリング中の内容を送信
	void FlashBuffer(int bodyIsCompleted);

	//////////////////////////////////////////////////////////////////////////////
	//	通信関数
	//////////////////////////////////////////////////////////////////////////////
	//!	ヘッダ受信を実行
	void InternalRecvHeader();

	//!	ボディ受信を実行
	int InternalRecvBody(CBinaryData &data, __int64 maxRecvSize);

	//!	ヘッダ送信を実行
	void InternalSendHeader(__int64 contentLength);

	//!	ボディ送信を実行
	int InternalSendBody(CBinaryData &data);


	//////////////////////////////////////////////////////////////////////////////
	//	メンバ変数
	//////////////////////////////////////////////////////////////////////////////
	//!	設定
	CConnectionControlSetting	m_setting;

	//!	スレッドステータス
	IConnectionThreadStatusPtr	m_threadStatus;

	//!	接続
	IClientConnectionTempPtr	m_connection;

	//!	コンテキスト
	CContext					m_context;

	//!	処理状況
	int							m_processState;

	//!	バッファリングモード
	int							m_bufferingMode;

	//!	バッファ
	CBinaryData					m_responseBody;

	//!	KeepAliveモード
	int							m_reuseConnection;

	//!	最大KeepAliveタイム
	int							m_waitNextRequestTime;

	//!	受信予定のデータサイズ(残り)
	__int64						m_requestBodySizeLeft;

	//!	送信予定のデータサイズ（残り）
	__int64						m_responseBodySizeLeft;

	//!	最大バッファリングサイズ
	int							m_maxBufferingSize;

	//!	作業バッファサイズ
	int							m_workingBufSize;

	//!	送信帯域
	int							m_sendLimit;

	//!	受信帯域
	int							m_recvLimit;

	//!	受信済みのデータサイズ(ヘッダ含む)
	__int64						m_receivedSize;

	//!	送信済みのデータサイズ（ヘッダ含む）
	__int64						m_sendedSize;
};
