if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}
(function($){
    $.fn.extend({
        lbListRotator: function(options) {
            if (this.length) {
                return this.each(function() {
                    var obj = Object.create(lbListRotatorClass);
                    obj.init(this, options);
                    $.data(this, 'lbListRotator', lbListRotatorClass);
                });
            }
        }
    });
})(jQuery);
var lbListRotatorClass = {
    init: function(element, options) {
        // Store "this" for reference
        var c = this;
        // Settings
        c.settings = jQuery.extend({
                                    rotationInterval: 5000,
                                    effectTimer: 1000,
                                    effect: 'fade',
                                    effectOptions: {},
                                    shuffle: false,
                                    randomStart: false,
                                    autoStart: true,
                                    disableRotationEngine: false,
                                    listRotatorHelper: false,
                                    activeItemClass: 'lbListRotatorItemActive',
                                    activeHelperItemClass: 'lbListRotatorHelperItemActive',
                                    helperInteraction: 'mouseover',
                                    startIndex: 0
                                   }, c.settings, options);
        // effect options
        c.effectOptions = jQuery.extend({
                                         slideBy: 100
                                        }, c.effectOptions, c.settings.effectOptions);

        // Store element for reference, both normal and jQuery
        c.listRotator = element;
        c.$listRotator = jQuery(element);
        // Total items (li's in ul)
        c.totalItems = c.$listRotator.find('li').length;
        // Current item
        c.currentItem = (c.settings.startIndex >= 0 && c.settings.startIndex < c.totalItems) ? c.settings.startIndex : 0;
        // Shuffle array
        c.shuffledItems = new Array();
        // Add currentItem to shuffle list to avoid showing item twice the first round
        c.shuffledItems.push(c.currentItem);
        // previousItem prevents shuffle ending and starting on the same item
        c.previousItem = null;
        // Timer
        c.tId = null;
        // User interaction
        c.userInteraction = false;
        // Random start
        if (c.settings.randomStart) {
            c.currentItem = c.random(c.totalItems);
        }

        // Display first content
        c.$listRotator.children().each(function(index) {
            if (index == c.currentItem) {
                if (c.settings.effect == 'slide') {
                    var pos = '-' + c.currentItem*c.effectOptions.slideBy;
                    c.$listRotator.css('left', pos);
                }
                jQuery(this).show();
                jQuery(this).addClass(c.settings.activeItemClass);
                c.setHelperClass(c, index, true);
            }
        });

        // Loop all helper elements within the ul and bind mouseover/mouseout functionality to them
        if (jQuery(c.settings.listRotatorHelper).length > 0) {
            jQuery(c.settings.listRotatorHelper).children().each(function() {
                jQuery(this).bind(c.settings.helperInteraction, function() {
                    // Set userInteraction true
                    c.userInteraction = true;
                    // Stop rotationEngine
                    c.stopRotationEngine(c);
                    // Hide active content
                    if (c.settings.effect != 'slide') {
                        c.$listRotator.children().hide();
                    }
                    // Remove active class from helper
                    c.$listRotator.children().removeClass(c.settings.activeItemClass);
                    jQuery(c.settings.listRotatorHelper).children().removeClass(c.settings.activeHelperItemClass);
                    // Find position of current item
                    c.currentItem = jQuery(this).index();
                    // Show current content
                    c.$listRotator.children().each(function (index) {
                        if (index == c.currentItem) {
                            // Stop animations on this element
                            jQuery(this).stop();
                            
                            // Reset opacity incase animation was fade
                            jQuery(this).css('opacity', 1);
                            // Show element
                            jQuery(this).show();
                            
                            if (c.settings.effect == 'slide') {
                                c.runEffect(c, jQuery(this), false);
                            }

                            // Add active class to helper
                            jQuery(this).addClass(c.settings.activeItemClass);
                            c.setHelperClass(c, index, true);
                            return false;
                        }
                    });
                });
                jQuery(this).bind('mouseout', function() {
                    // Start rotationEngine
                    c.startRotationEngine(c);
                });
            });
        }

        // Start rotationEngine if autoStart is true
        if (c.settings.autoStart) {
            c.startRotationEngine(c);
        }
    },

    // rotationEngine
    rotationEngine: function(c) {
        // Stop rotationEngine
        c.stopRotationEngine(c);

        // Reset userInteraction
        c.userInteraction = false;

        // Hide open content
        c.$listRotator.children().each(function(index) {
            if (index == c.currentItem) {
                // Is shuffle set?
                if (c.settings.shuffle) {
                    // Get a random item, but make sure every item is shown in each rotation
                    c.currentItem = c.shuffleRotationEngine(c, c.totalItems);
                } else {
                    // Activate next item
                    c.currentItem++;
                    // Make sure currentItem resets at the end of the itemlist
                    c.currentItem = (c.currentItem >= c.totalItems) ? 0 : c.currentItem;
                }

                // Loop all li elements until you locate the new active item
                c.$listRotator.children().each(function (idx) {
                    // Is next item found?
                    if (idx == c.currentItem) {
                        // Show item
                        jQuery(this).show();
                        // Give it the active class
                        c.setHelperClass(c, idx, true);
                        // Remove active class from current active item
                        c.setHelperClass(c, index, false);

                        return false;
                    }
                });

                // Run effect
                c.runEffect(c, jQuery(this), true);

                return false;
            }
        });
    },

    continueRotation: function(c, e, h) {
        // Check if user interacted with helper during effect duration
        if (! c.userInteraction) {
            // Make sure the element is hidden when effect is done, not all effects end with hide
            if (h) {
                e.hide();
            }
            // Remove active class on previous active item
            e.removeClass(c.settings.activeItemClass);

            // Loop all li elements until you locate the new active item
            c.$listRotator.children().each(function (index) {
                // Is next item found?
                if (index == c.currentItem) {
                    // Give it the active class
                    jQuery(this).addClass(c.settings.activeItemClass);

                    return false;
                }
            });

            // Start rotationEngine
            this.startRotationEngine(c);
        }
    },

    runEffect: function(c, e, runCallback) {
        // Make sure jQuery UI is installed before running UI effects, if fade effect or UI isn't installed, run the standard fadeOut effect
        if (c.settings.effect == 'slide') {
            var pos = '-' + c.currentItem*c.effectOptions.slideBy;
            c.$listRotator.animate({left: pos}, c.settings.effectTimer, 'swing', function() {
                if (runCallback) {
                    c.continueRotation(c, e, false);
                }
            });
        } else if (e.effect && c.settings.effect != 'fade') {
            e.effect(c.settings.effect, c.effectOptions, c.settings.effectTimer, function() {
                if (runCallback) {
                    c.continueRotation(c, e, true);
                }
            });
        } else {
            e.fadeOut(c.settings.effectTimer, function() {
                if (runCallback) {
                    c.continueRotation(c, e, true);
                }
            });
        }
    },

    stopRotationEngine: function(c) {
        // Stop rotationEngine
        clearInterval(c.tId);
    },

    startRotationEngine: function(c) {
        // Stop rotationEngine
        c.stopRotationEngine(c);
        // Start rotationEngine as long as disableRotationEngine is false
        if (! c.settings.disableRotationEngine) {
            c.tId = setInterval(function() {c.rotationEngine(c)}, c.settings.rotationInterval);
        }
    },

    shuffleRotationEngine: function(c, max) {
        // Number holds the random generated number
        var number = c.random(max);
        // Loop until we get a random number that has not been used in this rotation or was the last number of the previous rotation
        while (c.in_array(number, c.shuffledItems) || number == c.previousItem) {
            // Generate a new number until we get the one we want
            number = c.random(max);
        }
        // Set generated number to previousItem
        c.previousItem = number;
        // Add generated number to shuffle list to avoid showing it twice or more each rotation
        c.shuffledItems.push(number);
        // Reset shuffle list if we've been through all the items
        if (c.shuffledItems.length == c.totalItems) {
            c.shuffledItems = new Array();
        }
        // Return generated number
        return number;
    },

    in_array: function(needle, haystack) {
        // Returns true if needle is in haystack
        for (n in haystack) {
            if (haystack[n] == needle) {
                return true;
            }
        }
        return false;
    },

    random: function(max) {
        // Return a number between 0 and "max"
        return Math.floor(Math.random()*max);
    },

    setHelperClass: function(c, n, status) {
        // Make sure helper object is set
        if (jQuery(c.settings.listRotatorHelper).length > 0) {
            // Loop childs of helper object
            jQuery(c.settings.listRotatorHelper).children().each(function(index) {
                // Find the correct child
                if (index == n) {
                    // Toggle class
                    if (status) {
                        jQuery(this).addClass(c.settings.activeHelperItemClass);
                    } else {
                        jQuery(this).removeClass(c.settings.activeHelperItemClass);
                    }
                    return false;
                }
            });
        }
    }
}
