/*
	CTimeOutMgr
	非同期タイムアウト処理を行う実行クラス
	このクラスは、グローバル上に１つだけ生成され、全ての非同期タイムアウトの処理を行う。
	非同期処理用スレッドを持つ。

	Version		: 0.0 (Release1)

	作成日		: 2002/05/25 (Yuh)
	修正日		: ----/--/--
	改定履歴	: 
*/

#include "stdafx.h"
#include "TimeOut.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//	標準タイムアウト時間
#define	DEFAULT_TIME_OUT	180000

//	タイムアウトマネージャ本体
CTimeOutMgr	_globalManager;

//////////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////////

CTimeOutMgr::CTimeOutMgr()
{
	SCOPE_LOCK();

	m_break = 0;
	m_thread = NULL;
	StartThread();
	m_defaultTimeOutTime = DEFAULT_TIME_OUT;
}

CTimeOutMgr::~CTimeOutMgr()
{
	m_break = 1;

	while(IsRunning())
		Sleep(100);
}

//////////////////////////////////////////////////////////////////////
// スレッド管理
//////////////////////////////////////////////////////////////////////
//	開始
void CTimeOutMgr::StartThread()
{
	CWinThread *tmp = AfxBeginThread(WorkThread,(LPVOID)this);
	tmp->SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
	m_thread = tmp->m_hThread;
}


//	実行関数
UINT CTimeOutMgr::WorkThread(LPVOID pParam)
{
	CTimeOutMgr	*obj = (CTimeOutMgr*)pParam;
	obj->ThreadMain();

	return(0);
}

//	メイン
void CTimeOutMgr::ThreadMain()
{

	while(m_break == 0)
	{
		Sleep(100);
		{
			SCOPE_LOCK();

			int		i;
			DWORD	curTick = GetTickCount();
			for(i=(int)m_timeOutArray.GetSize() - 1;i>=0;i--)
			{
				if(m_timeOutArray[i].m_timeOutTime <= curTick || m_timeOutArray[i].m_startTick > curTick)
				{
					CTimeOut * timeOut = m_timeOutArray[i].m_class;

					m_timeOutArray.RemoveAt(i);
					timeOut->m_timeOutFlag = 1;
					timeOut->OnTimeOut();
					break;
				}
			}
		}
	}
}

//	実行中？
int CTimeOutMgr::IsRunning()
{
	if(m_thread==NULL)
		return(0);

	DWORD	tmp;
	::GetExitCodeThread(m_thread,&tmp);

	if(tmp==STILL_ACTIVE)
	{
		return(1);
	}

	m_thread=NULL;
	return(0);

}

//////////////////////////////////////////////////////////////////////
// タイムアウト制御
//////////////////////////////////////////////////////////////////////
//	追加
void CTimeOutMgr::AddTimeOut(CTimeOut *timeOut, int tick)
{
	if(tick <=0)
		tick = m_defaultTimeOutTime;

	CTimeOutInfo	add;
	add.m_class = timeOut;
	add.m_startTick = GetTickCount();
	add.m_timeOutTime = add.m_startTick + tick;

	SCOPE_LOCK();
	m_timeOutArray.Add(add);
}

//	削除
void CTimeOutMgr::DeleteTimeOut(CTimeOut *timeOut)
{
	SCOPE_LOCK();

	int	i;
	for(i=(int)m_timeOutArray.GetSize() - 1;i>=0;i--)
	{
		if(m_timeOutArray[i].m_class == timeOut)
			m_timeOutArray.RemoveAt(i);
	}
}

//////////////////////////////////////////////////////////////////////
// 設定
//////////////////////////////////////////////////////////////////////
void CTimeOutMgr::SetDefaultTimeOutTime(int tick)
{
	SCOPE_LOCK();

	m_defaultTimeOutTime = tick;
}

//////////////////////////////////////////////////////////////////////
// マネージャの取得
//////////////////////////////////////////////////////////////////////
CTimeOutMgr * CTimeOutMgr::GetGlobalManager()
{
	return(&_globalManager);
}



//////////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////////

CTimeOut::CTimeOut()
{
	m_timeOutFlag = 0;
}

CTimeOut::~CTimeOut()
{
	StopTimeOut();
}

void CTimeOut::OnTimeOut()
{

}

//////////////////////////////////////////////////////////////////////
// タイムアウトの設定
//////////////////////////////////////////////////////////////////////
void CTimeOut::SetTimeOut(int tick)
{
	m_timeOutFlag = 0;
	StopTimeOut();
	CTimeOutMgr::GetGlobalManager()->AddTimeOut(this,tick);
}

void CTimeOut::StopTimeOut()
{
	CTimeOutMgr::GetGlobalManager()->DeleteTimeOut(this);
}
