 /***************************************************************************
 * menu.js
 *  Functions to build the table of contents menu
 *
 *  The required <body onLoad="..."> call is 'buildMenus();'
 *
 *  Simon Hunt
 *  May 2007
 ***************************************************************************/


/** Stuff to get done when the page loads into the browser */
function buildMenus(pathToRoot)
{
    setupMenuArray(pathToRoot);   // defined in toc.js (which is generated from toc.txt)
    _BuildMenus();      // generates the HTML for the menus
    _RenderMenus();
}


/* Initialization - done before the body is loaded */
var goStuff;

if (goStuff == null) {
    /** Configurable Parameters Here: **/
    var menuWidth = 120;

    /** Best not to mess with stuff below here: **/
    var isIE = (navigator.userAgent.toLowerCase().indexOf("msie")!=-1);
    var isNetscape = (navigator.userAgent.toLowerCase().indexOf("compatible")==-1);

    var newLineChar = String.fromCharCode(10);
    var menuPlaceHolder = "<!--LOAD_MENU_CELLS_HERE-->";

    var goNav;      // global object Navigation (Menu Definition Object?)
    var goMenu;     // global object Menu staging array

    var oNav1Menu = null;   // level 1 menu object
    var oNav2Menu = null;   // level 2 menu object

    _InitGlobals();
    _InitMenu();

} // if need to initialize


function _InitGlobals()
{
    //alert("_InitGlobals()");
    goStuff = new Array();
    goStuff.menuDrawn = false;

    goNav = new Array();
    goMenu = new Array();
} // func _InitGlobals

function _InitMenu()
{
    //alert("_InitMenu()");

    // : This is the table containing the top level menu items (and filler) :
    goNav.menuString1 =
        "<table border='0' cellspacing='0' cellpadding='0' width='" +
            menuWidth + "'> " + menuPlaceHolder + "</table>";

    // : This holds the hidden divs for the sub menu blocks :
    goNav.menuString = "";

} // func _InitMenu


//=============================================================================
// Func:    createMenu( sMenuID, sMenuDisplay [, sMenuURL [, sTarget]] )
// Desc:    Create Top Level Menu (Level 1)
// Args:    sMenuID        - ID of menu to link 2nd level items
//          sMenuDisplay   - Title to display on the menubar
//          sMenuURL (opt) - If menu item does not contain submenu, URL to go to
//          sTarget (opt)  - Target location for document to be displayed
// Return:  None
//=============================================================================
function createMenu(sMenuID, sMenuDisplay) {
    var sPath = ""; // path to root
    var sMenuURL = "";      // URL to point to
    var sTarget  = "_top";  // Target for link
    var aMenu = new Array(5);

    if (createMenu.arguments.length > 2)
        sMenuURL = createMenu.arguments[2];

    if (createMenu.arguments.length > 3)
        sPath = createMenu.arguments[3];

    if (createMenu.arguments.length > 4)
        sTarget = createMenu.arguments[4];

    if (sPath && (sMenuURL.indexOf("http://") != 0)) {
    	sMenuURL = sPath + "/" + sMenuURL;
    }

    aMenu[0] = "Level1";                    // menu level
    aMenu[1] = "TOC_" + sMenuID + "_MENU";  // menu ID
    aMenu[2] = sMenuDisplay;                // display string
    aMenu[3] = sMenuURL;                    // dest URL
    aMenu[4] = sTarget;                     // target for link

    goMenu.push(aMenu);
} // func createMenu

