// Generates nested expanding html menus.
// Main menu is always open. 
// Submenus open on hover, lock open on click.
//
// Bart Mebane, Mebane Software Systems, 2008.
//
// Menu structure:
//
//	<ul ...> main menu
//		...
//		<li ...> menu item for a web page link
//			<a href=...> link to web page </a>
//		</li>
//		...
//		<li ...> menu item for a submenu - encloses entire submenu
//			<a id=...> link to expand submenu </a>
//			<ul ...> submenu
//				...
//				<li ...>
//					<a href=...> link to web page </a>
//				</li>
//				...
//				<li ...>
//					nested submenu with same structure
//				</li>
//				...
//			</ul> end of submenu
//		</li> end of enclosing menu item
//		...
//	</ul> end of main menu
//	
var maxLevel = 4;
var currentLevel = -1;
var topActiveLevel = -1;
var topLockedLevel = -1;
var menuItemCount = new Array ();
var activeMenu = new Array (); // Enclosing li element
var activeMenuID = new Array (); // ID of ul
var lockedMenu = new Array (); // Enclosing li element
var lockedMenuID = new Array (); // ID of ul
var activeClass = 'active'; // must match css stylesheet
var inactiveClass = '';
var menuLinkClass = 'expand'; // must match css stylesheet
var menuClass;
var menuID;
//
// Routines to generate html for menus
//
function openMenu (classText)
{
	for (var level = 0; level <= maxLevel; level ++)
	{
		menuItemCount [level] = 0;
		activeMenu [level] = null;
		activeMenuID [level] = '';
		lockedMenu [level] = null;
		lockedMenuID [level] = '';
	}
	currentLevel = -1;
	topActiveLevel = -1;
	topLockedLevel = -1;
	menuClass = classText;
	menuID = menuClass + '_0';
	window.document.body.onclick = function (){onBodyClick ();};
}

function closeMenu ()
{
	for (var level = 0; level <= currentLevel; level ++)
	{
		closeLi ();
		closeUl ();
	}
}

function addMenuItem (menuLevel, linkText, targetUrl)
{
	var newLevel = menuLevel - 1;
	// Housekeeping for menu structure
	if ((newLevel < 0) || (newLevel > maxLevel) || (newLevel > (currentLevel + 1)))
	{
		alert ('Incorrect menu level for ' + linkText);
		return;
	}
	else if (newLevel > currentLevel) // Begin new menu or submenu
	{
		currentLevel = newLevel;
		menuItemCount [currentLevel] = 0;
		if (currentLevel == 0)
		{
			openUl (menuID, menuClass);
		}
		else
		{
			openUl (menuID, menuClass + '_sub');
			hideElement (menuID);
		}
	}
	else if (newLevel == currentLevel) // Next item in current menu or submenu
	{
		closeLi ();
	}
	else if (newLevel < currentLevel) // End of submenu; back to previous menu or submenu
	{
		closeLi ();
		for (var level = currentLevel; level > newLevel; level --)
		{
			closeUl ();
			closeLi ();
		}
		currentLevel = newLevel;
	}
	// Build container <li> and link <a> for this menu item
	menuItemCount [currentLevel] ++;
	menuID = menuClass;
	for (level = 0; level <= currentLevel; level ++)
	{
		menuID += '_' + menuItemCount [level].toString ();
	}
	if (targetUrl == '') // Menu link
	{
		var mouseOverMenuLink = 'onMenuLinkMouseOver(' + currentLevel + ', \'' + menuID + '\',this);';
		var mouseOutMenuLink = 'onMenuLinkMouseOut(' + currentLevel + ', \'' + menuID + '\',this);';
		var clickMenuLink = 'onMenuLinkClick(' + currentLevel + ', \'' + menuID + '\',this, event);';
		openLi (mouseOverMenuLink, mouseOutMenuLink, clickMenuLink);
		
		openMenuLink (menuID + '_link', menuLinkClass);
		document.writeln (linkText);
		closeMenuLink ();
	}
	else // Page link
	{
		var mouseOverPageLink = 'onPageLinkMouseOver (this);';
		var	mouseOutPageLink = 'onPageLinkMouseOut (this);';
		var	clickPageLink = 'onPageLinkClick (event);';
		openLi (mouseOverPageLink, mouseOutPageLink, clickPageLink);
		
		openPageLink (targetUrl);
		document.writeln (linkText);
		closePageLink ();
	}
}
//
// Utility routines used to generate html
//
function openUl (idText, classText)
{
	startOpenTag ('ul');
	writeAttribute ('id', idText);
	writeAttribute ('class', classText);
	endOpenTag ();
}

function closeUl ()
{
	closeTag ('ul');
}

function openLi (mouseOverCode, mouseOutCode, clickCode)
{
	startOpenTag ('li');
	writeAttribute ('onmouseover', mouseOverCode);
	writeAttribute ('onmouseout', mouseOutCode);
	writeAttribute ('onclick', clickCode);
	endOpenTag ();
}

function closeLi ()
{
	closeTag ('li');
}

function openMenuLink (idText, classText)
{
	startOpenTag ('a');
	writeAttribute ('id', idText);
	writeAttribute ('class', classText);
	endOpenTag ();
}

