/*
 *  GTRunLoopDelegate.cpp
 *  All
 *
 *  Created by nhn on 11. 1. 1..
 *  Copyright 2011 nhn KEH. All rights reserved.
 *
 */

#include "GTRunLoopSource.h"
#include "GTRunLoopTimer.h"
#include "GTEventDelegate.h"
#include "GTAutoReleasePool.h"
#include <libkern/OSAtomic.h>
#include "GTLog.h"
#include "TypeDefinition.h"
#include <errno.h>
#include "GTLog.h"

static int g_timerHandle = 0;

#define INITLOCK(mutex, attr)	{ int _reti = pthread_mutex_init(&mutex, &attr);	assert(_reti == 0); }
#define LOCK(mutex)				{ int _retl = pthread_mutex_lock(&mutex);			assert(_retl == 0); }
#define TRYLOCK(mutex)			pthread_mutex_trylock(&mutex);
#define UNLOCK(mutex)			{ int _retu = pthread_mutex_unlock(&mutex);			assert(_retu == 0); }
#define DESTROYLOCK(mutex)		{ int _retd = pthread_mutex_destroy(&mutex);		assert(_retd == 0); }


//------------------------------------------------------
// Create Function

IGTEventDelegate *CreateEventDelegate(IGTEventDelegateEvent *pEvent)
{
	return new CGTEventDelegate(pEvent);
}
//------------------------------------------------------



@interface MyGTRunLoopDelegateImpl : NSObject
{
	CGTEventDelegate *delegate;
	
	NSMutableArray *sourceInfos;
	NSMutableArray *timerInfos;
	
	NSRecursiveLock *lockSource;
	NSRecursiveLock *lockDelete;
	
	BOOL deleteFlag;
}

- (id)initWithDelegate:(CGTEventDelegate *)aDelegate;

- (GTRunLoopTimer *)findTimer:(GT_EVENT_HANDLE)handle;

- (void)releaseAllEventResource;
@end



@implementation MyGTRunLoopDelegateImpl

- (id)initWithDelegate:(CGTEventDelegate *)aDelegate
{
	if((self = [super init]))
	{
		sourceInfos = [[NSMutableArray alloc] init];
		timerInfos = [[NSMutableArray alloc] init];
		delegate = aDelegate;
		deleteFlag = NO;
		lockDelete = [[NSRecursiveLock alloc] init];
		lockSource = [[NSRecursiveLock alloc] init];
	}
	return self;
}

- (void)dealloc
{
	[self releaseAllEventResource];
	
	[lockDelete release];
	[lockSource release];
	
	[super dealloc];
}


- (void)releaseAllEventResource
{
	[lockDelete lock];
	
	[lockSource lock];
	
	deleteFlag = YES;
		
	if(sourceInfos)
	{
		while([sourceInfos count] > 0)
		{
			GTRunLoopContext *obj = [sourceInfos objectAtIndex:0];
			
			[obj.source invalidate];
		}

		ASSERT([sourceInfos count] == 0);

		[sourceInfos removeAllObjects];
		[sourceInfos release];
		
		sourceInfos = nil;
	}	
	
	if(timerInfos)
	{
		[timerInfos removeAllObjects];	
		[timerInfos release];
		
		timerInfos = nil;
	}

	// must clear here..
	delegate = nil;

	[lockSource unlock];
	
	[lockDelete unlock];
}


- (void)createSource:(GT_EVENT_HANDLE)handle withParam:(GT_PARAM)param1 andParam:(GT_PARAM)param2 withRunLoop:(CFRunLoopRef)runLoop
{
	[lockDelete lock];
	
	if(NO == deleteFlag)
	{
		NSDictionary *command = [[NSDictionary alloc] initWithObjectsAndKeys:
								 [NSNumber numberWithInt:handle], @"handle", 
								 [NSNumber numberWithLong:(intptr_t)param1], @"param1",
								 [NSNumber numberWithLong:(intptr_t)param2], @"param2",
								 nil];
		
		GTRunLoopSource *source = [[GTRunLoopSource alloc] initWithDelegate:self withDisposableSource:YES];
		
		[source addCommand:command];
		
		if(runLoop == NULL)
			[source addToMainRunLoop];
		else
			[source addToRunLoop:runLoop];
		
		// source will be retained when context added to sourceInfos above call (refer to onGTRunLoop_RegisterSource)
		// So, this source'retain count remains 2.
		// Here we must release source (source'retaincount - 1) 
		[source release];
		
		[command release];
		
	}
	
	[lockDelete unlock];
}


