// <SCRIPT LANGUAGE="JAVASCRIPT">
// -<>---------------------------------------------------------------------------------------------
//
//   Document: navigationMenu.js
//    Purpose: To provide functionality for rendering a navigation menu.
//	  Assumes: o objMenu has been set up as a root level menu object (see navigationMenu.js).
//             o calling page implements a _nmPerformAction function that will be run when an 
//			     item is clicked.
//   Requires: navigationMenuContent.js 
//    To Call: o Issue call to objMenu.renderMenu() after body tag in calling page.
//			   o Issue call to objMenu.displayMenu() in body.onLoad event.
//
//		Notes: There are four types of menu that can be created using this include.
//
//			   o Dynamic LHS menu - where the menu is dynamically re-drawn in a column when 
//				 menu items are selected. Specified by setting the cascading property of the
//				 root menu item to false. e.g.
//				 1					1				1
//				 2	--> becomes -->	2.1				2.1
//				 3					2.2	--> becomes 2.2
//									3				2.2.1
//													3
//
//			   o Vertically Cascading menus - where selections cascade vertically. Specified 
//				 by setting the cascading property of the root menu item to false, and the 
//				 alignment property of a style object to vertical. e.g.
//				 1					1					1
//				 2	--> becomes	-->	2* 2.1				2* 2.1
//				 3					3  2.2	--> becomes	3  2.2*	2.1.1
//
//			   o Horizontally Cascading menus - where selections cascade horizontally. Specified 
//				 by setting the cascading property of the root menu item to false, and the 
//				 alignment property of a style object to horizontal. e.g.
//				 1	 2*	 3 --> Becomes --> 1   2*   3 --> Becomes --> 1   2*   3
//									       2.1   2.2				  2.1   2.2*
//																	  2.2.1
//
//			   o Hybrid Cascading menu - where vertical and horizontal cascades are used 
//				 together. e.g.
//				 1   2   3 --> Becomes --> 1   2*   3					1   2*   3
//											   2.1							2.1
//											   2.2     --> Becomes -->		2.2* 2.1.1	
//			     Note - different alignments can be used at the same level. 
//
// -><---------------------------------------------------------------------------------------------


// -<>- Constants ---------------------------------------------------------------------------------

var
	FLOW_ASCENDING = 1,
	FLOW_DESCENDING = 2;	

// -<>- Variables ---------------------------------------------------------------------------------

var
	_WasInDisplay;

// -<>- Cross-browser functions -------------------------------------------------------------------

// -<>---------------------------------------------------------------------------------------------
//
//    Function : _nmManipulateLayer
// Description : To manipulate the given layer.
//  Parameters : o pstrLayerID - the ID of the layer to manipulate ('State-MenuIndex', e.g. 'Out-1.2').
//               o pintTop - The top coordinate to position the layer
//               o pintLeft - The left coordinate to position the layer
//               o pstrVisibility	- The required visibility of the layer
//	   Returns : Layer object for pstrLayerID
//
//     History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmManipulateLayer(pstrLayerID, pintTop, pintLeft, pstrVisibility)
{
	var
		eleLayer = null;

	if (typeof(pstrLayerID) == "object")
		return(pstrLayerID);

	if (typeof(pstrLayerID) == "string")
	{
		// -- DOM handler --
		if (document.getElementById)
			eleLayer = document.getElementById(pstrLayerID).style;
			
		// -- IE handler --		
		if (document.all)	
			eleLayer = document.all[pstrLayerID].style;

		// -- NN4 handler --	
		if (document.layers)			
			eleLayer = document.layers[pstrLayerID];

		// Set style from provided parameters
		if (eleLayer)
		{
			if(pintTop != null)
				eleLayer.top = pintTop;
			if(pintLeft != null)
				eleLayer.left = pintLeft;
			if(pstrVisibility != null)
				eleLayer.visibility = pstrVisibility;
		}
		
		// Return layer object to the caller		
		if (eleLayer)
			return(eleLayer)
		else
			alert('NavigationMenu:\nObject reference for ' + pstrLayerID + ' not found.');
	}
	return(null);
}

// -<>- Private Functions -------------------------------------------------------------------------

// -<>---------------------------------------------------------------------------------------------
//
//    Function: _nmRenderMenu
// Description: To render the navigation menu. Initiates process to output menu HTML 
//     Effects: Writes to the document.
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmRenderMenu()
{
	var
		strReturn = '';

//	// Do we need to render 'home' layers
//	if(objMenu.HasHome)
//		strReturn += _nmBuildHome(objMenu);

	// Identifies children of navigationMenu. These are all top level menu items. Each level 1
	// menu item passed to _nmRenderEntry to output complete sub-menu structure.
	for (var intEntry = 0; intEntry < this.children.length; intEntry++)
		strReturn += _nmRenderEntry(intEntry+1,0,this.children[intEntry]);
	
	// Output HTML for menu structure	
	document.write(strReturn);
}


// -<>---------------------------------------------------------------------------------------------
//
//    Function: _nmMenuSource
// Description: To return the source HTML for the menu structure to the caller
//     Returns: String containing HTML that will render the menu.
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmMenuSource()
{
	var
		strReturn = '';

	// Identifies children of navigationMenu. These are all top level menu items. Each level 1
	// menu item passed to _nmRenderEntry to output complete sub-menu structure.
	for (var intEntry = 0; intEntry < this.children.length; intEntry++)
		strReturn += _nmRenderEntry(intEntry+1,0,this.children[intEntry]);
	
	// Output HTML for menu structure	
	return strReturn
}