//=============================================================================
// Func:    addMenuItem( sMenuID, sSubMenu, sSubMenuURL [, sTarget] )
// Desc:    Adds a sub-menu item under the specified menu item.
// Args:    sMenuID        - ID of menu item
//          sSubMenu       - Label for Sub-Menu item
//          sSubMenuURL    - URL associated with the sub-menu item
//          sPathToRoot (opt) - path for this page to reference root dir
//          sTarget (opt)  - target location for document to be displayed
// Return:  None
//=============================================================================
function addMenuItem(sMenuID, sSubMenu, sSubMenuURL) {
    var sPath = ""; // path to root
    var sTarget = "_top"; // Target of link.
    var aMenu = new Array(5);

    if (addMenuItem.arguments.length > 3) {
        sPath = addMenuItem.arguments[3];
    }
    if (addMenuItem.arguments.length > 4) {
        sTarget = addMenuItem.arguments[4];
    }
    if (sPath && (sSubMenuURL.indexOf("http://") != 0)) {
    	sSubMenuURL = sPath + "/" + sSubMenuURL;
    }

    aMenu[0] = "Level2";
    aMenu[1] = "TOC_" + sMenuID + "_MENU";
    aMenu[2] = sSubMenu;
    aMenu[3] = sSubMenuURL;
    aMenu[4] = sTarget;

    goMenu.push(aMenu);
} // func addMenuItem


//=============================================================================
// Func:    _BuildMenus()
// Desc:    Builds the HTML for the Menus
// Args:    None
// Return:  None
//=============================================================================
function _BuildMenus()
{
    var aMenu;
    for(var i=0; i < goMenu.length; i++) {
        aMenu = goMenu[i];
        switch (aMenu[0]) {
            case "Level1":
                _CreateMenu(aMenu[1], aMenu[2], aMenu[3], aMenu[4]);
                break;

            case "Level2":
                _AddMenuItem(aMenu[1], aMenu[2], aMenu[3], aMenu[4]);
                break;
        } // switch
    } // for

    //clear out the array
    goMenu = new Array();
} // func _BuildMenus


//=============================================================================
// Func:    _CreateMenu(sMenuID, sMenuDisplay)
// Desc:    Internal Call - Create Top Level Menu (Level 1)
// Args:    sMenuID - ID of menu to link 2nd level items
//          sMenuDisplay - Title of menu item
// Return:  None
//=============================================================================
function _CreateMenu(sMenuID, sMenuDisplay, sMenuURL, sTarget)
{
    var sMenu = newLineChar;
    var sLinkMenuID = "AM_" + sMenuID;

    var handleMouse =
            "onmouseout=\"_DelayHideMenu();\" " +
            "onmouseover=\"_DoMenu(event, '" + sLinkMenuID + "', '" +
                                sMenuID + "', '');\" ";

    var linkDef =
        "<a id='idLocalNav' class='nolink' " +
        "href=\"javascript:void();\" onclick=\"return false;\" " +
        "style='text-decoration:none;'>" +
        sMenuDisplay + "</a>";

    if( sMenuURL.length > 0 ){
	linkDef = 
                "<a id='idLocalNav' target=\"" + sTarget + "\" " +
		" href='" + sMenuURL + "' " +
		">" + sMenuDisplay + "</a>";
    }


    sMenu += "<tr><div style='position:relative'>" +
            "<td class='nav1Up' ID='" + sLinkMenuID + "' nowrap " +
            handleMouse + ">" + linkDef +
            "</td></div></tr>" +
            menuPlaceHolder;

    // : insert our generated HTML into our menu string construction :
    goNav.menuString1 = goNav.menuString1.replace(menuPlaceHolder, sMenu);
} //func _CreateMenu



//=============================================================================
// Func:    _AddMenuItem(sMenuID, sSubMenu, sSubMenuURL, sTarget)
// Desc:    Associates this "sub-menu" item to the specified menu item
// Args:    sMenuID - ID of menu item
//          sSubMenu - Label
//          sSubMenuURL - URL
//          sTarget - target location for document to be displayed
// Return:  None
//=============================================================================
function _AddMenuItem(sMenuID, sSubMenu, sSubMenuURL, sTarget)
{
    var sMenuString = goNav.menuString;
    var sURL = sSubMenuURL;
    var sMenuType = "idLocalNav";
    var sLookUpTag  = "<!--" + sMenuID + "-->";
    var iPos = sMenuString.indexOf(sLookUpTag);
    var sTemp = newLineChar;

    if (iPos <= 0) {
        // : didn't find the menu tag in the nav menu string :
        sMenuString += newLineChar + newLineChar +
            "<div id='" + sMenuID + "' " +  " style='display:none;'>";
    }

    if (sURL) {
        // catch CALENDAR tag and convert to URL for correct month
        if (sURL.match(/CALENDAR/)) {
            sURL = sURL.replace("CALENDAR", getCalendarMonthURL());
        }

        sTemp += "<div class='nav2MenuItem' nowrap>" +
                "<a id=\"" + sMenuType + "\" target=\"" + sTarget + "\" ";

        sTemp += " href='" + sURL + "' ";

        sTemp += ">" + sSubMenu + "</a></div>";
    } else {
        /** used for separators?? **/
        sTemp += "<label>" + sSubMenu + "</label>";
    }

    sTemp += sLookUpTag;

    if (iPos <= 0) {
        // : this is the first sub menu item :
        sMenuString += sTemp + "</div>";
    }
    else {
        // : div already exists - append sub menu item
        sMenuString = sMenuString.replace(sLookUpTag, sTemp);
    }

    goNav.menuString = sMenuString;
} // func _AddMenuItem


