/**
 * jQuery.timers - Timer abstractions for jQuery
 * Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com)
 * Licensed under the WTFPL (http://sam.zoy.org/wtfpl/).
 * Date: 2008/08/26
 *
 * @author Blair Mitchelmore
 * @version 1.0.0
 *
 **/

jQuery.fn.extend({
   everyTime: function(interval, label, fn, times, belay) {
      return this.each(function() {
         jQuery.timer.add(this, interval, label, fn, times, belay);
      });
   },
   oneTime: function(interval, label, fn) {
      return this.each(function() {
         jQuery.timer.add(this, interval, label, fn, 1);
      });
   },
   stopTime: function(label, fn) {
      return this.each(function() {
         jQuery.timer.remove(this, label, fn);
      });
   }
});

jQuery.extend({
   timer: {
      guid: 1,
      global: {},
      regex: /^([0-9]+)\s*(.*s)?$/,
      powers: {
         // Yeah this is major overkill...
         'ms': 1,
         'cs': 10,
         'ds': 100,
         's': 1000,
         'das': 10000,
         'hs': 100000,
         'ks': 1000000
      },
      timeParse: function(value) {
         if (value == undefined || value == null)
            return null;
         var result = this.regex.exec(jQuery.trim(value.toString()));
         if (result[2]) {
            var num = parseInt(result[1], 10);
            var mult = this.powers[result[2]] || 1;
            return num * mult;
         } else {
            return value;
         }
      },
      add: function(element, interval, label, fn, times, belay) {
         var counter = 0;
         
         if (jQuery.isFunction(label)) {
            if (!times) 
               times = fn;
            fn = label;
            label = interval;
         }
         
         interval = jQuery.timer.timeParse(interval);

         if (typeof interval != 'number' || isNaN(interval) || interval <= 0)
            return;

         if (times && times.constructor != Number) {
            belay = !!times;
            times = 0;
         }
         
         times = times || 0;
         belay = belay || false;
         
         if (!element.$timers) 
            element.$timers = {};
         
         if (!element.$timers[label])
            element.$timers[label] = {};
         
         fn.$timerID = fn.$timerID || this.guid++;
         
         var handler = function() {
            if (belay && this.inProgress) 
               return;
            this.inProgress = true;
            if ((++counter > times && times !== 0) || fn.call(element, counter) === false)
               jQuery.timer.remove(element, label, fn);
            this.inProgress = false;
         };
         
         handler.$timerID = fn.$timerID;
         
         if (!element.$timers[label][fn.$timerID]) 
            element.$timers[label][fn.$timerID] = window.setInterval(handler,interval);
         
         if ( !this.global[label] )
            this.global[label] = [];
         this.global[label].push( element );
         
      },
      remove: function(element, label, fn) {
         var timers = element.$timers, ret;
         
         if ( timers ) {
            
            if (!label) {
               for ( label in timers )
                  this.remove(element, label, fn);
            } else if ( timers[label] ) {
               if ( fn ) {
                  if ( fn.$timerID ) {
                     window.clearInterval(timers[label][fn.$timerID]);
                     delete timers[label][fn.$timerID];
                  }
               } else {
                  for ( var fn in timers[label] ) {
                     window.clearInterval(timers[label][fn]);
                     delete timers[label][fn];
                  }
               }
               
               for ( ret in timers[label] ) break;
               if ( !ret ) {
                  ret = null;
                  delete timers[label];
               }
            }
            
            for ( ret in timers ) break;
            if ( !ret ) 
               element.$timers = null;
         }
      }
   }
});

if (jQuery.browser.msie)
   jQuery(window).one("unload", function() {
      var global = jQuery.timer.global;
      for ( var label in global ) {
         var els = global[label], i = els.length;
         while ( --i )
            jQuery.timer.remove(els[i], label);
      }
   });

