/** hpMenu.js

    A multi-level horizontal pop-up menu
    
    23 August 2001
    Konrad Markus <konrad.markus@uk.didata.com>

    A horizontally expanding multi-level popup menu.
    

    Requires:
    =========
    leLayer     [obj: lelayer.js]

    Example:
    ========
    There are two leLayer objects needed for each level.

        HTML:
            ...
            
            <div id="level0Content">
            </div>
            <div id="level0Spacer">
            </div>

            <div id="level1Content">
            </div>
            <div id="level1Spacer">
            </div>

            ...
        -----------------------------
        CSS:
            ...
            
            // for leLayer objects
            #level0Content 	{ position:absolute; left:0px; top:0px; z-index:1; visibility: hidden; }
            #level0Spacer 	{ position:absolute; left:0px; top:0px; z-index:3; visibility: hidden; }

            #level1Content 	{ position:absolute; left:0px; top:0px; z-index:4; visibility: hidden; }
            #level1Spacer 	{ position:absolute; left:0px; top:0px; z-index:6; visibility: hidden; }
            
            // style the menu
            .level0On {
                font-family: Verdana, Helvetica, sans-serif;
                font-size: 11px;
                font-weight: bold;
                color: #330066;
                background: #CB99CC;
            }
            .level0Off {
                font-family: Verdana, Helvetica, sans-serif;
                font-size: 11px;
                font-weight: bold;
                color: #FFFFFF;
                background: #CB99CC;
            }

            .level1On {
                font-family: Verdana, Helvetica, sans-serif;
                font-size: 11px;
                font-weight: bold;
                color: #330066;
                background: #CB99CC;
            }
            .level1Off {
                font-family: Verdana, Helvetica, sans-serif;
                font-size: 11px;
                font-weight: bold;
                color: #FFFFFF;
                background: #CB99CC;
            }


            ...
        -----------------------------
        SCRIPT:
            ...

            // need one for each level of menu.
            l_level0 = new leLayer('level0Content');
            leLayerLinkTo(l_level0, new leLayer('level0Spacer'));
            leLayerSetLinkInset(l_level0, 0);
            leLayerSetBackground(l_level0, '#CB99CC');

            l_level1 = new leLayer('level1Content');
            leLayerLinkTo(l_level1, new leLayer('level1Spacer'));
            leLayerSetLinkInset(l_level1, 0);
            leLayerSetBackground(l_level1, '#CB99CC');

            // instantiate the menu object
            // hpMenu(leLayer layer, int width, string name, int left, int top)
            menu = new hpMenu(l_level0, 96, 'menu', 0, 110);
            menu.seplineStyle     = 'sepline';
            menu.seplineThickness = 1;
            menu.spacerImage      = 'images/spacer.gif';
            menu.gutterWidth      = 8;
            
            // add some items
            // hpMenuFAddItem(hpMenu menu, string label, string link, int height, string off_style_name, string on_style_name)
            hpMenuFAddItem(menu, 'an item label', 'http://www.link.com/', 23, 'level0Off', 'level0On');
            hpMenuFAddItem(menu, 'another item label', 'link.html', 25, 'level0Off', 'level0On');

            // add a sub menu to the second item
            // hpMenuItemFAddSubMenu(hpMenuItem parent_item, leLayer layer, int width)
            hpMenuItemFAddSubMenu(menu.items[1], l_level1, 260);
            
            // add some items to the submenu
            hpMenuFAddItem(menu.items[1].subMenu, 'a submenu item label', 'link1.html', 23, 'level1Off', 'level1On');

            // make the menu visible
            hpMenuFShow(menu, true);

            ...


    Compatability:
    ==============
        - should work on most netscape 4+ and internet explorer 4+ on PC/MAC

        - *FIXME* more precise testing.

    Known bugs/Issues:
    ==================
        - flickery on netscape 4?

        - *FIXME* others
 */

// var errwin = window.open('scripts/err.html', 'errwin');
// errwin.printlnerr('konkerisking');    

/** Global 'consts'
 */
var hpM_SHOW_DELAY      = 400;
var hpM_HIDE_DELAY      = 300;

var hpMenuMotherTimerId = null;
var _hpMenuDeepHideLock = false;

var hpMenuTimerIds = new Array();

// defaults
var hpM_INVALID_INDEX             = -1;
var hpM_DEFAULT_SPACER_IMAGE      = 'images/spacer.gif';
var hpM_DEFAULT_SEPLINE_STYLE     = 'sepline';
var hpM_DEFAULT_SEPLINE_THICKNESS = 1;
var hpM_DEFAULT_GUTTER_WIDTH      = 8;