function _RenderMenus()
{
    var sHTML;
    sHTML = "<div>" + goNav.menuString1 + "</div>";

    sHTML += "<div id='popmenu' class='nav2Skin' "+
            "onMouseover=\"_ClearHideMenuTimeout();_HighlightNav2Menu(event,'on');\" "+
            "onMouseout=\"_HighlightNav2Menu(event,'off');_DynamicHide(event);\"></div>" +
            goNav.menuString;

    // finally, insert the HTML into the document...
    var d = document.getElementById("TOC_Goes_Here");
    if (d) {
        d.innerHTML = sHTML;
    } // if

    goStuff.menuDrawn = true;
} // func _RenderMenus



//==============================================================================
// Function: _HideMenu
// Description: hide the dropdown menu
// Inputs: None
// Return: None
//==============================================================================
function _HideMenu() {

    // Check if we have a nav2 menu.
    if (oNav2Menu) {
        if (isIE) {
            _ShowElement("SELECT");
            _ShowElement("OBJECT");
            _ShowElement("IFRAME");
        }

        oNav2Menu.thestyle.visibility = "hidden";
        oNav2Menu.innerHTML = "";

        // Reset the nav1 to up.
        if (oNav1Menu) {
            oNav1Menu.className = "nav1Up";
        }
    }
}


//==============================================================================
// Function: _ContainsNetscape
// Description: Determines if 1 element is contained in another
// Inputs: a - element
//         b - element
// Return: None
//==============================================================================
function _ContainsNetscape(a, b) {
    while (b.parentNode)
    {
        if ((b = b.parentNode) == a) {
            return true;
        }
    }
    return false;
}

//==============================================================================
// Function: _DynamicHide
// Description: Sets the delay for the hiding of the menu.
// Inputs: e - event
// Return: None
//==============================================================================
function _DynamicHide(e){
    if (isIE&&!oNav2Menu.contains(e.toElement))
        _DelayHideMenu();
    else if (isNetscape&&e.currentTarget!= e.relatedTarget&& !_ContainsNetscape(e.currentTarget, e.relatedTarget))
        _DelayHideMenu();
}

//=============================================================================
// Func:    _DelayHideMenu
// Desc:    Sets the timeout to hide the menu.
// Args:    None
// Return:  None
//=============================================================================
function _DelayHideMenu(){
    var iDelay = 250;

    delayhide=setTimeout("_HideMenu()", iDelay);
} // func _DelayHideMenu

//=============================================================================
// Func:    _ClearHideMenuTimeout
// Desc:    Clears the timeout to hide the menu.
// Args:    None
// Return:  None
//=============================================================================
function _ClearHideMenuTimeout(){
    if (window.delayhide)
        clearTimeout(delayhide);
}


//==============================================================================
// Function: _HighlightNav2Menu
// Description: Highlights a link within the nav2 menu.
// Inputs: e - event element
//         state - state of the element
// Return: None
//==============================================================================
function _HighlightNav2Menu(e, state){
    var source_el;

    if (isIE) {
        source_el = e.srcElement; // IE
    } else {
        source_el = e.target; // Netscape
    }

    if (source_el.className=="nav2MenuItem") {
        source_el.id = (state=="on") ? "nav2DownHover" : "";
    } else {
        // : walk up through containment hierarchy to find the nav2MenuItem :
        while(source_el.id!="popmenu"){
            source_el=document.getElementById ? source_el.parentNode : source_el.parentElement;
            if (source_el.className=="nav2MenuItem") {
                source_el.id=(state=="on")? "nav2DownHover" : "";
            }
        } // while
    } // if-else
} // func _HighlightNav2Menu


