#include "StdAfx.h"
#include "RunLoop.h"
#include <Foundation/Foundation.h>
#include <CoreFoundation/CoreFoundation.h>
#include <map>

class SimpleRunLoopImpl
{
public:
	SimpleRunLoopImpl();
	~SimpleRunLoopImpl();
	
	bool AddTimer(TIMER_HANDLE handle, IGTRunLoopTimerEvent* eventHandler, double interval, void* param);
	bool AddSource(SOURCE_HANDLE handle, IGTRunLoopSourceEvent* eventHandler, void* param);
	
	bool RemoveTimer(TIMER_HANDLE handle);
	void RemoveTimerAll();
	bool RemoveSource(SOURCE_HANDLE handle);
	void RemoveSourceAll();
	
	bool Signal(SOURCE_HANDLE handle, void* sigParam1, void* sigParam2);
	
	void InitRunLoopInYourThread(void);
	bool RunRunLoopInNoMainThread(double interval);
	void StopRunLoopFromAnotherThread();
	
public:
	struct RunLoopSource
	{
		SOURCE_HANDLE handle;
		CFRunLoopRef runLoop;
		CFRunLoopSourceRef source;
		IGTRunLoopSourceEvent* eventHandler;
		void* param;
		void* sigParam1;
		void* sigParam2;
	};
	
	struct RunLoopTimer
	{
		TIMER_HANDLE handle;
		CFRunLoopRef runLoop;
		CFRunLoopTimerRef timer;
		IGTRunLoopTimerEvent* eventHandler;
		void* param;
	};
	
private:
	static void RunLoopSourceScheduleRoutine(void* info, CFRunLoopRef rl, CFStringRef mode);
	static void RunLoopSourcePerformRoutine(void* info);
	static void RunLoopSourceCancelRoutine(void* info, CFRunLoopRef rl, CFStringRef mode);
	static void RunLoopTimerCallback(CFRunLoopTimerRef timer, void *info);
	
private:
	typedef std::map<SOURCE_HANDLE, RunLoopSource*> SOURCE_MAP;
	SOURCE_MAP m_sources;
	typedef std::map<TIMER_HANDLE, RunLoopTimer*> TIMER_MAP;
	TIMER_MAP m_timers;
	
	CFRunLoopRef theRunLoop;
};

SimpleRunLoopImpl::SimpleRunLoopImpl()
: m_sources()
, m_timers()
, theRunLoop(nil)
{
}

SimpleRunLoopImpl::~SimpleRunLoopImpl()
{
	RemoveSourceAll();
	RemoveTimerAll();
}

bool SimpleRunLoopImpl::AddTimer(TIMER_HANDLE handle, IGTRunLoopTimerEvent* eventHandler, double interval, void* param)
{
	TIMER_MAP::iterator itr = m_timers.find(handle);
	if( m_timers.end() != itr )
	{
		return false;
	}
	
	RunLoopTimer* rltimer = new RunLoopTimer;
	rltimer->handle = handle;
	rltimer->runLoop = theRunLoop;
	rltimer->eventHandler = eventHandler;
	rltimer->param = param;

	CFAbsoluteTime fireDate = CFAbsoluteTimeGetCurrent() + interval;
	
	CFRunLoopTimerContext context = {0, rltimer, NULL, NULL, NULL};
	rltimer->timer = CFRunLoopTimerCreate(kCFAllocatorDefault, fireDate, interval, 0, 0, &RunLoopTimerCallback, &context);
	CFRunLoopAddTimer(rltimer->runLoop, rltimer->timer, kCFRunLoopCommonModes);

	m_timers.insert( TIMER_MAP::value_type(handle, rltimer) );
	
	return true;
}

bool SimpleRunLoopImpl::RemoveTimer(TIMER_HANDLE handle)
{
	TIMER_MAP::iterator itr = m_timers.find(handle);
	if( m_timers.end() != itr )
	{
		RunLoopTimer* rltimer = (*itr).second;
		CFRunLoopTimerInvalidate(rltimer->timer);
		CFRunLoopRemoveTimer(rltimer->runLoop, rltimer->timer, kCFRunLoopCommonModes);
		CFRelease(rltimer->timer);
		delete rltimer;

		m_timers.erase(itr);
		
		return true;
	}
	
	return false;
}

