//----------init------------
		public CCScheduler(){
			_timeScale = 1.0f;
			
			// used to trigger CCTimer#update
			updateSelector = "update";
//			impMethod = (TICK_IMP) [CCTimerTargetSelector instanceMethodForSelector:updateSelector];

			// updates with priority
			updates0 = new utList<tListEntry>();
			updatesNeg = new utList<tListEntry>();
			updatesPos = new utList<tListEntry>();
			hashForUpdates = new UTHash<int, tHashUpdateEntry>();
			
			// selectors with interval
			currentTarget = null;
			currentTargetSalvaged = false;
			hashForTimers =  new UTHash<int, tHashTimerEntry>();
			updateHashLocked = false;
			_paused = false;

		}
		//-------------update------------
		/** 'update' the scheduler.
		 You should NEVER call this method, unless you know what you are doing.
		 */
		public void update(float dt){
			if (_paused)
				return;
			updateHashLocked = true;
			if (!FloatUtils.EQ(_timeScale , 1.0f))
				dt *= _timeScale;
			
			// Iterate all over the Updates selectors
			// updates with priority < 0
			{
				
				for( utNode<tListEntry> tmp = updatesNeg.head; tmp != null ; tmp = tmp.next ) {
					utNode<tListEntry> entry = tmp;
					if(! entry.obj.paused && !entry.obj.markedForDeletion){
						entry.obj.impMethod.Invoke(dt);
					}
				}
			}
			// updates with priority == 0
			{
				for( utNode<tListEntry> tmp = updates0.head; tmp != null ; tmp = tmp.next ) {
					utNode<tListEntry> entry = tmp;
					if(! entry.obj.paused && !entry.obj.markedForDeletion)
						entry.obj.impMethod.Invoke(dt);
				}
			}
			// updates with priority > 0
			{
				
				for( utNode<tListEntry> tmp = updatesPos.head; tmp != null ; tmp = tmp.next ) {
					utNode<tListEntry> entry = tmp;
					if(! entry.obj.paused && !entry.obj.markedForDeletion)
						entry.obj.impMethod.Invoke(dt);
				}
			}

//			 Iterate all over the custom selectors (CCTimers)
			if(hashForTimers.Any()){
				var enumerator = new Dictionary<int, tHashTimerEntry>(hashForTimers).GetEnumerator();
				while (enumerator.MoveNext()) {
					var elt = enumerator.Current.Value;
					currentTarget = elt;
					currentTargetSalvaged = false;
					if( ! currentTarget.paused){
						for(elt.timerIndex = 0; elt.timerIndex < elt.timers.Count; elt.timerIndex ++ ){
							elt.currentTimer = elt.timers[elt.timerIndex];
							elt.currentTimerSalvaged = false;
							elt.currentTimer.update(dt);
							elt.currentTimer = null;
						}
					}
					if(currentTargetSalvaged && currentTarget.timers.Count == 0)
						removeHashElement(currentTarget);
				}
			}

			
			for (utNode<tListEntry> tmp = updatesNeg.head; tmp != null; tmp = tmp.next) {
				utNode<tListEntry> entry = tmp;
				if(entry.obj.markedForDeletion){
					removeUpdatesFromHash(entry);
				}
			}
			
			for (utNode<tListEntry> tmp = updates0.head; tmp != null; tmp = tmp.next) {
				utNode<tListEntry> entry = tmp;
				if(entry.obj.markedForDeletion){
					removeUpdatesFromHash(entry);
				}
			}

			
			for (utNode<tListEntry> tmp = updatesPos.head; tmp != null; tmp = tmp.next) {
				utNode<tListEntry> entry = tmp;
				if(entry.obj.markedForDeletion){
					removeUpdatesFromHash(entry);
				}
			}
			updateHashLocked = false;
			currentTarget = null;
		}
		/** The scheduled method will be called every 'interval' seconds.
		 If paused is YES, then it won't be called until it is resumed.
		 If 'interval' is 0, it will be called every frame, but if so, it recommended to use 'scheduleUpdateForTarget:' instead.
		 If the selector is already scheduled, then only the interval parameter will be updated without re-scheduling it again.
		 repeat lets the action be repeated repeat + 1 times, use kCCRepeatForever to let the action run continuously
		 delay is the amount of time the action will wait before it'll start

		 @since v0.99.3, repeat and delay added in v1.1
		 */
		public void schedule(TICK_IMP selector, System.Object target, float interval, uint repeat, bool paused, float delay=0){
			NSUtils.Assert( selector != null, "Argument selector must be non-nil");
			NSUtils.Assert( target != null, "Argument target must be non-nil");

			tHashTimerEntry element = hashForTimers.HASH_FIND_INT(target.GetHashCode());
			if (element == null) {
				element = new tHashTimerEntry ();
				element.target = target;
				hashForTimers.HASH_ADD_INT(target.GetHashCode(), element);

				// Is this the 1st element ? Then set the pause level to all the selectors of this target
				element.paused = paused;
			} else 
				NSUtils.Assert( element.paused == paused, "CCScheduler. Trying to schedule a selector with a pause value different than the target");


			if (element.timers == null)
				element.timers = new List<CCTimer> (10);
			else {
				var enumerator = element.timers.GetEnumerator();
				while (enumerator.MoveNext()) {
					CCTimer timer = enumerator.Current;
					if(timer is CCTimerTargetSelector && selector == ((CCTimerTargetSelector)timer).selector){
						CCDebug.Log("CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: {0:0.0000} to {1:0.0000}", timer.interval, interval);
						timer.interval = interval;
						return;
					}
				}
			}
			CCTimerTargetSelector timerSelector = new CCTimerTargetSelector(target, selector, interval, repeat, delay);
			element.timers.Add(timerSelector);
		}
		public void scheduleBlockForKey(string key, System.Object owner, float interval, uint repeat, float delay, bool paused, TICK_IMP block)
		{
			NSUtils.Assert( block != null, "Argument block must be non-nil");
			NSUtils.Assert( owner != null, "Argument owner must be non-nil");
			
			tHashTimerEntry element = hashForTimers.HASH_FIND_INT(owner.GetHashCode());
			
			if (element == null) {
				element = new tHashTimerEntry ();
				element.target = owner;
				hashForTimers.HASH_ADD_INT(owner.GetHashCode(), element);
				
				// Is this the 1st element ? Then set the pause level to all the selectors of this target
				element.paused = paused;
				
			} else
				NSUtils.Assert( element.paused == paused, "CCScheduler. Trying to schedule a block with a pause value different than the target");
			
			
			if (element.timers == null)
				element.timers = new List<CCTimer> (10);
			else
			{
				var enumerator = element.timers.GetEnumerator();
				while (enumerator.MoveNext()) {
					CCTimer timer = enumerator.Current;
					if(timer is CCTimerBlock  && key == ((CCTimerBlock)timer).key) {
						CCDebug.Log("CCScheduler#scheduleBlock. Block already scheduled. Updating interval from: {0:0.0000} to {1:0.0000}", timer.interval, interval);
						timer.interval = interval;
						return;
					}
				}
			}
			
			CCTimerBlock timerBlock = new CCTimerBlock(owner, interval, key, block, repeat, delay);
			element.timers.Add(timerBlock);
		}
		void removeHashElement(tHashTimerEntry element){
			hashForTimers.HASH_DEL (element.target.GetHashCode());
			element.timers = null;
			element.target = null;
		}