// These are the four variables that you will need to define beforehand.
var toggleOpenIcon = "url('images/LgPlus.gif')"; // The icon that is wanted to the left of the <li> that has a subtree, but the subtree is currently closed
var toggleIconWidth = 16; // The width of the icon (because I need to determine whether the click was in the "icon" region, or in the "link" region)
var toggleCloseIcon = "url('images/LgMinus.gif')"; // The icon that is wanted to the left of the <li> that has a subtree, but the subtree is currently opened
var toggleNoIcon = ""; // The icon that is wanted (if any) to the left of the <li> that has no subtree at all.
var showSelectedSubchild = true; // If you want to open up the submenu for the selected node, set this to true.
// End of variables needed to define.

// A standard IModules function ... remove from code when you want to implement this.
function $(elem)
{
	return document.getElementById(elem);
}
// End of standard IModules function

// The constructor. All you have to do is something like:
//
// Menu = new AccordianMenu('myRootListItem');
//
// and that will do everything for you automatically. Just make sure that your DOM includes only ULs and LIs (and not OLs or DL/DT/DDs)
function AccordionMenu(rootListItem)
{
	this.rootItem	= $(rootListItem);
	this.map		= new Array();
	this.nodeIdCounter = 0;
	this.init(); // Get the stuff rolling...
	this.controller = this;
	this.selectedNode = false;
}

