#include "StdAfx.h"
#include "ConnectionThread.h"
#include "ConnectionControl.h"
#include "ServerResponse.h"
#include "ResponseManager.h"
#include "FilterControl.h"

#define	CLASS_NAME	"ConnectionThread"

CConnectionThread::CConnectionThread(void)
{
}

CConnectionThread::~CConnectionThread(void)
{
	Stop();
}


/////////////////////////////////////////////////////////////////////////////////////
//	操作
/////////////////////////////////////////////////////////////////////////////////////
/*!
	開始
*/
int CConnectionThread::Start(	IServerToolIIPtr				serverTool,
								IConnectionThreadParentIIPtr	threadManager,
								IConetextGeneIIPtr			contexGene,
								IClientConnectionIIPtr		connection,
								LONG						connectionID)
{
	m_serverTool = serverTool;
	m_threadManager = threadManager;
	m_contexGene = contexGene;
	m_connection = connection;
	m_connectionID = connectionID;

	return StartThread();
}

/*!
	停止
*/
void CConnectionThread::Stop()
{
	EndThread();
}

/////////////////////////////////////////////////////////////////////////////////////
//	スレッド関数
/////////////////////////////////////////////////////////////////////////////////////
/*!
	スレッド
*/
void CConnectionThread::ThreadMain()
{
	//	接続初期化
	m_connection->AttacheToThread(m_serverTool->GetIServerTool(), GetIConnectionThreadStatus());

	try
	{
		//	KEEP-ALIVEループ
		int	waitTime = 0;
		do
		{
			//	リクエスト処理
			waitTime = OneRequest();
		}
		while(waitTime > 0 && m_connection->WaitNextConnection(waitTime));
	}
	catch(CServerResponseException err)
	{
		m_serverTool->WriteSystemLog(CLASS_NAME, SERVER_STATUS_ERROR, "内部エラー：リクエスト処理で不正な例外が発生しました");
	}
	catch(CConnectionErrorException err)
	{
		m_serverTool->WriteSystemLog(CLASS_NAME, SERVER_STATUS_ERROR, "内部エラー：リクエスト処理で不正な例外が発生しました");
	}

	//	接続停止
	m_connection->Close();
	m_connection.Delete();

	//	終了を通知
	m_threadManager->EndConnection(this);
}

/*!
	リクエスト処理
*/
int CConnectionThread::OneRequest()
{
	//	コンテキスト生成
	CContext	context = m_contexGene->GetNewContext(m_connectionID);

	//	接続コントローラ生成
	CConnectionControl	connection;
	connection.AttacheConnection(m_serverTool->GetIServerTool(), GetIConnectionThreadStatus(), m_connection, context);

	//	フィルタ生成
	CFilterControl		filters;
	filters.AttachFilters(m_serverTool->GetIServerTool(), GetIConnectionThreadStatus(), connection.GetIConnectionControl(), context);

	//	エラースコープ
	try
	{
		/***************************************************************/
		//	オーバーロード？
		/***************************************************************/
		//	オーバーロード？
		if(m_threadManager->InOverloadMode())
			throw CServerResponseException(503, _T("最大接続数を超えました"));


		/***************************************************************/
		//	リクエスト受信
		/***************************************************************/
		//!	ヘッダ受信
		RecvRequestHeader(connection, context, filters);

		//	レスポンスモジュール取得
		CResponseControl	response;
		response.LoadResponseModule(m_serverTool->GetIServerTool(),
									GetIConnectionThreadStatus(),
									connection.GetIConnectionControl(),
									context);

		//	レスポンスモジュールへリクエストを設定
		response.SetRequest();

		//	ボディ受信
		RecvRequestBody(connection, context, filters, response);


		/***************************************************************/
		//	レスポンス生成
		/***************************************************************/
		//	ステータス
		context.SetStatus(_T("レスポンス生成中..."));

		//	レスポンス生成
		filters.FilterBuildResponse();
		response.BuildResponse();


		/***************************************************************/
		//	レスポンス送信
		/***************************************************************/
		//!	ヘッダ送信
		SendResponseHeader(connection, context, filters, response);

		//	ボディ送信
		SendResponseBody(connection, context, filters, response);

		//	レスポンス削除
		response.FreeResponseModule();

		//	正常終了
		context.SetStatus(_T("正常に終了しました"));
	}
	catch(CServerResponseException serverResponse)
	{
		//	サーバレスポンス
		SendServerResponse(connection, context, filters, serverResponse);
	}
	catch(CConnectionErrorException err)
	{
		//	サーバエラー
		CServerResponseException	serverResponse(500, err.m_errorInfo);
		SendServerResponse(connection, context, filters, serverResponse);
	}

	//	リクエスト完了
	UpdateTransInfo(connection, context);
	filters.DetachFilters();
	connection.DetacheConnection();
	m_contexGene->ReleaseContext(context);

	//	キープアライブ？
	if(connection.CanReuseConnection())
		return(connection.GetWaitNextRequestTime());
	return(0);
}


