/**
 * 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: 2009/02/08
 *
 * @author Blair Mitchelmore
 * @version 1.1.2
 *
 **/
;(function($) {

    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.event.special

    jQuery.extend({
        timer: {
            global: [],
            guid: 1,
            dataKey: "jQuery.timer",
            regex: /^([0-9]+(?:\.[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 = parseFloat(result[1]);
                    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;

                var timers = jQuery.data(element, this.dataKey) || jQuery.data(element, this.dataKey, {});

                if (!timers[label])
                    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 (!timers[label][fn.timerID])
                    timers[label][fn.timerID] = window.setInterval(handler,interval);

                this.global.push( element );

            },
            remove: function(element, label, fn) {
                var timers = jQuery.data(element, this.dataKey), 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 )
                        jQuery.removeData(element, this.dataKey);
                }
            }
        }

    });


    jQuery(window).bind("unload", function() {
        jQuery.each(jQuery.timer.global, function(index, item) {
            jQuery.timer.remove(item);
        });
    });
})(jQuery);