function closeMenuLink ()
{
	closeTag ('a');
}

function openPageLink (targetUrl)
{
	startOpenTag ('a');
	writeAttribute ('href', targetUrl);
	endOpenTag ();
}

function closePageLink ()
{
	closeTag ('a');
}

function openTag (tagText)
{
	document.writeln ('<' + tagText + '>');
}

function startOpenTag (tagText)
{
	document.write ('<' + tagText);
}

function endOpenTag ()
{
	document.writeln ('>');
}

function closeTag (tagText)
{
	document.writeln ('</' + tagText + '>');
}

function writeAttribute (attribute, attributeText)
{
	if (attributeText != '')
	{
		document.write (' ' + attribute + '=\"' + attributeText + '\"');
	}
}
//
// Event handlers to activate/deactivate and lock/unlock menus
//
function onMenuLinkMouseOver (level, idMenu, liElement)
{
	if (level > topLockedLevel)
	{
		activateMenu (level, idMenu, liElement);
	}
}

function onMenuLinkMouseOut (level, idMenu, liElement)
{
	if (level > topLockedLevel)
	{
		deactivateMenu (level, idMenu, liElement);
	}
}

function onMenuLinkClick (level, idMenu, liElement, evnt)
{
	if (lockedMenuID [level] == '') // Nothing at this level is locked
	{
		lockMenu (level, idMenu, liElement);
		lockParentMenus (level);
	}
	else if (lockedMenuID [level] == idMenu) // This menu is locked
	{
		unlockChildMenus (level);
		unlockMenu (level);
	}
	else // A different menu at this level is locked
	{
		unlockChildMenus (level);
		unlockMenu (level);
		activateMenu (level, idMenu, liElement);
		lockMenu (level, idMenu, liElement);
		lockParentMenus (level);
	}
	cancelEvent (evnt);
}

function onPageLinkMouseOver (liElement)
{
	activateLink (liElement);
}
		
function onPageLinkMouseOut (liElement)
{
	deactivateLink (liElement);
}
		
function onPageLinkClick (evnt)
{
	unlockAllMenus ();
	deactivateAllMenus ();
	cancelEvent (evnt);
}

function onBodyClick ()
{
	unlockAllMenus ();
}
//
// Utility routines used by event handlers
//
function activateMenu (level, idMenu, liElement)
{
	showElement (idMenu);
	activateLink (liElement);
	activeMenu [level] = liElement;
	activeMenuID [level] = idMenu;
	if (level > topActiveLevel)
	{
		topActiveLevel = level;
	}
}

function deactivateMenu (level, idMenu, liElement)
{
	hideElement (idMenu);
	deactivateLink (liElement);
	activeMenu [level] = null;
	activeMenuID [level] = '';
	if (level == topActiveLevel)
	{
		topActiveLevel --;
	}
}

function activateLink (liElement)
{
	setClass (liElement, activeClass);
}

function deactivateLink (liElement)
{
	setClass (liElement, inactiveClass);
}

function lockMenu (level, idMenu, liElement)
{
	lockedMenu [level] = liElement;
	lockedMenuID [level] = idMenu;
	if (level > topLockedLevel)
	{
		topLockedLevel = level;
	}
	if (activeMenuID [level] != idMenu)
	{
		activateMenu (level, idMenu, liElement);
	}
}

function unlockMenu (level)
{
	var liSave = lockedMenu [level];
	var idSave = lockedMenuID [level];
	lockedMenu [level] = null;
	lockedMenuID [level] = '';
	if (topLockedLevel == level)
	{
		topLockedLevel --;
	}
	deactivateMenu (level, idSave, liSave);
}

function lockParentMenus (menuLevel)
{
	for (var level = menuLevel - 1; level >= 0; level --)
	{
		lockMenu (level, activeMenuID [level], activeMenu [level]);
	}
}

function unlockChildMenus (menuLevel)
{
	var topLevel = topLockedLevel;
	for (var level = menuLevel + 1; level <= topLevel; level ++)
	{
		unlockMenu (level);
	}
}
		
function unlockAllMenus ()
{
	var topLevel = topLockedLevel;
	for (var level = topLevel; level >= 0; level --)
	{
		unlockMenu (level);
	}
}

function deactivateAllMenus ()
{
	var topLevel = topActiveLevel;
	for (var level = topLevel; level >= 0; level --)
	{
		if (activeMenuID [level] != '')
		{
			deactivateMenu (level, activeMenuID [level], activeMenu [level]);
		}
	}
}
		
function hideElement (idText)
{
	var elmnt = document.getElementById (idText);
	if (elmnt != null)
	{
		elmnt.style.display = 'none';
	}
}	

function showElement (idText)
{
	var elmnt = document.getElementById (idText);
	if (elmnt != null)
	{
		elmnt.style.display = '';
	}
}

function setClass (elmnt, classText)
{
	elmnt.setAttribute ('class', classText); // Non-IE
	elmnt.setAttribute ('className', classText); // IE only
}

function cancelEvent (evnt)
{
	if (!evnt)
	{
		evnt = window.event; // IE only
	}
	evnt.cancelBubble = true;
	if (evnt.stopPropagation) // Non-IE
	{
		 evnt.stopPropagation ();
	}
}
