// ----------------------------------------------
// KNOWLEDGE MAP DYNAMIC NAVIGATION BAR FUNCTIONS
// ----------------------------------------------
// Copyright (c) 2004-2007 The Salamander Organization Ltd.  All Rights Reserved.
//
// THIS WORK IS SUBJECT TO U.K. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
//
// DISCLAIMER:
//
// The Salamander Organization Ltd. (hereto referred as "Salamander") makes no representations or warranties
// with respect to the contents or use of this code, and specifically disclaims any express or implied
// warranties of merchantability or fitness for any particular purpose.  Further, Salamander reserves the right
// to revise this publication and to make changes to its content, at any time, without obligation to notify any
// person or entity of such revisions or changes.
//
// Further, Salamander makes no representations or warranties with respect to any software, and specifically
// disclaims any express or implied warranties of merchantability or fitness for any particular purpose.  Salamander
// reserves the right to make changes to any and all parts of the software, at any time, without obligation to notify
// any person or entity of such changes.
//
// Inclusion of the above notice does not necessarily imply publication.

// ########################
// ### SYSTEM VARIABLES ###

var blockCount = 0;
var blocks = new Array();

var areaCount = 0;
var areas = new Array();

var areaSuffix = "NavigationArea";


// #########################################
// ### GENERIC NAVIGATION MENU FUNCTIONS ###

// create a navigation link string and add it to selected block
// SUMMARY:
//		string navBlockName		- name of the navigation block to send this navigation item to (e.g. "top", "control", etc)
//		string linkName			- name of the link to appear on the page
//		string linkUrl			- well known function or link id || a partial url || an absolute url
//		string htmlLinkOpen		- html to open each link (can be empty)
//		string htmlLinkClose	- html to close each link (can be empty)
//		string toolTipText		- text to appear in a tooltip mouseover
//		string linkIdText		- DOM id to use for this link
//		bool isOutsideKMap		- set "true" for "link is outside KMap, do not add URL path", else omit or set false
function AddNavigationLink(navBlockName, linkName, linkUrl, htmlLinkOpen, htmlLinkClose, toolTipText, linkIdText, isOutsideKMap)
{	
	var block = GetNavigationBlock(navBlockName);

	if (block)
	{
		var classIdText = block.classIdText;
		
		var navString = CreateNavigationLink(linkName, linkUrl, toolTipText, classIdText, linkIdText, isOutsideKMap);
		
		var navLink = new NavigationLink(navString, htmlLinkOpen, htmlLinkClose);

		AddItem(block, navLink, htmlLinkOpen, htmlLinkClose);
	}
}

// create a block item string and add it to the selected block
// SUMMARY:
//		string navBlockName		- name of the navigation block to send this item to (e.g. "top", "control", etc)
//		string itemName			- name of the item if a well-known block item, else a blank string
//		string itemText			- arbitrary text (can include html) for the block item - well-known blocks may override this parameter
//		string htmlItemOpen		- html to open each item (can be empty)
//		string htmlItemClose	- html to close each item (can be empty)
//		string toolTipText		- text to appear in a tooltip mouseover - well-known blocks may override this parameter
//		string linkIdText		- DOM id to use for this link (may be ignored, depending on the block item)
//		string overrideClassIdText	- css class to use for this block - OVERRIDES the default class id for this block for this item only
function AddBlockItem(navBlockName, itemName, itemText, htmlItemOpen, htmlItemClose, toolTipText, linkIdText, overrideClassIdText)
{
	var block = GetNavigationBlock(navBlockName);
	
	if (block)
	{
		var classIdText = ""
		
		if (overrideClassIdText == "")
		{
			classIdText = block.classIdText;
		}
		else
		{
			classIdText = overrideClassIdText;
		}
		
		var itemString = CreateBlockItem(itemName, itemText, toolTipText, classIdText, linkIdText);
		
		var blockItem = new BlockItem(itemString, htmlItemOpen, htmlItemClose);
		
		AddItem(block, blockItem);
	}
}

