1 /****************************************************************************
  2  Copyright (c) 2008-2010 Ricardo Quesada
  3  Copyright (c) 2011-2012 cocos2d-x.org
  4  Copyright (c) 2013-2014 Chukong Technologies 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 //data structures
 36 /**
 37  * A list double-linked list used for "updates with priority"
 38  * @Class
 39  * @name cc.ListEntry
 40  * @param {cc.ListEntry} prev
 41  * @param {cc.ListEntry} next
 42  * @param {function} callback
 43  * @param {cc.Class} target not retained (retained by hashUpdateEntry)
 44  * @param {Number} priority
 45  * @param {Boolean} paused
 46  * @param {Boolean} markedForDeletion selector will no longer be called and entry will be removed at end of the next tick
 47  */
 48 cc.ListEntry = function (prev, next, callback, target, priority, paused, markedForDeletion) {
 49     this.prev = prev;
 50     this.next = next;
 51     this.callback = callback;
 52     this.target = target;
 53     this.priority = priority;
 54     this.paused = paused;
 55     this.markedForDeletion = markedForDeletion;
 56 };
 57 
 58 /**
 59  * A update entry list
 60  * @Class
 61  * @name cc.HashUpdateEntry
 62  * @param {Array} list Which list does it belong to ?
 63  * @param {cc.ListEntry} entry entry in the list
 64  * @param {cc.Class} target hash key (retained)
 65  * @param {function} callback
 66  * @param {Array} hh
 67  */
 68 cc.HashUpdateEntry = function (list, entry, target, callback, hh) {
 69     this.list = list;
 70     this.entry = entry;
 71     this.target = target;
 72     this.callback = callback;
 73     this.hh = hh;
 74 };
 75 
 76 //
 77 /**
 78  * Hash Element used for "selectors with interval"
 79  * @Class
 80  * @param {Array} timers
 81  * @param {cc.Class} target  hash key (retained)
 82  * @param {Number} timerIndex
 83  * @param {cc.Timer} currentTimer
 84  * @param {Boolean} currentTimerSalvaged
 85  * @param {Boolean} paused
 86  * @param {Array} hh
 87  */
 88 cc.HashTimerEntry = cc.hashSelectorEntry = function (timers, target, timerIndex, currentTimer, currentTimerSalvaged, paused, hh) {
 89     var _t = this;
 90     _t.timers = timers;
 91     _t.target = target;
 92     _t.timerIndex = timerIndex;
 93     _t.currentTimer = currentTimer;
 94     _t.currentTimerSalvaged = currentTimerSalvaged;
 95     _t.paused = paused;
 96     _t.hh = hh;
 97 };
 98 
 99 /**
100  * Light weight timer
101  * @class
102  * @extends cc.Class
103  */
104 cc.Timer = cc.Class.extend(/** @lends cc.Timer# */{
105     _scheduler: null,
106     _elapsed:0.0,
107     _runForever:false,
108     _useDelay:false,
109     _timesExecuted:0,
110     _repeat:0, //0 = once, 1 is 2 x executed
111     _delay:0,
112     _interval:0.0,
113 
114     /**
115      * @return {Number} returns interval of timer
116      */
117     getInterval : function(){return this._interval;},
118     /**
119      * @param {Number} interval set interval in seconds
120      */
121     setInterval : function(interval){this._interval = interval;},
122 
123     setupTimerWithInterval: function(seconds, repeat, delay){
124         this._elapsed = -1;
125         this._interval = seconds;
126         this._delay = delay;
127         this._useDelay = (this._delay > 0);
128         this._repeat = repeat;
129         this._runForever = (this._repeat === cc.REPEAT_FOREVER);
130     },
131 
132     trigger: function(){
133         return 0;
134     },
135 
136     cancel: function(){
137         return 0;
138     },
139 
140     /**
141      * cc.Timer's Constructor
142      * Constructor of cc.Timer
143      */
144     ctor:function () {
145         this._scheduler = null;
146         this._elapsed = -1;
147         this._runForever = false;
148         this._useDelay = false;
149         this._timesExecuted = 0;
150         this._repeat = 0;
151         this._delay = 0;
152         this._interval = 0;
153     },
154 
155     /**
156      * triggers the timer
157      * @param {Number} dt delta time
158      */
159     update:function (dt) {
160         if (this._elapsed === -1) {
161             this._elapsed = 0;
162             this._timesExecuted = 0;
163         } else {
164             this._elapsed += dt;
165             if (this._runForever && !this._useDelay) {//standard timer usage
166                 if (this._elapsed >= this._interval) {
167                     this.trigger();
168                     this._elapsed = 0;
169                 }
170             } else {//advanced usage
171                 if (this._useDelay) {
172                     if (this._elapsed >= this._delay) {
173                         this.trigger();
174 
175                         this._elapsed -= this._delay;
176                         this._timesExecuted += 1;
177                         this._useDelay = false;
178                     }
179                 } else {
180                     if (this._elapsed >= this._interval) {
181                         this.trigger();
182 
183                         this._elapsed = 0;
184                         this._timesExecuted += 1;
185                     }
186                 }
187 
188                 if (!this._runForever && this._timesExecuted > this._repeat)
189                     this.cancel();
190             }
191         }
192     }
193 });
194 
195 cc.TimerTargetSelector = cc.Timer.extend({
196     _target: null,
197     _selector: null,
198 
199     ctor: function(){
200         this._target = null;
201         this._selector = null;
202     },
203 
204     initWithSelector: function(scheduler, selector, target, seconds, repeat, delay){
205         this._scheduler = scheduler;
206         this._target = target;
207         this._selector = selector;
208         this.setupTimerWithInterval(seconds, repeat, delay);
209         return true;
210     },
211 
212     getSelector: function(){
213         return this._selector;
214     },
215 
216     trigger: function(){
217         //override
218         if (this._target && this._selector){
219             this._target.call(this._selector, this._elapsed);
220         }
221     },
222 
223     cancel: function(){
224         //override
225         this._scheduler.unschedule(this._selector, this._target);
226     }
227 
228 });
229 
230 cc.TimerTargetCallback = cc.Timer.extend({
231 
232     _target: null,
233     _callback: null,
234     _key: null,
235 
236     ctor: function(){
237         this._target = null;
238         this._callback = null;
239     },
240 
241     initWithCallback: function(scheduler, callback, target, key, seconds, repeat, delay){
242         this._scheduler = scheduler;
243         this._target = target;
244         this._callback = callback;
245         this._key = key;
246         this.setupTimerWithInterval(seconds, repeat, delay);
247         return true;
248     },
249 
250     getCallback: function(){
251         return this._callback;
252     },
253 
254     getKey: function(){
255         return this._key;
256     },
257 
258     trigger: function(){
259         //override
260         if(this._callback)
261             this._callback.call(this._target, this._elapsed);
262     },
263 
264     cancel: function(){
265         //override
266         this._scheduler.unschedule(this._key, this._target);
267     }
268 
269 });
270 
271 /**
272  * <p>
273  *    Scheduler is responsible of triggering the scheduled callbacks.<br/>
274  *    You should not use NSTimer. Instead use this class.<br/>
275  *    <br/>
276  *    There are 2 different types of callbacks (selectors):<br/>
277  *       - update callback: the 'update' callback will be called every frame. You can customize the priority.<br/>
278  *       - custom callback: A custom callback will be called every frame, or with a custom interval of time<br/>
279  *       <br/>
280  *    The 'custom selectors' should be avoided when possible. It is faster, and consumes less memory to use the 'update callback'. *
281  * </p>
282  * @class
283  * @extends cc.Class
284  *
285  * @example
286  * //register a schedule to scheduler
287  * cc.director.getScheduler().schedule(callback, this, interval, !this._isRunning);
288  */
289 cc.Scheduler = cc.Class.extend(/** @lends cc.Scheduler# */{
290     _timeScale:1.0,
291 
292     //_updates : null, //_updates[0] list of priority < 0, _updates[1] list of priority == 0, _updates[2] list of priority > 0,
293     _updatesNegList: null,
294     _updates0List: null,
295     _updatesPosList: null,
296 
297     _hashForTimers:null, //Used for "selectors with interval"
298     _arrayForTimers:null, //Speed up indexing
299     _hashForUpdates:null, // hash used to fetch quickly the list entries for pause,delete,etc
300     //_arrayForUpdates:null, //Speed up indexing
301 
302     _currentTarget:null,
303     _currentTargetSalvaged:false,
304     _updateHashLocked:false, //If true unschedule will not remove anything from a hash. Elements will only be marked for deletion.
305 
306 
307     ctor:function () {
308         this._timeScale = 1.0;
309         this._updatesNegList = [];
310         this._updates0List = [];
311         this._updatesPosList = [];
312 
313         this._hashForUpdates = {};
314         this._hashForTimers = {};
315         this._currentTarget = null;
316         this._currentTargetSalvaged = false;
317         this._updateHashLocked = false;
318 
319         this._arrayForTimers = [];
320         //this._arrayForUpdates = [];
321 
322     },
323 
324     //-----------------------private method----------------------
325 
326     _schedulePerFrame: function(callback, target, priority, paused){
327         var hashElement = this._hashForUpdates[target.__instanceId];
328         if (hashElement && hashElement.entry){
329             // check if priority has changed
330             if (hashElement.entry.priority !== priority){
331                 if (this._updateHashLocked){
332                     cc.log("warning: you CANNOT change update priority in scheduled function");
333                     hashElement.entry.markedForDeletion = false;
334                     hashElement.entry.paused = paused;
335                     return;
336                 }else{
337                     // will be added again outside if (hashElement).
338                     this.unscheduleUpdate(target);
339                 }
340             }else{
341                 hashElement.entry.markedForDeletion = false;
342                 hashElement.entry.paused = paused;
343                 return;
344             }
345         }
346 
347         // most of the updates are going to be 0, that's way there
348         // is an special list for updates with priority 0
349         if (priority === 0){
350             this._appendIn(this._updates0List, callback, target, paused);
351         }else if (priority < 0){
352             this._priorityIn(this._updatesNegList, callback, target, priority, paused);
353         }else{
354             // priority > 0
355             this._priorityIn(this._updatesPosList, callback, target, priority, paused);
356         }
357     },
358 
359     _removeHashElement:function (element) {
360         delete this._hashForTimers[element.target.__instanceId];
361         cc.arrayRemoveObject(this._arrayForTimers, element);
362         element.Timer = null;
363         element.target = null;
364         element = null;
365     },
366 
367     _removeUpdateFromHash:function (entry) {
368         var self = this, element = self._hashForUpdates[entry.target.__instanceId];
369         if (element) {
370             //list entry
371             cc.arrayRemoveObject(element.list, element.entry);
372 
373             delete self._hashForUpdates[element.target.__instanceId];
374             //cc.arrayRemoveObject(self._hashForUpdates, element);
375             element.entry = null;
376 
377             //hash entry
378             element.target = null;
379         }
380     },
381 
382     _priorityIn:function (ppList, callback,  target, priority, paused) {
383         var self = this,
384             listElement = new cc.ListEntry(null, null, callback, target, priority, paused, false);
385 
386         // empey list ?
387         if (!ppList) {
388             ppList = [];
389             ppList.push(listElement);
390         } else {
391             var index2Insert = ppList.length - 1;
392             for(var i = 0; i <= index2Insert; i++){
393                 if (priority < ppList[i].priority) {
394                     index2Insert = i;
395                     break;
396                 }
397             }
398             ppList.splice(i, 0, listElement);
399         }
400 
401         //update hash entry for quick access
402         self._hashForUpdates[target.__instanceId] = new cc.HashUpdateEntry(ppList, listElement, target, null);
403 
404         return ppList;
405     },
406 
407     _appendIn:function (ppList, callback, target, paused) {
408         var self = this, listElement = new cc.ListEntry(null, null, callback, target, 0, paused, false);
409         ppList.push(listElement);
410 
411         //update hash entry for quicker access
412         self._hashForUpdates[target.__instanceId] = new cc.HashUpdateEntry(ppList, listElement, target, null, null);
413     },
414 
415     //-----------------------public method-------------------------
416     /**
417      * <p>
418      *    Modifies the time of all scheduled callbacks.<br/>
419      *    You can use this property to create a 'slow motion' or 'fast forward' effect.<br/>
420      *    Default is 1.0. To create a 'slow motion' effect, use values below 1.0.<br/>
421      *    To create a 'fast forward' effect, use values higher than 1.0.<br/>
422      *    @warning It will affect EVERY scheduled selector / action.
423      * </p>
424      * @param {Number} timeScale
425      */
426     setTimeScale:function (timeScale) {
427         this._timeScale = timeScale;
428     },
429 
430     /**
431      * Returns time scale of scheduler
432      * @return {Number}
433      */
434     getTimeScale:function () {
435         return this._timeScale;
436     },
437 
438     /**
439      * 'update' the scheduler. (You should NEVER call this method, unless you know what you are doing.)
440      * @param {Number} dt delta time
441      */
442     update:function (dt) {
443         this._updateHashLocked = true;
444         if(this._timeScale !== 1)
445             dt *= this._timeScale;
446 
447         var i, list, len, entry;
448 
449         for(i=0,list=this._updatesNegList, len = list.length; i<len; i++){
450             entry = list[i];
451             if(!entry.paused && !entry.markedForDeletion)
452                 entry.callback(dt);
453         }
454 
455         for(i=0, list=this._updates0List, len=list.length; i<len; i++){
456             entry = list[i];
457             if (!entry.paused && !entry.markedForDeletion)
458                 entry.callback(dt);
459         }
460 
461         for(i=0, list=this._updatesPosList, len=list.length; i<len; i++){
462             entry = list[i];
463             if (!entry.paused && !entry.markedForDeletion)
464                 entry.callback(dt);
465         }
466 
467         // Iterate over all the custom selectors
468         var elt, arr = this._arrayForTimers;
469         for(i=0; i<arr.length; i++){
470             elt = arr[i];
471             this._currentTarget = elt;
472             this._currentTargetSalvaged = false;
473 
474             if (!elt.paused){
475                 // The 'timers' array may change while inside this loop
476                 for (elt.timerIndex = 0; elt.timerIndex < elt.timers.length; ++(elt.timerIndex)){
477                     elt.currentTimer = elt.timers[elt.timerIndex];
478                     elt.currentTimerSalvaged = false;
479 
480                     elt.currentTimer.update(dt);
481                     elt.currentTimer = null;
482                 }
483             }
484 
485             // elt, at this moment, is still valid
486             // so it is safe to ask this here (issue #490)
487             //elt = elt.hh.next;
488 
489             // only delete currentTarget if no actions were scheduled during the cycle (issue #481)
490             if (this._currentTargetSalvaged && this._currentTarget.timers.length === 0)
491                 this._removeHashElement(this._currentTarget);
492         }
493 
494         // delete all updates that are marked for deletion
495         // updates with priority < 0
496         for(i=0,list=this._updatesNegList; i<list.length; ){
497             entry = list[i];
498             if(entry.markedForDeletion)
499                 this._removeUpdateFromHash(entry);
500             else
501                 i++;
502         }
503 
504         for(i=0, list=this._updates0List; i<list.length; ){
505             entry = list[i];
506             if (entry.markedForDeletion)
507                 this._removeUpdateFromHash(entry);
508             else
509                 i++;
510         }
511 
512         for(i=0, list=this._updatesPosList; i<list.length; ){
513             entry = list[i];
514             if (entry.markedForDeletion)
515                 this._removeUpdateFromHash(entry);
516             else
517                 i++;
518         }
519 
520         this._updateHashLocked = false;
521         this._currentTarget = null;
522     },
523 
524     /**
525      * <p>
526      *   The scheduled method will be called every 'interval' seconds.</br>
527      *   If paused is YES, then it won't be called until it is resumed.<br/>
528      *   If 'interval' is 0, it will be called every frame, but if so, it recommended to use 'scheduleUpdateForTarget:' instead.<br/>
529      *   If the callback function is already scheduled, then only the interval parameter will be updated without re-scheduling it again.<br/>
530      *   repeat let the action be repeated repeat + 1 times, use cc.REPEAT_FOREVER to let the action run continuously<br/>
531      *   delay is the amount of time the action will wait before it'll start<br/>
532      * </p>
533      * @deprecated since v3.4 please use .schedule
534      * @param {cc.Class} target
535      * @param {function} callback_fn
536      * @param {Number} interval
537      * @param {Number} repeat
538      * @param {Number} delay
539      * @param {Boolean} paused
540      * @example
541      * //register a schedule to scheduler
542      * cc.director.getScheduler().scheduleCallbackForTarget(this, function, interval, repeat, delay, !this._isRunning );
543      */
544     scheduleCallbackForTarget: function(target, callback_fn, interval, repeat, delay, paused){
545         //cc.log("scheduleCallbackForTarget is deprecated. Please use schedule.");
546         this.schedule(callback_fn, target, interval, repeat, delay, paused, target.__instanceId + "");
547     },
548 
549     schedule: function(callback, target, interval, repeat, delay, paused, key){
550         var isSelector = false;
551         if(typeof callback !== "function"){
552             var selector = callback;
553             isSelector = true;
554         }
555 
556         if(isSelector === false){
557             //callback, target, interval, repeat, delay, paused, key
558             //callback, target, interval, paused, key
559             if(arguments.length === 5){
560                 key = delay;
561                 paused = repeat;
562                 delay = 0;
563                 repeat = cc.REPEAT_FOREVER;
564             }
565         }else{
566             //selector, target, interval, repeat, delay, paused
567             //selector, target, interval, paused
568             if(arguments.length === 4){
569                 paused = repeat;
570                 repeat = cc.REPEAT_FOREVER;
571                 delay = 0;
572             }
573         }
574 
575         cc.assert(target, cc._LogInfos.Scheduler_scheduleCallbackForTarget_3);
576         if(isSelector === false)
577             cc.assert(key, "key should not be empty!");
578 
579         var element = this._hashForTimers[target.__instanceId];
580 
581         if(!element){
582             // Is this the 1st element ? Then set the pause level to all the callback_fns of this target
583             element = new cc.HashTimerEntry(null, target, 0, null, null, paused, null);
584             this._arrayForTimers.push(element);
585             this._hashForTimers[target.__instanceId] = element;
586         }else{
587             cc.assert(element.paused === paused, "");
588         }
589 
590         var timer, i;
591         if (element.timers == null) {
592             element.timers = [];
593         } else if(isSelector === false) {
594             for (i = 0; i < element.timers.length; i++) {
595                 timer = element.timers[i];
596                 if (callback === timer._callback) {
597                     cc.log(cc._LogInfos.Scheduler_scheduleCallbackForTarget, timer.getInterval().toFixed(4), interval.toFixed(4));
598                     timer._interval = interval;
599                     return;
600                 }
601             }
602         }else{
603             for (i = 0; i < element.timers.length; ++i){
604                 timer =element.timers[i];
605                 if (timer && selector === timer.getSelector()){
606                     cc.log("CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: %.4f to %.4f", timer.getInterval(), interval);
607                     timer.setInterval(interval);
608                     return;
609                 }
610             }
611             //ccArrayEnsureExtraCapacity(element->timers, 1);
612         }
613 
614         if(isSelector === false){
615             timer = new cc.TimerTargetCallback();
616             timer.initWithCallback(this, callback, target, key, interval, repeat, delay);
617             element.timers.push(timer);
618         }else{
619             timer = new cc.TimerTargetSelector();
620             timer.initWithSelector(this, selector, target, interval, repeat, delay);
621             element.timers.push(timer);
622         }
623     },
624 
625     scheduleUpdate: function(target, priority, paused){
626         this._schedulePerFrame(function(dt){
627             target.update(dt);
628         }, target, priority, paused);
629     },
630 
631     _getUnscheduleMark: function(key, timer){
632         //key, callback, selector
633         switch (typeof key){
634             case "number":
635             case "string":
636                 return key === timer.getKey();
637             case "function":
638                 return key === timer._callback;
639             default:
640                 return key === timer.getSelector();
641         }
642     },
643     unschedule: function(key, target){
644         //key, target
645         //selector, target
646         //callback, target - This is in order to increase compatibility
647 
648         // explicity handle nil arguments when removing an object
649         if (!target || !key)
650             return;
651 
652         var self = this, element = self._hashForTimers[target.__instanceId];
653         if (element) {
654             var timers = element.timers;
655             for(var i = 0, li = timers.length; i < li; i++){
656                 var timer = timers[i];
657                 if (this._getUnscheduleMark(key, timer)) {
658                     if ((timer === element.currentTimer) && (!element.currentTimerSalvaged)) {
659                         element.currentTimerSalvaged = true;
660                     }
661                     timers.splice(i, 1);
662                     //update timerIndex in case we are in tick;, looping over the actions
663                     if (element.timerIndex >= i) {
664                         element.timerIndex--;
665                     }
666 
667                     if (timers.length === 0) {
668                         if (self._currentTarget === element) {
669                             self._currentTargetSalvaged = true;
670                         } else {
671                             self._removeHashElement(element);
672                         }
673                     }
674                     return;
675                 }
676             }
677         }
678     },
679 
680     unscheduleUpdate: function(target){
681         if (target == null)
682             return;
683 
684         var element = this._hashForUpdates[target.__instanceId];
685 
686         if (element){
687             if (this._updateHashLocked){
688                 element.entry.markedForDeletion = true;
689             }else{
690                 this._removeUpdateFromHash(element.entry);
691             }
692         }
693     },
694 
695     unscheduleAllForTarget: function(target){
696         // explicit nullptr handling
697         if (target == null){
698             return;
699         }
700 
701         // Custom Selectors
702         var element = this._hashForTimers[target.__instanceId];
703 
704         if (element){
705             if (element.timers.indexOf(element.currentTimer) > -1
706                 && (! element.currentTimerSalvaged)){
707                 element.currentTimerSalvaged = true;
708             }
709             //        ccArrayRemoveAllObjects(element.timers);
710             element.timers.length = 0;
711 
712             if (this._currentTarget === element){
713                 this._currentTargetSalvaged = true;
714             }else{
715                 this._removeHashElement(element);
716             }
717         }
718 
719         // update selector
720         this.unscheduleUpdate(target);
721     },
722 
723     unscheduleAll: function(){
724         this.unscheduleAllWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM);
725     },
726 
727     unscheduleAllWithMinPriority: function(minPriority){
728         // Custom Selectors
729         var i, element, arr = this._arrayForTimers;
730         for(i=0; i<arr.length; i++){
731             element = arr[i];
732             this.unscheduleAllForTarget(element.target);
733         }
734 
735         // Updates selectors
736         var entry;
737         if(minPriority < 0){
738             for(i=0; i<this._updatesNegList.length; i++){
739                 entry = this._updatesNegList[i];
740                 if (entry) {
741                     if(entry.priority >= minPriority){
742                         this.unscheduleUpdate(entry.target);
743                     }
744                 }
745             }
746         }
747 
748         if(minPriority <= 0){
749             for(i=0; i<this._updates0List.length; i++){
750                 entry = this._updates0List[i];
751                 if (entry) {
752                     this.unscheduleUpdate(entry.target);
753                 }
754             }
755         }
756 
757         for(i=0; i<this._updatesPosList.length; i++){
758             entry = this._updatesPosList[i];
759             if (entry) {
760                 if(entry.priority >= minPriority)
761                 {
762                     this.unscheduleUpdate(entry.target);
763                 }
764             }
765         }
766     },
767 
768     isScheduled: function(key, target){
769         //key, target
770         //selector, target
771         cc.assert(key, "Argument key must not be empty");
772         cc.assert(target, "Argument target must be non-nullptr");
773 
774         var element = this._hashForUpdates[target.__instanceId];
775 
776         if (!element){
777             return false;
778         }
779 
780         if (element.timers == null){
781             return false;
782         }else{
783             var timers = element.timers;
784             for (var i = 0; i < timers.length; ++i){
785                 var timer =  timers[i];
786 
787                 if (key === timer.getKey()){
788                     return true;
789                 }
790             }
791             return false;
792         }
793     },
794 
795     /**
796      * <p>
797      *  Pause all selectors from all targets.<br/>
798      *  You should NEVER call this method, unless you know what you are doing.
799      * </p>
800      */
801     pauseAllTargets:function () {
802         return this.pauseAllTargetsWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM);
803     },
804 
805     /**
806      * Pause all selectors from all targets with a minimum priority. <br/>
807      * You should only call this with kCCPriorityNonSystemMin or higher.
808      * @param {Number} minPriority
809      */
810     pauseAllTargetsWithMinPriority:function (minPriority) {
811         var idsWithSelectors = [];
812 
813         var self = this, element, locArrayForTimers = self._arrayForTimers;
814         var i, li;
815         // Custom Selectors
816         for(i = 0, li = locArrayForTimers.length; i < li; i++){
817             element = locArrayForTimers[i];
818             if (element) {
819                 element.paused = true;
820                 idsWithSelectors.push(element.target);
821             }
822         }
823 
824         var entry;
825         if(minPriority < 0){
826             for(i=0; i<this._updatesNegList.length; i++){
827                 entry = this._updatesNegList[i];
828                 if (entry) {
829                     if(entry.priority >= minPriority){
830                         element.paused = true;
831                         idsWithSelectors.push(element.target);
832                     }
833                 }
834             }
835         }
836 
837         if(minPriority <= 0){
838             for(i=0; i<this._updates0List.length; i++){
839                 entry = this._updates0List[i];
840                 if (entry) {
841                     element.paused = true;
842                     idsWithSelectors.push(element.target);
843                 }
844             }
845         }
846 
847         for(i=0; i<this._updatesPosList.length; i++){
848             entry = this._updatesPosList[i];
849             if (entry) {
850                 if(entry.priority >= minPriority){
851                     element.paused = true;
852                     idsWithSelectors.push(element.target);
853                 }
854             }
855         }
856 
857         return idsWithSelectors;
858     },
859 
860     /**
861      * Resume selectors on a set of targets.<br/>
862      * This can be useful for undoing a call to pauseAllCallbacks.
863      * @param {Array} targetsToResume
864      */
865     resumeTargets:function (targetsToResume) {
866         if (!targetsToResume)
867             return;
868 
869         for (var i = 0; i < targetsToResume.length; i++) {
870             this.resumeTarget(targetsToResume[i]);
871         }
872     },
873 
874     /**
875      * <p>
876      *    Pauses the target.<br/>
877      *    All scheduled selectors/update for a given target won't be 'ticked' until the target is resumed.<br/>
878      *    If the target is not present, nothing happens.
879      * </p>
880      * @param {cc.Class} target
881      */
882     pauseTarget:function (target) {
883 
884         cc.assert(target, cc._LogInfos.Scheduler_pauseTarget);
885 
886         //customer selectors
887         var self = this, element = self._hashForTimers[target.__instanceId];
888         if (element) {
889             element.paused = true;
890         }
891 
892         //update callback
893         var elementUpdate = self._hashForUpdates[target.__instanceId];
894         if (elementUpdate) {
895             elementUpdate.entry.paused = true;
896         }
897     },
898 
899     /**
900      * Resumes the target.<br/>
901      * The 'target' will be unpaused, so all schedule selectors/update will be 'ticked' again.<br/>
902      * If the target is not present, nothing happens.
903      * @param {cc.Class} target
904      */
905     resumeTarget:function (target) {
906 
907         cc.assert(target, cc._LogInfos.Scheduler_resumeTarget);
908 
909         // custom selectors
910         var self = this, element = self._hashForTimers[target.__instanceId];
911 
912         if (element) {
913             element.paused = false;
914         }
915 
916         //update callback
917         var elementUpdate = self._hashForUpdates[target.__instanceId];
918 
919         if (elementUpdate) {
920             elementUpdate.entry.paused = false;
921         }
922     },
923 
924     /**
925      * Returns whether or not the target is paused
926      * @param {cc.Class} target
927      * @return {Boolean}
928      */
929     isTargetPaused:function (target) {
930 
931         cc.assert(target, cc._LogInfos.Scheduler_isTargetPaused);
932 
933         // Custom selectors
934         var element = this._hashForTimers[target.__instanceId];
935         if (element) {
936             return element.paused;
937         }
938         var elementUpdate = this._hashForUpdates[target.__instanceId];
939         if (elementUpdate) {
940             return elementUpdate.entry.paused;
941         }
942         return false;
943     },
944 
945     /**
946      * <p>
947      *    Schedules the 'update' callback_fn for a given target with a given priority.<br/>
948      *    The 'update' callback_fn will be called every frame.<br/>
949      *    The lower the priority, the earlier it is called.
950      * </p>
951      * @deprecated since v3.4 please use .scheduleUpdate
952      * @param {cc.Class} target
953      * @param {Number} priority
954      * @param {Boolean} paused
955      * @example
956      * //register this object to scheduler
957      * cc.director.getScheduler().scheduleUpdateForTarget(this, priority, !this._isRunning );
958      */
959     scheduleUpdateForTarget: function(target, priority, paused){
960         //cc.log("scheduleUpdateForTarget is deprecated. Please use scheduleUpdate.");
961         this.scheduleUpdate(target, priority, paused);
962     },
963 
964     /**
965      * <p>
966      *   Unschedule a callback function for a given target.<br/>
967      *   If you want to unschedule the "update", use unscheudleUpdateForTarget.
968      * </p>
969      * @deprecated since v3.4 please use .unschedule
970      * @param {cc.Class} target
971      * @param {function} callback callback[Function] or key[String]
972      * @example
973      * //unschedule a callback of target
974      * cc.director.getScheduler().unscheduleCallbackForTarget(function, this);
975      */
976     unscheduleCallbackForTarget:function (target, callback) {
977         //cc.log("unscheduleCallbackForTarget is deprecated. Please use unschedule.");
978         this.unschedule(callback, target);
979     },
980 
981     /**
982      * Unschedules the update callback function for a given target
983      * @param {cc.Class} target
984      * @deprecated since v3.4 please use .unschedule
985      * @example
986      * //unschedules the "update" method.
987      * cc.director.getScheduler().unscheduleUpdateForTarget(this);
988      */
989     unscheduleUpdateForTarget:function (target) {
990         //cc.log("unscheduleUpdateForTarget is deprecated. Please use unschedule.");
991         this.unscheduleUpdate(target);
992     },
993 
994     /**
995      * Unschedules all function callbacks for a given target. This also includes the "update" callback function.
996      * @deprecated since v3.4 please use .unscheduleAll
997      * @param {cc.Class} target
998      */
999     unscheduleAllCallbacksForTarget: function(target){
1000         //cc.log("unscheduleAllCallbacksForTarget is deprecated. Please use unscheduleAll.");
1001         this.unschedule(target.__instanceId + "", target);
1002     },
1003 
1004     /**
1005      *  <p>
1006      *      Unschedules all function callbacks from all targets. <br/>
1007      *      You should NEVER call this method, unless you know what you are doing.
1008      *  </p>
1009      * @deprecated since v3.4 please use .unscheduleAllWithMinPriority
1010      */
1011     unscheduleAllCallbacks: function(){
1012         //cc.log("unscheduleAllCallbacks is deprecated. Please use unscheduleAll.");
1013         this.unscheduleAllWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM);
1014     },
1015 
1016     /**
1017      * <p>
1018      *    Unschedules all function callbacks from all targets with a minimum priority.<br/>
1019      *    You should only call this with kCCPriorityNonSystemMin or higher.
1020      * </p>
1021      * @deprecated since v3.4 please use .unscheduleAllWithMinPriority
1022      * @param {Number} minPriority
1023      */
1024     unscheduleAllCallbacksWithMinPriority:function (minPriority) {
1025         //cc.log("unscheduleAllCallbacksWithMinPriority is deprecated. Please use unscheduleAllWithMinPriority.");
1026         this.unscheduleAllWithMinPriority(minPriority);
1027     }
1028 });
1029 /**
1030  * Priority level reserved for system services.
1031  * @constant
1032  * @type Number
1033  */
1034 cc.Scheduler.PRIORITY_SYSTEM = (-2147483647 - 1);
1035