﻿/*
Ticker plugin by Hallvarsson&Halvarsson
*/

(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.first();
                }
                
    		    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);

