/*
 * name: jQuery marquee
 * 
 */
;(function(window, document, $) {
    /*
        Function: $.fn.marquee

        Marquee is being used colloquially to define a slideshow-esque presentation layer to DOM content.

        Parameters:
            _left - Left control selector or an object collection with the named parameters without the preceding underscore
            _right - Right control selector
            _state - Progress control selector
            _display - Display control children selector
            _play - Play/pause button selector
            _active - Active elements className
            _start - Starting position for display images
            _speed - Speed at which the marquee should run
            _change - Optional animation function, will override default animation
	        
        Return:
            jQuery chainables
    */
	$.fn.marquee = function(_left, _right, _state, _display, _play, _start, _speed, _active, _change) {
		var test = (typeof _left == "object"),
            // Set defaults for plugin
            options = $.extend({
                // Selectors - required
                left: (test) ? "" : (_left || ""),
                right: _right || "",
                state: _state || "",
                display: _display || "",
				active: _active || "active",
                play: _play || null,
                // Display optionsuration - optional
                start: _start || 0,
                speed: _speed || 0,
                // Custom animation function
                change: _change || null
            }, (test) ? _left : {});

        // Bind the change event
        if(options.change) {
            this.bind("change", options.change);
        }

        // Normalize left and right
        options.left = (typeof options.left == "object" && options.left.length) ? options.left : $(options.left, this);
        options.right = (typeof options.right == "object" && options.right.length) ? options.right : $(options.right, this);

        // Handle no left or right
        options.left = (options.left.length > 0) ? options.left : $("<div/>");
        options.right = (options.right.length > 0) ? options.right : $("<div/>");

        return this.each(function() {
            var $this = $(this),
                paused = false;
            // Cache state and display jQuery objects
            var $state = $(options.state, this), $display = $(options.display, this), $play = $(options.play, this),
                // Interval variable
                interval = null;

            // Handle no state
            if(!$state.length) {
                $state = $("<ul/>");
            }

            for(var i=0,len=$display.length; i<len; i++) {
                $state.prepend("<li class='inactive'>"+ (len-i) +"</li>");
            }
            $state.find("li:last").addClass("last");
            
            // Set up the initial state and display controls
            $state.children().eq(options.start).addClass("active");
            $display.eq(options.start).show();
            
            // Auto start code
            if(options.speed > 0) {
                interval = window.setInterval(function() {
                    if(!paused) {
                        change.call(options.right[0]);
                    }
                }, options.speed);
            }

            /*
                Function: change
                
                Change image in marquee
            */
            function change() {
                // Cache control, and active state jQuery objects
                var $control = $(this), $active_state = $state.children("."+options.active),
                    // Test for left control, default to right
                    direction = ( $control[0] === options.left[0] ) ? "left" : "right",
                    // Obtain current active position, or use the start index, also set to prev_position
                    prev_position = position = $state.children().index($active_state),	
                    // Increment or decrement the position based on direction
                    display_count = $display.length;
                
                // Test if animation is in progress via psuedo class, if not change position
                if(!$display.eq(prev_position).is(":animated")) {
                    // Normalize the position using modulus
                    position = ( direction === "left" ) ? (((position-1)%display_count) + display_count) % display_count : (((position+1)%display_count) + display_count) % display_count;

                    // Set the new active class
                    $active_state.removeClass(options.active);
                    $state.children().eq(position).addClass(options.active);
                    
                    $this.trigger("change", [position]);

                    // If no change event added fire default
                    if(!options.change) {
                        $display.eq(prev_position).fadeOut("slow");
                        $display.eq(position).fadeIn("slow");
                    }
                }
            }

            $play.bind("click", function() {
                paused = !paused;

                var $this = $(this);
                if($this.hasClass("pause")) {
                    $this.addClass("play").removeClass("pause");
                }
                else {
                    $this.addClass("pause").removeClass("play");
                }
            });

            // Li clicks
            $state.delegate("li.inactive", "click", function() {
                // Cancel interval
                if(!$play.is(".play")) {
                    $play.trigger("click");
                }

                // Cache local reference
                var $this = $(this),
                    index = 0;
                // Remove all active classes
                $state.find("."+options.active).removeClass(options.active).addClass("inactive");

                // Add the new active class
                $this.addClass(options.active).removeClass("inactive");
                
                // Cross fade in the correct div
                var index = $state.find("li").index($this);
                $this.trigger("change", [index]);

                if(!options.change) {
                    $display.filter(":visible").fadeOut("slow");
                    $display.eq(index).fadeIn("slow");
                }
            });
            
            options.left.add(options.right).bind("mousedown", function() {
                // Cancel interval
                if(!paused) { paused = true; }
                
                // Execute change image
                change.call(this);
            });
        });
			
	}
})(this, this.document, this.jQuery);