- (NSInteger)createTimer:(GT_EVENT_HANDLE)handle withInterval:(int)msec withParam:(GT_PARAM)param
{
	[lockDelete lock];
	
	if(NO == deleteFlag)
	{
		if(0 == handle)
		{
			OSAtomicIncrement32(&g_timerHandle);
			handle = g_timerHandle;
		}
		
		if([self findTimer:handle])
		{
			[lockDelete unlock];
			return NO;
		}
		
		[lockSource lock];
		
		NSDictionary *userinfo = [[NSDictionary alloc] initWithObjectsAndKeys:
								  [NSNumber numberWithInt:handle], @"handle", 
								  [NSNumber numberWithLong:(intptr_t)param], @"param",
								  nil];
		
		GTRunLoopTimer *timer = [[GTRunLoopTimer alloc] initWithDelegate:self withInterval:msec withParam:userinfo];
		
		
		[timerInfos addObject:timer];
		[timer release];
		
		[lockSource unlock];
		
        [timer addToMainRunLoop];
//		[timer addToCurrentRunLoop];
	}
	
	[lockDelete unlock];
		
	return handle;
}


- (GTRunLoopTimer *)findTimer:(GT_EVENT_HANDLE)handle
{
	id objFind = nil;
	
	[lockDelete lock];
	
	if(NO == deleteFlag)
	{
		[lockSource lock];
		
		for(GTRunLoopTimer *timerSource in timerInfos)
		{
			NSDictionary *dictionary = timerSource.userInfo;
			assert(dictionary);
			
			NSNumber *handleNumber = [dictionary objectForKey:@"handle"];		
			if([handleNumber intValue] == handle)
			{
				objFind = timerSource;
				break;
			}
		}
		
		[lockSource unlock];
	}
	
	[lockDelete unlock];
	
	return objFind;
}

- (void)removeTimer:(GT_EVENT_HANDLE)handle
{
	[lockDelete lock];
	
	if(NO == deleteFlag)
	{		
		id objToRemove = [self findTimer:handle];
		
		if(objToRemove)
		{
//			[lockSource lock];
			[timerInfos removeObject:objToRemove];
//			[lockSource unlock];
		}	
	}
	
	[lockDelete unlock];
}

- (void)onGTRunLoop_RegisterSource:(GTRunLoopContext *)sourceInfo
{
	// Don't need to lock.. 
	// This function is called from createTimer that already locked
	ASSERT(deleteFlag == NO);

	delegate->_Retain();
	
	[lockSource lock];
	[sourceInfos addObject:sourceInfo];
	[lockSource unlock];
	
	[sourceInfo.source fireAllCommandsOnRunLoop:sourceInfo.runLoop];
}


- (void)onGTRunLoop_RemoveSource:(GTRunLoopContext *)sourceInfo
{
	[lockSource lock];
	GTRunLoopContext* objToRemove = nil;
	
	for(GTRunLoopContext *context in sourceInfos)
	{
		if([context isEqual:sourceInfo])
		{
			objToRemove = context;
			break;
		}
	}
	
	if(objToRemove)
	{
		[sourceInfos removeObject:objToRemove];
	}
	
	[lockSource unlock];
	
	// Don't need to lock.. 
	// 1. This function is called from releaseAllEventResource that already locked lockDelete..
	// 2. delegate is must alive because if _Release() is not called now, never dealloc this memory! 
	delegate->_Release();
}

- (void)onGTRunLoop:(GTRunLoopSource *)source didSourceFiredWithCommand:(id)command
{
	NSDictionary *dictionary = command;
	
	assert(dictionary);
	
	NSNumber *handleNumber = [dictionary objectForKey:@"handle"];
	assert(handleNumber);
	NSNumber *param1Number = [dictionary objectForKey:@"param1"];
	assert(param1Number);
	NSNumber *param2Number = [dictionary objectForKey:@"param2"];
	assert(param2Number);

	// Don't need to lock.. 
	// deleteFlag must be NO!
	ASSERT(deleteFlag == NO);
		
	delegate->_FireSourceEvent((GT_EVENT_HANDLE)[handleNumber intValue], 
						 (GT_PARAM)[param1Number longValue], 
						 (GT_PARAM)[param2Number longValue]);
}



