#include "StdAfx.h"
#include "PipeServer.h"

#define	IOCP_EXIT		0
#define	IOCP_PIPE_0		1000

CPipeServer::CPipeServer(void)
{
	m_keyCounter = IOCP_PIPE_0;
}

CPipeServer::~CPipeServer(void)
{
	EndThread();
}


//////////////////////////////////////////////////////////////////////////////////
//	開始・停止
//////////////////////////////////////////////////////////////////////////////////
/*!
	開始
*/
int CPipeServer::Start(CString pipeName, int maxConnect, CPipeCommandExecuteBase *executer)
{
	//	ICOCPポート生成
	if(m_iocp.Create(1))
		return(-1);

	//!	ポート待ち受け開始
	if(m_pipeListener.Init(pipeName, maxConnect))
		return(-1);

	//	コピー
	m_executer = executer;

	return(StartThread());
}

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

//////////////////////////////////////////////////////////////////////////////////
//	スレッド関数
//////////////////////////////////////////////////////////////////////////////////
/*!
	スレッドメイン
*/
void CPipeServer::ThreadMain()
{
	while(1)
	{
		//	パイプを生成し、接続待ちを開始
		m_pipeListener.StartWaitPipe(m_iocp, m_keyCounter);

		//	切断したパイプ、送信タイムアウトしたパイプを探す
		CheckDisconnect();

		//	イベントを待つ
		LPOVERLAPPED	ovrp;
		DWORD			transBytes;
		DWORD			completionKey;
		if(!GetQueuedCompletionStatus(m_iocp, &transBytes, &completionKey, &ovrp, 500))
		{
			//	本当にエラー？
			if(ovrp == NULL)
			{
				//	タイムアウト？
				if(GetLastError() != WAIT_TIMEOUT)
				{
					//	それ以外のエラーらしい
					Sleep(500);
				}
				continue;
			}
		}


		//	終了
		if(completionKey == IOCP_EXIT)
		{
			CloseAll();
			return;
		}
		
		//	パイプ接続
		if(completionKey == m_keyCounter)
		{
			NewConnect();
			continue;
		}

		//	パイプ処理
		if(completionKey >= IOCP_PIPE_0)
		{
			PipeTask(completionKey);
			continue;
		}
	}
}

/*!
	中断
*/
void CPipeServer::Break()
{
	//	終了を投げる
	static OVERLAPPED	ovrp;
	INIT_OVERLAPPED(ovrp, NULL);
	::PostQueuedCompletionStatus(m_iocp, 0, IOCP_EXIT, &ovrp);

	CThreadSkeleton::Break();
}


//////////////////////////////////////////////////////////////////////////////////
//	処理
//////////////////////////////////////////////////////////////////////////////////
/*!
	終了
*/
void CPipeServer::CloseAll()
{
	m_pipeListener.Close();

	//	全部削除
	for(int i=0;i<m_commandPipes.GetCount();i++)
		delete m_commandPipes[i];
	m_commandPipes.RemoveAll();
}


/*!
	新規接続
*/
void CPipeServer::NewConnect()
{
	//	パイプマネージャ生成
	CCommandRecvPipe *pipe = new CCommandRecvPipe();
	pipe->Init(this, m_executer, m_pipeListener.GetNewPipe(), m_keyCounter);
	m_commandPipes.Add(pipe);
	TRACE("Command pipe : Connect\n");

	m_keyCounter++;
	if(m_keyCounter == 0)	//	オーバーフロー
		m_keyCounter = IOCP_PIPE_0;
}

/*!
	パイプ通信タスク
*/
void CPipeServer::PipeTask(DWORD completeKey)
{
	CCommandRecvPipe *pipe = GetPipe(completeKey);
	if(pipe != NULL)
	{
		pipe->PipeTask();
	}
}

/*!
	閉じているか確認
*/
void CPipeServer::CheckDisconnect()
{
	for(int i=(int)m_commandPipes.GetCount()-1;i>=0;i--)
	{
		if(m_commandPipes[i]->CheckDisconnect())
		{
			delete m_commandPipes[i];
			m_commandPipes.RemoveAt(i);

			TRACE("Command Pipe : Discoonect\n");
		}
	}
}

/*!
	パイプ取得
*/
CCommandRecvPipe *CPipeServer::GetPipe(DWORD completeKey)
{
	//	検索
	for(int i=0;i<m_commandPipes.GetCount();i++)
	{
		if(m_commandPipes[i]->GetCompleteKey() == completeKey)
			return(m_commandPipes[i]);
	}

	return(NULL);
}
