/*
 * @(#)dhtmlMenu.js	3.0 04/22/04
 * 
 * Copyright (c) 2004 JSoft, Inc. All Rights Reserved.
 *
 * JSoft grants you ("Licensee") a non-exclusive license to use and modify
 * this software in source and binary code form, provided that i) this 
 * copyright notice and license appear on all copies of the software; and
 * ii) Licensee does not utilize the software in a manner which is
 * disparaging to JSoft.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. JSOFT AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL JSOFT OR ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF JSOFT HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 */

/*
 * The purpose of the menu dropdown javascript utilities is to provide a set of
 * dhtml menu APIs that support DB/XML configuration of a dhtml navigation
 * menu.
 */

HJ.Menu = {};

HJ.Menu.currentButton = null;

HJ.menu = function(elementOrEvent)
{
    var el = null;
    if (elementOrEvent.innerHTML == undefined || elementOrEvent.srcElement != undefined)
    {
        el = HJ.Event.getTargetElement(elementOrEvent);
    }
    else
    {
        el = HJ.el(elementOrEvent);
    }
    return HJ.Element.getParentByClassName(el, 'menu');
}

HJ.Menu.closeMenu = function()
{
    if (HJ.Menu.currentButton) { resetButton(HJ.Menu.currentButton); HJ.Menu.currentButton = null; }
};


/*
* Pass in a javascript array of menu objects. For example:
    [ { id: 'FILE', label: 'File', submenu:
            [ { id: 'FILE_SAVE',  label: 'Save', onclick: 'HJ.win(event).save()', width: '60px' },
              { id: 'FILE_CLOSE', label: 'Exit', onclick: 'HJ.win(event).close()'} ] },
      { id: 'HELP', label: 'Help', href: 'Help.jsp' } ] 

Returns the top level dom element passed in or created(<span>)
*/

