/**
 * Multi-level Drop Down Menu (multi-ddm)
 * March 26, 2009
 * Corey Hart @ http://www.codenothing.com
 *
 * @timer: [Default 500] Time in milliseconds to hold menu's open on mouseouts
 * @parentMO: CSS class to add/remove from parent menu on mouseover/mouseouts
 * @childMO: CSS class to add/remove to ALL child menus
 * @levels: Array of CSS classes in order of appearance on drop downs
 * @parentTag: List type of the parent menu ('ul' or 'ol')
 * @childTag: List type of each menu level ('ul' or 'ol')
 * @tags: List type of each level in order ('ul' or 'ol' for each)
 * @numberOfLevels: [Default 5] Number of levels the menu has. Will default to 
 * 	length of levels array when childMO is null.
 */ 
;(function($) {
    $.fn.dropDownMenu = function(options) {
        var menus = new Array();
        var css;
        var tag;
        var internal;
        var timeout;
        var settings = $.extend({
            timer: 500,
            parentMO: null,
            childMO: null,
            levels: [],
            parentTag: 'ul',
            childTag: 'ul',
            tags: [],
            numberOfLevels: 5
        }, options || {});

        // Set number of levels
        if (settings.tags.length > 0) {
            settings.numberOfLevels = settings.tags.length;
        } else if (settings.levels.length) {
            settings.numberOfLevels = settings.levels.length;
        }

        // Set css levels with childMO
        if (settings.childMO) {
            for (var i = 0; i < settings.numberOfLevels; i++) settings.levels[i] = settings.childMO;
        }

        // Set tag levels with tag
        if (settings.tags.length < 1) {
            for (var i = 0; i < settings.numberOfLevels; i++) settings.tags[i] = settings.childTag;
        }

        // Run through each level
        menus[0] = $(this).children('li');
        for (var i = 1; i < settings.numberOfLevels + 2; i++) {
            // Tags/CSS
            css = (i == 1) ? settings.parentMO : settings.levels[i - 2];
            tag = (i == 1) ? settings.parentTag : settings.tags[i - 2];

            // level selector
            menus[i] = menus[i - 1].children(settings.tag).children('li');

            // Action
            menus[i - 1].attr({ rel: css + ';' + tag }).mouseenter(function(e) {
                //$("span.pageTitleColor").append("<span>enter " + $(this).attr("id") + "</span><br/>");
                if (timeout) clearTimeout(timeout);
                internal = $(this).attr("rel").split(";");
                hidesubmenu($(this).siblings('li').children('a').removeClass(internal[0]).siblings(internal[1]));
                delayedshowsubmenu($(this).children('a').addClass(internal[0]).siblings(internal[1]), e);
                delayedshowsubmenu($(this).children('ul').children('li'), e);
            }).mouseleave(function() {
                //$("span.pageTitleColor").append("<span>leave " + $(this).attr("id") + "</span><br/>");
                delayedhidesubmenu($(this).children('ul').hide());
                internal = $(this).attr("rel").split(";");
                if (internal[0] == settings.parentMO) {
                    timeout = setTimeout(function() { closemenu(); }, settings.timer);
                }
            });
        }

        // Allows user option to close menus by clicking outside the menu on the body
        $(document).click(function() { closemenu(); });

        // Closes all open menus
        var closemenu = function() {
            for (var i = menus.length; i > -1; i--) {
                if (menus[i] && menus[i].attr("rel")) {
                    internal = menus[i].attr("rel").split(";");
                    menus[i].children(internal[1]).hide().siblings('a').removeClass(internal[0]);
                    delayedhidesubmenu(menus[i].children(internal[1]));
                }
            }
            $('a', menus[0]).removeClass(settings.parentMO);
            $("ul", menus[0]).removeClass("horizontalInverse").removeClass("verticalInverse");
            if (timeout) clearTimeout(timeout);
        }

        var delayedshowsubmenu = function(nodes, e) {
            setTimeout(function() { showsubmenu(nodes, e); }, 50);
        }

        var delayedhidesubmenu = function(nodes) {
            setTimeout(function() { hidesubmenu(nodes); }, 50);
        }

        // shows submenu
        var showsubmenu = function(nodes, e) {
            nodes.each(function() {
                var node = $(this);
                node.show();
                if (node.is("ul")) {
                    var parent = node.parent();
                    if (!parent.is("li")) {
                        parent = parent.parent();
                    }

                    if (node.hasClass("level1")) {
                        var delta = parseInt(e.clientX) - parseInt(node.offset().left);
                        var oldLeft = (node.css("left") != undefined) ? node.css("left").replace("px", "") : 0;
                        node.css("left", (parseInt(oldLeft) + parseInt(delta)) + "px");
                    }


                    if (((node.offset().left + node.width() > $(window).width()) || (node.parents(".horizontalInverse").size() > 0)) && (parent.offset().left - node.width() > 0)) {
                        var delta = (node.offset().left - parent.offset().left) + node.width();
                        var oldLeft = (node.css("left") != undefined) ? node.css("left").replace("px", "") : 0;
                        node.css("left", (oldLeft - delta) + "px");
                        if (!node.hasClass("horizontalInverse")) {
                            node.addClass("horizontalInverse");
                            if (node.attr("rel") == undefined) {
                                node.attr("rel", oldLeft + ";no");
                            } else {
                                var split = node.attr("rel").split(';');
                                split[0] = oldLeft;
                                node.attr("rel", split.join(';'));
                            }
                        }
                    }

                    if (((node.offset().top + node.height() > $(window).height()) || (node.parents(".verticalInverse").size() > 0)) && (parent.offset().top - node.height() > 0)) {
                        var delta = (node.offset().top - parent.offset().top) + node.height() - parent.height();
                        var oldTop = (node.css("top") != undefined) ? node.css("top").replace("px", "") : 0;
                        node.css("top", (oldTop - delta) + "px");
                        if (!node.hasClass("verticalInverse")) {
                            node.addClass("verticalInverse");
                            if (node.attr("rel") == undefined) {
                                node.attr("rel", "no;" + (oldTop == 0 ? "no" : oldTop));
                            } else {
                                var split = node.attr("rel").split(';');
                                split[1] = oldTop;
                                node.attr("rel", split.join(';'));
                            }
                        }
                    }
                }
            });
        }

        // hide submenu
        var hidesubmenu = function(nodes) {
            nodes.stop();
            nodes.hide();
            $("ul.horizontalInverse", nodes).each(function() {
                $(this).removeClass("horizontalInverse");
                if ($(this).attr("rel") != undefined) {
                    var split = $(this).attr("rel").split(';');
                    $(this).css("left", (split[0] != "no") ? (split[0] + "px") : "");
                }
            });
            $("ul.verticalInverse", nodes).each(function() {
                $(this).removeClass("verticalInverse");
                if ($(this).attr("rel") != undefined) {
                    var split = $(this).attr("rel").split(';');
                    $(this).css("top", (split[1] != "no") ? (split[1] + "px") : "");
                }
            });
        }
    };
})(jQuery);

