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._callback, 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=arr.length-1; i>=0; i--){
731             element = arr[i];
732             this.unscheduleAllForTarget(element.target);
733         }
734 
735         // Updates selectors
736         var entry;
737         var temp_length = 0;
738         if(minPriority < 0){
739             for(i=0; i<this._updatesNegList.length; ){
740                 temp_length = this._updatesNegList.length;
741                 entry = this._updatesNegList[i];
742                 if(entry && entry.priority >= minPriority)
743                     this.unscheduleUpdate(entry.target);
744                 if (temp_length == this._updatesNegList.length)
745                     i++;
746             }
747         }
748 
749         if(minPriority <= 0){
750             for(i=0; i<this._updates0List.length; ){
751                 temp_length = this._updates0List.length;
752                 entry = this._updates0List[i];
753                 if (entry)
754                     this.unscheduleUpdate(entry.target);
755                 if (temp_length == this._updates0List.length)
756                     i++;
757             }
758         }
759 
760         for(i=0; i<this._updatesPosList.length; ){
761             temp_length = this._updatesPosList.length;
762             entry = this._updatesPosList[i];
763             if(entry && entry.priority >= minPriority)
764                 this.unscheduleUpdate(entry.target);
765             if (temp_length == this._updatesPosList.length)
766                 i++;
767         }
768     },
769 
770     isScheduled: function(key, target){
771         //key, target
772         //selector, target
773         cc.assert(key, "Argument key must not be empty");
774         cc.assert(target, "Argument target must be non-nullptr");
775 
776         var element = this._hashForUpdates[target.__instanceId];
777 
778         if (!element){
779             return false;
780         }
781 
782         if (element.timers == null){
783             return false;
784         }else{
785             var timers = element.timers;
786             for (var i = 0; i < timers.length; ++i){
787                 var timer =  timers[i];
788 
789                 if (key === timer.getKey()){
790                     return true;
791                 }
792             }
793             return false;
794         }
795     },
796 
797     /**
798      * <p>
799      *  Pause all selectors from all targets.<br/>
800      *  You should NEVER call this method, unless you know what you are doing.
801      * </p>
802      */
803     pauseAllTargets:function () {
804         return this.pauseAllTargetsWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM);
805     },
806 
807     /**
808      * Pause all selectors from all targets with a minimum priority. <br/>
809      * You should only call this with kCCPriorityNonSystemMin or higher.
810      * @param {Number} minPriority
811      */
812     pauseAllTargetsWithMinPriority:function (minPriority) {
813         var idsWithSelectors = [];
814 
815         var self = this, element, locArrayForTimers = self._arrayForTimers;
816         var i, li;
817         // Custom Selectors
818         for(i = 0, li = locArrayForTimers.length; i < li; i++){
819             element = locArrayForTimers[i];
820             if (element) {
821                 element.paused = true;
822                 idsWithSelectors.push(element.target);
823             }
824         }
825 
826         var entry;
827         if(minPriority < 0){
828             for(i=0; i<this._updatesNegList.length; i++){
829                 entry = this._updatesNegList[i];
830                 if (entry) {
831                     if(entry.priority >= minPriority){
832 						entry.paused = true;
833                         idsWithSelectors.push(entry.target);
834                     }
835                 }
836             }
837         }
838 
839         if(minPriority <= 0){
840             for(i=0; i<this._updates0List.length; i++){
841                 entry = this._updates0List[i];
842                 if (entry) {
843 					entry.paused = true;
844                     idsWithSelectors.push(entry.target);
845                 }
846             }
847         }
848 
849         for(i=0; i<this._updatesPosList.length; i++){
850             entry = this._updatesPosList[i];
851             if (entry) {
852                 if(entry.priority >= minPriority){
853 					entry.paused = true;
854                     idsWithSelectors.push(entry.target);
855                 }
856             }
857         }
858 
859         return idsWithSelectors;
860     },
861 
862     /**
863      * Resume selectors on a set of targets.<br/>
864      * This can be useful for undoing a call to pauseAllCallbacks.
865      * @param {Array} targetsToResume
866      */
867     resumeTargets:function (targetsToResume) {
868         if (!targetsToResume)
869             return;
870 
871         for (var i = 0; i < targetsToResume.length; i++) {
872             this.resumeTarget(targetsToResume[i]);
873         }
874     },
875 
876     /**
877      * <p>
878      *    Pauses the target.<br/>
879      *    All scheduled selectors/update for a given target won't be 'ticked' until the target is resumed.<br/>
880      *    If the target is not present, nothing happens.
881      * </p>
882      * @param {cc.Class} target
883      */
884     pauseTarget:function (target) {
885 
886         cc.assert(target, cc._LogInfos.Scheduler_pauseTarget);
887 
888         //customer selectors
889         var self = this, element = self._hashForTimers[target.__instanceId];
890         if (element) {
891             element.paused = true;
892         }
893 
894         //update callback
895         var elementUpdate = self._hashForUpdates[target.__instanceId];
896         if (elementUpdate) {
897             elementUpdate.entry.paused = true;
898         }
899     },
900 
901     /**
902      * Resumes the target.<br/>
903      * The 'target' will be unpaused, so all schedule selectors/update will be 'ticked' again.<br/>
904      * If the target is not present, nothing happens.
905      * @param {cc.Class} target
906      */
907     resumeTarget:function (target) {
908 
909         cc.assert(target, cc._LogInfos.Scheduler_resumeTarget);
910 
911         // custom selectors
912         var self = this, element = self._hashForTimers[target.__instanceId];
913 
914         if (element) {
915             element.paused = false;
916         }
917 
918         //update callback
919         var elementUpdate = self._hashForUpdates[target.__instanceId];
920 
921         if (elementUpdate) {
922             elementUpdate.entry.paused = false;
923         }
924     },
925 
926     /**
927      * Returns whether or not the target is paused
928      * @param {cc.Class} target
929      * @return {Boolean}
930      */
931     isTargetPaused:function (target) {
932 
933         cc.assert(target, cc._LogInfos.Scheduler_isTargetPaused);
934 
935         // Custom selectors
936         var element = this._hashForTimers[target.__instanceId];
937         if (element) {
938             return element.paused;
939         }
940         var elementUpdate = this._hashForUpdates[target.__instanceId];
941         if (elementUpdate) {
942             return elementUpdate.entry.paused;
943         }
944         return false;
945     },
946 
947     /**
948      * <p>
949      *    Schedules the 'update' callback_fn for a given target with a given priority.<br/>
950      *    The 'update' callback_fn will be called every frame.<br/>
951      *    The lower the priority, the earlier it is called.
952      * </p>
953      * @deprecated since v3.4 please use .scheduleUpdate
954      * @param {cc.Class} target
955      * @param {Number} priority
956      * @param {Boolean} paused
957      * @example
958      * //register this object to scheduler
959      * cc.director.getScheduler().scheduleUpdateForTarget(this, priority, !this._isRunning );
960      */
961     scheduleUpdateForTarget: function(target, priority, paused){
962         //cc.log("scheduleUpdateForTarget is deprecated. Please use scheduleUpdate.");
963         this.scheduleUpdate(target, priority, paused);
964     },
965 
966     /**
967      * <p>
968      *   Unschedule a callback function for a given target.<br/>
969      *   If you want to unschedule the "update", use unscheudleUpdateForTarget.
970      * </p>
971      * @deprecated since v3.4 please use .unschedule
972      * @param {cc.Class} target
973      * @param {function} callback callback[Function] or key[String]
974      * @example
975      * //unschedule a callback of target
976      * cc.director.getScheduler().unscheduleCallbackForTarget(function, this);
977      */
978     unscheduleCallbackForTarget:function (target, callback) {
979         //cc.log("unscheduleCallbackForTarget is deprecated. Please use unschedule.");
980         this.unschedule(callback, target);
981     },
982 
983     /**
984      * Unschedules the update callback function for a given target
985      * @param {cc.Class} target
986      * @deprecated since v3.4 please use .unschedule
987      * @example
988      * //unschedules the "update" method.
989      * cc.director.getScheduler().unscheduleUpdateForTarget(this);
990      */
991     unscheduleUpdateForTarget:function (target) {
992         //cc.log("unscheduleUpdateForTarget is deprecated. Please use unschedule.");
993         this.unscheduleUpdate(target);
994     },
995 
996     /**
997      * Unschedules all function callbacks for a given target. This also includes the "update" callback function.
998      * @deprecated since v3.4 please use .unscheduleAll
999      * @param {cc.Class} target
1000      */
1001     unscheduleAllCallbacksForTarget: function(target){
1002         //cc.log("unscheduleAllCallbacksForTarget is deprecated. Please use unscheduleAll.");
1003         this.unschedule(target.__instanceId + "", target);
1004     },
1005 
1006     /**
1007      *  <p>
1008      *      Unschedules all function callbacks from all targets. <br/>
1009      *      You should NEVER call this method, unless you know what you are doing.
1010      *  </p>
1011      * @deprecated since v3.4 please use .unscheduleAllWithMinPriority
1012      */
1013     unscheduleAllCallbacks: function(){
1014         //cc.log("unscheduleAllCallbacks is deprecated. Please use unscheduleAll.");
1015         this.unscheduleAllWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM);
1016     },
1017 
1018     /**
1019      * <p>
1020      *    Unschedules all function callbacks from all targets with a minimum priority.<br/>
1021      *    You should only call this with kCCPriorityNonSystemMin or higher.
1022      * </p>
1023      * @deprecated since v3.4 please use .unscheduleAllWithMinPriority
1024      * @param {Number} minPriority
1025      */
1026     unscheduleAllCallbacksWithMinPriority:function (minPriority) {
1027         //cc.log("unscheduleAllCallbacksWithMinPriority is deprecated. Please use unscheduleAllWithMinPriority.");
1028         this.unscheduleAllWithMinPriority(minPriority);
1029     }
1030 });
1031 /**
1032  * Priority level reserved for system services.
1033  * @constant
1034  * @type Number
1035  */
1036 cc.Scheduler.PRIORITY_SYSTEM = (-2147483647 - 1);
1037