var goldenrod
if (!goldenrod) goldenrod = {}


goldenrod.listMenu = {};

goldenrod.listMenu.NAME = "goldenrod.listMenu";

goldenrod.listMenu.ATTR = "menu";
goldenrod.listMenu.ACTIVE = "active";
goldenrod.listMenu.ACTIVE_YES = "yes";
goldenrod.listMenu.ACTIVE_NO = "no";
goldenrod.listMenu.MENU_ITEM = "menuItem";
goldenrod.listMenu.MENU_LIST = "menuList";
goldenrod.listMenu.CHILD = "Child";
goldenrod.listMenu.PARENT = "Parent";
goldenrod.listMenu.SCROLL = "Scroll";
goldenrod.listMenu.SCROLL_YES = "yes";
goldenrod.listMenu.SCROLL_NO = "no";
goldenrod.listMenu.DEFAULT_HOVER = "menuHover";
goldenrod.listMenu.DEFAULT_MOUSE_OUT = "menuOut";
goldenrod.listMenu.HOVER = "hoverClass";
goldenrod.listMenu.LINK_HOVER = "linkHoverClass";
goldenrod.listMenu.MENU_HOVER = "menuHoverClass";
goldenrod.listMenu.MOUSE_OUT = "outClass";

/*---------------------------------------------------------
This establishes a user defined function called when the mouse 
moves over or off a menu Item.
-----------------------------------------------------------*/
goldenrod.listMenu.HOVER_FUNC = "hoverFunc";
goldenrod.listMenu.OUT_FUNC = "outFunc";

/*---------------------------------------------------------
This establishes a user defined function called when the
a new menu is displayed or removed 
-----------------------------------------------------------*/
goldenrod.listMenu.MENUHOVER_FUNC = "menuHoverFunc";
goldenrod.listMenu.MENUOUT_FUNC = "menuOutFunc";

/*-----------Default Hover and Out function names----------*/
goldenrod.listMenu.DEFAULT_HOVER_FUNC = "hover";
goldenrod.listMenu.DEFAULT_OUT_FUNC = "out";


goldenrod.listMenu.hover = function() {};
goldenrod.listMenu.out = function() {};

goldenrod.listMenu.functions = {
	hover : goldenrod.listMenu.hover,
	out   : goldenrod.listMenu.out
};

//goldenrod.listMenu.ITEM_TAG = "LI"  I realize we can use any element not only list elements
//goldenrod.listMenu.LIST_TAG = "UL"
goldenrod.listMenu.MenuItemType = {
	Menu : 'menu',
	Link : 'link'
}
goldenrod.listMenu.MenuListType = {
	Root : 'root',
	Node : 'node'
}

/*----------------------------------------------------------------------------------------------
	This is the initialization routine for the menu structure.  We will add to this a routine
	to get all roots once at load time - and set up an array so that this possibly time consuming
	task is sped up.
	
	We can call this routine with any element as a parameter and all descendants of that element
	that are menuItems or menu Nodes are initialized
----------------------------------------------------------------------------------------------*/
goldenrod.listMenu.setHandlers = function(rootElt) {
	
	function inner(elt) {
		var children = elt.childNodes;
		
		for(var i=0; i<children.length; i++) {
			var child = children[i];
			if( (child.nodeType == 1) && child.getAttribute(goldenrod.listMenu.ATTR) ) {
				//Do not put mouse handlers on root menu
				if(goldenrod.listMenu.isMENU_ITEM(child) ) {
					child.onmouseover = goldenrod.listMenu.mouseOver;
					child.onmouseout = goldenrod.listMenu.mouseOut;
				}
				else if(goldenrod.listMenu.isMENU_LIST_NODE(child) ) {
					child.onmouseout = goldenrod.listMenu.mouseOut;
				}
				
			}	//End of if
			inner(child);	
		}	//End of for
		
	}
	
	if(rootElt){
		if(typeof rootElt == "string") rootElt = document.getElementById(rootElt);	
	}
	else{
		rootElt = document;
	}
	
	inner(rootElt);
	goldenrod.listMenu.getALL_ROOTS_INIT();
}