- (void)onGTRunLoop_RegisterTimer:(GTRunLoopTimer *)timer
{
	// Don't need to lock.. 
	// deleteFlag must be NO!
	ASSERT(deleteFlag == NO);
	
	delegate->_Retain();
}


- (void)onGTRunLoop_RemoveTimer:(GTRunLoopTimer *)timer
{
	// Don't need to lock..
	// 1. This function is called from releaseAllEventResource that already locked lockDelete..
	// 2. delegate is must alive because if _Release() is not called now, never dealloc this memory! 	
	delegate->_Release();
}


- (void)onGTRunLoop_TimerFired:(GTRunLoopTimer *)timer
{
	NSDictionary *dictionary = timer.userInfo;
	
	assert(dictionary);
	
	NSNumber *handleNumber = [dictionary objectForKey:@"handle"];
	assert(handleNumber);
	NSNumber *paramNumber = [dictionary objectForKey:@"param"];
	assert(paramNumber);
	
	// Don't need to lock.. 
	// deleteFlag must be NO!
	ASSERT(deleteFlag == NO);
	
	delegate->_FireTimerEvent((GT_EVENT_HANDLE)[handleNumber intValue], 
							  (GT_PARAM)[paramNumber longValue]);
}

@end
//////////////////////////////////////////////////////////////////////////////




typedef struct 
{
	CFRunLoopRef runLoop;
	int nPositionID;
}_PrivateRunLoopTarget;


CGTEventDelegate::CGTEventDelegate(IGTEventDelegateEvent *pEvent) : 
	m_pDelegateImpl(NULL), 
	m_nRetainCount(0), 
	m_nSourceTargetCount(0), 
	m_nCheckReadyObserver(NOTHING), 
	m_nStatusMark(ACTIVE),
	m_bObserverFireDoing(false),
	m_pEvent(pEvent)
{
	id impl = [[MyGTRunLoopDelegateImpl alloc] initWithDelegate:this];
	m_pDelegateImpl = impl;
	
	pthread_mutexattr_t   mta;
	int rc = 0;
	rc = pthread_mutexattr_init(&mta);
	assert(rc == 0);
	rc = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE);
	assert(rc == 0);

	INITLOCK(m_mutexSourceTarget, mta);
	INITLOCK(m_mutexObserverTemp, mta);
	INITLOCK(m_mutexObserver, mta);
	INITLOCK(m_mutexStatus, mta);
	
	_Retain();
	
	if(m_pEvent)
		m_pEvent->OnGTEventDelegateEvent_DidCreated(this);
}


CGTEventDelegate::~CGTEventDelegate(void)
{
	assert(m_nStatusMark == DELETE);
	
	GT_PLOG("[ENTER] CGTEventDelegate::~CGTEventDelegate(void) : %p", this);
	MyGTRunLoopDelegateImpl *pImpl = (MyGTRunLoopDelegateImpl*)m_pDelegateImpl;
	[pImpl release];
	
	LOCK(m_mutexSourceTarget);
	
	listsourcetarget_t::iterator it = m_mapSourceTarget.begin();
	for(; it != m_mapSourceTarget.end(); it++)
	{
		listprivate_t *plist = it->second;
		assert(plist);
		
		listprivate_t::iterator it2 = plist->begin();
		for(; it2 != plist->end(); it2++)
		{
			free(it2->second);
		}
		plist->clear();
		
		delete plist;
	}
	m_mapSourceTarget.clear();
	
	UNLOCK(m_mutexSourceTarget);

	DESTROYLOCK(m_mutexSourceTarget);
	DESTROYLOCK(m_mutexObserverTemp);
	DESTROYLOCK(m_mutexObserver);
	DESTROYLOCK(m_mutexStatus);
	
	GT_PLOG("[LEAVE] CGTEventDelegate::~CGTEventDelegate(void) : %p", this);
}


// This Function is NOT THREAD SAFE!!!
void CGTEventDelegate::Delete(void)
{
	if(DELETE != m_nStatusMark)
	{
		GT_PLOG(">> CGTEventDelegate::Delete %p, m_nStatusMark == false thread %p impl %p", this, pthread_self(), m_pDelegateImpl);

		MyGTRunLoopDelegateImpl *pImpl = (MyGTRunLoopDelegateImpl*)m_pDelegateImpl;
		[pImpl releaseAllEventResource];		

		m_nStatusMark = DELETE;

		_Release();

		return;
	}

	GT_PLOG(">> CGTEventDelegate::Delete %p, m_nStatusMark == true %p", this, pthread_self());
}