void SimpleRunLoopImpl::RemoveTimerAll()
{
	for(TIMER_MAP::iterator itr = m_timers.begin(); itr != m_timers.end(); ++itr)
	{
		RunLoopTimer* rltimer = (*itr).second;
		CFRunLoopTimerInvalidate(rltimer->timer);
		CFRunLoopRemoveTimer(rltimer->runLoop, rltimer->timer, kCFRunLoopCommonModes);
		CFRelease(rltimer->timer);
		delete rltimer;
	}
		
	m_timers.clear();
}

bool SimpleRunLoopImpl::AddSource(SOURCE_HANDLE handle, IGTRunLoopSourceEvent* eventHandler, void* param)
{
	SOURCE_MAP::iterator itr = m_sources.find(handle);
	if( m_sources.end() != itr )
	{
		return false;
	}
	
	RunLoopSource* rlsource = new RunLoopSource;
	rlsource->handle = handle;
	rlsource->runLoop = theRunLoop;
	rlsource->eventHandler = eventHandler;
	rlsource->param = param;
	
	CFRunLoopSourceContext context = {0, rlsource, NULL, NULL, NULL, NULL, NULL,
		&RunLoopSourceScheduleRoutine,
		RunLoopSourceCancelRoutine,
		RunLoopSourcePerformRoutine};
	rlsource->source = CFRunLoopSourceCreate(NULL, 0, &context);
	CFRunLoopAddSource(rlsource->runLoop, rlsource->source, kCFRunLoopDefaultMode);

	m_sources.insert( SOURCE_MAP::value_type(handle, rlsource) );
	
	return true;
}

bool SimpleRunLoopImpl::RemoveSource(SOURCE_HANDLE handle)
{	
	SOURCE_MAP::iterator itr = m_sources.find(handle);
	if( m_sources.end() != itr )
	{
		RunLoopSource* rlsource = (*itr).second;
		CFRunLoopSourceInvalidate(rlsource->source);
		CFRunLoopRemoveSource(rlsource->runLoop, rlsource->source, kCFRunLoopCommonModes);
		CFRelease(rlsource->source);
		
		printf( "RUNLOOP >>>>>>>>>>>>>>>>>>> REMOVE %08X %08X %d\n", rlsource->runLoop, rlsource, rlsource->handle );

		delete rlsource;
	
		m_sources.erase(itr);
		
		return true;
	}
	
	return false;
}

void SimpleRunLoopImpl::RemoveSourceAll()
{
	for(SOURCE_MAP::iterator itr = m_sources.begin(); itr != m_sources.end(); ++itr)
	{
		RunLoopSource* rlsource = (*itr).second;
		CFRunLoopSourceInvalidate(rlsource->source);
		CFRunLoopRemoveSource(rlsource->runLoop, rlsource->source, kCFRunLoopCommonModes);
		CFRelease(rlsource->source);
		
		printf( "RUNLOOP >>>>>>>>>>>>>>>>>>> REMOVE(ALL) %08X %08X, %d\n", rlsource->runLoop, rlsource, rlsource->handle);
		
		delete rlsource;
	}
	
	m_sources.clear();
}

bool SimpleRunLoopImpl::Signal(SOURCE_HANDLE handle, void* sigParam1, void* sigParam2)
{
	SOURCE_MAP::iterator itr = m_sources.find(handle);
	if( m_sources.end() != itr )
	{
		RunLoopSource* rlsource = (*itr).second;
		
		rlsource->sigParam1 = sigParam1;
		rlsource->sigParam2 = sigParam2;
		
		printf( "RUNLOOP >>>>>>>>>>>>>>>>>>> SIGNAL REQUEST %08X %08X %d\n", rlsource->runLoop, rlsource, rlsource->handle );
		
		CFRunLoopSourceSignal(rlsource->source);
		CFRunLoopWakeUp(rlsource->runLoop);
		
		return true;
	}
	
	return false;
}


bool SimpleRunLoopImpl::RunRunLoopInNoMainThread(double interval)
{
	if( CFRunLoopGetMain() == theRunLoop )
	{
		return false;
	}
	
	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	
	bool done = false;
	
	do
	{
		SInt32 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, interval, true);
		if((result == kCFRunLoopRunStopped) || (result == kCFRunLoopRunFinished))
			done = true;
	}
	while(!done);
	
	[pool release];
	
	return true;
}