HJ.Menu.create = function (menuArray, contextPath, menu, topLevelMenu)
{
    // contextPath is prepended to each url on the menu, it should NOT contain a '/' at the end;
    ctxPath = contextPath || '';
    
    var menubar = null;
    if (!menu)
    {
        menu = document.createElement('span');
        topLevelMenu = menu;
        menu.style.width = '100%';
        menu.className = 'HJmenu'; // ??????
        
        menubar = document.createElement('div');
        menu.appendChild(menubar);

        menubar.className = 'menuBar opaque';
        menubar.style.position = 'relative';
        menubar.style.top = '0px';
        menubar.style.left = '0px';
    }
    else if (!topLevelMenu)
    {
        topLevelMenu = menu;
    }
    
    for (var i=0; i<menuArray.length; i++)
    {
        var menuObj = menuArray[i];
        
        if (!menuObj.submenu  && !menubar)
        {
            /* A lowest level menu item
              <span>\
                <A class=menuItem onclick="HJ.win(this).save()">Save</A>\
              </span>\
            */
            var menuItem = document.createElement('span');
            menu.appendChild(menuItem);
            
            if (menuObj.width) menuItem.style.width = menuObj.width;
            
            var menuItemA = document.createElement('a');

            menuItem.appendChild(menuItemA);
            
            if (menuObj.img) {
                var img = document.createElement('img');
                img.src = menuObj.img;
                img.border=0;
                menuItemA.appendChild(img);
                if (menuObj.label) {
                    menuItemA.appendChild(document.createTextNode(' '));
                }
            }
            if (menuObj.label) {
                menuItemA.appendChild(document.createTextNode(menuObj.label));
            }
            menuItemA.className = 'menuItem';
            
            if (menuObj.href) {
                var sep = '';
                if (ctxPath.length > 0 && !HJ.Util.startsWith(menuObj.href, '/')) sep='/';
                menuItemA.href = ctxPath + sep + menuObj.href;
            }
            else { menuItemA.href = '#'; }
            var s = menuObj.onclick;
            
            if (menuObj.onclick)
            {
                HJ.Element.registerHandler(menuItemA, 'click', s);
                // Automatically close the menu when one is selected.
                HJ.Element.registerHandler(menuItemA, 'click', HJ.Menu.closeMenu);
            }
            
            // TODO create amouse over event handler so that if a sub menu is displayed but you move
            // on to the next menu item, the sub menu will go away.
            //HJ.Element.registerHandler(menuItemA, 'mouseover', checkForSubMenusToClose);
        }
        else
        {
            var submenuId = menuObj.id + 'SUB' + i;
            var submenuA = null;
            
            if (menubar)
            {
                // First level menu item (always displayed)
              /*  
              <span>\
	            <A class=menuButton onmouseover="buttonMouseover(event);return true;"\
	              onclick="return buttonClick(event);" href="">\
	              File</A>\
              </span>\
              */
                var submenuSpan = document.createElement('span');
                if (menuObj.width) submenuSpan.style.width = menuObj.width;
                
                if (menuObj.id) { submenuSpan.id = menuObj.id; }
                
                submenuA = document.createElement('a');
                submenuSpan.appendChild(submenuA);
                
                submenuA.className   = 'menuButton';

                if (menuObj.href != undefined && menuObj.href != null)
                {
                    var sep = '';
                    if (ctxPath.length > 0 && !HJ.Util.startsWith(menuObj.href, '/')) sep='/';
                    submenuA.href = ctxPath + sep + menuObj.href;
                }
                else if (HJ.Browser.isIE)
                {
                    submenuA.href = '';
                }
                
                HJ.Element.registerHandler(submenuA, 'mouseover', function(event) {
                        eval( 'buttonMouseover(event);' );
                        return true;
                    });
                    
                if (menuObj.submenu)
                {
                    HJ.Element.registerHandler(submenuA, 'click', function(event) {
                        return eval( 'buttonClick(event);' );
                        });
                }
                
                if (menuObj.onclick)
                {
                    HJ.Element.registerHandler(submenuA, 'click', menuObj.onclick);
                }
                
                if (menuObj.img) {
                    var img = document.createElement('img');
                    img.src = menuObj.img;
                    img.border=0;
                    submenuA.appendChild(img);
                }
                if (menuObj.label) {
                    submenuA.appendChild(document.createTextNode(menuObj.label));
                }
                
                menubar.appendChild(submenuSpan);
            }
            else
            {
                /* A menu item that has a sub menu
                <span>\
                    <A class=menuItem onmouseover="menuItemMouseover(event);return true;"
                                      onclick="return buttonClick(event);" href="">\
                    <span class=menuItemText>\
                        Animals</span><span class=menuItemArrow>&raquo;</span>\
                    </A>\
                </span>
                */
                var submenuSpan = document.createElement('span');
                submenuA = document.createElement('a');
                submenuSpan.appendChild(submenuA);
                
                submenuA.className   = 'menuItem';
                
                HJ.Element.registerHandler(submenuA, 'mouseover', function(event) {
                        eval( 'menuItemMouseover(event);' );
                        return true;
                    });
                HJ.Element.registerHandler(submenuA, 'click', function(event) {
                        return eval( 'buttonClick(event);' );
                    });
                
                var labelSpan = document.createElement('span');
                labelSpan.className = 'menuItemText';
                labelSpan.appendChild(document.createTextNode(menuObj.label));
                
                if (menuObj.width) labelSpan.style.width = menuObj.width;
                
                var arrowSpan = document.createElement('span');
                arrowSpan.className = 'menuItemArrow';
                arrowSpan.appendChild(document.createTextNode(''));
                submenuA.appendChild(labelSpan);
                submenuA.appendChild(arrowSpan);
                
                menu.appendChild(submenuSpan);
            }
            
            if (!menuObj.submenu) continue;
            
            // Create the div for the submenu
            /*
            <div class="menu opaque" style="z-index:5000" id=SUBMENUID onmouseover=menuMouseover(event)>\
            */
            
            var submenu = document.createElement('div');
            submenu.className = 'menu opaque';
            submenu.style.zIndex = 5000;
            HJ.Element.registerHandler(submenu, 'mouseover', function(event) {
                    eval( 'menuMouseover(event);' );
                });
            
            
            var theSubmenu = HJ.Menu.create(menuObj.submenu, ctxPath, submenu, topLevelMenu); 
            submenu.id = submenuId;
  
            topLevelMenu.appendChild(submenu);
            
            if (menubar) { submenuA.menu = submenu; }
            else { submenuA.subMenu = submenu; }

            initializeMenu(submenuA);
            
        }
        
    }
    
    return menu;
}
 
/*****************************************************
********** CLICK HANDLERS / BUTTON FUNCTIONS *********
*****************************************************/

/*****************************************************
* Setup internal mouseclick handler.  This will allow
* for page mouseclicks to be capture in order to in
* turn handle (current) button processing.
*
*****************************************************/
HJ.Element.registerHandler(document, 'mousedown', clickCloseMenu);

/***********************************************
* Function: clickCloseMenu()
* Parms:    event
* Purpose:  Closes the current menu if the user clicks
*           elsewhere in the document.
* Usage:    Internal
*
* Description:
* 
***********************************************/
function clickCloseMenu(event)
{
	if (HJ.Menu.currentButton == null)
	{
		return;
	}

	// What was clicked?
	var theElement = HJ.Event.getTargetElement(event);
	
	if (theElement == HJ.Menu.currentButton)
	{
		return;
	}
	
	// If the clicked element isn't in a menu, reset it and the
	// current button.
	if (!HJ.Element.isClass(theElement, 'menuItem') &&
	    HJ.Element.getParentByTagAndClassName(theElement, 'a', 'menuItem') == null &&
	    HJ.Element.getParentByTagAndClassName(HJ.Menu.currentButton, "DIV", "menu") == null)
	{
		resetButton(HJ.Menu.currentButton);
		HJ.Menu.currentButton = null;
	}
}