// get HTML for a named navigation block with its navigation links
function GetNavigation(navBlockName)
{	
	var navigationOutput = "";
	
	var block = GetNavigationBlock(navBlockName);
	
	if (block)
	{
		if (block.count > 0)
		{
			// add the HTML lead in
			navigationOutput = block.htmlBlockOpen;
			
			for (var i = 0; i < block.count; i++)
			{
				var currentItem = block.navigation[i];
				
				var itemHtml = currentItem.htmlOpen + currentItem.itemHtml + currentItem.htmlClose;
				
				if (i == 0)
				{
					// first item in list, just add it
					navigationOutput += itemHtml;
				}
				else
				{
					// any other list item, add a separator, then add it
					navigationOutput += block.htmlSeparator + itemHtml;
				}
			
				block.visibleCount = block.visibleCount + 1;  // added a link to the block, increment the visible links count
			}
			
			// add the HTML lead out
			navigationOutput += block.htmlBlockClose;
		}
	}
	
	return navigationOutput;
}

// write out a navigation area with its navigation blocks to the associated templateBlock
function WriteNavigationArea(area, templateBlock)
{
	if (templateBlock)
	{
		var templateOutput = "";
		
		if (area)
		{
			if (area.count > 0)
			{
				for (var i = 0; i < area.count; i++)
				{
					var currentBlock = area.blocks[i];
					
					var areaSeparator = "";
					var navOutput = "";

					if (area.visibleCount != 0)
					{
						if (area.htmlSeparator != "")
						{
							// for items other than the first get the block separator (added if this block has visible items)
							areaSeparator = area.htmlSeparator;
						}
					}

					navOutput = GetNavigation(currentBlock.blockName);

					if (currentBlock.visibleCount > 0)
					{
						// collate the output, adding a separator (if necessary) and the current navigation output
						templateOutput += areaSeparator + navOutput;
						
						// block has visible items, therefore block is displayed
						area.visibleCount = area.visibleCount + 1;  // added block to the area, increment the visible blocks counter
					}
				}
			}
		}
		
		templateBlock.innerHTML = templateOutput;  // dump the output to the templateBlock
	}
}

// write out all navigation areas, checking to see if their templateBlocks are available on this template page
function WriteNavigationAreas()
{
	// iterate through all the available navigation areas to see if they need writing
	for (var i = 0; i < areaCount; i++)
	{
		var area = areas[i];
		
		var areaId = area.areaName + areaSuffix;
		
		var templateBlock = document.getElementById(areaId);
		
		// make sure we're supposed to be writing this area - if we've got the templateBlock we write the navigationArea to it
		if (templateBlock)
		{
			WriteNavigationArea(area, templateBlock);
		}
	}
}

// #########################################
// ### NAVIGATION MENU SUPPORT FUNCTIONS ###

// [constructor] navigation area object
// SUMMARY:
//		string areaName			- string for the area's name, used to reference navigation blocks to this area
//		string htmlSeparator	- html to separate each block in the area
function NavigationArea(areaName, htmlSeparator)
{
	this.areaName = areaName;
	this.htmlSeparator = htmlSeparator;
	this.blocks = new Array();  // array of blocks in this area
	this.count = 0;  // number of blocks in this area
	this.visibleCount = 0;  // number of blocks visible in this area
	RegisterNavigationArea(this);
}

// [constructor] navigation block object
// SUMMARY:
//		string blockName		- string for the block's name, used to reference navigation links to this block
//		string classIdText		- css class id to use for this block's links
//		string htmlBlockOpen	- html to open the link block
//		string htmlSeparator	- html to separate each link in the block
//		string htmlBlockClose	- html to close each link block
function NavigationBlock(blockName, classIdText, htmlBlockOpen, htmlSeparator, htmlBlockClose)
{
	this.blockName = blockName;
	this.classIdText = classIdText;
	this.htmlBlockOpen = htmlBlockOpen;
	this.htmlSeparator = htmlSeparator;
	this.htmlBlockClose = htmlBlockClose;
	this.navigation = new Array();  // array of items in this block
	this.count = 0;  // number of items in this block
	this.visibleCount = 0;  // number of items visible in this block
	RegisterNavigationBlock(this);
}