goldenrod.listMenu.isMENU_ITEM = function(elt) {
	return elt && (elt.nodeType == 1) && ( goldenrod.Utility.hasAttr(elt, goldenrod.listMenu.MENU_ITEM, goldenrod.listMenu.ATTR)  );
}

goldenrod.listMenu.isMENU_ITEM_LINK = function(elt) {
	return elt && (elt.nodeType == 1) && 
		( goldenrod.Utility.getAttrValue(elt, goldenrod.listMenu.MENU_ITEM, goldenrod.listMenu.ATTR) == goldenrod.listMenu.MenuItemType.Link  );	
}

goldenrod.listMenu.isMENU_ITEM_MENU = function(elt) {
	return elt && (elt.nodeType == 1) && 
		( goldenrod.Utility.getAttrValue(elt, goldenrod.listMenu.MENU_ITEM, goldenrod.listMenu.ATTR) == goldenrod.listMenu.MenuItemType.Menu  );	
}

goldenrod.listMenu.isMENU_LIST = function(elt) {
	return elt && (elt.nodeType == 1) && ( goldenrod.Utility.hasAttr(elt, goldenrod.listMenu.MENU_LIST, goldenrod.listMenu.ATTR)  );
}

goldenrod.listMenu.isMENU_LIST_NODE = function(elt) {
	return elt && (elt.nodeType == 1) && 
		( goldenrod.Utility.getAttrValue(elt, goldenrod.listMenu.MENU_LIST, goldenrod.listMenu.ATTR) == goldenrod.listMenu.MenuListType.Node  );	
}

goldenrod.listMenu.getMENU_SCROLLVALUE = function(elt) {
	var returnValue = false;
	if(goldenrod.listMenu.isMENU_LIST(elt)){
		returnValue = goldenrod.Utility.getAttrValue(elt, goldenrod.listMenu.SCROLL, goldenrod.listMenu.ATTR);
		if(!returnValue) returnValue = goldenrod.listMenu.SCROLL_YES; 
	}
	return returnValue;
}

goldenrod.listMenu.isMENU_LIST_ROOT = function(elt) {
	return elt && (elt.nodeType == 1) && 
		( goldenrod.Utility.getAttrValue(elt, goldenrod.listMenu.MENU_LIST, goldenrod.listMenu.ATTR) == goldenrod.listMenu.MenuListType.Root  );	
}

/*----------------------------------------------------------------------------------------------
	NOTE: getTHE_MENU and getTHE_PARENT are each the inverse of the other!
	
	getTHE_MENU:  menuItem - to - menuList
	getTHE_PARENT: menuList - to - menuItem
-----------------------------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------------------------
	elt - must be a menuItem that is a menu - otherwise it returns false.
	Such an element refers to a unique menuList. This list is either one of it's childern or
	pointed to by the construct child=......;; within the menu attribute.
-----------------------------------------------------------------------------------------------*/
goldenrod.listMenu.getTHE_MENU = function(elt) {
	var child, children;
	if( goldenrod.listMenu.isMENU_ITEM_MENU(elt) ) {
		
		if( (child= goldenrod.Utility.getAttrValue(elt, goldenrod.listMenu.CHILD, goldenrod.listMenu.ATTR)) ) {
			return document.getElementById(child);
		}
		else {  
			children = elt.childNodes;
			for(var i=0; i<children.length; i++) {
				child = children[i];
		
				if( goldenrod.listMenu.isMENU_LIST_NODE(child) ){
					//alert("The menu is = " + child.id);
					return child;
				}	
			}
		}
	}
	return false;
}

