﻿
﻿/*
Ticker plugin
*/

(function($){
    
    /* PLUGIN IMPLEMENTATION/DEFINITION */
    
    var plugin = $.fn.ticker = function(options){
        var options = $.extend({}, $.fn.ticker.defaults, options);
        options.defaults = $.fn.ticker.defaults;
        
        options._items = options._this = this;
        options._items.not(":first").hide();
        
        options._startTicker.apply(options._this, Array(options));
        
        options.mouseOverElements.hover(function(){
            $(this).addClass(options._hoverClass);
            options._stopTicker.apply(options._this, Array(options));
        }, function(){
            $(this).removeClass(options._hoverClass);
            options._startTicker.apply(options._this, Array(options));
        });
        
        return options; // not chainable but otherwise how to get options? :/
    };
    
    /* PLUGIN DEFAULT OPTIONS */
    
    // Put lots of modular stuff here.
    
    plugin.defaults = {
        showElement:function(options, oldElement, newElement, doneCallback){
            oldElement.fadeOut(500, function(){
            });
            newElement.fadeIn(500, function(){
                doneCallback();
            });
        },
        mouseOverElements: $(),
        // feel free to use/call these _methods, especially start/stop,
        // but don't change them at runtime unless you're +31317.
        _items: null,
        _timeout: 3000,
        _hoverClass: "ticker-hover",
        _indexOfItem: function(element, elements){
            for(var i = 0; i < elements.length; i++){
                if(element[0] == elements[i]){
                    return i;
                }
            }
            
            return -1;
        },
        _startTicker: function(options){
            options._stopTicker.apply(options._this, Array(options));
            
            if(options.mouseOverElements.is("." + options._hoverClass)){
                return;
            }
            
            options._nextElementTimeout = setTimeout(function(){
                var visibleElement = options._items.filter(":visible:first");
                
                var visibleElementIndex = options._indexOfItem(visibleElement, options._items);
                
                var nextElement = options._items.eq(visibleElementIndex + 1);
                
                if(!nextElement.length){
                    nextElement = options._items.eq(0);
                }
                
                options.showElement.apply(
                    options._this,
                    Array(
                        options,
                        visibleElement,
                        nextElement,
                        function(){
                            options._startTicker.apply(options._this, Array(options));
                        }
                    )
                );
            },
            options._timeout);
        },
        _stopTicker: function(options){
            clearTimeout(options._nextElementTimeout);
            options._nextElementTimeout = null;
        },
        _nextElementTimeout: null
    }
    
    /* OPTIONS API */
    
    // The following code enables all properties to also be functions, which is good.
    //
    // If a function is specified in options, then you can use the functionTarget parameter
    // to enable the use of "this" in those functions, and it should point to the object that
    // the function is being applied to form the beginnning.
    //
    // That is to say; $("a.more").plugin() <-- that "a.more" link is expected to be the "this"
    // variable in any specified functions.
    //
    // Also, the api provides a method for callbacks and a method for calling on methods.
    
    function valueIsValid(options, key){
        return options[key] == 0 || options[key]?true:false;
    }
    
    function getValue(options, key, functionTarget, opts){
        var value = options[key];
        
        if(typeof value == "function"){
            value = value.apply(functionTarget, new Array(options));
        }
        
        if(!value){
            if(opts && (opts["default"] == 0 || opts["default"])){
                return opts["default"];
            }
            
            return value;
        }
        
        if(opts && opts.suffix){
            return value + opts.suffix;
        } else {
            return value;
        }
    }
    
    function executeCallback(options, key, functionTarget){
        getValue(options, key, functionTarget);
    }
})(jQuery);