// -<>---------------------------------------------------------------------------------------------
//
//    Function: _nmRenderEntry
// Description: To build the HTML to represent the menu tree for a menu item.
//  Parameters: o pstrID - The ID of the Parent menuItem
//			    o pintLevel - The level of the parent menu item (level 1 is top level)
//				o pobjMenuItem - Parent menu item
//	   Returns: HTML string
//
//	   History: 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmRenderEntry(pstrID, pintLevel, pobjMenuItem)
{
	var
		strReturn = '';
	
	// Build string containing HTML for current menuItem
	strReturn += _nmBuildMenuItem(pstrID, pintLevel, pobjMenuItem);

	// Set appropriate properties for current menuItem object
	pobjMenuItem.ID = pstrID;
	pobjMenuItem.level = pintLevel;

	if (pobjMenuItem.children.length > 0)
	{
		// Iterate through the children of current menuItem and render them recursively	
		for (var intEntry = 0; intEntry < pobjMenuItem.children.length; intEntry++)
			strReturn += _nmRenderEntry(pstrID+'.'+(intEntry+1),pintLevel+1,pobjMenuItem.children[intEntry]);			
	}
	return(strReturn);
}


// -<>---------------------------------------------------------------------------------------------
//
//    Function: _nmBuildMenuItem
// Description: Compiles a HTML string to represent an individual menuItem
//  Parameters: o pstrID - The ID of the current menuItem
//			    o pintMenuLevel - The level of the current menu item (level 1 is top level)
//				o pobjMenuItem - Current menuItem object
//	   Returns: HTML string
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmBuildMenuItem(pstrID, pintMenuLevel, pobjMenuItem)
{
	var 
		blnSelectedIndicator,
		strSelectedOutline,
		strSelectedFull,
		intTextWidth;
	
	intTextWidth = pobjMenuItem.style._TextWidth;
	
	// Is a graphic required to indicate that the current menu item is selected / unselected
	blnSelectedIndicator = pobjMenuItem.style.selectedIndicator;
	if(blnSelectedIndicator)
	{
		strSelectedOutline = '<img src="../images/selected_indicator_outline.gif" border="0">';
		strSelectedFull = '<img src="../images/selected_indicator_full.gif" border="0">';
	}
	else
	{
		strSelectedOutline = '&nbsp;';
		strSelectedFull = '&nbsp;';
	}

	var	
		// Construct ID's for the out, over and on layers for the current menu item
		strOutID = _nmBuildOptionLayerID('Out', pstrID),
		strOverID = _nmBuildOptionLayerID('Over', pstrID),
		strOnID = _nmBuildOptionLayerID('On', pstrID),
		strOut,
		blnNormalMenu = true;
		
		
		if(pobjMenuItem.title == 'Select report')
		{
			intTextWidth = intTextWidth - 0;
			objMenu.selectReportID = pstrID;
			
			// Main HTML String
			strOut =
				'<div id="' + strOutID + '" class="level' + (pintMenuLevel+1) + '">' +
				'<table border="0" cellpadding="0" cellspacing="0" class="selectReportOut" width="' + pobjMenuItem.style.width + '">' +
				'<tr>' + 
				'<td class="selectReportOut" width="' + intTextWidth + '" height="' + pobjMenuItem.style.height + '">' +
					pobjMenuItem.title +
				'</td>' +
				'<td width="' + pobjMenuItem.style.rightGap + '" align="center">' + strSelectedOutline + '</td>' +
				'</tr>' +
				'</table>' +
				'</div>' +
				'<div id="' + strOverID + '" class="level' + (pintMenuLevel+1) + '">' +
				'<table border="0" cellpadding="0" cellspacing="0"  class="selectReportOver" width="' + pobjMenuItem.style.width + '">' +
				'<tr>' + 
				'<td class="selectReportOver" width="' + intTextWidth + '" height="' + pobjMenuItem.style.height + '">' +
					pobjMenuItem.title +
				'</td>' +
				'<td width="' + pobjMenuItem.style.rightGap + '" align="center">' + strSelectedFull + '</td>' +
				'</tr>' +
				'</table>' +
				'</div>' +
				'<div id="' + strOnID + '" class="level' + (pintMenuLevel+1) + '">' +
				'<table border="0" cellpadding="0" cellspacing="0" class="selectReportOn" width="' + pobjMenuItem.style.width + '">' +
				'<tr>' + 
				'<td class="selectReportOn" width="' +  intTextWidth + '" height="' + pobjMenuItem.style.height + '">' +
					pobjMenuItem.title +
				'</td>' +
				'<td width="' + pobjMenuItem.style.rightGap + '" align="center">' + strSelectedFull + '</td>' +
				'</tr>' +
				'</table>' +
				'</div>';	
				
				blnNormalMenu = false	
		}
		
		if(pobjMenuItem.title == 'Home Page')
		{
			intTextWidth = intTextWidth - 0;
			//objMenu.selectReportID = pstrID;
			
			// Main HTML String
			strOut =
				'<div id="' + strOutID + '" class="level' + (pintMenuLevel+1) + '">' +
				'<table border="0" cellpadding="0" cellspacing="0" class="selectReportOut" width="' + pobjMenuItem.style.width + '">' +
				'<tr>' + 
				'<td class="selectReportOut" width="' + intTextWidth + '" height="' + pobjMenuItem.style.height + '">' +
					pobjMenuItem.title +
				'</td>' +
				'<td width="' + pobjMenuItem.style.rightGap + '" align="center">' + strSelectedOutline + '</td>' +
				'</tr>' +
				'</table>' +
				'</div>' +
				'<div id="' + strOverID + '" class="level' + (pintMenuLevel+1) + '">' +
				'<table border="0" cellpadding="0" cellspacing="0"  class="selectReportOver" width="' + pobjMenuItem.style.width + '">' +
				'<tr>' + 
				'<td class="selectReportOver" width="' + intTextWidth + '" height="' + pobjMenuItem.style.height + '">' +
					pobjMenuItem.title +
				'</td>' +
				'<td width="' + pobjMenuItem.style.rightGap + '" align="center">' + strSelectedFull + '</td>' +
				'</tr>' +
				'</table>' +
				'</div>' +
				'<div id="' + strOnID + '" class="level' + (pintMenuLevel+1) + '">' +
				'<table border="0" cellpadding="0" cellspacing="0" class="selectReportOn" width="' + pobjMenuItem.style.width + '">' +
				'<tr>' + 
				'<td class="selectReportOn" width="' +  intTextWidth + '" height="' + pobjMenuItem.style.height + '">' +
					pobjMenuItem.title +
				'</td>' +
				'<td width="' + pobjMenuItem.style.rightGap + '" align="center">' + strSelectedFull + '</td>' +
				'</tr>' +
				'</table>' +
				'</div>';	
				
				blnNormalMenu = false	
		}		
		
		
		
		if(blnNormalMenu)
		{
			// Main HTML String
			strOut =
				'<div id="' + strOutID + '" class="level' + (pintMenuLevel+1) + '">' +
				'<table border="0" cellpadding="0" cellspacing="0" class="level' + (pintMenuLevel+1) + 'Out" width="' + pobjMenuItem.style.width + '">' +
				'<tr>';
				  
			//if(pintMenuLevel == 0)
			//{
			//	strOut += '<td width="13"><img src="../images/spacer.gif" width="13" height="20" border="0"></td>';
			//	intTextWidth = intTextWidth - 13;
			//}
			
			strOut +=
				'<td class="level' + (pintMenuLevel+1) + 'Out" width="' + intTextWidth + '" height="' + pobjMenuItem.style.height + '">' +
					pobjMenuItem.title +
				'</td>' +
				'<td width="' + pobjMenuItem.style.rightGap + '" align="center">' + strSelectedOutline + '</td>' +
				'</tr>' +
				'</table>' +
				'</div>' +
				'<div id="' + strOverID + '" class="level' + (pintMenuLevel+1) + '">' +
				'<table border="0" cellpadding="0" cellspacing="0"  class="level' + (pintMenuLevel+1) + 'Over" width="' + pobjMenuItem.style.width + '">' +
				'<tr>';
				  
			//if(pintMenuLevel == 0)
			//{
			//	strOut += '<td width="13"><img src="../images/spacer.gif" width="13" height="20" border="0"></td>';
			//}

			strOut +=			  
				'<td class="level' + (pintMenuLevel+1) + 'Over" width="' + intTextWidth + '" height="' + pobjMenuItem.style.height + '">' +
					pobjMenuItem.title +
				'</td>' +
				'<td width="' + pobjMenuItem.style.rightGap + '" align="center">' + strSelectedFull + '</td>' +
				'</tr>' +
				'</table>' +
				'</div>' +
				'<div id="' + strOnID + '" class="level' + (pintMenuLevel+1) + '">' +
				'<table border="0" cellpadding="0" cellspacing="0" class="level' + (pintMenuLevel+1) + 'On" width="' + pobjMenuItem.style.width + '">' +
				'<tr>';
				  
			//if(pintMenuLevel == 0)
			//{
			//	strOut += '<td width="13"><img src="../images/spacer.gif" width="13" height="20" border="0"></td>';
			//}
				  
			strOut +=			  			  
				'<td class="level' + (pintMenuLevel+1) + 'On" width="' +  intTextWidth + '" height="' + pobjMenuItem.style.height + '">' +
					pobjMenuItem.title +
				'</td>' +
				'<td width="' + pobjMenuItem.style.rightGap + '" align="center">' + strSelectedFull + '</td>' +
				'</tr>' +
				'</table>' +
				'</div>';
		}
		
		// Add Image layer for current menuItem
		strOut += _nmBuildImageDIV(pstrID, pintMenuLevel, pobjMenuItem);

	return(strOut);
}