/*----------------------------------------------------------------------------------------------
	elt - must be a menuList element.
	A menuList is either a root (in which case there is nothing above it) or a node - in which 
	case a menuItem (which must have menu="...........menuItem=menu;;...............) points to
	this element.
-----------------------------------------------------------------------------------------------*/
goldenrod.listMenu.getTHE_PARENT = function(elt){
	var parent;
	if( this.isMENU_LIST_NODE(elt) ){
		if( (parent = goldenrod.Utility.getAttrValue(elt, goldenrod.listMenu.PARENT, goldenrod.listMenu.ATTR)) )
			parent = document.getElementById(parent);
		else 
			parent = elt.parentNode;
		return parent;
	}
	alert("getTHE_PARENT was called on an elt that is not a menuList - node");
}

/*----------------------------------------------------------------------------------------------
	This is called only for a menuItem. A menuItem belongs to a menu. The menuItem is a descendant
	of a menuList. So we proceed up the document tree until we come to a menuList element.
-----------------------------------------------------------------------------------------------*/
goldenrod.listMenu.getTHE_PARENT_MENU = function(elt){
	for(var parentMenu = elt.parentNode; !(this.isMENU_LIST(parentMenu)); parentMenu = parentMenu.parentNode);
	return parentMenu;
}

/*----------------------------------------------------------------------------------------------
	This is called only for either a menuItem or a menuList!
-----------------------------------------------------------------------------------------------*/
goldenrod.listMenu.getTHE_ROOT = function(menuElt) {
	if(menuElt){
		if( goldenrod.listMenu.isMENU_ITEM(menuElt) ){
			menuElt = this.getTHE_PARENT_MENU(menuElt);
		}
		
		if( goldenrod.listMenu.isMENU_LIST_NODE(menuElt) ){
			for(menuElt = this.getTHE_PARENT_MENU( this.getTHE_PARENT(menuElt) ); 
				!(this.isMENU_LIST_ROOT(menuElt)); 
				menuElt = this.getTHE_PARENT_MENU( this.getTHE_PARENT(menuElt) ));
			return menuElt;
		}
		else if( goldenrod.listMenu.isMENU_LIST_ROOT(menuElt) ){
			return menuElt;
		}
	}
	return false;
}

goldenrod.listMenu.getALL_ROOTS = function() {
	return goldenrod.listMenu.ALL_ROOTS;
}

/*--------------------------------------------------------------------------------------------
	This routine creates an array of all elements that have an attribute of "menu" with a
	parameter/value pair or menuList=root. This will optomize processing of menu operation.
--------------------------------------------------------------------------------------------*/
goldenrod.listMenu.getALL_ROOTS_INIT = function() {
	var theBody = document.getElementsByTagName('body')[0];
	goldenrod.listMenu.ALL_ROOTS = goldenrod.Utility.getElementsByName(theBody, 
									goldenrod.listMenu.MENU_LIST, 
									goldenrod.listMenu.MenuListType.Root, 
									goldenrod.listMenu.ATTR);
	return;
}

goldenrod.listMenu.ALL_ROOTS;

/*--------------------------------------------------------------------------------------------
	This routine is called for a menuList. 
--------------------------------------------------------------------------------------------*/
goldenrod.listMenu.menu_Active = function(elt) {
	//alert("menu_Active: " + elt.id )
	this._getMouseData(elt, true);
	elt.style.display = 'block';


	var scrollValue = goldenrod.listMenu.getMENU_SCROLLVALUE(elt);
	if(scrollValue && (scrollValue == goldenrod.listMenu.SCROLL_YES)) goldenrod.Dom.scrollIntoView(elt);
	this.functions[this.mouseData[this.HOVER_FUNC]](elt);
	var parentMenu = this.getTHE_PARENT_MENU(this.getTHE_PARENT(elt));
	goldenrod.Utility.setAttrValue(parentMenu, goldenrod.listMenu.ACTIVE, goldenrod.listMenu.ACTIVE_YES, goldenrod.listMenu.ATTR);
}

