var disappeardelay=250  // menu disappear speed onMouseout (in miliseconds)
var enableanchorlink=0  // Enable or disable the anchor link when clicked on? (1=e, 0=d)
var hidemenu_onclick=1  // hide menu when user clicks within menu? (1=yes, 0=no) (NOTE: Not yet implemented)
var vert_submenu_offset_x=8
var vert_submenu_offset_y=3
var horiz_submenu_offset_x=0
var horiz_submenu_offset_y=0

//Class
//AnyLinkSub.prototype.highlight_trails   = highlight_trails;
//AnyLinkSub.prototype.unhighlight_trails = unhighlight_trails;
AnyLinkSub.prototype.findopenmenu       = findopenmenu;
AnyLinkSub.prototype.get_menunode       = get_menunode;
AnyLinkSub.prototype.hidesubmenus       = hidesubmenus;
AnyLinkSub.prototype.dropdownmenu       = dropdownmenu;
AnyLinkSub.prototype.handle_onmouseover_nonsubmenu = handle_onmouseover_nonsubmenu;
AnyLinkSub.prototype.handle_onmouseout  = handle_onmouseout;
AnyLinkSub.prototype.clearhidemenu      = clearhidemenu;
AnyLinkSub.prototype.hideall            = hideall;
AnyLinkSub.prototype.showMenus          = showMenus;

//Constructor
function AnyLinkSub()
{
	this.highlight_trails_enabled = true;

	this.menuRoot = new Object();
	this.menuRoot.ID = "_root";
	this.menuRoot.menu = null;
	this.menuRoot.menuItem = null;
	this.menuRoot.nextNode = null;
	this.menuRoot.prevNode = null;
	this.menuEnd = this.menuRoot;

	this.delayHide = 0; //Just declaring here
}

/////No further editting needed

var ie5 = document.all;
var ns6 = document.getElementById && !document.all;


function getposOffset(what, offsettype)
{
	var totaloffset = (offsettype=="left") ? what.offsetLeft : what.offsetTop;
	var parentEl = what.offsetParent;
	
	while (parentEl != null)
	{
		totaloffset += (offsettype=="left") ? parentEl.offsetLeft :  parentEl.offsetTop;
		parentEl = parentEl.offsetParent;
	}
	
	return totaloffset;
}

function iecompattest()
{
	return (document.compatMode && document.compatMode != "BackCompat") ? document.documentElement : document.body;
}

function clearbrowseredge(menu, menuItem, whichedge)
{
	var edgeoffset=0;
	
	if (whichedge=="rightedge")
	{
		var windowedge = (ie5 && !window.opera) ?
							iecompattest().scrollLeft+iecompattest().clientWidth-15 :
							window.pageXOffset+window.innerWidth-15;
							
		menu.contentmeasure = menu.offsetWidth;
		
		if (windowedge-menu.x < menu.contentmeasure)
			edgeoffset = menu.contentmeasure - menuItem.offsetWidth;
	}
	else
	{
		var topedge = (ie5 && !window.opera) ? iecompattest().scrollTop : window.pageYOffset;
		var windowedge = (ie5 && !window.opera) ?
							iecompattest().scrollTop+iecompattest().clientHeight-15 :
							window.pageYOffset+window.innerHeight-18;

		menu.contentmeasure = menu.offsetHeight;
		if (windowedge-menu.y < menu.contentmeasure) //move up?
		{
			edgeoffset = menu.contentmeasure - menuItem.offsetHeight;

			if ((menu.y-topedge) < menu.contentmeasure) //up no good either?
					edgeoffset = menu.y - topedge;
		}
	}
	
	return edgeoffset;
}

function findopenmenu(menu)
{
	var currNode;

	if(this.menuRoot.nextNode != null)
	{
		for(currNode = this.menuRoot.nextNode; typeof currNode != "undefined"; currNode = currNode.nextNode)
		{
			if(currNode.menu == menu)
				return currNode;
		}
	}
	return null;
}