// -<>---------------------------------------------------------------------------------------------
//
//    Function: _nmBuildOptionLayerID
// Description: To build and return the layer ID for the specified menu option.
//  Parameters: o State - the state of the option (Out|Over|On|Image)
//		    	o MenuIndex - the ID of the current menuItem
//     Returns: A layer ID ('State-MenuIndex', e.g. 'Out-1.2').
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmBuildOptionLayerID(State, MenuIndex)
{
	return(State + '-' + MenuIndex);
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmBuildImageDIV
//    Purpose: To build the layer that contains the 'selected' image the traps menu option events
// Parameters: o pstrID - the ID of the current menuItem
//			   o pintMenuLevel - The level of the current menu item (level 1 is top level)
//    Returns: A string containing HTML to render.
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmBuildImageDIV(pstrID, pintMenuLevel, pobjMenuItem)
{
	var
		strID = _nmBuildOptionLayerID('Image', pstrID),
		strParameters = '\'' + pstrID + '\'',		
		strOut =
			'<div id="' + strID + '" class="eventImage">' +
			 '<table border="0" cellpadding="0" cellspacing="0" width="' + pobjMenuItem.style.width + '">' +
			  '<tr>' +
			   '<td>' +
				'<a href="javascript:;" ' +
				   'onmouseout="_nmOptionOnMouseOutOrOver(false, ' + strParameters + ');" ' +
				   'onmouseover="_nmOptionOnMouseOutOrOver(true, ' + strParameters + ');" ' +
				   'onclick="_nmOptionOnClick(' + strParameters + ');">' +
				 '<img border="0" src="../images/spacer.gif" width="' + pobjMenuItem.style.width + '" height="' + pobjMenuItem.style.height + '">' +
				'</a>' +
			   '</td>' +
			  '</tr>' +
			 '</table>' +
			'</div>';
			
	return(strOut);	
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmHideAllSections
//    Purpose: Identifies all level 1 (top level) menu items and initiates hide of all submenus
//    Returns: A string containing HTML to render.
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmHideAllSections()
{
	for (var intEntry = 0; intEntry < objMenu.children.length; intEntry++)
		_nmHideSection(intEntry+1,objMenu.children[intEntry]);
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmHideSection
//    Purpose: Hides all submenus for specified menuItem
// Parameters: o pstrID - the ID of the current menuItem
//			   o pobjMenuItem - Menu item whose submenu is to be hidden
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmHideSection(pstrID, pobjMenuItem)
{

	// hide current menuItem
	_nmHideItem(pstrID, pobjMenuItem);
	
	// iterate through the children of the current menuItem and hide them recursively
	if (pobjMenuItem.children.length > 0)
	{
		for (var intEntry = 0; intEntry < pobjMenuItem.children.length; intEntry++)
			_nmHideSection(pstrID+'.'+(intEntry+1),pobjMenuItem.children[intEntry]);
	}
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmHideSectionToLevel
//    Purpose: Hides all active sections at a level equal or greater than the level of the current
//			   menu item. e.g. if menu 4.1.1 and 4.1.2 are shown (from a previous selection of
//			   4.1) and 4.2 is selected - 4.1.1 and 4.1.2 will be hidden by this function.
// Parameters: o pintLevel - The level of the current menu item
//
//    History : 16/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmHideSectionToLevel(pintLevel)
{
	var 
		objMenuItem;
	
	// Loop round all active controls at a level greater than or equal to the level of the
	// current menuItem (indicated by pintLevel);
	for(var intCount = pintLevel; intCount <= objMenu.activeMenuItems.length; intCount++)
	{
		// Object reference to the current active control
		objMenuItem = objMenu.activeMenuItems[intCount];
		
		// Object reference will be null if there is no active control at this level.
		if(objMenuItem != null)
		{
			for (var intEntry = 0; intEntry < objMenuItem.children.length; intEntry++)
			{
				// Hide the old activeMenuItems
				_nmHideItem(objMenuItem.children[intEntry].ID, objMenuItem.children[intEntry]);
			}
		}
	}
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmDisplaySection
//    Purpose: Displays all children (a complete menu section) for the specified menuItem
// Parameters: o pobjMenuItem - The current menuItem object (section parent)
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmDisplaySection(pobjMenuItem)
{
	var 
		intTop = 0,
		intLeft = 0,
		intMenuLevel,
		intCurrentMenuLevel,
		strAlignment,
		intFlow,
		intChildIndex,
		blnCollapseBranch = false,
		objActiveMenuItem,
		objStyle;
	
	// Determine level of current menu item
	intCurrentMenuLevel = pobjMenuItem.level;
	
	// Does the current menu level have an active control. If not, this is the first time a menu item
	// at this level has been expanded - and there are no other sections at this level to be hidden.
	if(objMenu.activeMenuItems[intCurrentMenuLevel] != null)
		_nmHideSectionToLevel(intCurrentMenuLevel);	
	
	// Cope with the collapse of a sub menu tree - determine the active menuItem at this level
	objActiveMenuItem = objMenu.activeMenuItems[intCurrentMenuLevel];
	// If there is an active control at this level - and the ID matches the current menuItem ID
	// then we need to collapse the branch.
	if(objActiveMenuItem != null && objActiveMenuItem.ID == pobjMenuItem.ID)
	{
		// Clear the highlight on the object
		_nmClearHighlight(objActiveMenuItem.ID, objActiveMenuItem.top, objActiveMenuItem.left);
	
		// Set the active control at this level to null - to allow the branch to be redisplayed
		// if selected.
		objMenu.activeMenuItems[intCurrentMenuLevel] = null;
		
		// Do not continue to display the current section (effectively collapsing the branch)
		return;					
	}	
		
	// Is this the root object. If so - don't need to set an active control at this level.
	if(pobjMenuItem.ID != 0)
		objMenu.activeMenuItems[intCurrentMenuLevel] = pobjMenuItem;
	
	// Loop round all children of the current menuItem
	for (var intEntry = 0; intEntry < pobjMenuItem.children.length; intEntry++)
	{
		// Determine the level, alignment and direction of the current child
		intMenuLevel = pobjMenuItem.children[intEntry].level;
		strAlignment = pobjMenuItem.children[intEntry].style.alignment;
		intFlow = pobjMenuItem.children[intEntry].style.flow;
	
		// Set origin for first menu item in this section - subsequent menu items recieve appropriate offset.
		// Note that the correct position for the display of the first menuItem in a section is stored in 
		// properties of thr menuItem object.
		if(intEntry == 0)
		{
			// top / left properties for root object and menuItem objects are different.
			if(pobjMenuItem.ID == 0)
			{
				intTop = pobjMenuItem.top;
				intLeft = pobjMenuItem.left;
			}
			else
			{
				intTop = pobjMenuItem.topForNextSection;
				intLeft = pobjMenuItem.leftForNextSection;
			}
		}
		// Having placed the first item in the section - calculate relative positions for the 
		// remaining menu items in this section.
		else
		{
			objStyle = pobjMenuItem.children[0].style;
			if(strAlignment == 'vertical')
				intTop = intTop + objStyle.height + objStyle.gap;
			else
				intLeft = intLeft + objStyle.width + objStyle.gap;
		}
		
		// Do we need to invert the order of the menu items in this section?
		if(intFlow == FLOW_ASCENDING)
			intChildIndex = intEntry;
		else
			intChildIndex = pobjMenuItem.children.length - intEntry - 1;
		
		// Display specific menu Item
		_nmDisplayItem(pobjMenuItem.children[intChildIndex].ID, intTop, intLeft, pobjMenuItem.children[intChildIndex]);
	}
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmMarkItemsForDisplay
//    Purpose: Sets toBeDisplayed property of all menuItems that are to be displayed when a menu
//			   item is clicked.
// Parameters: o pobjMenuItem - The current menuItem object (menu item that was selected)
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmMarkItemsForDisplay(pobjMenuItem)
{
	var 
		intStartingLevel,
		intCurrentLevel;
		
	// Determine the level of the selected menu item 
	intStartingLevel = pobjMenuItem.level;
	
	// Ensure current menu item is marked for display with 'On' style
	pobjMenuItem.markAsOn = true;
	
	// Mark Children of the selected node - if we are not collapsing a menu tree
	if(!objMenu._collapseMenuTree)
	{
		if(pobjMenuItem.children.length > 0)
		{
			for (var intEntry = 0; intEntry < pobjMenuItem.children.length; intEntry++)
				pobjMenuItem.children[intEntry].toBeDisplayed = true;
		}	
	}
	
	// Mark parent & parent siblings (and parents.parents siblings etc. until root is hit)
	for (var intEntry = 0; intEntry < intStartingLevel + 1; intEntry++)
	{
		// Determine parameters 
		pobjMenuItem.toBeDisplayed = true;
		intCurrentLevel = pobjMenuItem.level;
		
		// Go to parent menu item 
		pobjMenuItem = pobjMenuItem.parent;
		
		// Ensure current menu item is marked for display with 'On' style
		pobjMenuItem.markAsOn = true;
		
		if(intCurrentLevel >= objMenu.HideUnselectedOptionsAtLevel)
		{
			// Loop through children
			for (var intChild = 0; intChild < pobjMenuItem.children.length; intChild++)
				pobjMenuItem.children[intChild].toBeDisplayed = true;
		}
	}
	
	// Hide current menu items to prepare for re-display
	_nmHideAllSections();
	
	// Display correct menu items
	_nmDisplayAllMarkedItems(objMenu);
	
	// Reset origin for next re-display
	objMenu._menuItemTop = objMenu.top;
	objMenu._menuItemLeft = objMenu.left;	
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmDisplayAllMarkedItems
//    Purpose: Traverses the entire menu tree looking for menuItem objects with the toBeDisplayed
//			   property set. All menuItems that have this property set will be displayed.
// Parameters: o pobjMenuItem - The current menuItem object 
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmDisplayAllMarkedItems(pobjMenuItem)
{
	var 
		intLeft,
		strAlignment,
		intMenuLevel,
		strID;
	
	// Retrieve info on current menuItem
	strID = pobjMenuItem.ID;	
			
	// Display current menuItem?
	if (pobjMenuItem.toBeDisplayed == true)
	{
		// Clear display property - don't want to show next time round
		pobjMenuItem.toBeDisplayed = false;	
		
		// removes the gap between a top level menu item and its children
		if(objMenu._previousMenuItem)
		{
			if(pobjMenuItem.level > objMenu._previousMenuItem.level && pobjMenuItem.level == 1)
				objMenu._menuItemTop = objMenu._menuItemTop - 0;	
		}
		
		if(pobjMenuItem.markAsOn)
		{
			// Clear 'On' Style for next re-display. 
			pobjMenuItem.markAsOn = false;
			// Display appropriate 'on' layer.
			_nmHighlightItem(strID, objMenu._menuItemTop, objMenu._menuItemLeft);
		}
		else
		{
			// Display menuItem
			_nmDisplayItem(strID, objMenu._menuItemTop, objMenu._menuItemLeft, pobjMenuItem);
		}
		
		// Retrieve properties for current menu item
		intMenuLevel = pobjMenuItem.level;
		strAlignment = pobjMenuItem.style.alignment;
		
		// Calculate position
		objMenu._menuItemTop = objMenu._menuItemTop + pobjMenuItem.style.height + pobjMenuItem.style.gap;	
		objMenu._previousMenuItem = pobjMenuItem;				
		
	}
	
	// iterate through the children and render them recursively
	if (pobjMenuItem.children.length > 0)
	{
		for (var intEntry = 0; intEntry < pobjMenuItem.children.length; intEntry++)
			_nmDisplayAllMarkedItems(pobjMenuItem.children[intEntry]);
	}
	
	// leave a larger gap between specific menu items
	if(pobjMenuItem.title == 'Bus Performance' && objMenu._currentMenuItem.title == 'Select report')
		objMenu._menuItemTop = objMenu._menuItemTop + 0;	
	
	// seperates the expanded second level menu section from the next top level menu item.
	if(objMenu._previousMenuItem)
	{
		if(intMenuLevel < objMenu._previousMenuItem.level && intMenuLevel == 0)
			objMenu._menuItemTop = objMenu._menuItemTop + 0;	
	}
	
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmHideItem
//    Purpose: Hide all layers associated with a particular menu item.
// Parameters: o pstrID - The ID of the current menuItem
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmHideItem(pstrID, pobjMenuItem)
{
    _nmManipulateLayer(_nmBuildOptionLayerID('Out',pstrID), null, null, 'hidden');
	_nmManipulateLayer(_nmBuildOptionLayerID('Over',pstrID), null, null, 'hidden');
	_nmManipulateLayer(_nmBuildOptionLayerID('On',pstrID), null, null, 'hidden');
	_nmManipulateLayer(_nmBuildOptionLayerID('Image',pstrID), null, null, 'hidden');
	
	pobjMenuItem.visible = false;
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmDisplayItem
//    Purpose: Display all layers associated with a particular menu item.
// Parameters: o pstrID - The ID of the current menuItem
//			   o pintTop - The top coordinate for the current menuItem
//			   o pintLeft - The left coordinate for the current menuItem
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmDisplayItem(pstrID, pintTop, pintLeft, pobjMenuItem)
{
	var 
		intLevel,
		objChild,
		strChildAlignment,
		strCurrentAlignment,
		objChildStyle;
	
	// leave a larger gap between specific menu items
	if(pobjMenuItem.title == 'Select report')
	{
		pintTop = pintTop + 0;	
		objMenu.selectReportTop = pintTop;
		objMenu.selectReportLeft = pintLeft;
	}
	
	// Set correct layer visibility
	_nmManipulateLayer(_nmBuildOptionLayerID('Out',pstrID), pintTop, pintLeft, 'visible');
	_nmManipulateLayer(_nmBuildOptionLayerID('Over',pstrID), pintTop, pintLeft, 'hidden');
	_nmManipulateLayer(_nmBuildOptionLayerID('Image',pstrID), pintTop, pintLeft, 'visible');
	
	pobjMenuItem.visible = true;
	
	// Set top and left properties for current menuItem - will be used when highlighting the
	// selected menu item in a cascading menu.
	pobjMenuItem.top = pintTop;
	pobjMenuItem.left = pintLeft;
		
	// Determine the level and alignment of the selected menuItem.
	intLevel = pobjMenuItem.level;
	strCurrentAlignment = pobjMenuItem.style.alignment;
	
	// If the current menuItem has children - determine the child level alignment
	if (pobjMenuItem.children.length > 0)
		strChildAlignment = pobjMenuItem.children[0].style.alignment;
	
	// Are the any children? if so set the coordinates of the child section
	if (pobjMenuItem.children.length > 0)
	{
		// Calculate the top and left coordinates that should be used as the origin for the next section when it
		// is displayed in a cascading menu. Coordinates will be dependant on the alignment of the current menuItem
		// and the alignment of the child menu items.
		if(strCurrentAlignment == 'vertical')
		{
			// Do the elements in the section need to be inverted if so set an appropriate top coordinate?
			if(pobjMenuItem.children[0].style.flow == FLOW_ASCENDING)
				pobjMenuItem.topForNextSection = pintTop;
			else
				pobjMenuItem.topForNextSection = pintTop - ((pobjMenuItem.children[0].style.gap + pobjMenuItem.children[0].style.height) * (pobjMenuItem.children.length - 1));
			
			// Set left coordinate
			pobjMenuItem.leftForNextSection = pintLeft + pobjMenuItem.style.width + pobjMenuItem.style.gap;
		}
		else
		{
			// Verical menu displayed from a horizontal menu
			if(strChildAlignment == 'vertical')
			{
				pobjMenuItem.topForNextSection = pintTop + pobjMenuItem.style.height + pobjMenuItem.style.gap;
				pobjMenuItem.leftForNextSection = pintLeft;
			}
			else
			{
				// Set top coordinate
				pobjMenuItem.topForNextSection = pintTop + pobjMenuItem.style.height + pobjMenuItem.style.gap + 1;
					
				// Do the elements in the section need to be inverted if so set an appropriate left coordinate?					
				if(pobjMenuItem.children[0].style.flow == FLOW_ASCENDING)
					pobjMenuItem.leftForNextSection = pintLeft;
				else
				{
					// Position the child menu section to end to the right edge of the parent
					objChildStyle = pobjMenuItem.children[0].style;
					pobjMenuItem.leftForNextSection = pintLeft - ((objChildStyle.gap + objChildStyle.width) * (pobjMenuItem.children.length - 1)) + (pobjMenuItem.style.width - objChildStyle.width);
				
				}
			}
		}
	}
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmHighlightItem
//    Purpose: Highlight a particular menu item (displays appropriate 'on' layer).
// Parameters: o pstrID - The ID of the current menuItem
//			   o pintTop - The top coordinate for the current menuItem
//			   o pintLeft - The left coordinate for the current menuItem
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmHighlightItem(pstrID, pintTop, pintLeft)
{
	_nmManipulateLayer(_nmBuildOptionLayerID('On',pstrID), pintTop, pintLeft, 'visible');
	_nmManipulateLayer(_nmBuildOptionLayerID('Out',pstrID), pintTop, pintLeft, 'hidden');
	_nmManipulateLayer(_nmBuildOptionLayerID('Over',pstrID), pintTop, pintLeft, 'hidden');
	_nmManipulateLayer(_nmBuildOptionLayerID('Image',pstrID), pintTop, pintLeft, 'visible');
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmClearHighlight
//    Purpose: Removes the highlight a particular menu item (displays appropriate 'out' layer).
// Parameters: o pstrID - The ID of the current menuItem
//			   o pintTop - The top coordinate for the current menuItem
//			   o pintLeft - The left coordinate for the current menuItem
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmClearHighlight(pstrID, pintTop, pintLeft)
{
	_nmManipulateLayer(_nmBuildOptionLayerID('On',pstrID), pintTop, pintLeft, 'hidden');
	_nmManipulateLayer(_nmBuildOptionLayerID('Out',pstrID), pintTop, pintLeft, 'visible');
	_nmManipulateLayer(_nmBuildOptionLayerID('Over',pstrID), pintTop, pintLeft, 'hidden');
	_nmManipulateLayer(_nmBuildOptionLayerID('Image',pstrID), pintTop, pintLeft, 'visible');
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmDisplay
//    Purpose: To display the navigation menu.
//
//    Effects: Changes the visbility of menu item layers.
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmDisplayMenu()
{
	_WasInDisplay = true;

	// Hide all sections
	_nmHideAllSections();

	// Display the first section
	_nmDisplaySection(objMenu);
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmHideSelect
//    Purpose: Hides the 'select report' menu item.
//
//    History : 15/10/2002. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmHideSelect()
{
	var 
		strOutID = _nmBuildOptionLayerID('Out', objMenu.selectReportID),
		strOverID = _nmBuildOptionLayerID('Over', objMenu.selectReportID),
		strOnID = _nmBuildOptionLayerID('On', objMenu.selectReportID),
		strImageID = _nmBuildOptionLayerID('Image', objMenu.selectReportID);

	if(document.getElementById(strOutID))
	{
		_nmManipulateLayer(strOutID, -100, -100, 'hidden');
		_nmManipulateLayer(strOverID, -100, -100, 'hidden');
		_nmManipulateLayer(strOnID, -100, -100, 'hidden');
		_nmManipulateLayer(strImageID, -100, -100, 'hidden');
	}
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmShowSelect
//    Purpose: Shows the 'select report' menu item.
//
//    History : 15/10/2002. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmShowSelect()
{
	var 
		strOutID = _nmBuildOptionLayerID('Out', objMenu.selectReportID),
		strOverID = _nmBuildOptionLayerID('Over', objMenu.selectReportID),
		strOnID = _nmBuildOptionLayerID('On', objMenu.selectReportID),
		strImageID = _nmBuildOptionLayerID('Image', objMenu.selectReportID);

	if(document.getElementById(strOutID))
	{
		_nmManipulateLayer(strOutID, objMenu.selectReportTop, objMenu.selectReportLeft, 'visible');
		_nmManipulateLayer(strOverID, objMenu.selectReportTop, objMenu.selectReportLeft, 'visible');
		_nmManipulateLayer(strOnID, objMenu.selectReportTop, objMenu.selectReportLeft, 'visible');
		_nmManipulateLayer(strImageID, objMenu.selectReportTop, objMenu.selectReportLeft, 'visible');
	}
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmAddChild
//    Purpose: Adds a child item to the specified menu item
// Parameters: o pstrTitle - The title for the menuItem
//			   o pstrURL - The URL of the action associated with the menuItem
//			   o pstrDescription - Description of the action associated with the menuItem
//			   o pobjStyle - Style object to be linked with the new menu item
//			   o pobjRoot - Root menu object
//    Returns: New chile menuItem object.
//
// -><---------------------------------------------------------------------------------------------

function _nmAddChild(pstrTitle, pstrURL, pstrDescription, pblnDisplaySelect, pobjStyle, pobjRoot)
{
	var 
		objChild = new menuItem(pstrTitle, pstrURL, pstrDescription, pblnDisplaySelect, this, pobjStyle, pobjRoot);

	this.children[this.children.length] = objChild;
	return(objChild);
}


// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmRetrieveMenuItemFromID
//    Purpose: Returns the MenuItem object identified by the ID
// Parameters: o pstrID - The ID of the current menuItem
//			   o pobjMenuItem - The current menu item object (root on intial call)
//    Returns: menuItem object.
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmRetrieveMenuItemFromID(pstrID, pobjMenuItem)
{
	var 
		astrID = pstrID.split('.');
		
	// Does Current menu item have children
	if (pobjMenuItem.children.length > 0)
	{	
		// Loop around children of current menu item
		for (var intEntry = 0; intEntry < pobjMenuItem.children.length; intEntry++)
		{
			// Does current menu item match the supplied ID? If so set _currentMenuItem on menu (root) object
			if (pobjMenuItem.children[intEntry].ID == pstrID)
				objMenu._currentMenuItem = pobjMenuItem.children[intEntry];
			else
				_nmRetrieveMenuItemFromID(pstrID, pobjMenuItem.children[intEntry]);
		}
	}
}


// -<>- Default Event Handlers --------------------------------------------------------------------
// -!!- These should be overridden as required.

// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmOptionOnMouseOutOrOver
//    Purpose: Handler for pointer moving out of or over an option.
// Parameters: pblnHasMovedOver - whether the pointer has moved over the option
//			   pintID - the index of the section this option belongs to
//    Effects: Changes the visibility of appropriate layers.
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmOptionOnMouseOutOrOver(pblnHasMovedOver, pintID)
{
	if(_WasInDisplay)
		_WasInDisplay = false;
	else
	{
		var
			strOut = (pblnHasMovedOver) ? 'hidden' : 'visible';
			strOver = (pblnHasMovedOver) ? 'visible' : 'hidden';

		_nmManipulateLayer(_nmBuildOptionLayerID('Out',pintID), null, null, strOut);
		_nmManipulateLayer(_nmBuildOptionLayerID('Over',pintID), null, null, strOver);
	}
}

// -<>---------------------------------------------------------------------------------------------
//
//   Function: _nmOptionOnClick
//    Purpose: Handler for when a menu option is clicked
// Parameters: o pobjMenuItem - the ID menuItem object that has been selected
//    Effects: Initiates display of the appropriate menu actions.
//
//    History : 09/05/2001. GAS. Created. 
//
// -><---------------------------------------------------------------------------------------------

function _nmOptionOnClick(pstrID)
{
	var 
		objMenuItem,
		intLevel,
		objActiveMenuItem;
	
	if(_WasInDisplay)
		_WasInDisplay = false;

	// Set private _currentMenuItem property of root menu object from current item's id
	_nmRetrieveMenuItemFromID(pstrID, objMenu);
	
	// Retrieve object reference
	objMenuItem = objMenu._currentMenuItem;
	
	// Set private property to collapse the current menu tree if a selected node is already expanded
	if(objMenu._previousMenuItemID == objMenuItem.ID)
		objMenu._collapseMenuTree = !objMenu._collapseMenuTree;
	else
		objMenu._collapseMenuTree = false;
			
	// Keep a record of previous menu itemID
	objMenu._previousMenuItemID = objMenuItem.ID;
	
	// If the menu is not defined as a cascading menu - construct a fully dynamic LHS menu
	if(!objMenu.cascading)
	{
		// Traverse menu tree marking menu items to be displayed
		if(objMenuItem.title != 'Select report')
			_nmMarkItemsForDisplay(objMenuItem);
	}
	else
	{
		// The menu is a cascading menu - initiate display accordingly
		
		// Clear any previous highlight
		intLevel = objMenuItem.level;
		objActiveMenuItem = objMenu.activeMenuItems[intLevel];
		
		// If there is an active menu item at this level and it is still visible - clear it's highlight
		if(objActiveMenuItem != null && objActiveMenuItem.visible == true)
			_nmClearHighlight(objActiveMenuItem.ID, objActiveMenuItem.top, objActiveMenuItem.left);
		
		// Highlight the selected menu item
		_nmHighlightItem(pstrID, objMenuItem.top, objMenuItem.left);
		
		// Display the appropriate section
		_nmDisplaySection(objMenuItem)		
	}

	// Perform the desired action having clicked on the menu item
	_nmPerformAction(objMenuItem);
}


// -<>- Constructors ------------------------------------------------------------------------------
// -!!- Should use prototypes instead of function reference assignment for methods

function navigationMenu(pblnHideUnselectedOptionsAtLevel, pblnCascading, pblnHasHome, pblnHasTail)
{
	_navigationMenu = new Object();

	// Initialise properties and collections
	_navigationMenu.HideUnselectedOptionsAtLevel = pblnHideUnselectedOptionsAtLevel;
	_navigationMenu.cascading = pblnCascading;
	_navigationMenu.ID = 0;
	_navigationMenu.level = 0;
	_navigationMenu.children = new Array();
	_navigationMenu.activeMenuItems = new Array();
	_navigationMenu.title = "root";
	_navigationMenu.selectReportID = 0;
	_navigationMenu.selectReportTop = 0;
	_navigationMenu.selectReportLeft = 0;

	// Layout specific properties
	_navigationMenu.left = 0;
	_navigationMenu.top = 92;

	// Private Properties
	_navigationMenu._menuItemTop = _navigationMenu.top;
	_navigationMenu._menuItemLeft = _navigationMenu.left;
	_navigationMenu._currentMenuItem = null;
	_navigationMenu._previousMenuItemID = null;
	_navigationMenu._collapseMenuTree = false;
	_navigationMenu._previousMenuItem = null;

	// Initialise methods
	_navigationMenu.addChild = _nmAddChild;
	_navigationMenu.renderMenu = _nmRenderMenu;
	_navigationMenu.displayMenu = _nmDisplayMenu;	
	_navigationMenu.hideSelect = _nmHideSelect;	
	_navigationMenu.showSelect = _nmShowSelect;	


	return(_navigationMenu);
}

function menuItem(pstrTitle, pstrURL, pstrDescription, pblnDisplaySelect, pobjParent, pobjStyle, pobjRoot)
{
	_menuItem = new Object();
	
	// Initialise properties
	_menuItem.title = pstrTitle;
	_menuItem.url = pstrURL;
	_menuItem.description = pstrDescription;
	_menuItem.displaySelect = pblnDisplaySelect;
	_menuItem.children = new Array();	
	_menuItem.parent = pobjParent;
	_menuItem.style = pobjStyle;	
	_menuItem.top = 0;
	_menuItem.left = 0;
	_menuItem.topForNextSection = 0;
	_menuItem.leftForNextSection = 0;
	_menuItem.root = pobjRoot;
	
	// Private Properties
	_menuItem.visible = false;
	
	// Initialise methods
	_menuItem.addChild = _nmAddChild;
	
	return(_menuItem);
}

function menuStyle(pstrLevel, pblnAlignment, pblnSelectedIndicator, objRoot)
{
	_menuStyle = new Object();
	
	// Initialise properties
	_menuStyle.width = 182;
	_menuStyle.rightGap = 20;
	_menuStyle.level = pstrLevel;
	_menuStyle.height = 20;
	_menuStyle.gap = 2;
	_menuStyle.alignment = pblnAlignment;
	_menuStyle.flow = FLOW_ASCENDING;
	_menuStyle.selectedIndicator = pblnSelectedIndicator;
	
	// Private properties
	_menuStyle._TextWidth = _menuStyle.width - _menuStyle.rightGap;

	// Initialise the active menu item for the current level
	objRoot.activeMenuItems[pstrLevel-1] = null;
	
	return(_menuStyle);
}