//============================================================================
// Function: _getInnerText(level2Item)
// Description: This function is written because innerText function is not
//              supported in mozilla. This function will take an element and
//              get the text from it. The text produced will have lot of
//              spaces ??!!
// Inputs: level2Item - second level menu item
// Return: The inner text.
//==============================================================================
function _getInnerText(level2Item) {
    var finalStr = level2Item.innerHTML.replace(/<[^>]+>/g,"");

    // replace the &nbsp - spaces
    while (finalStr.indexOf("&nbsp;") != -1) {
        finalStr = finalStr.replace("&nbsp;", "");
    }

    escapedFinalStr = escape(finalStr);
    // hex version of the return character (%0D) and/or new line character (%0A),
    while(escapedFinalStr.indexOf("%0D") != -1) {
        escapedFinalStr = escapedFinalStr.replace("%0D", "");
    }
    while(escapedFinalStr.indexOf("%0A") != -1) {
        escapedFinalStr = escapedFinalStr.replace("%0A", "");
    }

    finalStr = unescape(escapedFinalStr);
    return finalStr;
}

//============================================================================
// Functions to get the true offset of anything on NS4, IE4/5 & NS6,
//  even if it's in a table. Also taking into account how the window
// might be scrolled.
//============================================================================
function getAbsX(elt)
{
    return (elt.x) ? elt.x : getAbsPos(elt,"Left");
}

function getAbsY(elt)
{
    return (elt.y) ? elt.y : getAbsPos(elt,"Top");
}

function getAbsPos(elt, which)
{
    var iPos = 0;
    while (elt != null) {
    iPos += elt["offset" + which];
        elt = elt.offsetParent;
    }
    return iPos;
}


//============================================================================
// Func:    _DoMenu(e, sLinkMenuID, sMenuID, sMenuURL)
// Desc:    Display Popup submenu
// Args:    e           - the event
//          sLinkMenuID - the ID of the level 1 Menu Cell
//          sMenuID     - the ID of the submenu div block
//          sMenuURL    - the URL if the level 1 is a LINK, not a submenu
// Return:  false
//==============================================================================
function _DoMenu(e, sLinkMenuID, sMenuID, sMenuURL) {
    var posX;
    var posY;
    var redisplay = false;
    var source_el;

    var oMenu = document.getElementById(sMenuID);
    var oSelectedNav1Menu = document.getElementById(sLinkMenuID);

    if (isIE) {
        source_el = e.srcElement; // IE
    } else {
        source_el = e.target; // Netscape
    }

    // Set the selected menu as down.
    oSelectedNav1Menu.className = "nav1DownHover";

    // Check if we have an old nav 1 menu.
    if (oNav1Menu) {
        // Make sure that it doesn't match the selected one.
        if (oNav1Menu != oSelectedNav1Menu) {
            // Change it to nav1up.
            oNav1Menu.className = "nav1Up";
        } else {
            redisplay = true;
        }
    } // if

    // Now remember the menu we just set down.
    oNav1Menu = oSelectedNav1Menu;

    _ClearHideMenuTimeout();

    oNav2Menu = document.getElementById("popmenu");
    oNav2Menu.thestyle = oNav2Menu.style;
    if( oMenu == null ){
    	oNav2Menu.innerHTML = "";
    }
    else{
		oNav2Menu.innerHTML = oMenu.innerHTML;
    }
    if (oNav2Menu.innerHTML != "") {
        /** workaround for the bug where some form elements
         *   get rendered over a layered div.
         *  Show any that were hidden by a previous call
         */
        if (isIE) {
            _ShowElement("SELECT");
            _ShowElement("OBJECT");
            _ShowElement("IFRAME");
        }

        // record height and width
        oNav2Menu.contentheight=oNav2Menu.offsetHeight;
        oNav2Menu.contentwidth=oNav2Menu.offsetWidth;

        // Get the X and Y positions for the display of the menu.
        posX = getAbsX(source_el.offsetParent) + menuWidth ;

        // make sure we are measuring from the TD element, not the A
        // (to prevent menu 'jitter' in FireFox)
        if (source_el.className == "nolink") {
            posY = getAbsY(source_el.offsetParent);
        } else {
            posY = getAbsY(source_el) ;
        }

        // debugging: output x and y:
        var dbg = document.getElementById("dbg");
        if (dbg) {
            dbg.innerHTML = "[ " + posX + ", " + posY + " ]";
        } // if

        // set the position of the menu
        oNav2Menu.thestyle.left = posX + "px";
        oNav2Menu.thestyle.top = posY + "px";

        if (isIE) {
            _HideElement(oNav2Menu, "SELECT");
            _HideElement(oNav2Menu, "OBJECT");
            _HideElement(oNav2Menu, "IFRAME");
        }

        oNav2Menu.thestyle.visibility="visible";
    } else {
        oNav2Menu.thestyle.visibility = "hidden";
    }

    return false;
}