function get_menunode(menu)
{
	var currNode;

	for(currNode = this.menuEnd; currNode.ID != "_root"; currNode = currNode.prevNode)
	{
		if(ie5 ? currNode.menu.contains(menu) : contains_ns6(currNode.menu, menu))
			return currNode;
	}
	
	return null;
}

function nodecontains(node1, node2)
{
	var currNode;
	
	for(currNode = node1; currNode != null; currNode = currNode.nextNode)
	{
		if(currNode == node2)
		{
			return true;
		}
	}
	
	return false;
}

function contains_ns6(a, b)
{
	while (b.parentNode)
	{
		if (b == a)
			return true;
			
		b =  b.parentNode;
	}

	return false;
}

function hidesubmenus(node)
{
	var currNode;

	if(node == null)
		return;
		
	for(currNode = this.menuEnd; currNode != node && currNode.ID != "_root"; currNode = currNode.prevNode)
	{
		currNode.menu.style.visibility = "hidden";
		if(this.highlight_trails_enabled)
			currNode.menuItem.unhighlight_trails(currNode.menuItem);
	}
		
	node.menu.style.visibility = "hidden";
	if(this.highlight_trails_enabled)
		node.menuItem.unhighlight_trails(node.menuItem);
	
	node.prevNode.nextNode = null;
	this.menuEnd = node.prevNode;
}

function dropdownmenu(menuItem, e, orientation, dropmenuID, parentmenuID)
{
	var currNode;

	if (window.event)
		event.cancelBubble = true;
	else if (e.stopPropagation)
		e.stopPropagation();

	var this_ = this; // Workaround for a JS closure oddity
	
	if (ie5||ns6)
	{
			// If hovering over top-level menu
 		if(typeof parentmenuID == "undefined")
		{
			this.hidesubmenus(this.menuRoot.nextNode);
			
			this.menuRoot.nextNode = new Object();
			currNode = this.menuRoot.nextNode;
			currNode.nextNode = null;
			currNode.prevNode = this.menuRoot;
		}
		else // if hovering over sub-menu
		{
			currNode = this.findopenmenu(document.getElementById(parentmenuID));
			
			if(currNode == null)
			{
				//alert("Couldn't find parent menu!"); //debug-only
				return;
			}

			this.hidesubmenus(currNode.nextNode);
			currNode.nextNode = new Object();
			currNode.nextNode.nextNode = null;
			currNode.nextNode.prevNode = currNode;
			
			currNode = currNode.nextNode;

		}
		this.clearhidemenu();

		currNode.ID = dropmenuID;
		currNode.menu = document.getElementById(dropmenuID);
		currNode.menuItem = menuItem;
		this.menuEnd = currNode;

		  // Parse orientation variable
		orientation = orientation.toLowerCase();
		if(orientation == "vertical" || orientation == "vert")
			orientation = "v";
		if(orientation == "horizontal" || orientation == "horiz")
			orientation = "h";

		  // Set up positioning offsets based on orientation
		if(orientation == "v")
		{
			offsetX = menuItem.offsetWidth - vert_submenu_offset_x;
			offsetY = vert_submenu_offset_y;
		}
		else // Use horizontal as default
		{
			offsetX = horiz_submenu_offset_x;
			offsetY = menuItem.offsetHeight - horiz_submenu_offset_y;
		}
		
		  // Place menu
		currNode.menu.x = getposOffset(currNode.menuItem, "left");
		currNode.menu.y = getposOffset(currNode.menuItem, "top");
		currNode.menu.style.left = currNode.menu.x - clearbrowseredge(currNode.menu, currNode.menuItem, "rightedge") + offsetX + "px";
		currNode.menu.style.top = currNode.menu.y - clearbrowseredge(currNode.menu, currNode.menuItem, "bottomedge") + offsetY + "px";

		if(this.highlight_trails_enabled)
		{
			for(currMenuChild = currNode.menu.firstChild; currMenuChild != null; currMenuChild = currMenuChild.nextSibling)
			{
					// Is it a menu option with no submenu attached?
				if(currMenuChild.nodeName == "A" && currMenuChild.onmouseover == null)
				{
					currMenuChild.onmouseover = ie5 ?
										function()      { this_.handle_onmouseover_nonsubmenu(event) } :
										function(event) { this_.handle_onmouseover_nonsubmenu(event) };
				}
			}
		}
		
		  // Show menu
		if(this.highlight_trails_enabled)
		{
			this.highlight_trails(currNode.menuItem);
			currNode.menuItem.unhighlight_trails = this_.unhighlight_trails;
		}
		currNode.menu.style.visibility = "visible";

		currNode.menu.onmouseover = ie5 ?
									function()      { this_.clearhidemenu() } :
									function(event) { this_.clearhidemenu() } ;
		currNode.menu.onmouseout = ie5 ?
									function()      { this_.handle_onmouseout(event) } :
									function(event) { this_.handle_onmouseout(event) } ;

		if(typeof parentmenuID == "undefined")
		{
			currNode.menuItem.onmouseout = currNode.menu.onmouseout;
		}
	}
	
	return clickreturnvalue(currNode);
}