/** hpMenu
 */
function hpMenu(menuRep, width, id, left, top, mother) {
    this.menuRep  = menuRep;
    this.width    = width    || 0;
    this.id       = id       || "";
    this.left     = left     || 0;
    this.top      = top      || 0;
    this.mother   = mother   || this;
    
    this.items         = new Array();
    
    this.height        = 0;
    this.parent        = null;
    this.selectedIndex = hpM_INVALID_INDEX;
    this.lastIndex     = hpM_INVALID_INDEX;
    this.depth         = 0;

    // 'public' members
    this.spacerImage      = hpM_DEFAULT_SPACER_IMAGE;
    this.seplineStyle     = hpM_DEFAULT_SEPLINE_STYLE;
    this.seplineThickness = hpM_DEFAULT_SEPLINE_THICKNESS;
    this.gutterWidth      = hpM_DEFAULT_GUTTER_WIDTH;
}

/** Hide the menu and any sub-menus
    uses _hpMenuDeepHideLock in an attempt to prevent conflicts
 */
function hpMenuFDeepHide(menu, _override_lock) {
    if (_hpMenuDeepHideLock && !_override_lock) {
        return;
    }
    _hpMenuDeepHideLock = true;

    if (menu.parent && !menu.parent.selected) {
        hpMenuFHide(menu);
    }
    else if (!menu.parent) {
        hpMenuFPaint(menu);
    }

    if (menu.selectedIndex != hpM_INVALID_INDEX && menu.items[menu.selectedIndex].subMenu) {
        hpMenuFDeepHide(menu.items[menu.selectedIndex].subMenu, true);
        menu.selectedIndex = hpM_INVALID_INDEX;
    }
    else {
        _hpMenuDeepHideLock = false;
        return;
    }
}

/** Hide the menu
 */
function hpMenuFHide(menu) {
    if (menu.parent) {
       leLayerSetVisible(menu.menuRep, false);
    }
}

/** Show the menu
    if now is true then hpM_SHOW_DELAY is not used and 
    the menu is shown immediately
 */
function hpMenuFShow(menu) {
    if (menu.parent && menu.parent.parent.lastIndex == menu.parent.index) {
        hpMenuFPaint(menu);
        leLayerSetVisible(menu.menuRep, true);
        menu.parent.parent.lastIndex = menu.parent.index;
        return;
    }

    leLayerMoveTo(menu.menuRep, menu.left, menu.top);
    leLayerSetWidth(menu.menuRep, menu.width);
    leLayerSetHeight(menu.menuRep, menu.height);
    hpMenuFPaint(menu);

    // write spacer layer
    var ss = '<table border="0" cellpadding="0" cellspacing="0" width="' + menu.width + '">\n';
    for (var i in menu.items) {
        ss += hpMenuItemFGetSpacerHTML(menu.items[i]);
    }
    ss += '</table>\n';
    leLayerWrite(menu.menuRep.linked, ss);

    // leLayerSetOpacity(menu.menuRep, 95);
    leLayerSetVisible(menu.menuRep, true);
}

/** Add a menu item to a menu
 */
function hpMenuFAddItem(menu, label, link, height, offStyle, onStyle) {
    var i = menu.items.length;
    menu.items[i] = new hpMenuItem(label, link, height, offStyle, onStyle);

    menu.items[i].parent = menu;
    menu.items[i].index  = i;
    
    hpMenuItemFSetWidth(menu.items[i], menu.width);
    hpMenuItemFSetTop(menu.items[i], menu.top + menu.height);
    hpMenuItemFSetLeft(menu.items[i], menu.left);
    
    menu.items[i].pathToTop = (menu.id + ".items[" + i + "]");
    menu.items[i].mother = menu.mother;
    menu.items[i].depth = menu.depth;
    
    menu.height += (menu.items[i].height + menu.seplineThickness);
    
}

function hpMenuFSetTop(menu, t) {
    menu.top = t;
    menu.tmp = 0;
    for (var i in menu.items) {
        hpMenuItemFSetTop(menu.items[i], t + tmp)
        tmp += menu.items[i].height;
    }
}

function hpMenuFSetLeft(menu, l) {
    menu.left = l;
    for (var i in menu.items) {
        hpMenuItemFSetLeft(menu.items[i], l)
    }
}

function hpMenuFSetWidth(menu, w) {
    menu.width = w;
    for (var i in menu.items) {
        hpMenuItemFSetWidth(menu.items[i], w)
    }
}

