#include "Ee_IdleEvaluator.h"

using namespace Ee;

void CIdleEvaluator::Reset()
{
	m_semaChecker.Reset();
	m_selfThreadRotate.Reset();
	m_threadRotateBounce.Reset();
}

bool CIdleEvaluator::IsIdle() const
{
	return m_semaChecker.m_isIdle ||
	       m_selfThreadRotate.m_isIdle ||
	       m_threadRotateBounce.m_isIdle;
}

void CIdleEvaluator::NotifyEvent(EVENT eventType, uint32 arg0, uint32 arg1)
{
	m_semaChecker.NotifyEvent(eventType, arg0, arg1);
	m_selfThreadRotate.NotifyEvent(eventType, arg0, arg1);
	m_threadRotateBounce.NotifyEvent(eventType, arg0, arg1);
}

void CIdleEvaluator::STRATEGY_SEMACHECKER::Reset()
{
	m_lastWaitSema = -1;
	m_lastSemaWaitCounter = 0;
	m_isIdle = false;
}

void CIdleEvaluator::STRATEGY_SEMACHECKER::NotifyEvent(EVENT eventType, uint32 arg0, uint32 arg1)
{
	switch(eventType)
	{
	case EVENT_WAITSEMA:
	case EVENT_SIGNALSEMA:
		if(m_lastWaitSema == arg0)
		{
			m_lastSemaWaitCounter++;
			if(m_lastSemaWaitCounter >= 100)
			{
				m_isIdle = true;
			}
		}
		else
		{
			m_lastSemaWaitCounter = 0;
			m_isIdle = false;
		}
		m_lastWaitSema = arg0;
		break;
	case EVENT_INTERRUPT:
	case EVENT_CHANGETHREAD:
		m_lastSemaWaitCounter = 0;
		m_lastWaitSema = -1;
		m_isIdle = false;
		break;
	default:
		break;
	}
}

void CIdleEvaluator::STRATEGY_SELFTHREADROTATE::Reset()
{
	m_threadId = -1;
	m_selfRotateThreadCount = 0;
	m_isIdle = false;
}

void CIdleEvaluator::STRATEGY_SELFTHREADROTATE::NotifyEvent(EVENT eventType, uint32 arg0, uint32 arg1)
{
	switch(eventType)
	{
	case EVENT_ROTATETHREADREADYQUEUE:
		if(arg0 == arg1)
		{
			m_selfRotateThreadCount++;
			m_threadId = arg0;
			if(m_selfRotateThreadCount > 500)
			{
				m_isIdle = true;
			}
		}
		else
		{
			m_selfRotateThreadCount = 0;
			m_threadId = -1;
			m_isIdle = false;
		}
		break;
	case EVENT_CHANGETHREAD:
		if(arg0 != m_threadId)
		{
			m_selfRotateThreadCount = 0;
			m_isIdle = false;
		}
		break;
	case EVENT_INTERRUPT:
		m_selfRotateThreadCount = 0;
		m_isIdle = false;
		break;
	default:
		break;
	}
}

void CIdleEvaluator::STRATEGY_THREADROTATEBOUNCE::Reset()
{
	m_threadPairFirst = -1;
	m_threadPairSecond = -1;
	m_bounceCount = 0;
	m_isIdle = false;
}

void CIdleEvaluator::STRATEGY_THREADROTATEBOUNCE::NotifyEvent(EVENT eventType, uint32 arg0, uint32 arg1)
{
	switch(eventType)
	{
	case EVENT_ROTATETHREADREADYQUEUE:
	{
		bool hasFirstThread = (arg0 == m_threadPairFirst) || (arg1 == m_threadPairFirst);
		bool hasSecondThread = (arg0 == m_threadPairSecond) || (arg1 == m_threadPairSecond);
		if(hasFirstThread && hasSecondThread)
		{
			m_bounceCount++;
		}
		else
		{
			m_bounceCount = 0;
		}
		m_threadPairFirst = arg0;
		m_threadPairSecond = arg1;
	}
	break;
	case EVENT_CHANGETHREAD:
		if(arg0 != m_threadPairFirst && arg0 != m_threadPairSecond)
		{
			m_bounceCount = 0;
		}
		break;
	case EVENT_INTERRUPT:
		m_bounceCount = 0;
		break;
	default:
		break;
	}
	m_isIdle = (m_bounceCount > 1000);
}