/***********************************************
* Function: buttonClick()
* Parms:    event, menu id
* Purpose:  Provides a mouse click (intended
*           for mousedown event) handler.
* Usage:    External
*
* Description:
* 
***********************************************/
function buttonClick(event, aMenuId)
{
	var theButton = HJ.Event.getTargetElement(event);
//	var theButton = HJ.Event.getTargetElementByTagName(event, 'a');

	if (!theButton) { return; }
	
	// Visual adjustment - outline issue.
	
	if (theButton.blur) theButton.blur();
	
	// Associate menu to button, and initialize.
	if (theButton.menu == null && aMenuId)
	{
		theButton.menu = document.getElementById(aMenuId);
		if (theButton.menu.isInitialized == null)
		{
			initializeMenu(theButton.menu);
		}
	}

	// Reset the current button.
	if (HJ.Menu.currentButton != null)
	{
		resetButton(HJ.Menu.currentButton);
	}

	// Deactivate current button, or depress newly current one.
	if (theButton == HJ.Menu.currentButton)
	{
		HJ.Menu.currentButton = null;
	}
	else
	{
		depressButton(theButton);
		HJ.Menu.currentButton = theButton;
	}

	return false;
}

HJ.Menu.buttonClick = buttonClick;


/***********************************************
* Function: buttonMouseover()
* Parms:    event, menu id
* Purpose:  Provides a mouseover handler.
* Usage:    External
*
* Description:
* 
***********************************************/
function buttonMouseover(event, menuId)
{
	var theButton = HJ.Event.getTargetElement(event);

    if (!menuId && theButton.menu == undefined)
    {
        // This button does not have a menu - simply deactivate the current
        	// Reset the current button.
	    if (HJ.Menu.currentButton != null)
	    {
		    resetButton(HJ.Menu.currentButton);
		    HJ.Menu.currentButton = null;
	    }
	    return;
    }

	// If any different menu is currently active, make this one active.
	if (HJ.Menu.currentButton != null && HJ.Menu.currentButton != theButton)
	{
		buttonClick(event, menuId);
	}
}

/***********************************************
* Function: depressButton()
* Parms:    theButton
* Purpose:  Make a button appear depressed.
* Usage:    Internal
*
* Description: Dynamically changes style class.
* 
***********************************************/
function depressButton(theButton)
{
    HJ.Element.addClass(theButton, "menuButtonActive");

    if (!theButton.menu) return; // no menu for this button
    
	// Show the associated dropdown menu.
	
    var pos = HJ.Element.getRelativePosition(theButton);

    pos.y += theButton.offsetHeight; // lower left corner of button

	if (HJ.Browser.isIE)
	{
		pos.x += theButton.offsetParent.clientLeft;
		pos.y += theButton.offsetParent.clientTop;
	}
	
    HJ.Element.setPosition(theButton.menu, pos);

	HJ.Element.show(theButton.menu);
}

/***********************************************
* Function: resetButton()
* Parms:    theButton
* Purpose:  Change a button's class to undepress
*           it and hide dropdowns.
* Usage:    Internal
*
* Description: Dynamically changes style class.
* 
***********************************************/
function resetButton(theButton)
{
	HJ.Element.removeClass(theButton, "menuButtonActive");
	if (theButton.menu != null)
	{
		closeMenu(theButton.menu);
		HJ.Element.hide(theButton.menu);
		//theButton.menu.style.visibility = "hidden";
	}
}

/*****************************************************
******************* MENU FUNCTIONS *******************
*****************************************************/

/***********************************************
* Function: menuMouseover()
* Parms:    event
* Purpose:  Provides a mouseover handler for
*           menus.
* Usage:    External
*
* Description:
* 
***********************************************/
function menuMouseover(event)
{
	var theMenu = HJ.Event.getTargetElementByTagAndClassName(event, "div", "menu");

	if (theMenu.activeItem != null)
	{
		closeMenu(theMenu);
	}
}