AccordionMenu.prototype =
{
	init : function()
	{
		// Parse the DOM and set up the control stuff.
		this.recurseMenu(this.rootItem);
		
		if (this.selectedNode)
		{
			if (showSelectedSubchild)
			{			
				if (this.selectedNode.subMenu)
				{
					this.selectedNode.subMenu.style.display = "block";
				}
			}
			this.openToSelected(this.selectedNode.parentNode);
		}
	},
	recurseMenu : function(parentNode)
	{				
		// if this is a UL item, it doesn't have any important features, so we just want to continue on really (other than a few minor things)
		if (this.isULElement(parentNode))
		{
			parentNode.controller = this;
			// Give it an id so that we can identify it (if need be)
			parentNode.nodeId = "node_"+this.nodeIdCounter++;
			
			for (var i = 0; i < parentNode.childNodes.length; i++)
			{
				var childNode = parentNode.childNodes[i];
				// If the child element is an LI, then we want to process it. Anything else we dump.
				if (this.isLIElement(childNode))
				{
					childNode.parentController = parentNode;
					this.recurseMenu(childNode);					
				}
			}
		}
		else if (this.isLIElement(parentNode))
		{
			// If this is an LI item, it has important features, so we need to do some stuff to it.
			if (this.isSelected(parentNode))
			{
				this.selectedNode = parentNode;
			}
			// Give it a controller, which references this whole object. The purpose is for eas(ier) access.
			parentNode.controller = this;
			// Default is that it does not have a submenu
			parentNode.subMenu = false;
			// Give it an id sot hat we can identify it (if need be)
			parentNode.nodeId = "node_"+this.nodeIdCounter++;
			
			// Loop through all of the child nodes.
			for (var i = 0; i < parentNode.childNodes.length; i++)
			{
				var childNode = parentNode.childNodes[i];
				// If it is a UL node, then we know that it has a submenu.
				if (this.isULElement(childNode))
				{
					// Set the submenu so that we can quickly access it later, if it is clicked or whatever.
					parentNode.subMenu = childNode;
					childNode.parentController = parentNode;
				}
				this.recurseMenu(childNode);
			}
			
			// If it has a submenu, then we will do some stuff to it.
			if (parentNode.subMenu)
			{
				// If it has a previous onclick function, then we need to keep track of it.
				// Note: I don't think that we can just do an AddEvent, because we need to determine the position of the click
				// before we allow for the previous onclick function(s) to be called.
				if (parentNode.onclick != null)
				{
					// Set the previous onclick to olOnClick for easy access later.
					parentNode.oldOnClick = parentNode.onclick;
				}
				else
				{
					// if there was no previous onclick, set it to false for an easy IF statement later on.
					parentNode.oldOnClick = false;
				}
				
				// Set the object's new onclick function.
				parentNode.onclick = 
				function(e) 
				{ 									
					// Even though this is in an onclick function, we still need to make sure that the element that was clicked
					// is in fact the LI element and not an element located in the li ul li of the DOM. I say that because
					// if you do click an li ul li element, then it will activate this. So, if the target is equal to the top li, then
					// we know that we are truly good to go.
					if (this.controller.getTarget(e) == this)
					{
						// Basically we just want to make sure that the click was in the correct location for us to either
						// follow the "link" or to expand/contract a submenu.
						if (this.controller.isToFollowLink(e, this))
						{		
							// We are to follow the link, if it exists.
							if (this.oldOnClick)
							{
								// Follow the link
								this.oldOnClick();
							}
						}
						else
						{
							// Just toggle the submenu.
							this.controller.toggleMenu(this);
						}
					}
				};
				// Set the icon of this item to be the open icon
				parentNode.style.backgroundImage = toggleOpenIcon;
				parentNode.style.backgroundRepeat = "no-repeat";
			} // if (parentNode.subMenu)
			else
			{
				// Since there is no subtree, we need to just give it the "blank" icon 
				parentNode.style.backgroundImage = toggleNoIcon;
				parentNode.style.backgroundRepeat = "no-repeat";
			}			
		}
	},
	openToSelected : function(elem)
	{	
		if (this.isLIElement(elem))
		{
			elem.style.backgroundImage = toggleCloseIcon
			elem.style.backgroundRepeat = "no-repeat";
		}
		elem.style.display = "block";
		if (elem.parentController != null)
		{
			this.openToSelected(elem.parentController);
		}
	},
	toggleMenu : function(elem)
	{	
		// A basic toggle function. Nothing special here other than the icons that will be set.
		if (elem.subMenu)
		{
			if (elem.subMenu.style.display == "none")
			{				
				elem.style.backgroundImage = toggleCloseIcon;
				elem.subMenu.style.display = "block";
			}
			else
			{
				elem.style.backgroundImage = toggleOpenIcon;
				elem.subMenu.style.display = "none";
			}
		}
	},
	openMenu : function(elem)
	{
		elem.style.backgroundImage = toggleCloseIcon;
		elem.style.backgroundRepeat = "no-repeat";
		elem.subMenu.style.display = "block";
		elem.style.display = "block";
	},
	closeMenu : function(elem)
	{
		elem.style.backgroundImage = toggleOpenIcon;
		elem.style.backgroundRepeat = "no-repeat";
		elem.subMenu.style.display = "none";
	},
	isLIElement : function(elem)
	{
		return ((elem.nodeName == "LI") ? true : false);
	},
	isULElement : function(elem)
	{
		return ((elem.nodeName == "UL") ? true : false);
	},
	isSelected : function(elem)
	{
		return ((elem.className == "navselected") ? true : false);
	},
	getTarget : function(e) 
	{
		// From http://www.quirksmode.org/js/events_properties.html
		var targ;
		if (!e) var e = window.event;
		if (e.target) targ = e.target;
		else if (e.srcElement) targ = e.srcElement;
		if (targ.nodeType == 3) // defeat Safari bug
			targ = targ.parentNode;
		return targ;
	},
	getMousePosition : function(e) 
	{
		// From http://www.quirksmode.org/js/events_properties.html
		var posx = 0;
		var posy = 0;
		if (!e) var e = window.event;
		if (e.pageX || e.pageY) 	{
			posx = e.pageX;
			posy = e.pageY;
		}
		else if (e.clientX || e.clientY) 	{
			posx = e.clientX + document.body.scrollLeft
				+ document.documentElement.scrollLeft;
			posy = e.clientY + document.body.scrollTop
				+ document.documentElement.scrollTop;
		}
		// posx and posy contain the mouse position relative to the document
		// Do something with this information
		
		return {'x' : posx, 'y' : posy};
	},
	findPos : function(obj) 
	{
		// From http://www.quirksmode.org/js/findpos.html
		var curleft = curtop = 0;
		if (obj.offsetParent) {
			curleft = obj.offsetLeft
			curtop = obj.offsetTop
			while (obj = obj.offsetParent) {
				curleft += obj.offsetLeft
				curtop += obj.offsetTop
			}
		}
		return {'x' : curleft, 'y' : curtop};
	},
	isToFollowLink : function(e, elem)
	{
		// Get the mouse position on the page
		var mousePos = this.getMousePosition(e);
		// Get the element postiion on the page.
		var elemPos = this.findPos(elem);
		
		// Subtract the mouse position from the element position.
		var mouseOffsetLeftOnElem = mousePos['x'] - elemPos['x'];
				
		// If this is NOT an Open or Close icon, and we are further to the right than the icon width, then we can go ahead and follow the link.
		// On the othe rhand, if it IS the "None" icon (or no icon at all) and it is further right than the width of the supposed icon, then we follow the link.
		if (mouseOffsetLeftOnElem > toggleIconWidth && elem.style.backgroundImage != toggleOpenIcon && elem.style.backgroundImage != toggleCloseIcon)
		{
			return true;
		}
		
		// Otherwise, exand the menu.
		return false;
	}
}

// The line that starts it all!
Menu = new AccordionMenu("rootMenu");