// [constructor] navigation link object
// SUMMARY:
//		string linkHTML			- html for the contents of the link
//		string htmlLinkOpen		- html to open each link
//		string htmlLinkClose	- html to close each link
function NavigationLink(linkHTML, htmlLinkOpen, htmlLinkClose)
{
	this.itemType = "link";
	this.itemHtml = linkHTML;
	if (htmlLinkOpen == "" || !htmlLinkOpen)
	{
		this.htmlOpen = "";
	}
	else
	{
		this.htmlOpen = htmlLinkOpen;
	}
	if (htmlLinkClose == "" || !htmlLinkClose)
	{
		this.htmlClose = "";
	}
	else
	{
		this.htmlClose = htmlLinkClose;
	}
}

// [constructor] block item object
// SUMMARY:
//		string itemHTML			- html for the contents of the item
//		string htmlItemOpen		- html to open each item
//		string htmlItemClose	- html to close each item
function BlockItem(itemHTML, htmlItemOpen, htmlItemClose)
{
	this.itemType = "item";
	this.itemHtml = itemHTML;
	if (htmlItemOpen == "" || !htmlItemOpen)
	{
		this.htmlOpen = "";
	}
	else
	{
		this.htmlOpen = htmlItemOpen;
	}
	if (htmlItemClose == "" || !htmlItemClose)
	{
		this.htmlClose = "";
	}
	else
	{
		this.htmlClose = htmlItemClose;
	}
}

// get a valid block item, when provided with either:
//		a) a well known block identifier (e.g. SEARCHINPUT) as itemName
//		b) an unknown block identifier as itemName and arbitrary text in itemText
function GetValidItem(itemName, itemText, toolTipText, classIdText, linkIdText)
{
	var validItem = "";
	
	itemName = itemName.toUpperCase();
	
	switch (itemName)
	{
		case "SEARCHINPUT" :
			validItem = "<input id=\"" + linkIdText + "\" type=\"text\" size=\"" + itemText + "\" maxlength=\"50\" />";
			break;
		case "SEARCHBUTTON" :
			validItem = "<input class=\"" + classIdText + "\" type=\"submit\" value=\"" + toolTipText + "\" onClick=\"return DoClientSearch('" + itemText + "');\" />";
			break;
		default :
			// not a recognised item, so just use the itemText as the item itself
			validItem = itemText;
			break;
	}
	
	return validItem;
}

// create a well-formed block item
// SUMMARY:
//		string itemName		- name of the item if a well-known block item, else a blank string
//		string itemText		- arbitrary text (can include html) for the block item - well-known blocks may override this parameter
//		string toolTipText	- text to appear in a tooltip mouseover - well-known blocks may override this parameter
//		string classIdText	- css class to use for this block item (may be ignored, depending on the block item)
//		string linkIdText	- DOM id to use for this link (may be ignored, depending on the block item)
function CreateBlockItem(itemName, itemText, toolTipText, classIdText, linkIdText)
{
	var validItem = GetValidItem(itemName, itemText, toolTipText, classIdText, linkIdText);
	
	var itemString = "";
	
	if (validItem == itemText)
	{
		// the itemName wasn't recognised, so just format some arbitrary text
		
		// is there tooltip text?
		var toolTip = "";
		if (toolTipText == "" || !toolTipText)
		{
			toolTip = "";
		}
		else
		{
			toolTip = " title=\"" + toolTipText + "\"";
		}

		// is there a CSS class to set?
		var classId = "";
		if (classIdText == "" || !classIdText) 
		{
			classId = "";
		}
		else
		{
			classId = " class=\"" + classIdText + "\"";
		}

		// is there a DOM id to set?
		var linkId = "";
		if (linkIdText == "" || !linkIdText)
		{
			linkId = "";
		}
		else
		{
			linkId = " id=\"" + linkIdText + "\"";
		}
		
		itemString = "<span" + toolTip + linkId + classId + ">" + itemText + "</span>";
	}
	else
	{
		// the itemName was recognised and has already been processed, so just use that
		
		itemString = validItem;
	}
	
	return itemString;
}