void SimpleRunLoopImpl::InitRunLoopInYourThread(void)
{
	if(theRunLoop == nil)
	{
		theRunLoop = CFRunLoopGetCurrent();
		printf("RUN LOOP REF SETTING %p\n", theRunLoop);
	}
}

void SimpleRunLoopImpl::StopRunLoopFromAnotherThread()
{
	printf("RUN LOOP REF STOP!!!! %p\n", theRunLoop);
	CFRunLoopStop(theRunLoop);
}

void SimpleRunLoopImpl::RunLoopSourceScheduleRoutine(void* info, CFRunLoopRef rl, CFStringRef mode)
{
	RunLoopSource* rlsource = (RunLoopSource*)info;
	
	if( NULL == rlsource || NULL == rlsource->eventHandler )
	{
		return ;
	}
	
	rlsource->eventHandler->IGTRunLoopSourceEvent_OnSourceSchedule(rlsource->handle, rlsource->param);
}

void SimpleRunLoopImpl::RunLoopSourcePerformRoutine(void* info)
{
	RunLoopSource* rlsource = (RunLoopSource*)info;
	
	if( NULL == rlsource || NULL == rlsource->eventHandler )
	{
		return ;
	}
	
	printf( "RUNLOOP >>>>>>>>>>>>>>>>>>> PERFORM %08X %08X \n", rlsource->runLoop, rlsource );
	rlsource->eventHandler->IGTRunLoopSourceEvent_OnSourcePerform(rlsource->handle, rlsource->param, rlsource->sigParam1, rlsource->sigParam2);
}

void SimpleRunLoopImpl::RunLoopSourceCancelRoutine(void* info, CFRunLoopRef rl, CFStringRef mode)
{
	// KEH_MOBILE_MARK_P2P
#ifdef __KEH_USE_LKWND__
	RunLoopSource* rlsource = (RunLoopSource*)info;
	
	if( NULL == rlsource || NULL == rlsource->eventHandler )
	{
		return ;
	}
	
	rlsource->eventHandler->IGTRunLoopSourceEvent_OnSourceCancel(rlsource->handle, rlsource->param);
#endif	
}

void SimpleRunLoopImpl::RunLoopTimerCallback(CFRunLoopTimerRef timer, void *info)
{
	RunLoopTimer* rltimer = (RunLoopTimer*)info;
	
	if( NULL == rltimer || NULL == rltimer->eventHandler )
	{
		return ;
	}
	
	rltimer->eventHandler->IGTRunLoopTimerEvent_OnTimer( rltimer->handle, rltimer->param );
}


CGTRunLoop::CGTRunLoop()
{
	m_pImpl = new SimpleRunLoopImpl;
}

CGTRunLoop::~CGTRunLoop()
{
	delete m_pImpl;
	m_pImpl = NULL;
}

bool CGTRunLoop::AddTimer(TIMER_HANDLE handle, IGTRunLoopTimerEvent* eventHandler, double interval, void* param)
{
	return m_pImpl->AddTimer(handle, eventHandler, interval, param);
}

void CGTRunLoop::RemoveTimer(TIMER_HANDLE handle)
{
	m_pImpl->RemoveTimer(handle);
}

bool CGTRunLoop::AddSource(SOURCE_HANDLE handle, IGTRunLoopSourceEvent* eventHandler, void* param)
{
	return m_pImpl->AddSource(handle, eventHandler, param);
}

void CGTRunLoop::RemoveSource(SOURCE_HANDLE handle)
{
	m_pImpl->RemoveSource(handle);
}

bool CGTRunLoop::Signal(SOURCE_HANDLE handle, void* sigParam1, void* sigParam2)
{
	return m_pImpl->Signal(handle, sigParam1, sigParam2);
}

bool CGTRunLoop::RunRunLoopInNoMainThread(double interval)
{
	return m_pImpl->RunRunLoopInNoMainThread(interval);
}

void CGTRunLoop::InitRunLoopInYourThread(void)
{
	m_pImpl->InitRunLoopInYourThread();
}

void CGTRunLoop::RemoveAllSourceAndTimer(void)
{
	m_pImpl->RemoveTimerAll();
	m_pImpl->RemoveSourceAll();	
}

void CGTRunLoop::StopRunLoopFromAnotherThread()
{
	RemoveAllSourceAndTimer();
	
	m_pImpl->StopRunLoopFromAnotherThread();
}
