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

(function (ns) {

    ns.menu = function (spec, my) {
        var that = {};

        spec = spec || {};
        spec.speed = spec.speed || 1;
        spec.mainItems = spec.mainItems || 'ul.main > li';
        spec.submenu = spec.submenu || '.submenu';
        spec.hideDelay = spec.hideDelay !== undefined ? spec.hideDelay : 250;
        spec.showSpeed = spec.showSpeed !== undefined ? spec.showSpeed : 150;
        spec.hideSpeed = spec.hideSpeed !== undefined ? spec.hideSpeed : 250;

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

        my = my || {};
        my.logger = gj.logging.getLogger('cmu.menu');
        // my.logger.setLevel(gj.logging.DEBUG);
        my.timers = {};

        var configure = function (newSpec) {
            if (newSpec) {
                var attr;
                for (attr in newSpec) {
                    spec[attr] = newSpec[attr];
                }
            }

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

            my.$mainItems = my.$viewNode.find(spec.mainItems);
            my.speedFactor = 1 / spec.speed;
            my.timers = {
                hideDelay: spec.hideDelay * my.speedFactor,
                show: spec.showSpeed * my.speedFactor,
                hide: spec.hideSpeed * my.speedFactor
            };
        };
        configure();

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

        var $visibleMenu;
        var hideTimeout;

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

        var init = function () {
            my.$mainItems.each(function () {
                var $this = $(this);
                var $menu = $this.find('.submenu');
                $this.data('submenu', $menu.length ? $menu : null);
            });

            // showMenu(my.$mainItems.eq(2).data('submenu'));
        };

        var showMenu = function ($menu, animate) {
            my.logger.debug('showMenu()');
            if ($visibleMenu) {
                my.logger.debug('Menu still visible, hiding first', $visibleMenu);
                hideMenu($visibleMenu, false);
                animate = false;
            }
            if (!$menu) {
                return;
            }
            if (animate && my.timers.show) {
                $menu.slideDown(my.timers.show);
            } else {
                $menu.show();
            }
            $visibleMenu = $menu;
        };

        var hideMenu = function ($menu, animate) {
            my.logger.debug('hideMenu()', {'animate': animate});
            var done = function () {
                $visibleMenu = null;
            };
            if (!$menu) {
                return done();
            }
            if (animate && my.timers.hide) {
                $menu.fadeOut(my.timers.hide, done);
            } else {
                // Immediately animate to finish (to preserve state),
                // then hide.
                $menu.stop(false, true);
                $menu.hide();
                done();
            }
        };

        my.$mainItems.hover(
            function (e) {
                my.logger.debug(e.type, $(this).index());
                if (hideTimeout) {
                    window.clearTimeout(hideTimeout);
                    hideTimeout = null;
                }
                var $subMenu = $(this).data('submenu');
                showMenu($subMenu, true);
            },
            function (e) {
                my.logger.debug(e.type, $(this).index());
                var $subMenu = $(this).data('submenu');
                var doHide = function () {
                    hideMenu($subMenu, true);
                };
                if (my.timers.hideDelay) {
                    my.logger.debug('  Delayed hide after ' + my.timers.hideDelay + ' ms');
                    hideTimeout = window.setTimeout(doHide, my.timers.hideDelay);
                } else {
                    my.logger.debug('  Immediate hide');
                    doHide();
                }
            }
        );

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

        that.configure = configure;

        // ------------------------------------------------------------------
        // Constructor
        // ------------------------------------------------------------------
        init();

        return that;
    };

})(window.cmu);