void CGTEventDelegate::ReleaseAllSourcesAndTimers(void)
{
	BEGIN_BLOCK_THREAD_SAFETY;
	
	GT_PLOG(">> CGTEventDelegate::ReleaseAllSourcesAndTimers %p thread %p impl %p", this, pthread_self(), m_pDelegateImpl);
	
	MyGTRunLoopDelegateImpl *pImpl = (MyGTRunLoopDelegateImpl*)m_pDelegateImpl;
	[pImpl releaseAllEventResource];		

	m_nStatusMark = RELEASE;
	
	END_BLOCK_THREAD_SAFETY;
	
	_Release(false);
}


void CGTEventDelegate::RegisterObserver(IGTRunLoopObserver *pObserver)
{
	BEGIN_BLOCK_THREAD_SAFETY;

	GT_PLOG(">> [ENTER] CGTEventDelegate::RegisterObserver %p => %p cnt : %d %d\n",  this, pObserver, m_listObservers.size(), m_listObservers_Newbie.size());

	LOCK(m_mutexObserver);

	if(false == m_bObserverFireDoing)
	{		
		m_listObservers.remove(pObserver);
		m_listObservers.push_back(pObserver);
	}
	else
	{
		_PushToNewbieList(pObserver);
	}

	UNLOCK(m_mutexObserver);
	
	GT_PLOG(">> [LEAVE] CGTEventDelegate::RegisterObserver %p => %p cnt : %d %d\n",  this, pObserver, m_listObservers.size(), m_listObservers_Newbie.size());
	
	END_BLOCK_THREAD_SAFETY;
}

void CGTEventDelegate::UnRegisterObserver(IGTRunLoopObserver *pObserver)
{
	BEGIN_BLOCK_THREAD_SAFETY;

	GT_PLOG(">> [ENTER] CGTEventDelegate::UnRegisterObserver %p => %p cnt : %d %d\n",  this, pObserver, m_listObservers.size(), m_listObservers_Garbage.size());

	LOCK(m_mutexObserver);

	if(false == m_bObserverFireDoing)
	{
		m_listObservers.remove(pObserver);
	}
	else
	{
		_PushToGarbageList(pObserver);
	}

	UNLOCK(m_mutexObserver);
	
	GT_PLOG(">> [LEAVE] CGTEventDelegate::UnRegisterObserver %p => %p cnt : %d %d\n",  this, pObserver, m_listObservers.size(), m_listObservers_Garbage.size());
	
	END_BLOCK_THREAD_SAFETY;
}


GT_EVENT_HANDLE CGTEventDelegate::SetTimer(GT_EVENT_HANDLE handle, int msec, GT_PARAM param)
{
	NSInteger tid = 0;
	BEGIN_BLOCK_THREAD_SAFETY;
	
	CGTAutoReleasePool pool;
	MyGTRunLoopDelegateImpl *pImpl = (id)m_pDelegateImpl;
	assert(pImpl);
	
	tid = [pImpl createTimer:handle withInterval:msec withParam:param];
	
	END_BLOCK_THREAD_SAFETY;
	
	return tid;
}


void CGTEventDelegate::KillTimer(GT_EVENT_HANDLE handle)
{
	BEGIN_BLOCK_THREAD_SAFETY;
	
	CGTAutoReleasePool pool;
	MyGTRunLoopDelegateImpl *pImpl = (id)m_pDelegateImpl;
	assert(pImpl);
	
	[pImpl removeTimer:handle];
	
	END_BLOCK_THREAD_SAFETY;
}


void CGTEventDelegate::RegisterSourceToCurrentRunLoop(int nPositionID, GT_EVENT_HANDLE handle)
{
	BEGIN_BLOCK_THREAD_SAFETY;

	LOCK(m_mutexSourceTarget);
	
	listsourcetarget_t::iterator it = m_mapSourceTarget.find(handle);
	
	listprivate_t *plist = NULL;
	if(it != m_mapSourceTarget.end())
	{
		plist = it->second;
	}
	else 
	{
		plist = new listprivate_t;
		m_mapSourceTarget.insert(listsourcetarget_t::value_type(handle, plist));
	}
	assert(plist);
	
	// delete previous data..
	listprivate_t::iterator it2 = plist->find(nPositionID);
	if(it2 != plist->end())
	{
		free(it2->second);
		plist->erase(it2);
	}
	
	// create new data..
	_PrivateRunLoopTarget *info = (_PrivateRunLoopTarget*)malloc(sizeof(_PrivateRunLoopTarget));
	info->nPositionID = nPositionID;
	info->runLoop = CFRunLoopGetCurrent();
	plist->insert(listprivate_t::value_type(nPositionID, info));

	InterlockedExchange(&m_nSourceTargetCount, m_mapSourceTarget.size());
	
	UNLOCK(m_mutexSourceTarget);
	
	END_BLOCK_THREAD_SAFETY;
}