//============================================================================
// Function: _HideElement(elmID)
// Description: Hide Elements on screen when displaying vertical dropdown
// Inputs: elmID - Element Type to hide
// Return:
//==============================================================================
function _HideElement(oNav2Menu, elmID) {
    if (isIE) {
        var i=0, obj, objLeft, objTop, objParent;
        var iNavTop, iNavLeft;

        iNavTop = parseInt(oNav2Menu.thestyle.pixelTop);
        iNavLeft = parseInt(oNav2Menu.thestyle.pixelLeft);

        for (i = 0; i < document.getElementsByTagName(elmID).length; i++) {
            obj = document.getElementsByTagName(elmID)[i];
            if (!obj || !obj.offsetParent) {
                continue;
            }

            objLeft   = obj.offsetLeft;
            objTop    = obj.offsetTop;
            objParent = obj.offsetParent;
            while (objParent != null){
               if (objParent.tagName.toUpperCase() != "BODY") {
                objLeft  += objParent.offsetLeft;
                objTop   += objParent.offsetTop;
                objParent = objParent.offsetParent;
               }else{
                 break;
               }
            }

            if ((objTop > (iNavTop + oNav2Menu.contentheight)) ||
                ((objTop + obj.clientHeight) < iNavTop)) {
                return;
            } else if ((objTop < (iNavTop + oNav2Menu.contentheight)) &&
                ((objTop + obj.clientHeight) > iNavTop) &&
                (objLeft > iNavLeft) &&
                (objLeft < (iNavLeft + oNav2Menu.contentwidth))) {
                obj.style.visibility = "hidden";
                obj.style.myFlagHide = true;
            } else if ((objTop < (iNavTop + oNav2Menu.contentheight)) &&
                ((objTop + obj.clientHeight) > iNavTop) &&
                ((objLeft + obj.clientWidth) > iNavLeft) &&
                ((objLeft + obj.clientWidth) < (iNavLeft + oNav2Menu.contentwidth))) {
                obj.style.visibility = "hidden";
                obj.style.myFlagHide = true;
            }
        }
    }
}

//============================================================================
// Function: _ShowElement(elmID)
// Description: Show Elements on screen when removing the vertical dropdown
// Inputs: elmID - Element Type to show
// Return:
//==============================================================================
function _ShowElement(elmID) {
    if (isIE) {
        var i=0, obj;

        for (i = 0; i < document.getElementsByTagName(elmID).length; i++) {
            obj = document.getElementsByTagName(elmID)[i];
            if (!obj)
                continue;

            if (obj.style.myFlagHide) {
                obj.style.visibility = "visible";
                obj.style.myFlagHide = false;
            }
        }
    }
} // func _ShowElement

function getCalendarMonthURL()
{
    var today = new Date();
    var year = today.getFullYear();
    var month = today.getMonth()+1;
    if (month < 10) month = "0" + month;
    var url = "/cal/" + year + "-" + month + ".html";
    return url;
}