goldenrod.listMenu.rootmenu_Inactive = function(/*Optional*/ elt) { 
//Call menu_ItemInactive for all other root menu's
	var theRoot = this.getTHE_ROOT(elt);
	var roots = this.getALL_ROOTS();
	if(roots && roots.length) {
		for(var i=0; i<roots.length; i++){
			var aMenu = roots[i];
			if(!theRoot || (aMenu != theRoot) ){
				if( aMenu.style.display != 'none' )
					this.menu_Inactive(aMenu);
			}
		}
	}
}

goldenrod.listMenu.menu_Inactive = function(elt) {
	
	if( this.isMENU_LIST_NODE(elt) ){
		this._getMouseData(elt, true);
		this.functions[this.mouseData[this.OUT_FUNC]](elt);
		elt.style.display = 'none';		//Set display to none
	}
		
	
	var children = elt.childNodes, theMenu;
	if(children && !children.length) return;
	for(var i=0; i<children.length; i++) {
		var child = children[i];
		if( goldenrod.listMenu.isMENU_ITEM(child) ) {
			goldenrod.listMenu.menu_ItemInactive(child);
			if( theMenu = goldenrod.listMenu.getTHE_MENU(child)) {
				/* I suppose we do not need to set the active attribute to no!
				goldenrod.Utility.setAttrValue
				(child, goldenrod.listMenu.ACTIVE, goldenrod.listMenu.ACTIVE_NO, goldenrod.listMenu.ATTR);*/
			}
		}
		else {
			goldenrod.listMenu.menu_Inactive(child);	//Recursion to descend to next level of child node
		}	
	}	
	
	
	//If parent is a menu item remove class
	if(this.isMENU_LIST_NODE(elt)){
		var parent = goldenrod.listMenu.getTHE_PARENT(elt);
		if( this.isMENU_ITEM(parent) ) {
			goldenrod.listMenu._getMouseData(parent);
			goldenrod.Dom.CSSClass.removeClass(parent, this.mouseData[this.HOVER]);
			goldenrod.Dom.CSSClass.removeClass(parent, this.mouseData[this.LINK_HOVER]);
			goldenrod.Dom.CSSClass.removeClass(parent, this.mouseData[this.MENU_HOVER]);
			goldenrod.Dom.CSSClass.addClass(parent, this.mouseData[this.MOUSE_OUT]);
			goldenrod.listMenu.functions[this.mouseData[this.OUT_FUNC]](parent);//Call the out function too!!
			parent = this.getTHE_PARENT_MENU(parent);
			//Set active to No
			goldenrod.Utility.setAttrValue(	parent, 
											goldenrod.listMenu.ACTIVE, 
											goldenrod.listMenu.ACTIVE_NO, 
											goldenrod.listMenu.ATTR);
		}	
	}
}

/*----------We Create on mouseData object which we will use to store the class information---*/
goldenrod.listMenu.mouseData = {}

goldenrod.listMenu._getMouseData = function(elt, menu_flag) {
	var parent;
	if(menu_flag) parent = elt;
	else parent = this.getTHE_PARENT_MENU(elt);
	
	if( !(this.mouseData[this.HOVER] = goldenrod.Utility.getAttrValue(parent, this.HOVER, this.ATTR)) ) {
		this.mouseData[this.HOVER] = this.DEFAULT_HOVER;
	}
	
	if( !(this.mouseData[this.LINK_HOVER] = goldenrod.Utility.getAttrValue(parent, this.LINK_HOVER, this.ATTR)) ) {
		this.mouseData[this.LINK_HOVER] = this.mouseData[this.HOVER];
	}
	
	if( !(this.mouseData[this.MENU_HOVER] = goldenrod.Utility.getAttrValue(parent, this.MENU_HOVER, this.ATTR)) ) {
		this.mouseData[this.MENU_HOVER] = this.mouseData[this.HOVER];
	}
	if( !(this.mouseData[this.MOUSE_OUT] = goldenrod.Utility.getAttrValue(parent, this.MOUSE_OUT, this.ATTR)) ) {
		this.mouseData[this.MOUSE_OUT] = this.DEFAULT_MOUSE_OUT;
	}
	
	if( !(this.mouseData[this.HOVER_FUNC] = goldenrod.Utility.getAttrValue(parent, this.HOVER_FUNC, this.ATTR)) ) {
		this.mouseData[this.HOVER_FUNC] = this.DEFAULT_HOVER_FUNC;
	}
	
	if( !(this.mouseData[this.OUT_FUNC] = goldenrod.Utility.getAttrValue(parent, this.OUT_FUNC, this.ATTR)) ) {
		this.mouseData[this.OUT_FUNC] = this.DEFAULT_OUT_FUNC;
	}
}