void CGTEventDelegate::UnRegisterSourceToCurrentRunLoop(int nPositionID, GT_EVENT_HANDLE handle)
{
	BEGIN_BLOCK_THREAD_SAFETY;
	
	LOCK(m_mutexSourceTarget);
	
	listsourcetarget_t::iterator it = m_mapSourceTarget.find(handle);
	if(it != m_mapSourceTarget.end())
	{
		listprivate_t *plist = it->second;
		assert(plist);
		
		listprivate_t::iterator it2 = plist->find(nPositionID);
		if(it2 != plist->end())
		{
			free(it2->second);
			plist->erase(it2);
		}
		
		if(plist->size() <= 0)
		{
			delete plist;
			m_mapSourceTarget.erase(it);
		}
	}
	
	InterlockedExchange(&m_nSourceTargetCount, m_mapSourceTarget.size());
	
	UNLOCK(m_mutexSourceTarget);
	
	END_BLOCK_THREAD_SAFETY;
}


void CGTEventDelegate::PostSourceEventEx(int nPositionID, GT_EVENT_HANDLE handle, GT_PARAM param1, GT_PARAM param2)
{
	BEGIN_BLOCK_THREAD_SAFETY;

	CGTAutoReleasePool pool;
	MyGTRunLoopDelegateImpl *pImpl = (id)m_pDelegateImpl;
	assert(pImpl);
	
	CFRunLoopRef runloop = NULL;
	
	// For perfermance..
	if(m_nSourceTargetCount > 0)
	{
		LOCK(m_mutexSourceTarget);
		
		listsourcetarget_t::iterator it = m_mapSourceTarget.find(handle);
		if(it != m_mapSourceTarget.end())
		{
			listprivate_t *plist = it->second;
			assert(plist);
			
			listprivate_t::iterator it2 = plist->find(nPositionID);
			if(it2 != plist->end())
			{
				_PrivateRunLoopTarget *info = (_PrivateRunLoopTarget*)it2->second;
				assert(info);
				runloop = info->runLoop;
			}
		}
		
		UNLOCK(m_mutexSourceTarget);
	}
	[pImpl createSource:handle withParam:param1 andParam:param2 withRunLoop:runloop];	
	
	END_BLOCK_THREAD_SAFETY;
}


void CGTEventDelegate::PostSourceEvent(GT_EVENT_HANDLE handle, GT_PARAM param1, GT_PARAM param2)
{
	PostSourceEventEx(-1, handle, param1, param2);
}


void CGTEventDelegate::_PushToNewbieList(IGTRunLoopObserver *observer)
{
	LOCK(m_mutexObserverTemp);
	
	m_listObservers_Newbie.push_back(observer);
	
	if(m_listObservers_Newbie.size() > 0)
	{
		InterlockedExchange(&m_nCheckReadyObserver, EXIST);
	}
	
	UNLOCK(m_mutexObserverTemp);	
}


void CGTEventDelegate::_PushToGarbageList(IGTRunLoopObserver *observer)
{
	LOCK(m_mutexObserverTemp);
	
	m_listObservers_Garbage.push_back(observer);
	
	if(m_listObservers_Garbage.size() > 0)
	{
		InterlockedExchange(&m_nCheckReadyObserver, EXIST);
	}
	
	UNLOCK(m_mutexObserverTemp);
}


bool CGTEventDelegate::_FindGarbageList(IGTRunLoopObserver *observer)
{
	if(NOTHING == m_nCheckReadyObserver)
		return false;
	
	LOCK(m_mutexObserverTemp);

	listobserver_t::iterator it = std::find(m_listObservers_Garbage.begin(), m_listObservers_Garbage.end(), observer);
	
	UNLOCK(m_mutexObserverTemp);
	
	if(it != m_listObservers_Garbage.end())
		return true;
	
	return false;
}