function hpMenuFPaint(menu) {
    if (menu.menuRep) {
        leLayerWrite(menu.menuRep, hpMenuFGetHTML(menu));
    }
}

function hpMenuFGetHTML(menu) {
    var ret = '<table border="0" cellpadding="0" cellspacing="0" width="' + menu.width + '">\n';
    ret += '<tr>\n';
    if (menu.parent) {
        ret += '<td class="' + menu.seplineStyle + '"><img src="' + menu.spacerImage + '" width="' + menu.seplineThickness + '" height="1" border="0"></td>';
    }

    ret += '<td><img src="' + menu.spacerImage + '" width="' + menu.gutterWidth + '" height="1" border="0"></td>';

    ret += '<td>\n<table border="0" cellpadding="0" cellspacing="0" width="' + (menu.width - (menu.parent ? menu.seplineThickness : 0) - (2*menu.gutterWidth)) + '">';
    for (var i in menu.items) {
        ret += hpMenuItemFGetContentHTML(menu.items[i], (i == (menu.items.length-1)));
    }
    ret += '</table></td>';
    
    ret += '<td><img src="' + menu.spacerImage + '" width="' + menu.gutterWidth + '" height="1" border="0"></td>';
    ret += '</tr></table>\n';
    return ret;
}

/** hpMenuItem
 */
function hpMenuItem(label, link, height, offStyle, onStyle) {
    this.label    = label    || "link";
    this.link     = link     || "#";
    this.height   = height   || 0;
    this.offStyle = offStyle || "";
    this.onStyle  = onStyle  || "";
    this.subMenu  = null;

    this.parent    = null;
    this.pathToTop = "";
    this.mother    = null;
    this.selected  = false;
    this.index     = hpM_INVALID_INDEX;
    this.top       = 0;
    this.left      = 0;
    this.width     = 0;
    this.depth     = 0;
}

function hpMenuItemFAddSubMenu(menuItem, menuRep, width) {
    menuItem.subMenu = new hpMenu(menuRep, width);
    menuItem.subMenu.depth = menuItem.depth + 1;
    
    if (hpMenuTimerIds.length < menuItem.subMenu.depth) {
        hpMenuTimerIds[menuItem.subMenu.depth] = 0;
    }
    
    menuItem.subMenu.parent  = menuItem;
    menuItem.subMenu.id      = menuItem.pathToTop + ".subMenu";
    menuItem.subMenu.mother  = menuItem.mother;

    menuItem.subMenu.spacerImage      = (menuItem.parent.spacerImage || hpM_DEFAULT_SPACER_IMAGE);
    menuItem.subMenu.seplineStyle     = (menuItem.parent.seplineStyle || hpM_DEFAULT_SEPLINE_IMAGE);
    menuItem.subMenu.seplineThickness = (menuItem.parent.seplineThickness || hpM_DEFAULT_SEPLINE_THICKNESS);
    menuItem.subMenu.gutterWidth      = (menuItem.parent.gutterWidth || hpM_DEFAULT_GUTTER_WIDTH);

    hpMenuFSetTop(menuItem.subMenu, menuItem.top);
    hpMenuFSetLeft(menuItem.subMenu, menuItem.left + menuItem.width);
}

function hpMenuItemFOver(menuItem) {
    if (_hpMenuDeepHideLock) {
        return false;
    }
    // cancel hide
    clearTimeout(hpMenuMotherTimerId);
    clearTimeout(hpMenuTimerIds[menuItem.depth]);

    if (menuItem.parent.parent) {
        clearTimeout(hpMenuTimerIds[menuItem.parent.parent.depth]);
    }

    // if have submenu open it
    if (menuItem.subMenu) {
        if (menuItem.parent.selectedIndex != hpM_INVALID_INDEX && menuItem.parent.items[menuItem.parent.selectedIndex].subMenu) {
            hpMenuTimerIds[menuItem.depth] = setTimeout('hpMenuFShow(' + menuItem.subMenu.id + ')', hpM_SHOW_DELAY);
        }
        else {
            hpMenuTimerIds[menuItem.depth] = setTimeout('hpMenuFShow(' + menuItem.subMenu.id + ')', hpM_SHOW_DELAY);
        }
    }
    else {
        // if previous submenu is open hide it
        if (menuItem.parent.selectedIndex != hpM_INVALID_INDEX && menuItem.parent.items[menuItem.parent.selectedIndex].subMenu) {
            hpMenuTimerIds[menuItem.depth] = setTimeout('hpMenuFDeepHide(' + menuItem.parent.items[menuItem.parent.selectedIndex].subMenu.id + ')', hpM_HIDE_DELAY);

        }
    }

    // highlight menu item and repaint
    if (!menuItem.selected) {
        menuItem.selected = true;
        
        menuItem.parent.selectedIndex = menuItem.index;
        
        hpMenuFPaint(menuItem.parent);
    }

    // make sure parent menu if any is in a consistent state
    if (menuItem.parent && menuItem.parent.parent) {
        with (menuItem.parent.parent) {
            if (parent.selectedIndex != index && !_hpMenuDeepHideLock) {
                selected = true;
                parent.items[parent.selectedIndex].selected = false;
                parent.selectedIndex = index;

                hpMenuFPaint(parent);
            }
        }
    }
    return true;
}