goldenrod.listMenu.menu_ItemActive = function(elt) {
	
	goldenrod.listMenu._getMouseData(elt);
	
	goldenrod.Dom.CSSClass.removeClass(elt, this.mouseData[this.MOUSE_OUT]);
	if(this.isMENU_ITEM_MENU(elt)){
		goldenrod.Dom.CSSClass.addClass(elt, this.mouseData[this.MENU_HOVER]);
	}
	else if(this.isMENU_ITEM_LINK(elt)){
		goldenrod.Dom.CSSClass.addClass(elt, this.mouseData[this.LINK_HOVER]);
	}
	
	goldenrod.listMenu.functions[this.mouseData[this.HOVER_FUNC]](elt);
	//If MenuItem is a link - just change appearance
	
	
	//If MenuItem is a menu - also change appearance and...
	//we expect one and only one of its children to be a menuList
	if( goldenrod.listMenu.isMENU_ITEM_MENU(elt) ) {
		var theMenu = goldenrod.listMenu.getTHE_MENU(elt);
		goldenrod.listMenu.menu_Active(theMenu);	
	}
}

goldenrod.listMenu.menu_ItemInactive = function(elt) {
	goldenrod.listMenu._getMouseData(elt);
	
	goldenrod.Dom.CSSClass.removeClass(elt, this.mouseData[this.HOVER]);
	goldenrod.Dom.CSSClass.removeClass(elt, this.mouseData[this.LINK_HOVER]);
	goldenrod.Dom.CSSClass.removeClass(elt, this.mouseData[this.MENU_HOVER]);
	goldenrod.Dom.CSSClass.addClass(elt, this.mouseData[this.MOUSE_OUT]);
	this.functions[this.mouseData[this.OUT_FUNC]](elt);
	
	if(this.isMENU_ITEM_MENU(elt) ) {
		var theMenu = goldenrod.listMenu.getTHE_MENU(elt);
		this.menu_Inactive(theMenu);
	}
}

/*-------------------------------------------------
	This is called for any element node - if
	that element has a descendant that is a menuItem that 
	item is return. Otherwise we return false`
---------------------------------------------------*/
goldenrod.listMenu.containsMENU_ITEM = function(e){
	var result = false;
	if(e.nodeType == 1){
		var children = e.childNodes;
		for(var i=0; i<children.length; i++){
			var child = children[i];
			if(this.isMENU_ITEM(child)){
				result = child;
				break;
			}
			else{
				if(result = this.containsMENU_ITEM(child))
					break;
			}
		}
	}
	return result;
}
goldenrod.listMenu.mouseGate = true;

goldenrod.listMenu.mouseGateSwitch = function(aBoolean){
	this.mouseGate = aBoolean;
}