/***********************************************
* Function: menuItemMouseover()
* Parms:    event, menu id
* Purpose:  Provides a mouseover handler for
*           menu items.
* Usage:    External
*
* Description:
* 
***********************************************/
function menuItemMouseover(event, menuId)
{
	var item = HJ.Event.getTargetElementByTagAndClassName(event, "a", "menuItem");
	var menu = HJ.Element.getParentByTagAndClassName(item, "DIV", "menu");
	
	menuId = menuId || menu.id;

	if (menu.activeItem != null)
	{
		closeMenu(menu);
	}
	menu.activeItem = item;

	item.className += " menuItemHighlight";

	if (item.subMenu == null)
	{
	    if (item.subMenuHidden) item.subMenu = item.subMenuHidden;
	    else item.subMenu = document.getElementById(menuId);
		if (item.subMenu.isInitialized == null)
		{
			initializeMenu(item.subMenu);
		}
	}
	
	var pos = HJ.Element.getRelativePosition(item);

	pos.x += item.offsetWidth; // submenu starts to right of the "item"
	
	// Based on window size, determine the maximum x and y values
	var maxX, maxY;

	if (HJ.Browser.isIE)
	{
		maxX = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft) +
		       (document.documentElement.clientWidth != 0 ? document.documentElement.clientWidth : document.body.clientWidth);
		maxY = Math.max(document.documentElement.scrollTop, document.body.scrollTop) +
		       (document.documentElement.clientHeight != 0 ? document.documentElement.clientHeight : document.body.clientHeight);
	} 
	else if (HJ.Browser.isNS)
	{
		maxX = window.scrollX + window.innerWidth;
		maxY = window.scrollY + window.innerHeight;
	}
	else if (HJ.Browser.isOP)
	{
		maxX = document.documentElement.scrollLeft + window.innerWidth;
		maxY = document.documentElement.scrollTop  + window.innerHeight;
	}

	maxX -= item.subMenu.offsetWidth;
	maxY -= item.subMenu.offsetHeight;

	if (pos.x > maxX)
	{
	    // menu goes off to the right of the page, put the menu to the left.
        pos.x = pos.x - item.offsetWidth - item.subMenu.offsetWidth;
        if (pos.x < 0) pos.x = 0;
	}
	
	if (pos.y > maxY)
	{
	    // menu gets cut off on the bottom, raise it up.
	    pos.y = maxY;
	    if (pos.y < 0) pos.y = 0;
	}

    HJ.Element.setPosition(item.subMenu, pos);
    
	HJ.Element.show(item.subMenu);
	HJ.Event.stop(event);
}

/***********************************************
* Function: closeMenu()
* Parms:    aMenu
* Purpose:  Close a menu.
* Usage:    Internal
*
* Description:
* 
***********************************************/
function closeMenu(aMenu)
{
	if (aMenu == null || aMenu.activeItem == null)
	{
		return;
	}

	if (aMenu.activeItem.subMenu != null)
	{
		closeMenu(aMenu.activeItem.subMenu);
		HJ.Element.hide(aMenu.activeItem.subMenu);
		aMenu.activeItem.subMenuHidden = aMenu.activeItem.subMenu;
		aMenu.activeItem.subMenu = null;
	}
	HJ.Element.removeClass(aMenu.activeItem, "menuItemHighlight");
	aMenu.activeItem = null;
}

/***********************************************
* Function: initializeMenu()
* Parms:    menu
* Purpose:  Initialize a menu.
* Usage:    Internal
*
* Description:
* 
***********************************************/
function initializeMenu(aMenu)
{
	// Use Webdings char 4 as an IE arrow replacement
	if (HJ.Browser.isIE)
	{
		aMenu.style.lineHeight = "2.5ex";
		var spans = aMenu.getElementsByTagName("SPAN");

		for (var i = 0; i < spans.length; i++)
		{
			if (HJ.Element.isClass(spans[i], "menuItemArrow"))
			{
				spans[i].style.fontFamily = "Webdings";
				spans[i].firstChild.nodeValue = "4";
			}
		}
	}

	// What is the width of an item? If none, return.
	var items = aMenu.getElementsByTagName("A");
	var itemWidth;
	if (items.length > 0)
	{
		itemWidth = items[0].offsetWidth;
	}
	else
	{
		return;
	}

	// If an item has an arrow, need to add spacing in order to
	// right justify.
	for (var i = 0; i < items.length; i++)
	{
		var spans = items[i].getElementsByTagName("SPAN");
		var theText  = null;
		var theArrow = null;

		for (var j = 0; j < spans.length; j++)
		{
			if (HJ.Element.isClass(spans[j], "menuItemText"))
			{
				theText = spans[j];
			}
			if (HJ.Element.isClass(spans[j], "menuItemArrow"))
			{
				theArrow = spans[j];
			}
		}
		
		if (theText != null && theArrow != null)
		{
			theText.style.paddingRight = (itemWidth - (theText.offsetWidth + theArrow.offsetWidth)) + "px";
			if (HJ.Browser.isOP)
			{
				theArrow.style.marginRight = "0px";
			}
		}
	}

	// Handle IE hover issue
	if (HJ.Browser.isIE)
	{
		var wid = items[0].offsetWidth;
		items[0].style.width = wid + "px";
		owid = items[0].offsetWidth - wid;
		wid -= owid;
		items[0].style.width = wid + "px";
	}

	aMenu.isInitialized = true;
}