void CGTEventDelegate::_ApplyObserverList()
{
	if(EXIST == m_nCheckReadyObserver)	// For Performance.. m_nCheckReadyObserver is interlocked operated..
	{
		GT_PLOG(">> [ENTER] CGTEventDelegate::_Release() : m_nCheckReadyObserver == EXIST %p ==> %d %d", 
				this, m_listObservers.size(), m_listObservers_Newbie.size(), m_listObservers_Garbage.size());
		
		LOCK(m_mutexObserver);
		LOCK(m_mutexObserverTemp);
		
		if(m_listObservers_Newbie.size() > 0)
		{
			listobserver_t::iterator it = m_listObservers_Newbie.begin();
			for (; it != m_listObservers_Newbie.end(); ++it)
			{
				m_listObservers.remove(*it);
				m_listObservers.push_back(*it);
			}
		}
		m_listObservers_Newbie.clear();
		
		
		if(m_listObservers_Garbage.size() > 0)
		{
			listobserver_t::iterator it = m_listObservers_Garbage.begin();
			for (; it != m_listObservers_Garbage.end(); ++it)
			{
				m_listObservers.remove(*it);
			}
		}	
		m_listObservers_Garbage.clear();
		
		UNLOCK(m_mutexObserverTemp);
		UNLOCK(m_mutexObserver);
		
		InterlockedExchange(&m_nCheckReadyObserver, NOTHING);
		
		GT_PLOG(">> [LEAVE] CGTEventDelegate::_Release() : m_nCheckReadyObserver == EXIST %p ==> %d %d", 
				this, m_listObservers.size(), m_listObservers_Newbie.size(), m_listObservers_Garbage.size());
	}
}


void CGTEventDelegate::_FireSourceEvent(GT_EVENT_HANDLE handle, GT_PARAM param1, GT_PARAM param2)
{	
	// Don't need to lock..
	// Already m_nRetainCount + 1 in onGTRunLoop_RegisterSource..
	// so you don't need to worry about that this class may be deleted while this function is processing.. 

	_Retain();
	
	LOCK(m_mutexObserver);
	m_bObserverFireDoing = true;
	UNLOCK(m_mutexObserver);

	//GT_PLOG("[ENTER] CGTEventDelegate::_FireSourceEvent : %p => handel = %d param1 = %d param2 = %d size = %d", this, handle, param1, param2, m_listObservers.size());
	
	listobserver_t::iterator it = m_listObservers.begin();
	for (; it != m_listObservers.end(); ++it)
	{
		if(_FindGarbageList(*it))
		{
			continue;
		}
		
		if((*it)->OnGTRunLoopObserver_SourceEvent(handle, param1, param2) == false)
			break;
	}
	
	// Don't need to lock by logic..
	m_bObserverFireDoing = false;

	_ApplyObserverList();
	
	_Release();
	
	//GT_PLOG("[LEAVE] CGTEventDelegate::_FireSourceEvent : %p => handel = %d param1 = %d param2 = %d size = %d", this, handle, param1, param2, m_listObservers.size());
}


void CGTEventDelegate::_FireTimerEvent(GT_EVENT_HANDLE handle, GT_PARAM param)
{	
	// Don't need to lock..
	// Already m_nRetainCount + 1 in onGTRunLoop_RegisterTimer..
	// so you don't need to worry about that this class may be deleted while this function is processing.. 

	_Retain();
	
	LOCK(m_mutexObserver);
	m_bObserverFireDoing = true;
	UNLOCK(m_mutexObserver);
	
	//GT_PLOG("[ENTER] CGTEventDelegate::_FireTimerEvent : %p => handel = %d param = %p size = %d", this, handle, param, m_listObservers.size());

	listobserver_t::iterator it = m_listObservers.begin();
	for (; it != m_listObservers.end(); ++it)
	{
		if(_FindGarbageList(*it))
		{
			continue;
		}
		
		if((*it)->OnGTRunLoopObserver_TimerEvent(handle, param) == false)
			break;	
	}

	// Don't need to lock by logic..
	m_bObserverFireDoing = false;
	
	_ApplyObserverList();
	
	_Release();

	//GT_PLOG("[LEAVE] CGTEventDelegate::_FireTimerEvent : %p => handel = %d param = %p size = %d", this, handle, param, m_listObservers.size());
}