goldenrod.listMenu.mouseOver = function(e) {
	e = e || window.event;
	//goldenrod.listMenu.mousereport(e, 'Over', elt);
	
	goldenrod.Dom.propagationHandler(e)	//From mouse over do not bubble and no default
	
	if(goldenrod.listMenu.mouseGate){
		var elt = this;		//This is always a menu item
		//Call menu_ItemInactive for all other root menu's
		goldenrod.listMenu.rootmenu_Inactive(elt);
		
		//If over a menuItem call menu_ItemInactive for all other menuItems
		//var siblings = elt.parentNode.childNodes;
		var siblings = goldenrod.listMenu.getTHE_PARENT_MENU(elt).childNodes;
		for(var i=0; i<siblings.length; i++) {
			var sibling = siblings[i], inner_sibling;
			if(sibling != elt){
				if(goldenrod.listMenu.isMENU_ITEM(sibling)){
					goldenrod.listMenu.menu_ItemInactive(sibling);
				}
				else if( inner_sibling = goldenrod.listMenu.containsMENU_ITEM(sibling) ){
					goldenrod.listMenu.menu_ItemInactive(inner_sibling);
				}
			}
		}
			
		//Then call menu_Active for the taget menuItem.
		goldenrod.listMenu.menu_ItemActive(elt);
	}
	return false;
}
goldenrod.listMenu.mousereport = function(){}

goldenrod.listMenu.mouseOut = function(e) {
	e = e || window.event;		
	
	goldenrod.Dom.propagationHandler(e)	//I decided not to bubble on mouse out.
	
	if(goldenrod.listMenu.mouseGate){
		var elt = this;
		var entered = (e.fromElement ? e.fromElement : e.relatedTarget);
		
		//Only if the mouse pointer is physically not in the box of the element that generated this event
		//	do we actually do something.
		if( !goldenrod.Dom.isIn([e.clientX,e.clientY], this) ) {
		
			//goldenrod.listMenu.mousereport(e, 'Out', elt);
			//if(entered == elt) {alert("entered = elt"); return false;} 
			//If for some crazy reason this is the case - as in Opera	
			
			//Case I: Leaving a menuItem	
			if( goldenrod.listMenu.isMENU_ITEM_LINK(elt) ) {	//Leaving a menuItem link.
				goldenrod.listMenu.menu_ItemInactive(elt);
				//If pointer is also not in the parent menu element
				var parent = goldenrod.listMenu.getTHE_PARENT_MENU(elt);
	//			var parent = elt.parentNode;
				
				//if we are also not in the parent menu_list call menu_Inactive.
				if(!goldenrod.Dom.isIn([e.clientX,e.clientY], parent) && 
						goldenrod.listMenu.isMENU_LIST_NODE(parent) ) {
						goldenrod.listMenu.menu_Inactive(parent);
				}
				
				//If menuItem in a menu - leave it be
				else if( goldenrod.listMenu.isMENU_ITEM_MENU(elt) ) {
				}
			}
			
			//Case II: Leaving a menuList and physically not in the list - that is not over a covering element.
			//	Quirk - we try to make it easier for the mouse it be percieved as being out. This work for
			//	The problem with FirFox and seems to be fine in general.
			else if(
						goldenrod.listMenu.isMENU_LIST(elt) &&
						goldenrod.listMenu.notIn([e.clientX,e.clientY], elt) && 
						( goldenrod.Utility.getAttrValue(elt, goldenrod.listMenu.ACTIVE, goldenrod.listMenu.ATTR) == 
						goldenrod.listMenu.ACTIVE_NO )
					) {
				goldenrod.listMenu.menu_Inactive(elt);
			}
		}
	}
	return false;
}

goldenrod.listMenu.notIn = function(point, elt, leeway) {
	var returnValue = undefined;
	if(!leeway) leeway = 1;
	var box, deltaBox = new goldenrod.Dom.Rectangle(leeway, leeway, -2*leeway, -2*leeway);
	if( box = goldenrod.Dom.eltBox(elt)) {
		box.add(deltaBox);
		returnValue = !box.isIn(point)
	}
	return returnValue;

}
