/*	File Version: 1.1; */
/*******************************************************************/
/*	This file contains scripts that control the interface (menus). */
/*	                                                               */
/*	Dependancies:                                                  */
/*		control.js                                                 */
/*******************************************************************/

/*	navlist is an array of DOM references (ul). Root level lists don't need to be stored as they never change. Each
	object stores its index number as FE_List_ID and also the index number of its parent link. */
var navlist = new Array();

/*	navlink is an array of DOM references (li). Each object also needs to record the index number of the navlist
	contained within (use -1 for none). Each object also stores the setTimeout ID (for menu hide delays) so timers can
	be cleared. */
var navlink = new Array();

/*******************************************************************************************************************/
/*	General functions. These will be used frequently by other functions for performing common tasks. These are not */
/*	context sensitive and can be called from anywhere.                                                             */
/*******************************************************************************************************************/

/*	Looks up the list structure to see if the list is an ancestor of the link */
function isAncestor(ListID, LinkID) {
/*	Root level links (with no parent list) have an FE_Parent_List value of -1. Anything else is the index number of the
	parent list. */
	while (navlink[LinkID].FE_Parent_List != -1) {
		if (navlink[LinkID].FE_Parent_List == ListID) return true;
		LinkID = navlist[navlink[LinkID].FE_Parent_List].FE_Parent_Link;
	}
	return false;
}

/*	Clears the timer associated with a link and resets the timer's FE_Timer_ID value. */
function clearTimer(LinkID) {
/*	If FE_Timer_ID is -1, the timer is not active for that link. */
	if (navlink[LinkID].FE_Timer_ID != -1) {
		clearTimeout(navlink[LinkID].FE_Timer_ID);
		navlink[LinkID].FE_Timer_ID = -1;
	}
}

/*	Hides a menu (instantly). */
function hideMenu(LinkID) {
/*	Clear any associated timeouts. There shouldn't really be any at this point, but it's always wise to check, and the
	performance hit will be minimal. */
	clearTimer(LinkID);
	navlist[navlink[LinkID].FE_Nested_List].className = '';
}

/*******************************************************************************************************/
/*	Event functions. These functions are all attached to events (and cannot be called out of context). */
/*******************************************************************************************************/

/*	Removes all timers on the menu so that it won't be hidden - e.g. when the user moves the mouse off the triggering
	link and then moves the mouse over the menu itself. This can cause a mouseout event to trigger. */
function holdMenu() {
	if (this.FE_Timer_ID == -1) return;
	clearTimeout(this.FE_Timer_ID);
}

/*	Hides a menu (after a delay). This sets a timer to call hideMenu after a delay set by Int_Menu_Hide_Delay. */
function hideMenuDelay(e) {
/*	'this' refers to the top level link due to the way the event system works. Because of this, the menus will disappear
	en mass rather than one by one. */
/*	In case something went wrong and there's already a timer on this object */
	clearTimer(this.FE_Link_ID);
/*	Already hidden. */
	if (navlist[this.FE_Nested_List].className == '') return;
/*	Visible - set to hide. */
	if (navlist[this.FE_Nested_List].className == 'menushow') {
		this.FE_Timer_ID = setTimeout('hideMenu(' + this.FE_Link_ID + ')', Int_Menu_Hide_Delay);
	}
}

function hideAllMenus() {
	var p;
	for (p = 0; p < navlist.length; p++) {
		hideMenu(navlink[navlist[p].FE_Parent_Link].FE_Link_ID);
	}
}

function hideOtherMenus(e) {
	var p;
	var t;
/*	If the event object isn't passed to the function, assign it. */
	if ((!e) && (window.event)) e = window.event;
	if (!e) return;
/*	Find the actual target, don't just use "this". The reason takes more explaining than is sensible in a comment! */
	if (e.target) t = e.target;
	else if (e.srcElement) t = e.srcElement;
	if (!t) return;
/*	Keep jumping up the node tree until a list element is found - this way the event target is found correctly even if
	the user clicks on the link itself, or an image etc. This also has a nice side effect of curing a Safari bug which
	has been documented by PPK at www.quirksmode.org. */
	while ((t.nodeName != 'LI') && (t.parentNode)) t = t.parentNode;
/*	If the current node isn't a list item then we must have looped right to the top of the node tree - something went
	wrong! There's nothing to do except give up. */
	if (t.nodeName != 'LI') return;
/*	t (the target) is the element in question, so go through an hide all other menus that aren't either direct children
	or ancestors of this element (in menu structure terms, not DOM terms!). */
	for (p = 0; p < navlist.length; p++) {
		if (!isAncestor(p, t.FE_Link_ID) && (p != t.FE_Nested_List)) {
			navlist[p].className = '';
		}
	}
}

