#include <LPeriodical.h>
#include "mac_cosmos.h"
#include "AppConstants.h"

extern "C" void wakeup_task(unsigned int key);

extern Point curMouse;
#if THREAD_DEBUG
extern "C" void ThreadDebugMessagePrint();
#endif
extern int readyThreadCount;

class CYieldRepeater : public LPeriodical
{
  public:
	static UInt32	curTick;

	CYieldRepeater(SInt32 quantum = -1) : mQuantum(quantum), mNextTicks(0)
	{
		StartRepeating();
	}
	
	static void	YieldToMainThread()
	{
		*sExitLoop = true;
		LThread::Yield(LThread::GetMainThread());
	}
	
	static void GetMouseEvent()
	{
		sGetMouseEvent = 16;
		sGoBack = LThread::GetCurrentThread();
		YieldToMainThread();
	}
	
	virtual void	SpendTime( const EventRecord& inMacEvent )
	{
		if ( sGetMouseEvent ) {
			if ( inMacEvent.what != mouseUp && inMacEvent.what != mouseDown ) {
				sGetMouseEvent--;
				theApp->SetSleepTime(0);
				return;
			}
			sGetMouseEvent = 0;
			sGoBack = 0;
			LThread::Yield(sGoBack);
		}
		
		if ( inMacEvent.what != 0 ) {
			theApp->SetSleepTime(0);
			return;
		}

		*sExitLoop = false;
		
		// set curMouse
		if ( inMacEvent.what != kHighLevelEvent )
			curMouse = inMacEvent.where;

		// wakeup event_thread if exsits
		extern LThread * event_thread;
		if ( event_thread ) {
			try {
				event_thread->Resume();
			} catch (...) {
				::DebugStr("\pcan't resume event_thread");
			}
			LThread::Yield(event_thread);
			if ( *sExitLoop ) {
				*sExitLoop = false;
				return;
			}
		}
		
		// yield to the other threads
		if (mQuantum < 0)
		{
			LThread::Yield();
		}
		else
		{
			theApp->SetSleepTime(0);
			curTick = TickCount();
			mNextTicks = curTick + mQuantum;
			do
			{
				readyThreadCount = LThread::CountReadyThreads();
				if ( readyThreadCount == 0 )
					break;
				LThread::Yield();
				if ( *sExitLoop ) {
					*sExitLoop = false;
					break;
				}
				curTick = TickCount();
				// If controled cpu too long time,
				// forcely switched to main thread and come here
				if ( LThread::GetPrevThread() && 
					curTick - LThread::GetPrevThread()->mTick > thTicksHeavyAlert ) {
					printf("!!! Heavy Thread : %s(%.1fsec)\n", LThread::GetPrevThread()->mName, (float)(curTick - LThread::GetPrevThread()->mTick)/60.0);
				}
				if ( LThread::GetPrevThread() == LThread::GetMainThread() ) {
					theApp->SetSleepTime(1);
					break;
				}
			} while (curTick <= mNextTicks);
		}
#if THREAD_DEBUG
		ThreadDebugMessagePrint();
#endif
	}
  protected:
	SInt32				mQuantum;
	UInt32				mNextTicks;
	static bool			*sExitLoop;
	static int			sGetMouseEvent;
	static LThread *	sGoBack;
	
	friend class LThread;
};