function handle_onmouseover_nonsubmenu(e)
{
	if(!this.highlight_trails_enabled)
		return;
		
	var toElement, toNode;
	toElement = ie5 ? e.toElement : e.relatedTarget;
	
	if(toElement.nodeName == "A")
	{
		toNode = this.get_menunode(toElement).nextNode;
		if(toNode != null)
		{
			toNode.menuItem.unhighlight_trails(toNode.menuItem);
			this.hidesubmenus(toNode);
		}
	}
}

function handle_onmouseout(e)
{
	var fromElement, toElement;
	var fromNode, toNode;
	var shouldHide;
	
	var this_ = this; // Workaround for a JS closure oddity

	fromElement = ie5 ? e.fromElement : e.currentTarget;
	toElement   = ie5 ? e.toElement   : e.relatedTarget;
	
	fromNode = this.get_menunode(fromElement);
	toNode   = this.get_menunode(toElement);
	
	shouldHide = false;
	
	if(fromNode != null)
	{
		if(toElement == null)
			return;
		else if(toNode == null)
			shouldHide = true;
		else if(!nodecontains(fromNode, toNode))
		{
			shouldHide = true;
			
// Causes minor glitch: top-level selection will sometimes lose highlight
//                      until mouse moves to another option, Occurs on
//                      moving up one level
//			if(this.highlight_trails_enabled)
//				toNode.menuItem.unhighlight_trails(toNode.menuItem);
		}
		else
		{
			if(this.highlight_trails_enabled)
			{
				this.highlight_trails(toNode.menuItem);
				toNode.menuItem.unhighlight_trails = this_.unhighlight_trails;
			}

			return;
		}

		if(toNode == null || toElement.nodeName == "HTML" || toElement.nodeName == "BODY")
			delayMenuToHide = this.menuRoot.nextNode;
		else
			delayMenuToHide = fromNode;
	}
	else if(fromElement == this.menuRoot.nextNode.menuItem)
	{
		if(this.highlight_trails_enabled && toNode == null)
			fromElement.unhighlight_trails(fromElement);

		shouldHide = true;
		delayMenuToHide = this.menuRoot.nextNode;
		delayMenuToHide.menuItem.onmouseout = null; 
	}

	var currNode;
	if(shouldHide)
		this.delayHide = setTimeout(function() { this_.hidesubmenus(delayMenuToHide); }, disappeardelay);
}

function clearhidemenu()
{
	if (typeof this.delayHide != "undefined")
		clearTimeout(this.delayHide);
}

function clickreturnvalue()
{
	if ((ie5||ns6) && !enableanchorlink)
		return false;
	else
		return true;
}

// Optional function for debugging
function hideall()
{
	this.hidesubmenus(this.menuRoot.nextNode);
}

// Optional function for debugging
function showMenus()
{
	var currNode;

	myString = "Menus: ";
	
	for(currNode = this.menuRoot.nextNode; currNode != null; currNode = currNode.nextNode)
		myString += currNode.ID + " -> ";

	alert(myString + "\nEnd: " + this.menuEnd.ID);
}