/*!
	ヘッダ受信
*/
void CConnectionThread::RecvRequestHeader(CConnectionControl &connectionControl, CContext &context, CFilterControl &filters)
{
	//	ステータス
	context.SetStatus(_T("リクエスト ヘッダを受信中..."));

	//	ヘッダ受信
	connectionControl.RecvRequestHeader();
	filters.FilterRequestHeader();
	UpdateTransInfo(connectionControl, context);
}

/*!
	ボディ受信
*/
void CConnectionThread::RecvRequestBody(CConnectionControl &connectionControl, CContext &context, CFilterControl &filters, CResponseControl &response)
{
	CBinaryData	buf;

	//	ステータス
	context.SetStatus(_T("リクエスト ボディを受信中..."));

	//	受信
	while(connectionControl.RecvRequestBody(buf) > 0)
	{
		//	ボディ処理
		filters.FilterRequestBody(buf);
		response.SetRequestBody(buf);
	}

	//	ボディ受信完了
	connectionControl.EndRecvRequest();
	filters.FilterEndRequest();
	response.EndRequest();
	UpdateTransInfo(connectionControl, context);
}

/*!
	ヘッダ送信
*/
void CConnectionThread::SendResponseHeader(CConnectionControl &connectionControl, CContext &context, CFilterControl &filters, CResponseControl &response)
{
	//	ステータス
	context.SetStatus(_T("レスポンス ヘッダを送信中..."));

	//	ヘッダ生成
	response.GetResponse();
	filters.FilterResponseHeader();
	connectionControl.SendResponseHeader();
	UpdateTransInfo(connectionControl, context);
}

/*!
	ボディ送信
*/
void CConnectionThread::SendResponseBody(CConnectionControl &connectionControl, CContext &context, CFilterControl &filters, CResponseControl &response)
{
	CBinaryData	buf;

	//	ステータス
	context.SetStatus(_T("レスポンス ボディを送信中..."));

	//	ボディ送信
	while(response.GetResponseBody(buf, connectionControl.GetBlockSize()) > 0)
	{
		filters.FilterResponseBody(buf);
		connectionControl.SendResponseBody(buf);
	}

	//	ボディ送信完了
	connectionControl.EndSendResponse();
	filters.FilterEndResponse();
	response.EndResponse();
	UpdateTransInfo(connectionControl, context);
}


/*!
	サーバレスポンスの送信
*/
void CConnectionThread::SendServerResponse(CConnectionControl &connectionControl, CContext &context, CFilterControl &filter, CServerResponseException &serverResponseException)
{
	try
	{
		//	サーバレスポンス生成
		CServerResponse	response;
		response.CreateServerResponse(	m_serverTool->GetIServerTool(), GetIConnectionThreadStatus(),
										connectionControl.GetIConnectionControl(), context, serverResponseException);

		//	レスポンス取得
		CBinaryData	body;
		response.GetResponseBody(body);

		//	フィルタ実行
		filter.FilterServerResponse(body);

		//	送信
		connectionControl.SendServerResponse(body);
		UpdateTransInfo(connectionControl, context);
	}
	catch(CServerResponseException err)
	{
		m_serverTool->WriteSystemLog(CLASS_NAME, SERVER_STATUS_ERROR, "内部エラー：サーバレスポンス送信処理で不正な例外が発生しました");
	}
	catch(CConnectionErrorException err)
	{
		m_serverTool->WriteSystemLog(CLASS_NAME, SERVER_STATUS_ERROR, "内部エラー：サーバレスポンス送信処理で不正な例外が発生しました");
	}
}

/*!
	通信状態の更新
*/
void CConnectionThread::UpdateTransInfo(CConnectionControl &connectionControl, CContext &context)
{
	context.SetSendSize(connectionControl.GetSendedSize());
	context.SetRecvSize(connectionControl.GetReceivedSize());
}