// get a valid link URL, when provided with either:
//		a) a well known url identifier (e.g. HOMEPAGE)
//		b) a well known function identifier (e.g. FEEDBACK)
//		c) an absolute url, including protocol  (e.g. http://www.tsorg.com/)
//		d) a partial url inside the KMap (e.g. HelperPages/somePage.htm)
function GetValidLinkUrl(linkUrl, isOutsideKMap)
{
	var validLinkUrl = "";

	// can't case protect linkUrl as it may be a valid case-sensitive URL string

	switch (linkUrl)
	{
		case "HOMEPAGE" :
			validLinkUrl = "javascript:DoNavigation(\"" + linkUrl + "_LINK\")";
			break;
		case "BACK" :
			validLinkUrl = "javascript:GoBack()";
			break;
		case "INDEXPAGES" :
			validLinkUrl = "javascript:DoNavigation(\"" + linkUrl + "_LINK\")";
			break;
		case "FAQ" :
			validLinkUrl = "javascript:DoNavigation(\"" + linkUrl + "_LINK\")";
			break;
		case "KNOWLEDGEINDEX" :
			validLinkUrl = "javascript:DoNavigation(\"" + linkUrl + "_LINK\")";
			break;
		case "FEEDBACK" :
			validLinkUrl = "javascript:MailFeedback(\"PAGE_NAME\")";
			break;
		case "HELP" :
			validLinkUrl = "javascript:DoNavigation(\"" + linkUrl + "_LINK\")";
			break;
		case "PRINTABLEPAGE" :
			validLinkUrl = "javascript:ShowPrintablePage()";
			break;
		case "SHOWALL" :
			validLinkUrl = "javascript:ShowAllSections()";
			break;
		case "HIDEALL" :
			validLinkUrl = "javascript:HideAllSections(true)";
			break;
		case "HIDEALL_NOTSTICKY" :
			validLinkUrl = "javascript:HideAllSections(false)";
			break;
		case "TOGGLEAUTOHIDE" :
			validLinkUrl = "javascript:ToggleAutoHide()";
			break;
		case "CLEARSTATECOOKIES" :
			validLinkUrl = "javascript:ClearStateCookies()";
			break;
		case "ARCHITECTURE_RV" :
			validLinkUrl = "javascript:DoNavigation(\"" + linkUrl + "_LINK\")";
			break;
		default :
			if (isOutsideKMap)
			{
				// link is outside the Knowledge Map, leave the linkUrl as is
				validLinkUrl = linkUrl;
			}
			else
			{
				// link is in the Knowledge Map - add the appropriate URL_PATH
				validLinkUrl = pageUrlPath + linkUrl;
			}
			break;
	}
	
	return validLinkUrl;
}

