var PullMenu =
{
    'active'      : {},
    'visible'     : {},
    'menuspacing' : -1,
    'timer'       : null,

    'init': function(id)
    {
		//alert(id);
        // Make sure that events will not fire at unload time, because that
        // generates JavaScript warnings in Firefox about PullMenu
        // that does not exist anymore at that time.
        var oldunload = window.onunload;
        window.onunload = function()
        {
            if (oldunload) oldunload();
            var root = document.getElementById('pullmenu_root_' + id);
            if (root) {
                root.onmouseover = null;
                root.onmouseout  = null;
            }
            var ahrefs = document.getElementsByTagName('a');
            for (var i=0; i<ahrefs.length; i++)
            {
                if (!ahrefs[i].rel) continue;
                var obj = ahrefs[i];

                if (obj.rel.indexOf('pullmenu_') == 0) {
                    obj.onmouseover = null;
                    obj.onmouseout  = null;
                }
            }
        }

        // Events for the root pullmenu item.
        var r = document.getElementById('pullmenu_root_' + id);
        if (!r) return;
        r.onmouseover = function() {
            PullMenu.stopCloseTimer();
            PullMenu.openSubMenu(null, id);
        };
        r.onmouseout  = function() {
            PullMenu.startCloseTimer();
        };

        // Events for the folders and forums.
        var ahrefs = document.getElementsByTagName('a');
        for (var i=0; i<ahrefs.length; i++)
        {
            if (!ahrefs[i].rel) continue;
            var obj = ahrefs[i];

            if (obj.rel == 'pullmenu_item')
            {
                obj.onmouseover = function() {
                    PullMenu.stopCloseTimer();
                    PullMenu.openSubMenu(this, id);
                };
                obj.onmouseout  = function() {
                    PullMenu.startCloseTimer();
                };
            }
            else if (obj.rel.substring(0,19) == 'pullmenu_folder')
            {
                var info = obj.rel.substring(20, obj.rel.length-1).split(',');
                obj.menu_id   = info[0];
                obj.parent_id = info[1];

                obj.onmouseover = function() {
                    PullMenu.stopCloseTimer();
                    PullMenu.openSubMenu(this, id);
                };
                obj.onmouseout  = function() {
                    PullMenu.startCloseTimer();
                };
            }
        }
    },

    'hideAll': function()
    {
        for (var depth in PullMenu.visible) {
            for (var idx in PullMenu.visible[depth]) {
                var o = PullMenu.visible[depth][idx];
                o.style.display = 'none';

                if (o.work_around_iframe) {
                    o.work_around_iframe.style.display = 'none';
                }
            }
        }

        PullMenu.active = {};
        PullMenu.visible = {};
    },

    'startCloseTimer': function()
    {
        if (PullMenu.timer != null) {
            clearTimeout(PullMenu.timer);
        }
        PullMenu.timer = setTimeout(function() {
            PullMenu.timer = null;
            PullMenu.hideAll();
        }, 500);
    },

    'stopCloseTimer': function()
    {
        if (PullMenu.timer != null) {
            clearTimeout(PullMenu.timer);
            PullMenu.timer = null;
        }
    },

    // Thanks to www.quirksmode.org for info on viewport properties:
    // http://www.quirksmode.org/viewport/compatibility.html
    'getScreenInfo': function()
    {
        var width, height;
        // All, except Explorer.
        if (self.innerHeight) {
            width  = self.innerWidth;
            height = self.innerHeight;
        }
        // Explorer 6 Strict Mode.
        else if (document.documentElement &&
                 document.documentElement.clientHeight) {
            width  = document.documentElement.clientWidth;
            height = document.documentElement.clientHeight;
        }
        // Other Explorers.
        else if (document.body) {
            width  = document.body.clientWidth;
            height = document.body.clientHeight;
        }

        // -16 for scrollbar that is counted in in some browsers.
        width  -= 16;
        height -= 16;

        var scroll_x, scroll_y;
        // All, except Explorer.
        if (self.pageYOffset) {
                scroll_x = self.pageXOffset;
                scroll_y = self.pageYOffset;
        }
        // Explorer 6 Strict.
        else if (document.documentElement && document.documentElement.scrollTop) {
                scroll_x = document.documentElement.scrollLeft;
                scroll_y = document.documentElement.scrollTop;
        }
        // All other Explorers.
        else if (document.body) {
                scroll_x = document.body.scrollLeft;
                scroll_y = document.body.scrollTop;
        }

        return {
            'width'     : width,
            'height'    : height,
            'scroll_x'  : scroll_x,
            'scroll_y'  : scroll_y,
            'visible_x' : width + scroll_x,
            'visible_y' : height + scroll_y
        };
    },

    'getStyle': function(obj, element)
    {
        if (obj.currentStyle) {
            return obj.currentStyle[element];
        } else if (window.getComputedStyle) {
            var s = document.defaultView.getComputedStyle(obj, null);
            return s.getPropertyValue(element);
        } else {
            return null;
        }
    },

    'getScreenPos': function(obj)
    {
        var top = left = 0;
        var rel_top = rel_left = null;

        do {
            top  += obj.offsetTop;
            left += obj.offsetLeft;
            if (obj && rel_top == null) {
                var pos = PullMenu.getStyle(obj, 'position');
                if (pos == 'relative' || pos == 'absolute') {
                    rel_top  = top;
                    rel_left = left;
                }
            }
            obj = obj.offsetParent;
        } while (obj);

        if (rel_left == null) {
            rel_left = left;
            rel_top  = top;
        }

        return {
            'top'      : top,
            'left'     : left,
            'rel_left' : rel_left,
            'rel_top'  : rel_top
        };
    },

    'openSubMenu': function(menu, id)
    {
        // If the menu is a menu item, then find its parent menu.
        // This way, deeper submenus that are possible opened
        // will be collapsed.
        if (menu && menu.className.indexOf('pullmenu_item') !== -1) {
            var n = menu.parentNode.id;
            if (n.indexOf('pullmenu_menu_content_' + id) == 0) {
                var menu_id = n.substr(22);
                if (menu_id == 0) {
                    menu = null;
                } else {
                    var pid = 'pullmenu_item_' + menu_id;
                    var p = document.getElementById(pid);
                    if (p) menu = p;
                }
            }
        }

        // Find the parent menu, parent item and child menu.
        var menu_id = menu == null ? id : menu.menu_id;
		//alert(menu_id);
        var parent_id = menu == null ? id : menu.parent_id;
		//alert(parent_id);
        var p_menu = menu_id == id
	          ? document.getElementById('pullmenu_menu_' + id)
              : document.getElementById('pullmenu_menu_' + parent_id);
        var p_item = menu_id == id
              ? document.getElementById('pullmenu_root_' + id)
              : document.getElementById('pullmenu_item_' + menu_id)
		//alert(menu_id);
        var c_menu = document.getElementById('pullmenu_menu_' + menu_id);
	    //alert(c_menu);
        // If we did not find the required objects, then silently ignore
        // the problem and stop processing.
        if (!p_item || !c_menu) return;
        if (menu_id != id && !p_menu) return;

        // Do some dimension handling and storage the first time that the
        // menu is opened.
        if (!c_menu.pullmenu_init_done)
        {
            // Without making the menu visible, we don't know the width/height
            // of the menu div, because those are only available after rendering
            // the menu HTML code. So for positioning the menu, we have a
            // chicken/egg problem to fix. I fix it by moving the egg out of
            // the visible screen area before making it visible.
            c_menu.style.top  = '-500px';
            c_menu.style.left = '-500px';
            c_menu.style.display = 'block';

            // This should put the menus on top at most pages.
            c_menu.style.zIndex = 1000;

            // force the widths for the <a href="..."> tags. this is needed to
            // make the links hoverable and clickable over the full menu width
            // in msie6 :(
            // the "var w" is used to prevent variable tag widths due to
            // accidental resizing of the menu while setting the tag widths
            // (i've seen that happening in opera).
            var ahrefs = c_menu.getElementsByTagName('a');
            var w = null;
            for (var i=0; i<ahrefs.length; i++) {
                var a = ahrefs[i];
                if (!w) w = a.offsetWidth;
                a.style.width = w;
            }

            // store the displaying dimensions in the div object.
            c_menu.pullmenu_width  = c_menu.offsetWidth;
            c_menu.pullmenu_height = c_menu.offsetHeight;

            // In MSIE, we have to fix the problem that windowed controls
            // like <select> will always be on top of <div>s. We can use
            // some special behavior of <iframe> for this. It's ugly but
            // the only way to make this work cleanly.
            // We do a check for MSIE here. It's no problem if other browsers
            // use a modified userAgent for some reason, triggering this code.
            // I only want to make sure that it is at least used in MSIE.
            if (navigator.userAgent && navigator.userAgent.indexOf('MSIE')>=0)
            {
                var i = document.createElement('iframe');
                i.scrolling      = 'no';
                i.frameborder    = '0';
                i.src            = 'javascript:false';
                i.style.border   = 'none';
                i.style.display  = 'block';
                i.style.left     = '0px';
                i.style.top      = '0px';
                i.style.width    = c_menu.pullmenu_width + 'px';
                i.style.height   = c_menu.pullmenu_height + 'px';
                i.style.position = 'absolute';
                i.style.zIndex  = c_menu.style.zIndex - 1;

                c_menu.parentNode.appendChild(i);

                c_menu.work_around_iframe = i;
            }

            c_menu.pullmenu_init_done = 1;
            c_menu.style.display = 'none';
        }

        // keep track of the menu depth and menu drawing direction.
        // first level menu.
        if (menu_id == id)
        {
            c_menu.depth = 1;

            // at the first level, we look at the main menu item. if that one
            // uses rel="pullmenu_left", then the direction of the whole
            // menu structure will be left. by default, this direction is right.
            c_menu.direction = 'right';
            if (p_item.rel && p_item.rel == 'pullmenu_left') {
                c_menu.direction = 'left';
            }
        }
        // second level and deeper.
        else
        {
            c_menu.depth = p_menu.depth + 1;

            // inherit the parent's menu direction.
            c_menu.direction = p_menu.direction;
        }

        // determine the screen dimensions.
        var scr = PullMenu.getScreenInfo();

        // determine the top-left of the parent menu item.
        var p_item_pos = PullMenu.getScreenPos(p_item);

        var top  = p_item_pos.rel_top;
        var left = p_item_pos.rel_left;

        // determine the location of the child menu.
        // the first level menu is placed directly beneath the main menu object.
        if (menu_id == id)
        {
            top  = top + p_item.offsetHeight;

            if (c_menu.direction == 'left')
            {
                left = left - (c_menu.pullmenu_width - p_item.offsetWidth);
                if (left < scr.scroll_x) left = scr.scroll_x + 2;
            }
            else
            {
                left = left;
                if ((left + c_menu.pullmenu_width) > scr.width) {
                    left = scr.width - c_menu.pullmenu_width - 2;
                }
            }
        }
        // second level and deeper levels are handled as standard menu popups
        // (placed to the right or left of the selected item).
        else
        {
            var dir = c_menu.direction;

            var left_pos =
                left // the left side of the parent menu item
                - PullMenu.menuspacing // handle menu spacing
                - p_item.parentNode.offsetLeft // adjustment for padding;
                - c_menu.pullmenu_width; // add child menu width;

            var right_pos =
                left // the left side of the parent menu item
                + PullMenu.menuspacing  // handle menu spacing
                - p_item.parentNode.offsetLeft // adjustment for padding;
                + p_menu.offsetWidth; // add parent menu width

            if (dir == 'left') {
                if (left_pos < scr.scroll_x) {
                    dir = 'right';
                } else {
                    left = left_pos;
                }
            }

            if (dir == 'right') {
                if ((right_pos + c_menu.pullmenu_width) > scr.visible_x) {
                    left = left_pos;
                } else {
                    left = right_pos;
                }
            }
        }

        // take extra vertical space into account for adjusting for
        // padding of the menu div.
        if (menu_id) {
            top -= p_item.parentNode.offsetTop;
        }

        // move the menu up if needed.
        if ((top + c_menu.pullmenu_height) > scr.visible_y) {
            top = scr.visible_y - c_menu.pullmenu_height - 2;
            if (top < scr.scroll_y) top = scr.scroll_y + 2;
        }

        // move the menu into position and make it visible.
        c_menu.style.top  = top  + 'px';
        c_menu.style.left = left + 'px';
        c_menu.style.display = 'block';

        // If we have an iframe for working around an MSIE problem, then
        // place that one as well. This one needs different placement in
        // case the menu is running within some absolute or relative div.
        if (c_menu.work_around_iframe) {
            i = c_menu.work_around_iframe;
            i.style.top  = top + 'px';
            i.style.left = left + 'px';
            i.style.display = 'block';
        }

        // keep track of the active menu for the current menu level.
        PullMenu.active[c_menu.depth] = c_menu;

        // cleanup the menus that should not be visible anymore.
        for (var depth in PullMenu.visible) {
            for (var idx in PullMenu.visible[depth]) {
                var o = PullMenu.visible[depth][idx];
                if (depth > c_menu.depth ||
                    o.id != PullMenu.active[depth].id) {
                    o.style.display = 'none';

                    if (o.work_around_iframe) {
                        o.work_around_iframe.style.display = 'none';
                    }
                }
            }
        }

        // keep track of visible menus.
        PullMenu.visible[c_menu.depth] = {};
        PullMenu.visible[c_menu.depth][c_menu.id] = c_menu;
    }

};
