/** Schedules the 'update' selector for a given target with a given priority.
         * The 'update' selector will be called every frame.
         * The lower the priority, the earlier it is called.
         * @since v0.99.3
         */
        public void scheduleUpdate(System.Object target, int priority, bool paused)
        {
            tHashUpdateEntry hashElement = hashForUpdates.HASH_FIND_INT(target.GetHashCode());

            if (hashElement != null)
            {
                if (CCDebug.COCOS2D_DEBUG >= 1)
                {
                    NSUtils.Assert(hashElement.entry.obj.markedForDeletion, "CCScheduler: You can't re-schedule an 'update' selector'. Unschedule it first");
                }

                // TODO : check if priority has changed!
                hashElement.entry.obj.markedForDeletion = false;
                return;
            }


            // most of the updates are going to be 0, that's way there
            // is an special list for updates with priority 0
            if (priority == 0)
            {
                appendIn(updates0, target, paused);
            }
            else if (priority < 0)
            {
                priorityIn(updatesNeg, target, priority, paused);
            }
            else             // priority > 0
            {
                priorityIn(updatesPos, target, priority, paused);
            }
        }
        void appendIn(utList <tListEntry> list, System.Object target, bool paused)
        {
            tListEntry listEntry = new tListEntry();

            listEntry.target            = target;
            listEntry.paused            = paused;
            listEntry.markedForDeletion = false;
            MethodInfo method = target.GetType().GetMethod(updateSelector);

            listEntry.impMethod = (TICK_IMP)Delegate.CreateDelegate(typeof(TICK_IMP), target, method);

            utNode <tListEntry> listElement = new utNode <tListEntry> ();

            listElement.next = listElement.prev = null;
            listElement.obj  = listEntry;

            list.DL_APPEND(listElement);

            tHashUpdateEntry hashElement = new tHashUpdateEntry();

            hashElement.target = target;
            hashElement.list   = list;
            hashElement.entry  = listElement;
            hashForUpdates.HASH_ADD_INT(target.GetHashCode(), hashElement);
        }
        void priorityIn(utList <tListEntry> list, System.Object target, int priority, bool paused)
        {
            tListEntry listEntry = new tListEntry();

            listEntry.target   = target;
            listEntry.priority = priority;
            listEntry.paused   = paused;
            MethodInfo method = target.GetType().GetMethod(updateSelector);

            listEntry.impMethod         = (TICK_IMP)Delegate.CreateDelegate(typeof(TICK_IMP), target, method);
            listEntry.markedForDeletion = false;

            utNode <tListEntry> listElement = new utNode <tListEntry> ();

            listElement.next = listElement.prev = null;
            listElement.obj  = listEntry;


            if (list.head == null)
            {
                list.DL_APPEND(listElement);
            }
            else
            {
                bool added = false;
                for (utNode <tListEntry> elem = list.head; elem != null; elem = elem.next)
                {
                    if (priority < elem.obj.priority)
                    {
                        if (elem == list.head)
                        {
                            list.DL_PREPEND(listElement);
                        }
                        else
                        {
                            listElement.next = elem;
                            listElement.prev = elem.prev;

                            elem.prev.next = listElement;
                            elem.prev      = listElement;
                        }
                        added = true;
                        break;
                    }
                }

                if (!added)
                {
                    list.DL_APPEND(listElement);
                }
            }
            tHashUpdateEntry hashElement = new tHashUpdateEntry();

            hashElement.target = target;
            hashElement.list   = list;
            hashElement.entry  = listElement;
            hashForUpdates.HASH_ADD_INT(target.GetHashCode(), hashElement);
        }
        void removeUpdatesFromHash(utNode <tListEntry> entry)
        {
            tHashUpdateEntry element = hashForUpdates.HASH_FIND_INT(entry.obj.target.GetHashCode());

            if (element != null)
            {
                // list entry
                element.list.DL_DELETE(element.entry);
                element.entry = null;

                // hash entry
                System.Object target = element.target;
                hashForUpdates.HASH_DEL(target.GetHashCode());
            }
        }
        /** Unschedules the update selector for a given target
         * @since v0.99.3
         */
        public void unscheduleUpdateForTarget(System.Object target)
        {
            if (target == null)
            {
                return;
            }
            tHashUpdateEntry element = hashForUpdates.HASH_FIND_INT(target.GetHashCode());

            if (element != null)
            {
                if (updateHashLocked)
                {
                    element.entry.obj.markedForDeletion = true;
                }
                else
                {
                    removeUpdatesFromHash(element.entry);
                }
            }
        }
        /** Pauses the target.
         * All scheduled selectors/update for a given target won't be 'ticked' until the target is resumed.
         * If the target is not present, nothing happens.
         * @since v0.99.3
         */
        public void pauseTarget(System.Object target)
        {
            NSUtils.Assert(target != null, "target must be non nil");

            // Custom selectors
            tHashTimerEntry element = hashForTimers.HASH_FIND_INT(target.GetHashCode());

            if (element != null)
            {
                element.paused = true;
            }

            // Update selector
            tHashUpdateEntry elementUpdate = hashForUpdates.HASH_FIND_INT(target.GetHashCode());

            if (elementUpdate != null)
            {
                NSUtils.Assert(elementUpdate.entry != null, "pauseTarget: unknown error");
                elementUpdate.entry.obj.paused = true;
            }
        }
        /** Returns whether or not the target is paused
         * @since v1.0.0
         */
        public bool isTargetPaused(System.Object target)
        {
            NSUtils.Assert(target != null, "target must be non nil");

            // Custom selectors
            tHashTimerEntry element = hashForTimers.HASH_FIND_INT(target.GetHashCode());

            if (element != null)
            {
                return(element.paused);
            }

            // We should check update selectors if target does not have custom selectors
            tHashUpdateEntry elementUpdate = hashForUpdates.HASH_FIND_INT(target.GetHashCode());

            if (elementUpdate != null)
            {
                return(elementUpdate.entry.obj.paused);
            }

            return(false);             // should never get here
        }