// create a well-formed HTML navigation link
// SUMMARY:
//		string linkName		- name of the link to appear on the page
//		string linkUrl		- well known function or link id || a partial url || an absolute url
//		string toolTipText	- text to appear in a tooltip mouseover
//		string classIdText	- css class to use for this link
//		string linkIdText	- DOM id to use for this link
//		bool isOutsideKMap	- set "true" for "this link is outside the KMap, do not add url path", else omit or set false
function CreateNavigationLink(linkName, linkUrl, toolTipText, classIdText, linkIdText, isOutsideKMap)
{
	var validLinkUrl = GetValidLinkUrl(linkUrl, isOutsideKMap);
	
	// is there tooltip text?
	var toolTip = "";
	if (toolTipText == "" || !toolTipText)
	{
		toolTip = "";
	}
	else
	{
		toolTip = " title=\"" + toolTipText + "\"";
	}

	// is there a CSS class to set?
	var classId = "";
	if (classIdText == "" || !classIdText) 
	{
		classId = "";
	}
	else
	{
		classId = " class=\"" + classIdText + "\"";
	}

	// is there a DOM id to set?
	var linkId = "";
	if (linkIdText == "" || !linkIdText)
	{
		linkId = "";
	}
	else
	{
		linkId = " id=\"" + linkIdText + "\"";
	}
	
	if (validLinkUrl && validLinkUrl.indexOf("javascript:") == 0)
	{
		return "<a href='#' onclick='" + validLinkUrl + "'" + toolTip + linkId + classId + ">" + linkName + "</a>";
	}
	else
	{
		return "<a href='" + validLinkUrl + "'" + toolTip + linkId + classId + ">" + linkName + "</a>";
	}
}

// find the NavigationBlock object that matches this navBlockName
function GetNavigationBlock(navBlockName)
{
	navBlockName = navBlockName.toLowerCase();  // case protection
	
	var block = new Object();
	
	for (var i = 0; i < blockCount; i++)
	{
		if (blocks[i].blockName == navBlockName)
		{
			block = blocks[i];
			break;  // got the block, stop searching
		}
	}
	
	return block;  // DEV NOTE:  may return a non-block...
}

// find the NavigationArea object that matches this navAreaName
function GetNavigationArea(navAreaName)
{
	navAreaName = navAreaName.toLowerCase();  // case protection
	
	var area = new Object();
	
	for (var i = 0; i < areaCount; i++)
	{
		if (areas[i].areaName == navAreaName)
		{
			area = areas[i];
			break;  // got the area, stop searching
		}
	}
	
	return area;  // DEV NOTE:  may return a non-area...
}

// used by the NavigationBlock constructor, registers a new navigation block with the system
function RegisterNavigationBlock(block)
{
	// add the block to the array
	blocks[blockCount] = block;
	
	blockCount++;  // increment the blockCount;
}

// used by the NavigationArea constructor, registers a new navigation area with the system
function RegisterNavigationArea(area)
{
	areas[areaCount] = area;
	
	areaCount++;
}

// add an item to this block
function AddItem(block, item)
{
	if (block.blockName)
	{
		block.navigation[block.count] = item;  // add item

		block.count = block.count + 1;  // increment block item count
	}
}

// add a block to this navigation area
function AddBlock(areaName, block)
{
	var area = GetNavigationArea(areaName);
	
	if (area.areaName)
	{
		area.blocks[area.count] = block;
		
		area.count = area.count + 1;
	}
}

// creates a new navigation block
function CreateNavigationBlock(areaNames, blockName, classIdText, htmlBlockOpen, htmlSeparator, htmlBlockClose)
{
	var newBlock = new NavigationBlock(blockName, classIdText, htmlBlockOpen, htmlSeparator, htmlBlockClose);
	
	var areasString = new String(areaNames);
	
	if (areasString.indexOf("|") != -1)
	{
		// add this block to multiple areas
		var areasArray = areasString.split("|");
		
		for (var i = 0; i < areasArray.length; i++)
		{
			AddBlock(areasArray[i], newBlock);
		}
	}
	else
	{
		// add this block to only one area
		AddBlock(areaNames, newBlock);
	}
}

// creates a new navigation area
function CreateNavigationArea(areaName, htmlSeparator)
{
	// areaName must not contain any | characters
	
	if (areaName.indexOf("|") == -1)
	{
		var newArea = new NavigationArea(areaName, htmlSeparator);
	}
	else
	{
		alert("ERROR:  Attempted to create navigation area named '" + areaName + "' but that name may not contain any '|' characters.");
	}
}


// #############################################
// ### DROP DOWN NAVIGATION SYSTEM VARIABLES ###

var hideDropDownTime = 400;

var dropDownMenus = new Array();
var dropDownMenuCount = 0;

