1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 
 28 /**
 29  * Minimum priority level for user scheduling.
 30  * @constant
 31  * @type Number
 32  */
 33 cc.PRIORITY_NON_SYSTEM = cc.PRIORITY_SYSTEM + 1;
 34 
 35 /**
 36  * Verify Array's Type
 37  * @param {Array} arr
 38  * @param {function} type
 39  * @return {Boolean}
 40  * @function
 41  */
 42 cc.arrayVerifyType = function (arr, type) {
 43     if (arr && arr.length > 0) {
 44         for (var i = 0; i < arr.length; i++) {
 45             if (!(arr[i] instanceof  type)) {
 46                 cc.log("element type is wrong!");
 47                 return false;
 48             }
 49         }
 50     }
 51     return true;
 52 };
 53 
 54 /**
 55  * Searches for the first occurance of object and removes it. If object is not found the function has no effect.
 56  * @function
 57  * @param {Array} arr Source Array
 58  * @param {*} delObj  remove object
 59  */
 60 cc.arrayRemoveObject = function (arr, delObj) {
 61     for (var i = 0, l = arr.length; i < l; i++) {
 62         if (arr[i] == delObj) {
 63             arr.splice(i, 1);
 64             break;
 65         }
 66     }
 67 };
 68 
 69 /**
 70  * Removes from arr all values in minusArr. For each Value in minusArr, the first matching instance in arr will be removed.
 71  * @function
 72  * @param {Array} arr Source Array
 73  * @param {Array} minusArr minus Array
 74  */
 75 cc.arrayRemoveArray = function (arr, minusArr) {
 76     for (var i = 0, l = minusArr.length; i < l; i++) {
 77         cc.arrayRemoveObject(arr, minusArr[i]);
 78     }
 79 };
 80 
 81 /**
 82  * Inserts some objects at index
 83  * @function
 84  * @param {Array} arr
 85  * @param {Array} addObjs
 86  * @param {Number} index
 87  * @return {Array}
 88  */
 89 cc.arrayAppendObjectsToIndex = function(arr, addObjs,index){
 90     arr.splice.apply(arr, [index, 0].concat(addObjs));
 91     return arr;
 92 };
 93 
 94 //data structures
 95 /**
 96  * A list double-linked list used for "updates with priority"
 97  * @Class
 98  * @Construct
 99  * @param {cc.ListEntry} prev
100  * @param {cc.ListEntry} next
101  * @param {cc.Class} target not retained (retained by hashUpdateEntry)
102  * @param {Number} priority
103  * @param {Boolean} paused
104  * @param {Boolean} markedForDeletion selector will no longer be called and entry will be removed at end of the next tick
105  */
106 cc.ListEntry = function (prev, next, target, priority, paused, markedForDeletion) {
107     this.prev = prev;
108     this.next = next;
109     this.target = target;
110     this.priority = priority;
111     this.paused = paused;
112     this.markedForDeletion = markedForDeletion;
113 };
114 
115 /**
116  *  a update entry list
117  * @Class
118  * @Construct
119  * @param {cc.ListEntry} list Which list does it belong to ?
120  * @param {cc.ListEntry} entry entry in the list
121  * @param {cc.Class} target hash key (retained)
122  * @param {Array} hh
123  */
124 cc.HashUpdateEntry = function (list, entry, target, hh) {
125     this.list = list;
126     this.entry = entry;
127     this.target = target;
128     this.hh = hh;
129 };
130 
131 //
132 /**
133  * Hash Element used for "selectors with interval"
134  * @Class
135  * @Construct
136  * @param {Array} timers
137  * @param {cc.Class} target  hash key (retained)
138  * @param {Number} timerIndex
139  * @param {cc.Timer} currentTimer
140  * @param {Boolean} currentTimerSalvaged
141  * @param {Boolean} paused
142  * @param {Array} hh
143  */
144 cc.HashTimerEntry = function (timers, target, timerIndex, currentTimer, currentTimerSalvaged, paused, hh) {
145     this.timers = timers;
146     this.target = target;
147     this.timerIndex = timerIndex;
148     this.currentTimer = currentTimer;
149     this.currentTimerSalvaged = currentTimerSalvaged;
150     this.paused = paused;
151     this.hh = hh;
152 };
153 
154 /**
155  * Light weight timer
156  * @class
157  * @extends cc.Class
158  */
159 cc.Timer = cc.Class.extend(/** @lends cc.Timer# */{
160     _interval:0.0,
161     _callback:null,//is called _callback before
162 
163     _target:null,//target of _callback
164     _elapsed:0.0,
165 
166     _runForever:false,
167     _useDelay:false,
168     _timesExecuted:0,
169     _repeat:0, //0 = once, 1 is 2 x executed
170     _delay:0,
171 
172     /**
173      * @return {Number} returns interval of timer
174      */
175     getInterval : function(){return this._interval;},
176     /**
177      * @param {Number} interval set interval in seconds
178      */
179     setInterval : function(interval){this._interval = interval;},
180 
181     /**
182      * @return {String|function} returns callback
183      */
184     getCallback : function(){return this._callback},
185 
186 
187     /**
188      * cc.Timer's Constructor
189      * @constructor
190      * @param {cc.Class} target target
191      * @param {String|function} selector Selector
192      * @param {Number} [seconds=0] second
193      * @param {Number} [repeat=cc.REPEAT_FOREVER] repeat times
194      * @param {Number} [delay=0] delay
195      */
196     ctor:function (target, callback, interval, repeat, delay) {
197         var self = this;
198         self._target = target;
199         self._callback = callback;
200         self._elapsed = -1;
201         self._interval = interval || 0;
202         self._delay = delay || 0;
203         self._useDelay = self._delay > 0;
204         self._repeat = (repeat == null) ? cc.REPEAT_FOREVER : repeat;
205         self._runForever = (self._repeat == cc.REPEAT_FOREVER);
206     },
207 
208     _doCallback:function(){
209         var self = this;
210         if (typeof(self._callback) == "string")
211             self._target[self._callback](self._elapsed);
212         else // if (typeof(this._callback) == "function") {
213             self._callback.call(self._target, self._elapsed);
214     },
215 
216     /**
217      * triggers the timer
218      * @param {Number} dt delta time
219      */
220     update:function (dt) {
221         var self = this;
222         if (self._elapsed == -1) {
223             self._elapsed = 0;
224             self._timesExecuted = 0;
225         } else {
226             var locTarget = self._target, locCallback = self._callback;
227             self._elapsed += dt;//standard timer usage
228             if (self._runForever && !self._useDelay) {
229                 if (self._elapsed >= self._interval) {
230                     if (locTarget && locCallback)
231                         self._doCallback();
232                     self._elapsed = 0;
233                 }
234             } else {
235                 //advanced usage
236                 if (self._useDelay) {
237                     if (self._elapsed >= self._delay) {
238                         if (locTarget && locCallback)
239                             self._doCallback();
240 
241                         self._elapsed = self._elapsed - self._delay;
242                         self._timesExecuted += 1;
243                         self._useDelay = false;
244                     }
245                 } else {
246                     if (self._elapsed >= self._interval) {
247                         if (locTarget && locCallback)
248                             self._doCallback();
249 
250                         self._elapsed = 0;
251                         self._timesExecuted += 1;
252                     }
253                 }
254 
255                 if (self._timesExecuted > self._repeat)
256                     cc.director.getScheduler().unscheduleCallbackForTarget(locTarget, locCallback);
257             }
258         }
259     }
260 });
261 
262 /**
263  * <p>
264  *    Scheduler is responsible of triggering the scheduled callbacks.<br/>
265  *    You should not use NSTimer. Instead use this class.<br/>
266  *    <br/>
267  *    There are 2 different types of callbacks (selectors):<br/>
268  *       - update callback: the 'update' callback will be called every frame. You can customize the priority.<br/>
269  *       - custom callback: A custom callback will be called every frame, or with a custom interval of time<br/>
270  *       <br/>
271  *    The 'custom selectors' should be avoided when possible. It is faster, and consumes less memory to use the 'update callback'. *
272  * </p>
273  * @class
274  * @extends cc.Class
275  *
276  * @example
277  * //register a schedule to scheduler
278  * cc.director.getScheduler().scheduleSelector(callback, this, interval, !this._isRunning);
279  */
280 cc.Scheduler = cc.Class.extend(/** @lends cc.Scheduler# */{
281     _timeScale:1.0,
282 
283     _updates : null, //_updates[0] list of priority < 0, _updates[1] list of priority == 0, _updates[2] list of priority > 0,
284 
285     _hashForUpdates:null, // hash used to fetch quickly the list entries for pause,delete,etc
286     _arrayForUpdates:null,
287 
288     _hashForTimers:null, //Used for "selectors with interval"
289     _arrayForTimes:null,
290 
291     _currentTarget:null,
292     _currentTargetSalvaged:false,
293     _updateHashLocked:false, //If true unschedule will not remove anything from a hash. Elements will only be marked for deletion.
294 
295     /**
296      * Constructor
297      */
298     ctor:function () {
299         var self = this;
300         self._timeScale = 1.0;
301         self._updates = [[], [], []];
302 
303         self._hashForUpdates = {};
304         self._arrayForUpdates = [];
305 
306         self._hashForTimers = {};
307         self._arrayForTimers = [];
308 
309         self._currentTarget = null;
310         self._currentTargetSalvaged = false;
311         self._updateHashLocked = false;
312     },
313 
314     //-----------------------private method----------------------
315     _removeHashElement:function (element) {
316         delete this._hashForTimers[element.target.__instanceId];
317         cc.arrayRemoveObject(this._arrayForTimers, element);
318         element.Timer = null;
319         element.target = null;
320         element = null;
321     },
322 
323     _removeUpdateFromHash:function (entry) {
324         var self = this, element = self._hashForUpdates[entry.target.__instanceId];
325         if (element) {
326             //list entry
327             cc.arrayRemoveObject(element.list, element.entry);
328 
329             delete self._hashForUpdates[element.target.__instanceId];
330             cc.arrayRemoveObject(self._arrayForUpdates, element);
331             element.entry = null;
332 
333             //hash entry
334             element.target = null;
335         }
336     },
337 
338     _priorityIn:function (ppList, target, priority, paused) {
339         var self = this, listElement = new cc.ListEntry(null, null, target, priority, paused, false);
340 
341         // empey list ?
342         if (!ppList) {
343             ppList = [];
344             ppList.push(listElement);
345         } else {
346             var index2Insert = ppList.length - 1;
347             for(var i = 0; i <= index2Insert; i++){
348                 if (priority < ppList[i].priority) {
349                     index2Insert = i;
350                     break;
351                 }
352             }
353             ppList.splice(i, 0, listElement);
354         }
355 
356         //update hash entry for quick access
357         var hashElement = new cc.HashUpdateEntry(ppList, listElement, target, null);
358         self._arrayForUpdates.push(hashElement);
359         self._hashForUpdates[target.__instanceId] = hashElement;
360 
361         return ppList;
362     },
363 
364     _appendIn:function (ppList, target, paused) {
365         var self = this, listElement = new cc.ListEntry(null, null, target, 0, paused, false);
366         ppList.push(listElement);
367 
368         //update hash entry for quicker access
369         var hashElement = new cc.HashUpdateEntry(ppList, listElement, target, null);
370         self._arrayForUpdates.push(hashElement);
371         self._hashForUpdates[target.__instanceId] = hashElement;
372     },
373 
374     //-----------------------public method-------------------------
375     /**
376      * <p>
377      *    Modifies the time of all scheduled callbacks.<br/>
378      *    You can use this property to create a 'slow motion' or 'fast forward' effect.<br/>
379      *    Default is 1.0. To create a 'slow motion' effect, use values below 1.0.<br/>
380      *    To create a 'fast forward' effect, use values higher than 1.0.<br/>
381      *    @warning It will affect EVERY scheduled selector / action.
382      * </p>
383      * @param {Number} timeScale
384      */
385     setTimeScale:function (timeScale) {
386         this._timeScale = timeScale;
387     },
388 
389     /**
390      * returns time scale of scheduler
391      * @return {Number}
392      */
393     getTimeScale:function () {
394         return this._timeScale;
395     },
396 
397     /**
398      * 'update' the scheduler. (You should NEVER call this method, unless you know what you are doing.)
399      * @param {Number} dt delta time
400      */
401     update:function (dt) {
402         var self = this;
403         var locUpdates = self._updates, locArrayForTimers = self._arrayForTimers;
404         var tmpEntry, elt;
405         self._updateHashLocked = true;
406 
407         if (this._timeScale != 1.0) {
408             dt *= this._timeScale;
409         }
410 
411         for(var i = 0, li = locUpdates.length; i < li && i >= 0; i++){
412             var update = self._updates[i];
413             for(var j = 0, lj = update.length; j < lj; j++){
414                 tmpEntry = update[j];
415                 if ((!tmpEntry.paused) && (!tmpEntry.markedForDeletion)) tmpEntry.target.update(dt);
416             }
417         }
418 
419         //Interate all over the custom callbacks
420         for(var i = 0, li = locArrayForTimers.length; i < li; i++){
421             elt = locArrayForTimers[i];
422             if(!elt) break;
423             self._currentTarget = elt;
424             self._currentTargetSalvaged = false;
425 
426             if (!elt.paused) {
427                 // The 'timers' array may change while inside this loop
428                 for (elt.timerIndex = 0; elt.timerIndex < elt.timers.length; elt.timerIndex++) {
429                     elt.currentTimer = elt.timers[elt.timerIndex];
430                     elt.currentTimerSalvaged = false;
431 
432                     elt.currentTimer.update(dt);
433                     elt.currentTimer = null;
434                 }
435             }
436 
437             if ((self._currentTargetSalvaged) && (elt.timers.length == 0)){
438                 self._removeHashElement(elt);
439                 i--;
440             }
441         }
442 
443         for(var i = 0, li = locUpdates.length; i < li; i++){
444             var update = self._updates[i];
445             for(var j = 0, lj = update.length; j < lj; ){
446                 tmpEntry = update[j];
447                 if(!tmpEntry) break;
448                 if (tmpEntry.markedForDeletion) self._removeUpdateFromHash(tmpEntry);
449                 else j++;
450             }
451         }
452 
453         self._updateHashLocked = false;
454         self._currentTarget = null;
455     },
456 
457     /**
458      * <p>
459      *   The scheduled method will be called every 'interval' seconds.</br>
460      *   If paused is YES, then it won't be called until it is resumed.<br/>
461      *   If 'interval' is 0, it will be called every frame, but if so, it recommended to use 'scheduleUpdateForTarget:' instead.<br/>
462      *   If the callback function is already scheduled, then only the interval parameter will be updated without re-scheduling it again.<br/>
463      *   repeat let the action be repeated repeat + 1 times, use cc.REPEAT_FOREVER to let the action run continuously<br/>
464      *   delay is the amount of time the action will wait before it'll start<br/>
465      * </p>
466      * @param {cc.Class} target
467      * @param {function} callback_fn
468      * @param {Number} interval
469      * @param {Number} repeat
470      * @param {Number} delay
471      * @param {Boolean} paused
472      * @example
473      * //register a schedule to scheduler
474      * cc.director.getScheduler().scheduleCallbackForTarget(this, function, interval, repeat, delay, !this._isRunning );
475      */
476     scheduleCallbackForTarget:function (target, callback_fn, interval, repeat, delay, paused) {
477         if(!callback_fn)
478             throw "cc.scheduler.scheduleCallbackForTarget(): callback_fn should be non-null.";
479 
480         if(!target)
481             throw "cc.scheduler.scheduleCallbackForTarget(): target should be non-null.";
482 
483         // default arguments
484         interval = interval || 0;
485         repeat = (repeat == null) ? cc.REPEAT_FOREVER : repeat;
486         delay = delay || 0;
487         paused = paused || false;
488 
489         var self = this, timer;
490         var element = self._hashForTimers[target.__instanceId];
491 
492         if (!element) {
493             // Is this the 1st element ? Then set the pause level to all the callback_fns of this target
494             element = new cc.HashTimerEntry(null, target, 0, null, null, paused, null);
495             self._arrayForTimers.push(element);
496             self._hashForTimers[target.__instanceId] = element;
497         }
498 
499         if (element.timers == null) {
500             element.timers = [];
501         } else {
502             for (var i = 0; i < element.timers.length; i++) {
503                 timer = element.timers[i];
504                 if (callback_fn == timer._callback) {
505                     cc.log("CCSheduler#scheduleCallback. Callback already scheduled. Updating interval from:"
506                         + timer.getInterval().toFixed(4) + " to " + interval.toFixed(4));
507                     timer._interval = interval;
508                     return;
509                 }
510             }
511         }
512 
513         timer = new cc.Timer(target, callback_fn, interval, repeat, delay);
514         element.timers.push(timer);
515     },
516 
517     /**
518      * <p>
519      *    Schedules the 'update' callback_fn for a given target with a given priority.<br/>
520      *    The 'update' callback_fn will be called every frame.<br/>
521      *    The lower the priority, the earlier it is called.
522      * </p>
523      * @param {cc.Class} target
524      * @param {Number} priority
525      * @param {Boolean} paused
526      * @example
527      * //register this object to scheduler
528      * cc.director.getScheduler().scheduleUpdateForTarget(this, priority, !this._isRunning );
529      */
530     scheduleUpdateForTarget:function (target, priority, paused) {
531         var self = this, locUpdates = self._updates;
532         var hashElement = self._hashForUpdates[target.__instanceId];
533 
534         if (hashElement) {
535             // TODO: check if priority has changed!
536             hashElement.entry.markedForDeletion = false;
537             return;
538         }
539 
540         // most of the updates are going to be 0, that's way there
541         // is an special list for updates with priority 0
542         if (priority == 0) {
543             self._appendIn(locUpdates[1], target, paused);
544         } else if (priority < 0) {
545             locUpdates[0] = self._priorityIn(locUpdates[0], target, priority, paused);
546         } else {
547             // priority > 0
548             locUpdates[2] = self._priorityIn(locUpdates[2], target, priority, paused);
549         }
550     },
551 
552     /**
553      * <p>
554      *   Unschedule a callback function for a given target.<br/>
555      *   If you want to unschedule the "update", use unscheudleUpdateForTarget.
556      * </p>
557      * @param {cc.Class} target
558      * @param {function} callback_fn
559      * @example
560      * //unschedule a callback of target
561      * cc.director.getScheduler().unscheduleCallbackForTarget(function, this);
562      */
563     unscheduleCallbackForTarget:function (target, callback_fn) {
564         // explicity handle nil arguments when removing an object
565         if ((target == null) || (callback_fn == null)) {
566             return;
567         }
568 
569         var self = this, element = self._hashForTimers[target.__instanceId];
570         if (element) {
571             var timers = element.timers;
572             for(var i = 0, li = timers.length; i < li; i++){
573                 var timer = timers[i];
574                 if (callback_fn == timer._callback) {
575                     if ((timer == element.currentTimer) && (!element.currentTimerSalvaged)) {
576                         element.currentTimerSalvaged = true;
577                     }
578                     timers.splice(i, 1)
579                     //update timerIndex in case we are in tick;, looping over the actions
580                     if (element.timerIndex >= i) {
581                         element.timerIndex--;
582                     }
583 
584                     if (timers.length == 0) {
585                         if (self._currentTarget == element) {
586                             self._currentTargetSalvaged = true;
587                         } else {
588                             self._removeHashElement(element);
589                         }
590                     }
591                     return;
592                 }
593             }
594         }
595     },
596 
597     /**
598      * Unschedules the update callback function for a given target
599      * @param {cc.Class} target
600      * @example
601      * //unschedules the "update" method.
602      * cc.director.getScheduler().unscheduleUpdateForTarget(this);
603      */
604     unscheduleUpdateForTarget:function (target) {
605         if (target == null) {
606             return;
607         }
608 
609         var self = this, element = self._hashForUpdates[target.__instanceId];
610         if (element != null) {
611             if (self._updateHashLocked) {
612                 element.entry.markedForDeletion = true;
613             } else {
614                 self._removeUpdateFromHash(element.entry);
615             }
616         }
617     },
618 
619     /**
620      * Unschedules all function callbacks for a given target. This also includes the "update" callback function.
621      * @param {cc.Class} target
622      */
623     unscheduleAllCallbacksForTarget:function (target) {
624         //explicit NULL handling
625         if (target == null) {
626             return;
627         }
628 
629         var self = this, element = self._hashForTimers[target.__instanceId];
630         if (element) {
631             var timers = element.timers;
632             if ((!element.currentTimerSalvaged) && (timers.indexOf(element.currentTimer) >= 0)) {
633                 element.currentTimerSalvaged = true;
634             }
635             timers.length = 0;
636 
637             if (self._currentTarget == element) {
638                 self._currentTargetSalvaged = true;
639             } else {
640                 self._removeHashElement(element);
641             }
642         }
643         // update callback
644         self.unscheduleUpdateForTarget(target);
645     },
646 
647     /**
648      *  <p>
649      *      Unschedules all function callbacks from all targets. <br/>
650      *      You should NEVER call this method, unless you know what you are doing.
651      *  </p>
652      */
653     unscheduleAllCallbacks:function () {
654         this.unscheduleAllCallbacksWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM);
655     },
656 
657     /**
658      * <p>
659      *    Unschedules all function callbacks from all targets with a minimum priority.<br/>
660      *    You should only call this with kCCPriorityNonSystemMin or higher.
661      * </p>
662      * @param {Number} minPriority
663      */
664     unscheduleAllCallbacksWithMinPriority:function (minPriority) {
665         // Custom Selectors
666         var self = this, locArrayForTimers = self._arrayForTimers, locUpdates = self._updates;
667         for(var i = 0, li = locArrayForTimers.length; i < li; i++){
668             // element may be removed in unscheduleAllCallbacksForTarget
669             self.unscheduleAllCallbacksForTarget(locArrayForTimers[i].target);
670         }
671         for(var i = 2; i >= 0; i--){
672             if((i == 1 && minPriority > 0) || (i == 0 && minPriority >= 0)) continue;
673             var updates = locUpdates[i];
674             for(var j = 0, lj = updates.length; j < lj; j++){
675                 self.unscheduleUpdateForTarget(updates[j].target);
676             }
677         }
678     },
679 
680     /**
681      * <p>
682      *  Pause all selectors from all targets.<br/>
683      *  You should NEVER call this method, unless you know what you are doing.
684      * </p>
685      */
686     pauseAllTargets:function () {
687         return this.pauseAllTargetsWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM);
688     },
689 
690     /**
691      * Pause all selectors from all targets with a minimum priority. <br/>
692      * You should only call this with kCCPriorityNonSystemMin or higher.
693      * @param minPriority
694      */
695     pauseAllTargetsWithMinPriority:function (minPriority) {
696         var idsWithSelectors = [];
697 
698         var self = this, element, locArrayForTimers = self._arrayForTimers, locUpdates = self._updates;
699         // Custom Selectors
700         for(var i = 0, li = locArrayForTimers.length; i < li; i++){
701             element = locArrayForTimers[i];
702             if (element) {
703                 element.paused = true;
704                 idsWithSelectors.push(element.target);
705             }
706         }
707         for(var i = 0, li = locUpdates.length; i < li; i++){
708             var updates = locUpdates[i];
709             for(var j = 0, lj = updates.length; j < lj; j++){
710                 element = updates[j];
711                 if (element) {
712                     element.paused = true;
713                     idsWithSelectors.push(element.target);
714                 }
715             }
716         }
717         return idsWithSelectors;
718     },
719 
720     /**
721      * Resume selectors on a set of targets.<br/>
722      * This can be useful for undoing a call to pauseAllCallbacks.
723      * @param targetsToResume
724      */
725     resumeTargets:function (targetsToResume) {
726         if (!targetsToResume)
727             return;
728 
729         for (var i = 0; i < targetsToResume.length; i++) {
730             this.resumeTarget(targetsToResume[i]);
731         }
732     },
733 
734     /**
735      * <p>
736      *    Pauses the target.<br/>
737      *    All scheduled selectors/update for a given target won't be 'ticked' until the target is resumed.<br/>
738      *    If the target is not present, nothing happens.
739      * </p>
740      * @param {cc.Class} target
741      */
742     pauseTarget:function (target) {
743         if(!target)
744             throw "cc.Scheduler.pauseTarget():target should be non-null";
745 
746         //customer selectors
747         var self = this, element = self._hashForTimers[target.__instanceId];
748         if (element) {
749             element.paused = true;
750         }
751 
752         //update callback
753         var elementUpdate = self._hashForUpdates[target.__instanceId];
754         if (elementUpdate) {
755             elementUpdate.entry.paused = true;
756         }
757     },
758 
759     /**
760      * Resumes the target.<br/>
761      * The 'target' will be unpaused, so all schedule selectors/update will be 'ticked' again.<br/>
762      * If the target is not present, nothing happens.
763      * @param {cc.Class} target
764      */
765     resumeTarget:function (target) {
766         if(!target)
767             throw "cc.Scheduler.resumeTarget():target should be non-null";
768 
769         // custom selectors
770         var self = this, element = self._hashForTimers[target.__instanceId];
771 
772         if (element) {
773             element.paused = false;
774         }
775 
776         //update callback
777         var elementUpdate = self._hashForUpdates[target.__instanceId];
778 
779         if (elementUpdate) {
780             elementUpdate.entry.paused = false;
781         }
782     },
783 
784     /**
785      * Returns whether or not the target is paused
786      * @param {cc.Class} target
787      * @return {Boolean}
788      */
789     isTargetPaused:function (target) {
790         if(!target)
791             throw "cc.Scheduler.isTargetPaused():target should be non-null";
792 
793         // Custom selectors
794         var element = this._hashForTimers[target.__instanceId];
795         if (element) {
796             return element.paused;
797         }
798         return false;
799     }
800 });
801 /**
802  * Priority level reserved for system services.
803  * @constant
804  * @type Number
805  */
806 cc.Scheduler.PRIORITY_SYSTEM = (-2147483647 - 1);
807