// jquery.events.frame.js
// 1.1 - lite
// Stephen Band
// 
// Project home:
// webdev.stephband.info/events/frame/
//
// Source:
// http://github.com/stephband/jquery.event.frame

(function(jQuery, undefined){

var timer;

// Timer constructor
// fn - callback to call on each frame, with context set to the timer object
// fd - frame duration in milliseconds

function Timer( fn, fd ) {
    var self = this,
        clock;
    
    function update(){
        self.frameCount++;
        fn.call(self);
    }
    
    this.frameDuration = fd || 25 ;
    this.frameCount = -1 ;
    this.start = function(){
        update();
        clock = setInterval(update, this.frameDuration);
    };
    this.stop = function(){
        clearInterval( clock );
        clock = null;
    };
}

// callHandler() is the callback given to the timer object,
// it makes the event object and calls the handler
// context is the timer object

function callHandler(){
    var fn = jQuery.event.special.frame.handler,
        event = jQuery.Event("frame"),
        array = this.array,
        l = array.length;
    
    // Give event object properties
    event.frameCount = this.frameCount;
    
    // Call handler on each elem in array
    while (l--) {
        fn.call(array[l], event);
    }
}

if (!jQuery.event.special.frame) {
    jQuery.event.special.frame = {
        // Fires the first time an event is bound per element
        setup: function(data, namespaces) {
            if ( timer ) {
                timer.array.push(this);
            }
            else {
                timer = new Timer( callHandler, data && data.frameDuration );
                timer.array = [this];
                
                // Queue timer to start as soon as this thread has finished
                var t = setTimeout(function(){
                    timer.start();
                    clearTimeout(t);
                    t = null;
                }, 0);
            }
            return;
        },
        // Fires last time event is unbound per element
        teardown: function(namespaces) {
            var array = timer.array,
                l = array.length;
            
            // Remove element from list
            while (l--) {
                if (array[l] === this) {
                    array.splice(l, 1);
                    break;
                }
            }
            
            // Stop and remove timer when no elems left
            if (array.length === 0) {
                timer.stop();
                timer = undefined;
            }
            return;
        },
        handler: function(event){
            // let jQuery handle the calling of event handlers

            // In jQuery >= 1.9.0 jQuery.event.handle is remove, see:
            // http://jquery.com/upgrade-guide/1.9/#other-undocumented-properties-and-methods
            if (jQuery.event.handle) {
                jQuery.event.handle.apply(this, arguments);
            } else {
                jQuery.event.dispatch.apply(this, arguments);
            }
        }
    };
}

})(jQuery);