var menuItemPrefix = "ddmenuitem_";
var dropDownPrefix = "dropdown_";


// ################################
// ### DROP DOWN USER INTERFACE ###

// --- Drop Down onMouseOver ---
function dropdownFocused(dropDownId)
{
	var ddMenu = GetDropDownMenu(dropDownId, true);

	if (ddMenu)
	{
		LockDropDownDisplay(ddMenu);
	}
}

// --- Drop Down onMouseOut ---
function dropdownBlurred(dropDownId)
{
	var ddMenu = GetDropDownMenu(dropDownId, true);
	
	if (ddMenu)
	{
		UnlockDropDownDisplay(ddMenu, hideDropDownTime);
	}
}

// --- onClick event for the menu item containing the drop down ---
function menuClicked(menuItemId)
{
	HideAllDropDowns();
	
	var ddMenu = GetDropDownMenu(menuItemId, false);
	
	if (ddMenu)
	{
		var menuItem = document.getElementById(ddMenu.menuItemId);

		if (menuItem)
		{
			var leftOffset = ElementLeftOffset(menuItem, 0);
			var topOffset = ElementTopOffset(menuItem, 0) + menuItem.offsetHeight;

			DropDownShow(ddMenu, topOffset, leftOffset);
			LockDropDownDisplay(ddMenu);  // need to lock the display of the drop down to prevent nav flicker
		}
	}
}


// ##############################
// ### DROP DOWN MANIPULATION ###

// show the drop down menu
function DropDownShow(ddMenu, topOffset, leftOffset)
{
	if (ddMenu)
	{
		var dropdown = document.getElementById(ddMenu.dropDownId);
		var linklist = document.getElementById(ddMenuListPrefix + ddMenu.dropDownId);
		var ddFrame = document.getElementById("ddMenuFrame");

		if (dropdown && linklist)
		{
			linklist.style.height = 1;  // must be non-zero and not set to "auto" to allow scrollHeight to read properly next
				
			var scrollHeightInteger = parseInt(StripChars(linklist.scrollHeight.toString(), "units"));
			var styleHeightInteger = parseInt(StripChars(dropdown.style.height.toString(), "units"));
			var frameHeight = MinNotZero(scrollHeightInteger, styleHeightInteger);
		
			if (ddMenu.display == "none")
			{
				ddZIndex = "100";  // arbitrary zIndex number greater than 1
			
				dropdown.style.left = leftOffset;
				dropdown.style.top = topOffset;

				dropdown.style.height = frameHeight;
				dropdown.style.width = ddMenu.width;
				
				dropdown.style.zIndex = ddZIndex;

				ddMenu.display = "block";
				
				// for plugin-based models, try to use a predefined iframe to layer the dropdown over the plugin
				if (ddFrame)
				{
					ddFrame.style.left = leftOffset;
					ddFrame.style.top = topOffset;
					
					ddFrame.style.height = frameHeight;
					ddFrame.style.width = ddMenu.width;
					
					ddFrame.style.zIndex = ddZIndex - 1;
					
					ddFrame.style.display = ddMenu.display;
				}

				dropdown.style.display = ddMenu.display;
				
				// when a div hasn't been displayed yet, scrollHeight == 0, but after it's displayed, scrollHeight is populated
				if (scrollHeightInteger == 0)
				{
					// now repeat the scrollHeight setting parameters - a little sleight of hand here
					scrollHeightInteger = parseInt(StripChars(linklist.scrollHeight.toString(), "units"));	
					frameHeight = MinNotZero(scrollHeightInteger, styleHeightInteger);
					
					dropdown.style.height = frameHeight;
					if (ddFrame) ddFrame.style.height = frameHeight;
				}
			
				ddMenu.isHiding = false;  // clear any hiding flags
			}
		}
	}
}

