window.cmu = window.cmu || {};

(function (ns) {

    ns.carousel = function (spec, my) {
        spec = spec || {};
        spec.content = spec.content || 'ul.content';
        spec.navigation = spec.navigation || 'ul.navigation';
        spec.slideTime = spec.slideTime || 4000;
        spec.fadeTime = spec.fadeTime !== undefined ? spec.fadeTime : 1000;
        spec.loop = (spec.loop !== undefined) ? spec.loop : true;
        spec.autoStart = (spec.autoStart !== undefined) ? spec.autoStart : true;
        spec.initialIndex = spec.initialIndex || 0;

        // ------------------------------------------------------------------
        // Shared properties
        // ------------------------------------------------------------------

        my = my || {};
        my.logger = gj.logging.getLogger('cmu.carousel');

        my.$viewNode = $(spec.viewNode);
        my.content = {
            $items: my.$viewNode.find(spec.content).children()
        };
        my.navigation = {
            $items: my.$viewNode.find(spec.navigation).children()
        };
        my.currentIndex = spec.initialIndex;
        my.previousIndex = null;
        my.isPlaying = false;

        // ------------------------------------------------------------------
        // Private properties
        // ------------------------------------------------------------------

        var that = {};
        var windowInterval;

        // ------------------------------------------------------------------
        // Private methods
        // ------------------------------------------------------------------

        var init = function () {
            my.logger.debug('init()');

            if (my.content.$items.length <= 1) {
                my.logger.info('Carousel has only one item, nothing to do');
                my.$viewNode.find(spec.navigation).hide();
                return null;
            }

            my.$viewNode.addClass('jsEnabled');

            // Hide all content items
            my.content.$items.hide();

            draw();
            spec.autoStart && that.start();

            return that;
        };

        var setCurrentIndex = function (newIndex) {

            // Update the state (model)
            my.currentIndex = newIndex;

            // Redraw (view)
            draw();

            // Remember the current index for next time (helps optimize drawing)
            my.previousIndex = my.currentIndex;
        };

        var draw = function () {
            my.logger.debug('draw()');

            if (my.currentIndex == my.previousIndex) {
                my.logger.info('draw() called, but nothing to do');
                return;
            }
            drawContent();
            drawNavigation();
        };

        var drawContent = function () {
            my.logger.debug('drawContent()');

            my.content.currentItem = my.content.$items.eq(my.currentIndex);

            if (my.content.previousItem) {
                if (spec.fadeTime) {
                    my.content.previousItem.fadeOut(spec.fadeTime);
                    my.content.currentItem.fadeIn(spec.fadeTime);
                } else {
                    my.content.previousItem.hide();
                    my.content.currentItem.show();
                }
            } else {
                my.content.currentItem.show();
            }
            my.content.previousItem = my.content.currentItem;
        };

        var drawNavigation = function () {
            my.logger.debug('drawNavigation()');

            my.navigation.$items.removeClass('active');
            my.navigation.$items.eq(my.currentIndex).addClass('active');
        };

        // ------------------------------------------------------------------
        // Public methods
        // ------------------------------------------------------------------

        that.next = function () {
            my.logger.debug('next()');
            var nextItemAvailable = my.currentIndex + 1 <= (my.content.$items.length - 1);

            if (!nextItemAvailable) {
                if (spec.loop) {
                    setCurrentIndex(0);
                } else {
                    // console.info('No more items available');
                    that.stop();
                    // console.groupEnd();
                    return;
                }
            } else {
                setCurrentIndex(my.currentIndex + 1);
            }
        };

        that.previous = function () {
            my.logger.debug('previous()');
        };

        that.start = function () {
            my.logger.debug('start()');

            if (my.isPlaying) {
                my.logger.debug('Already started');
                return;
            }
            my.isPlaying = true;

            windowInterval = window.setInterval(function () {
                that.next();
            }, spec.slideTime + spec.fadeTime);
        };

        that.stop = function () {
            my.logger.debug('stop()');

            window.clearInterval(windowInterval);
            my.isPlaying = false;
        };

        // ------------------------------------------------------------------
        // Event handlers
        // ------------------------------------------------------------------

        my.$viewNode.mouseenter(function (e) {
            my.isPlaying && that.stop();
        });

        my.$viewNode.mouseleave(function (e) {
            my.isPlaying || spec.autoStart && that.start();
        });

        my.navigation.$items.find('a').click(function (e) {
            var navigationItem = $(this).parents('li');
            setCurrentIndex(navigationItem.index());
        });

        $(window).focus(function (e) {
            // my.logger.warning(this, e.type);
            that.start();
        });

        $(window).blur(function (e) {
            // my.logger.warning(this, e.type);
            that.stop();
        });

        // ------------------------------------------------------------------
        // Constructor
        // ------------------------------------------------------------------

        return init();
    };

})(window.cmu);