function hpMenuItemFOut(menuItem) {
    if (_hpMenuDeepHideLock) {
        return false;
    }
    // unhighlight item and repaint
    menuItem.selected = false;

    // make sure parent menu if any is in a consistent state
    if (menuItem.parent && menuItem.parent.parent) {
        with (menuItem.parent.parent) {
            if (parent.selectedIndex == index && !_hpMenuDeepHideLock) {
                selected = false;
            }
        }
    }
    
    // set mother to do deep hide
    clearTimeout(hpMenuTimerIds[menuItem.depth]);
    hpMenuTimerIds[menuItem.depth] = setTimeout('hpMenuFDeepHide(' + menuItem.parent.id + ')', hpM_HIDE_DELAY);
    hpMenuMotherTimerId = setTimeout('hpMenuFDeepHide(' + menuItem.mother.id + ')', hpM_HIDE_DELAY);
    return true;
}

function hpMenuItemFMove(menuItem) {
    if (_hpMenuDeepHideLock) {
        return false;
    }
    if (menuItem.subMenu && !leLayerIsVisible(menuItem.subMenu.menuRep)) {
        return hpMenuItemFOver(menuItem);
    }
    return false;
}

function hpMenuItemFSetTop(menuItem, t) {
    menuItem.top = t;
    if (menuItem.subMenu) {
        hpMenuFSetTop(menuItem.subMenu, t);
    }
}

function hpMenuItemFSetLeft(menuItem, l) {
    menuItem.left = l;
    if (menuItem.subMenu) {
        hpMenuFSetLeft(menuItem.subMenu, l + menuItem.width);
    }
}

function hpMenuItemFSetWidth(menuItem, w) {
   menuItem.width = w;
    if (menuItem.subMenu) {
        hpMenuFSetWidth(menuItem.subMenu, w);
    }
}


var font_tag_begin = '<font face="Verdana, Helvetica, sans-serif" size="1" color="FFFFFF"><b>';
var font_tag_end = '</b></font>';

function hpMenuItemFGetContentHTML(menuItem, last) {
    ret = '<tr><td width="' + (menuItem.parent.width - (menuItem.parent.parent ? menuItem.parent.seplineThickness : 0) - (2*menuItem.parent.gutterWidth)) + '" height="' + menuItem.height + '" class="' + (menuItem.selected ? menuItem.onStyle : menuItem.offStyle) + '">' + ((document.layers)? font_tag_begin : '' ) + menuItem.label + ((document.layers)? font_tag_end : '' ) + '</td></tr>\n';
    if (!last || !(menuItem.parent.parent)) {
        ret += '<tr><td height="' + menuItem.parent.seplineThickness + '" valign="middle" align="center" class="' + menuItem.parent.seplineStyle + '"><img src="' + menuItem.parent.spacerImage + '" width="1" height="' + menuItem.parent.seplineThickness + '" border="0"></td></tr>\n';
    }
    return ret;
}

function hpMenuItemFGetSpacerHTML(menuItem) {
    return '<tr><td width="' + menuItem.parent.width + '" height="' + (menuItem.height+menuItem.parent.seplineThickness) + '"><a href="' + menuItem.link + '" onmouseover="hpMenuItemFOver(' + menuItem.pathToTop + ')" onmouseout="hpMenuItemFOut(' + menuItem.pathToTop + ')" onmousemove="hpMenuItemFMove(' + menuItem.pathToTop + ')"><img src="' + menuItem.parent.spacerImage + '" width="' + menuItem.parent.width + '" height="' + (menuItem.height+menuItem.parent.seplineThickness) + '" border="0"></a></td></tr>\n';
}