// hide the drop down menu
function DropDownHide(ddMenu)
{
	if (ddMenu)
	{
		var dropdown = document.getElementById(ddMenu.dropDownId);
		var ddFrame = document.getElementById("ddMenuFrame");

		if (dropdown)
		{
			if (ddMenu.display == "block")
			{
				ddMenu.display = "none";
				
				// for plugin-based models, also hide any predefined iframe used to layer the dropdown over the plugin
				if (ddFrame)
				{
					ddFrame.style.display = ddMenu.display;
				}

				dropdown.style.display = ddMenu.display;
			
				ddMenu.isHiding = false;  // clear any hiding flags
			}
		}
	}
}

// hide all drop down menus
function HideAllDropDowns()
{
	for (var i = 0; i < dropDownMenuCount; i++)
	{
		DropDownHide(dropDownMenus[i]);
	}
}

// hide all drop down menus that are currently tagged as closing
function HideClosingDropDowns()
{
	for (var i = 0; i < dropDownMenuCount; i++)
	{
		var currentDropDown = dropDownMenus[i];
		
		if (currentDropDown.isHiding)
		{
			DropDownHide(currentDropDown);
		}
	}
}


// ###################################
// ### DROP DOWN SUPPORT FUNCTIONS ###

// freeze the drop down open
function LockDropDownDisplay(ddMenu)
{
	ddMenu.isHiding = false;
	
	if(ddMenu.hideTimer) clearTimeout(ddMenu.hideTimer);
}

// clear the drop down freeze and, after a short delay, close it
function UnlockDropDownDisplay(ddMenu, timeOut)
{
	ddMenu.isHiding = true;
	
	ddMenu.hideTimer = setTimeout("HideClosingDropDowns();", timeOut);
}


// ############################
// ### DROP DOWN DEFINITION ###

// [constructor] drop down menu object
// SUMMARY:
//		string menuItemId		- DOM id for the menu item (including prefix)
//		string dropDownId		- DOM id for the drop down box (including prefix)
//		string name				- name of this menu
//		int height				- height of the menu (larger items cause scrolling)
//		int width				- width of the menu
function DropDownMenu(menuItemId, dropDownId, name, height, width)
{
	this.menuItemId = menuItemId;
	this.dropDownId = dropDownId;
	this.name = name;
	this.height = height;
	this.width = width;
	this.display = "none";
	this.hideTimer;
	this.showTimer;
	this.isHiding = false;
}

// create a new drop down menu
// SUMMARY:
//		string name				- name of this menu
//		int height				- height of the menu (larger items cause scrolling)
//		int width				- width of the menu
// RETURNS:
//		DropDownMenu instance
function CreateDropDownMenu(name, height, width)
{
	var uniqueId = GetUniqueSectionID(name);
	
	var menuItemId = menuItemPrefix + uniqueId;
	var dropDownId = dropDownPrefix + uniqueId;

	var newDropDown = new DropDownMenu(menuItemId, dropDownId, name, height, width);
	
	AddDropDownMenu(newDropDown);
	
	return newDropDown;
}

// register a drop down menu with the system
function AddDropDownMenu(newDropDown)
{
	dropDownMenus[dropDownMenuCount] = newDropDown;
	
	dropDownMenuCount++;
}

// get a drop down menu instance that matches a particular DOM id
// set isDropDownId = false when the DOM id passed is for the menu item
// set isDropDownId = true when the DOM id passed is for the drop down box 
function GetDropDownMenu(menuId, isDropDownId)
{
	var dropDownMenu = null;
	
	for (var i = 0; i < dropDownMenuCount; i++)
	{
		var currentDropDown = dropDownMenus[i];
		
		var currentDropDownId;
		
		// which type of id are we looking for?
		if (isDropDownId)
		{
			currentDropDownId = currentDropDown.dropDownId;
		}
		else
		{
			currentDropDownId = currentDropDown.menuItemId;
		}
		
		if (currentDropDownId == menuId)
		{
			dropDownMenu = currentDropDown;
			break;  // found, stop searching
		}
	}
	
	return dropDownMenu;
}