/*	Shows a menu. */
function showMenu(e) {
	var p;
	var t;
/*	See hideOtherMenus(e) for an explanation of this bit. */
	if ((!e) && (window.event)) e = window.event;
	if (!e) return;
	if (e.target) t = e.target;
	else if (e.srcElement) t = e.srcElement;
	if (!t) return;
	while ((t.nodeName != 'LI') && (t.parentNode)) t = t.parentNode;
	if (t.nodeName != 'LI') return;
/*	Clear any timeouts that exist. If a menu has just been shown then there shouldn't be any timers going on as all
	other menus are hidden instantly. */
	for (p = 0; p < navlink.length; p++) clearTimer(p);
/*	Show the relevant (child) menu, but hide others that may be open unless they are an ancestor of the current one. */
	for (p = 0; p < navlist.length; p++) {
		if (p == t.FE_Nested_List) {
			navlist[p].className = 'menushow';
		} else {
			if (!isAncestor(p, t.FE_Link_ID)) {
				navlist[p].className = '';
			}
		}
	}
}

/******************************************************************************************************/
/*	Setup functions - these are only run when the page is loaded and are all called by initNavEvents. */
/******************************************************************************************************/

/*	This function sets mouse events for hiding / showing menus on the links that have nested menus. */
function setNavEvents() {
	var p;
	for (p = 0; p < navlink.length; p++) {
		if (navlink[p].FE_Nested_List != -1) {
			navlink[p].onmouseover = showMenu;		/*	If you move the mouse over a link, show its nested menu. */
			navlink[p].onmouseout = hideMenuDelay;	/*	If you move the mouse out of a link, hide its nested menu after
														a short delay. */
			navlink[p].onmousemove = holdMenu;		/*	If the mouse then moves in the link again, the mouseout event
														was triggered erroneously (for example, when moving from the
														link to the nested menu). In this case, hold the menu where it
														is and cancel any timers set to hide the menu. */
		} else if (Int_Menu_Force_Hide) {
			navlink[p].onmouseover = hideOtherMenus;/*	Set links to hide other menus when you mouseover them - makes
														the interface cleaner. */
		}
	}
	document.onclick = hideAllMenus;	/*	Use onclick rather than onmousedown so this doesn't hide the link before the
											browser can respond. Use document.onclick rather than window.onclick or IE
											won't respond. */
}

/*	This function goes through each element in the navlink array (populated in getNavLinks) and finds child (not
	descendant) ul elements. It puts all these elements in the navlist array and assigns their respective index numbers
	to the FE_Nested_List property of their parent li. This allows nested lists to be quickly referenced from the links
	that trigger them.
	It also assigns values to the FE_Parent_List property of each navlink. */
function getNavLists() {
	var p;
	var q;
	var r;
	for (p = 0; p < navlink.length; p++) {
		for (q = 0; q < navlink[p].childNodes.length; q++) {
			if (navlink[p].childNodes[q].nodeName == 'UL') {
				navlink[p].FE_Nested_List = r = navlist.length;
				navlist[r] = navlink[p].childNodes[q];
				navlist[r].FE_List_ID = r;	/*	This may seem pointless, but it's not (see big comment above). */
				navlist[r].FE_Parent_Link = p;
			}
		}
	}
	for (p = 0; p < navlist.length; p++) {
		for (q = 0; q < navlist[p].childNodes.length; q++) {
			if (navlist[p].childNodes[q].nodeName == 'LI') {
				navlist[p].childNodes[q].FE_Parent_List = p;
			}
		}
	}
}

/*	This function finds all li elements that are descendants of navbar. It then puts these elements into an array for
	easy access later on, and assigns a few properties to make things easier when dealing with the DOM itself. */
function getNavLinks(navbar) {
	var a = navbar.getElementsByTagName('LI');
	var p;
	var q;
	for (p = 0; p < a.length; p++) {
		q = navlink.length;
		navlink[q] = a[p];
		navlink[q].FE_Link_ID = q;		/*	Index number of the link in the navlink array. This may seem pointless but
											this value is stored in the DOM object too, so the relevant navlink can be
											found from an event. */
		navlink[q].FE_Nested_List = -1;	/*	Index number of the nested list. -1 is default and means there are no nested
											lists. These values are populated by getNavLists(). */
		navlink[q].FE_Parent_List = -1;	/*	Index number of the list to which this link belongs. -1 is root. */
		navlink[q].FE_Timer_ID = -1;	/*	ID number of the setTimeout timer which is used to delay the hiding of
											nested menus. Storing the ID allows the timer to be cancelled. */
	}
}

/***********************************/
/*	Main interface setup function. */
/***********************************/

function initNavEvents() {
/*	Find all menu links */
	var temp = document.getElementsByTagName('div');
	var p;
	for (p = 0; p < temp.length; p++) {
		if (temp[p].className == 'navigation') getNavLinks(temp[p]);
	}
/*	Now associate relevant lis with their nested lists */
	getNavLists();
/*	Attach events to the relevant lis */
	setNavEvents();
}

/*	Set a variable so that the main script knows this file has loaded */
var file_interface = true;
