;~function($, win, doc) {
    
    /*
     * Custom carousel jQuery plugin
     * (c) 2010 - The Atom Group
     */
    $.fn.carousel = function(_options) {
        // Configuration options and variable declaration
        configuration: {
            // Config and storage object
            var config = $.extend({
                // UI customizations
                width: "700px",             // Width of entire carousel
                height: "300px",            // Height of entire carousel
                tabWidth: "225px",          // Width of just the right hand side tabs
                tabExtendWidth: 30,         // Width of how much the tab will extend after animating
                arrow: "arrow.gif",
                
                // Effects customizations
                tabFadeSpeed: "fast",       // Tab hover fade speed
                tabFadeColor: "#22AAFB",    // Tab hover to nice blue
                tabSlideColor: "#1188FB",   // Darker blue
                tabHoverColor: "#FFF",      // White
                slideFadeSpeed: "fast",        // Slide fade speed
                
                /* Tab object contains the following mutator properties:
                 *  - caption: Appears above text
                 *  - text: Displays below caption - more emphasis
                 *  { caption: "Test", text: "Message" }
                 *
                 * Slide object contains the following mutator properties:
                 *  - src: Relative/Absolute path to background image being displayed
                 *  - text: Displays in overlay, if omitted no overlay will show
                 *  { src: "image1.jpg", text: "Message" }
                 */
                tabs: [],                   // List of tab objects
                slides: [],                 // List of slide objects
                
                // Handle automatic cycling
                cycle: false,
                cycleSpeed: 500
            }, _options),
            // Cache context
            $this = this;
        }
                
        // Build DOM specific structure
        dom: {
            // Slide content will slide from different directions
            config.$slide_content = $("<div class='slide-content'></div>").appendTo($this);
            // Slide content background will slide from different directions and provide transparency to the content background
            config.$slide_content_background = $("<div class='slide-content-background'></div>").appendTo($this);
            // Slide container for the base image
            config.$slides = $("<div class='slide-container'/>").appendTo($this);
            // Slide overlay for transitions
            config.$slide_overlay = $("<div class='slide-overlay'></div>").appendTo($this);
            // Default to first image
            config.$slides.append("<img src='"+ config.slides[0].src +"'/>");
            // Create tabs container
            config.$tabs = $("<ul class='tab-container'/>").appendTo($this);
            // Cache current tab
            config.cTab = null;
            // Iterate over each tab, cache, and append to list
            for(var i=0,len=config.tabs.length; i<len; i++) {
                config.cTab = config.tabs[i];
                config.$tabs.append("<li><div class='underlay'/><div class='overlay'><div class='arrow'><img src='"+ config.arrow
                    +"' /></div></div><span>"+ config.cTab.caption +"</span><em>"+ config.cTab.text +"</em></li>");
            }
        }
        
        // Before doing anything else apply UI customizations
        styling: {
            // Set absolute width and height
            $this.css({
                width: config.width,
                height: config.height
            });
            
            // Customize tab container
            config.$tabs.css({
                width: config.tabWidth,
                height: config.height
            });
            
            // Calculate height per item
            config.tabHeight = parseInt(config.height) / config.tabs.length;
            config.$tabs.find("li").css("height", config.tabHeight +"px");
            config.$tabs.find("li").css("vertical-align", "middle");
            
            // Customize tab underlay fade color - and cache
            config.$tab_underlay = config.$tabs.find("li div.underlay")
                .css("background-color", config.tabFadeColor).fadeOut(0);
            
            // Customize tab overlay slide color - and cache
            config.$tab_overlay = config.$tabs.find("li div.overlay")
                .css("background-color", config.tabSlideColor).hide();
        }
        
        // Core functionality
        core: {
            
            // Transition functions
            // @_index: The current tab index
            // Returns: (Boolean) If animation was run or not
            function slideIn(_index) {                
                // Prep slide
                var slide_config = config.slides[_index];
                // Only do animation, change content if there is a slide content box defined
                if(typeof slide_config === "undefined" || !slide_config.text.length) {
                    config.$slide_content.css("display", "none");
                    return false;
                }
                
                // Apply the content styling for the main content block
                config.$slide_content.css({
                    top: slide_config.top || "auto",
                    left: slide_config.left || "auto",
                    right: slide_config.right || "auto",
                    bottom: slide_config.bottom || "auto",
                    
                    width: slide_config.width,
                    height: slide_config.height,
                    
                    color: slide_config.fgcolor,
                    display: "none"
                });
                
                // Apply the content styling for the main content background block 
                config.$slide_content_background.css({
                    top: slide_config.top || "auto",
                    left: slide_config.left || "auto",
                    right: slide_config.right || "auto",
                    bottom: slide_config.bottom || "auto",
                    
                    width: slide_config.width,
                    height: slide_config.height,
                    
                    backgroundColor: slide_config.bgcolor,
                    display: "none"
                });
                
                config.$slide_content.html(slide_config.text);
                config.$slide_content_background.stop(true, false).fadeTo(0, slide_config.opacity);
                
                // Combine elements for animation
                var elements = $(config.$slide_content).add(config.$slide_content_background);
                // Change animation based on direction
                switch(slide_config.slideFrom) {
                    case "top":
                        elements.css("top", (parseInt(slide_config.height)*-1) +"px");
                        elements.stop(true, false).animate({
                            top: slide_config.top
                        }, config.slideFadeSpeed).show();
                    break;
                    case "right":
                        elements.css("right", (parseInt(slide_config.width+config.tabAbsoluteWidth)*-1) +"px");
                        elements.stop(true, false).animate({
                            right: slide_config.right+config.tabAbsoluteWidth
                        }, config.slideFadeSpeed).show();
                    break;
                    case "bottom":
                        elements.css("bottom", (parseInt(slide_config.height)*-1) +"px");
                        elements.stop(true, false).animate({
                            bottom: slide_config.bottom
                        }, config.slideFadeSpeed).show();
                    break;
                    case "left":
                        elements.css("left", (parseInt(slide_config.width)*-1) +"px");
                        elements.stop(true, false).animate({
                            left: slide_config.left
                        }, config.slideFadeSpeed).show();
                    break;
                    // Default to fade in place
                    default:
                        config.$slide_content.fadeIn();
                    break;
                }
                
                return true;
            }
            
            // Cycle helpers
            function startCycle() {
                config.cycleInterval = window.setInterval(function() {
                    config.cycleIndex = (isNaN(config.cycleIndex)) ? 0 : (config.cycleIndex+1) % config.maxTabState;
                    config.$tabs.find("li").eq(config.cycleIndex).trigger("mousedown");
                }, config.cycleSpeed);
            }
            
            function stopCycle() {
                window.clearInterval(config.cycleInterval);
            }
            
            // Configuration modifications
            config.maxTabState = Math.max(config.tabs.length, config.slides.length);
            config.tabAbsoluteWidth = config.$tabs.find("li").outerWidth();
            
            // Trigger first mousedown
            window.setTimeout(function() {
                config.$tabs.find("li:eq(0)").trigger("mousedown");
            });
        }
        
        // Event binding
        events: {
            // Tab events
            config.$tabs.find("li")
                // Handle the hovering over of a tab
                .hover(function() {
                    // Cache tab object
                    var $this = $(this),
                        index = $this.index() % config.maxTabState;
                    
                    // Normalize width and height
                    config.$tab_underlay.eq(index).css({
                        width: config.tabAbsoluteWidth,
                        height: config.tabHeight +"px"
                    });
                    
                    // Fade in to specified color at specified speed
                    config.$tab_underlay.eq(index).stop(true, true).fadeIn(config.tabFadeSpeed);
                }, function() {
                    // Cache tab object
                    var $this = $(this),
                        index = $this.index() % config.maxTabState;
                    
                    // Easier fade back to normal color
                    config.$tab_underlay.eq(index).stop(true, true).fadeOut(config.tabFadeSpeed);
                })
                // Handle the mousedown of a tab
                .bind("mousedown", function() {
                    // Cache tab object
                    var $this = $(this),
                        index = $this.index() % config.maxTabState,
                        // Cache the current tab
                        current_tab = config.$tab_overlay.eq(index),
                        // Cache the current slide
                        current_slide = config.slides[index],
                        // Cache all other tabs
                        other_tabs = config.$tab_overlay.filter(":not(:eq("+ index +"))");
                    
                    // Disable animation action if current tab is active
                    if(current_tab.data("active") !== true) {
                        config.$slide_content.hide();
                        config.$slide_content_background.hide();
                        // Slide images crossfade
                        config.$slide_overlay.hide().append("<img src='"+ current_slide.src +"'/>")
                            .stop(true, false)
                            .fadeIn(config.slideFadeSpeed, function() {
                                var $this = $(this);
                                //if($this.find("img").length)
                                config.$slides.empty().append("<img src='"+ current_slide.src +"'/>");
                                //else
                                //    config.$slides.empty().append("<img src='"+ current_slide.src +"'/>");
                                $this.empty().hide();
                                
                                window.setTimeout(function() {
                                    
                                    slideIn(index);
                                }, 100);
                            });
                        
                        // Set active tab data
                        config.$tab_overlay.data("active", false);
                        current_tab.data("active", true);
                        
                        // Change font color
                        config.$tabs.find("li").find("span,em").css("color", "");
                        $this.find("span,em").css("color", config.tabHoverColor);
                        
                        // Make sure only this underlay is visible
                        config.$tab_underlay.filter(":not(:eq("+ index +"))").hide();
                        config.$tab_underlay.eq(index).show();
                        
                        // Normalize height and width
                        current_tab.css("height", config.tabHeight +"px");
                        
                        // Tab slide left animation
                        other_tabs.animate({ "width": "0px" }, config.tabSlideSpeed);
                        other_tabs.find("div.arrow").fadeOut(config.tabSlideSpeed);
                        
                        // Take the current tab and extend just a little outside the bounding box
                        current_tab.show().stop(true, true)
                            .animate({ "width": "100%" }, config.tabSlideSpeed)
                            .animate({
                                width: (config.tabAbsoluteWidth + config.tabExtendWidth) +"px"
                            }, config.tabSlideSpeed);
                            
                        // Fade in the arrow, if present as well
                        current_tab.find("div.arrow").fadeIn("slow");
                        
                        
                        
                        // Slide in the content overlay
                        //slideIn(index);
                    }
                    
                });
            
            // Make li's unselectable
            config.$tabs.find("li").each(function() {
                this.setAttribute("unselectable", "on");
                this.style["MozUserSelect"] = "none";
                this.onselectstart = function() {
                    return false;
                }
            });
            
            // Handle the cycling
            if(config.cycle) {
                startCycle();
            
                $this.bind("mouseenter", function() {
                        stopCycle();
                })
                .bind("mouseleave", function() {
                    startCycle();
                });
            }
        }
        
        // Return the collection for chaining
        return $this;
    }
    
}(jQuery, this, this.document);
