(function($) {

        jQuery.fn.slidertron = function(options) {

                var settings = jQuery.extend({
                        selectorParent:                jQuery(this)
                }, options);

                return jQuery.slidertron(settings);
        }

        jQuery.slidertron = function(options) {

                // Settings

                        var settings = jQuery.extend({

                                selectorParent:                                                null,                                                // If a jQuery object, all selectors will be restricted to its scope. Otherwise, all selectors will be global.

                                // Selectors

                                        viewerSelector:                                        null,                                                // Viewer selector
                                        slidesSelector:                                        null,                                                // Slides selector
                                        navNextSelector:                                null,                                                // 'Next' selector
                                        navPreviousSelector:                        null,                                                // 'Previous' selector
                                        navFirstSelector:                                null,                                                // 'First' selector
                                        navLastSelector:                                null,                                                // 'Last' selector
                                        navStopAdvanceSelector:                        null,                                                // 'Stop Advance' selector
                                        navPlayAdvanceSelector:                        null,                                                // 'Play Advance' selector

                                // General settings

                                        speed:                                                        'fast',                                                // Transition speed (0 for instant, 'slow', 'fast', or a custom duration in ms)
                                        navWrap:                                                true,                                                // Wrap navigation when we navigate past the first or last slide
                                        seamlessWrap:                                        true,                                                // Seamlessly wrap slides
                                        advanceDelay:                                        0,                                                        // Time to wait (in ms) before automatically advancing to the next slide (0 disables advancement entirely)
                                        advanceResume:                                        0,                                                        // Time to wait (in ms) before resuming advancement after a user interrupts it by manually navigating (0 disables resuming advancement)
                                        advanceNavActiveClass:                        'active'                                        // Active advancement navigation class

                        }, options);

                // Variables

                        // Operational stuff

                                var isConfigured = true,
                                        isLocked = false,
                                        isAdvancing = false,
                                        isSeamless = false,
                                        list = new Array(),
                                        currentIndex = false,
                                        timeoutID;

                        // jQuery objects

                                var __slides,
                                        __viewer,
                                        __navFirst,
                                        __navLast,
                                        __navNext,
                                        __navPrevious,
                                        __navStopAdvance,
                                        __navPlayAdvance;

                // Functions

                        function getElement(selector, required)
                        {
                                var x;

                                try
                                {
                                        if (selector == null)
                                                throw 'is undefined';

                                        if (settings.selectorParent)
                                                x = settings.selectorParent.find(selector);
                                        else
                                                x = jQuery(selector);

                                        if (x.length == 0)
                                                throw 'does not exist';

                                        return x;
                                }
                                catch (error)
                                {
                                        if (required == true)
                                        {
                                                alert('Error: Required selector "' + selector + '" ' + error + '.');
                                                isConfigured = false;
                                        }
                                }

                                return null;
                        }

                        function advance()
                        {
                                if (settings.advanceDelay == 0)
                                        return;

                                if (!isLocked)
                                        nextSlide();

                                timeoutID = window.setTimeout(advance, settings.advanceDelay);
                        }

                        function initializeAdvance()
                        {
                                if (settings.advanceDelay == 0)
                                        return;

                                if (__navPlayAdvance)
                                        __navPlayAdvance.addClass(settings.advanceNavActiveClass);

                                if (__navStopAdvance)
                                        __navStopAdvance.removeClass(settings.advanceNavActiveClass);

                                isAdvancing = true;
                                timeoutID = window.setTimeout(advance, settings.advanceDelay);
                        }

                        function interruptAdvance()
                        {
                                if (!isAdvancing)
                                        return;

                                if (settings.advanceDelay == 0)
                                        return;

                                window.clearTimeout(timeoutID);

                                if (settings.advanceResume == 0)
                                        return;

                                timeoutID = window.setTimeout(advance, settings.advanceResume);
                        }

                        function stopAdvance()
                        {
                                if (settings.advanceDelay == 0)
                                        return;

                                if (!isAdvancing)
                                        return;

                                isAdvancing = false;
                                window.clearTimeout(timeoutID);
                        }

                        function playAdvance(skip)
                        {
                                if (settings.advanceDelay == 0)
                                        return;

                                if (isAdvancing)
                                        return;

                                isAdvancing = true;

                                if (skip)
                                        timeoutID = window.setTimeout(advance, settings.advanceDelay);
                                else
                                        advance();
                        }

                        function firstSlide()
                        {
                                switchSlide((isSeamless ? 1 : 0));
                        }

                        function lastSlide()
                        {
                                switchSlide((isSeamless ? list.length - 2 : list.length - 1));
                        }

                        function nextSlide()
                        {
                                if (currentIndex < list.length - 1)
                                        switchSlide(currentIndex + 1);
                                else if (settings.navWrap || isAdvancing)
                                        switchSlide(0);
                        }

                        function previousSlide()
                        {
                                if (currentIndex > 0)
                                        switchSlide(currentIndex - 1);
                                else if (settings.navWrap)
                                        switchSlide(list.length - 1);
                        }

                        function switchSlide(index)
                        {
                                // Check locking status (so another switch can't be initiated while another is in progress)

                                if (isLocked)
                                        return false;

                                isLocked = true;

                                if (currentIndex === false)
                                {
                                        currentIndex = index;
                                        __reel.css('left', -1 * list[currentIndex].x);
                                        isLocked = false;
                                }
                                else
                                {
                                        var diff, currentX, newX;

                                        currentX = list[currentIndex].x;
                                        newX = list[index].x;
                                        diff = currentX - newX;

                                        __reel.animate({ left: '+=' + diff }, settings.speed, 'swing', function() {
                                                currentIndex = index;

                                                if (list[currentIndex].realIndex !== false)
                                                {
                                                        currentIndex = list[currentIndex].realIndex;
                                                        __reel.css('left', -1 * list[currentIndex].x);
                                                }

                                                isLocked = false;
                                        });
                                }
                        }

                        function initialize()
                        {
                                // Slides, viewer, reel

                                        __viewer = getElement(settings.viewerSelector, true);
                                        __reel = getElement(settings.reelSelector, true);
                                        __slides = getElement(settings.slidesSelector, true);

                                // Navigation

                                        __navFirst = getElement(settings.navFirstSelector);
                                        __navLast = getElement(settings.navLastSelector);
                                        __navNext = getElement(settings.navNextSelector);
                                        __navPrevious = getElement(settings.navPreviousSelector);
                                        __navStopAdvance = getElement(settings.navStopAdvanceSelector);
                                        __navPlayAdvance = getElement(settings.navPlayAdvanceSelector);

                                // Check configuration status

                                        if (isConfigured == false)
                                        {
                                                alert('Error: One or more configuration errors detected. Aborting.');
                                                return;
                                        }

                                // Set up

                                        // Viewer

                                                __viewer.css('position', 'relative');
                                                __viewer.css('overflow', 'hidden');

                                        // Reel

                                                __reel.css('position', 'absolute');
                                                __reel.css('left', 0);
                                                __reel.css('top', 0);

                                        // Slides

                                                var cx = 0, length = __slides.length;

                                                if (length > 2 && settings.seamlessWrap)
                                                {
                                                        isSeamless = true;

                                                        var first = __slides.first();
                                                        var last = __slides.last();

                                                        last.clone().insertBefore(first);
                                                        first.clone().insertAfter(last);

                                                        __slides = getElement(settings.slidesSelector, true);
                                                }

                                                __slides.each(function(index) {

                                                        var y = jQuery(this);

                                                        list[index] = {
                                                                object:                y,
                                                                x:                        cx,
                                                                realIndex:        false
                                                        };

                                                        y.css('position', 'absolute');
                                                        y.css('left', cx);
                                                        y.css('top', 0);

                                                        cx += y.width();
                                                });

                                                if (isSeamless)
                                                {
                                                        list[0].realIndex = length; // second to last
                                                        list[length + 1].realIndex = 1; // second
                                                }

                                        // Navigation

                                                if (__navFirst)
                                                        __navFirst.click(function(event) {
                                                                event.preventDefault();

                                                                if (isLocked)
                                                                        return false;

                                                                if (isAdvancing)
                                                                        interruptAdvance();

                                                                firstSlide();
                                                        });

                                                if (__navLast)
                                                        __navLast.click(function(event) {
                                                                event.preventDefault();

                                                                if (isLocked)
                                                                        return false;

                                                                if (isAdvancing)
                                                                        interruptAdvance();

                                                                lastSlide();
                                                        });

                                                if (__navNext)
                                                        __navNext.click(function(event) {
                                                                event.preventDefault();

                                                                if (isLocked)
                                                                        return false;

                                                                if (isAdvancing)
                                                                        interruptAdvance();

                                                                nextSlide();
                                                        });

                                                if (__navPrevious)
                                                        __navPrevious.click(function(event) {
                                                                event.preventDefault();

                                                                if (isLocked)
                                                                        return false;

                                                                if (isAdvancing)
                                                                        interruptAdvance();

                                                                previousSlide();
                                                        });

                                                if (__navStopAdvance)
                                                        __navStopAdvance.click(function(event) {
                                                                event.preventDefault();

                                                                if (isLocked)
                                                                        return false;

                                                                if (!isAdvancing)
                                                                        return false;

                                                                __navStopAdvance.addClass(settings.advanceNavActiveClass);

                                                                if (__navPlayAdvance)
                                                                        __navPlayAdvance.removeClass(settings.advanceNavActiveClass);

                                                                stopAdvance();
                                                        });

                                                if (__navPlayAdvance)
                                                        __navPlayAdvance.click(function(event) {
                                                                event.preventDefault();

                                                                if (isLocked)
                                                                        return false;

                                                                if (isAdvancing)
                                                                        return false;

                                                                __navPlayAdvance.addClass(settings.advanceNavActiveClass);

                                                                if (__navStopAdvance)
                                                                        __navStopAdvance.removeClass(settings.advanceNavActiveClass);

                                                                playAdvance();
                                                        });

                        }

                        // Ready

                                jQuery().ready(function() {
                                        initialize();
                                        initializeAdvance();
                                        firstSlide();
                                });
        };

})(jQuery);
