/* 3D7 Software JavaScript 1
 * 2005.01.16
 * Bradley Tetzlaff
 *
 * Algorithms and structure derived from Angus Turnbull's FreeStyle Menus v1.0 script.
 * http://www.twinhelix.com/dhtml/fsmenu/
 *
 */

// Compatability Code

var isDom = document.getElementById ? true : false;
var isDocAll = document.all ? true : false;
var isOpera = self.opera ? true : false;

// General Object Interaction Code

/** Gets an object reference.
 */
function getObject(objID) {

	if (isDocAll) {
		return document.all[objID];
	} else if (isDom) {
		return document.getElementById(objID);
	} else if (document.layers) {
		return document.layers[objID];
	}
}

/** Adds a event to a given object.
 */
function addHandler(actObject, eventName, newFunct) {
	if (actObject["addEventListenter"]) {
		return actObject["addEventListenter"](eventName, newFunct, false);
	}
	actObject["on" + eventName] = function(eventName) {
		
		// Add the function.
		actObject.funct = newFunct;
		return actObject.funct(eventName || self.event) != true;
	}
}

/** Submits a form, used to eliminate the "name" attribute.
 */
function submitForm(formID) {
	getObject(formID).submit();
}

// Hierarchy Menu Functions

/** Constructs a hierarchy menu.
 */
function HierarchyMenu(initMenuName) {
	this.menuName = initMenuName;
	
	// The class that is used for the parent item lighting.
	this.litClass = "lit";
	
	// The root node is already present.
	this.menuNodes = { root: new HierarchyMenuNode("root", this) };
	this.shownMenu = [];
	this.menuTimer = null;
	this.showDelay = 0;
	this.hideDelay = 600;
	this.switchDelay = 150;
}

/** Shows part of the menu.
 */
HierarchyMenu.prototype.showMenu = function(menuNodeList) {
	this.shownMenu.length = arguments.length;
	
	// Add the shown menu elements from the argument list.
	for (var argIndex = 0; argIndex < arguments.length; argIndex++) {
		this.shownMenu[argIndex] = arguments[argIndex];
		clearTimeout(this.menuTimer);
		this.menuTimer = setTimeout(this.menuName + ".menuNodes.root.over();", 10);
	}
}

/** Hides part of a menu.
 */
HierarchyMenu.prototype.hideMenu = function(menuNodeItem) {
	clearTimeout(this.menuTimer);
	if (this.menuNodes[menuNodeItem] != null) {
		this.menuNodes[menuNodeItem].out();
	}
}

/** Constructs a new hierarchy menu node. These are subelements of the menu.
 */
function HierarchyMenuNode(initId, initMenuObj) {
	this.id = initId;
	this.menuObj = initMenuObj;
	this.nodeTimer = null;
	this.isVisible = null;
	this.objectRef = null;
	this.styleRef = null;
	this.argArray = [];
	
	// These form the hierarchy.
	this.childNode = null;
	this.parentNode = null;
	var theNode = this;
	
	/** This function handles the event of a mouseover on a menu node.
	 */
	this.over = function(nodeEvent) {
		with (theNode) with (menuObj) {
			clearTimeout(menuTimer);
			clearTimeout(nodeTimer);
			
			if (shownMenu.length > 0) {
				var menuPart = shownMenu[0];
				
				// Construct a new menu node if it does not exist.
				if (menuNodes[menuPart] == null || menuNodes[menuPart].objectRef == null) {
					menuNodes[menuPart] = new HierarchyMenuNode(menuPart, menuObj);
				}
				var curNode = menuNodes[menuPart];
				
				/*if (initId != "root") {
					
					// Center large menus to fit them on the screen better.
					if (curNode.length) {
						getObject(initId).style["top"] = (curNode.length * -16) + "px";
					}
				}*/
				
				if (curNode == theNode) {

					// Clears the memory.
					shownMenu.length = 0;
					return;
				}
				var shownMenuRef = shownMenu;
				clearTimeout(curNode.nodeTimer);
				if (curNode != childNode && curNode.objectRef != null) {
					curNode.argArray.length = shownMenuRef.length;
					
					// Copy the node over.
					for (var argIndex = 0; argIndex < shownMenuRef.length; argIndex++) {
						curNode.argArray[argIndex] = shownMenuRef[argIndex];
					}
					
					// Set the delay depending on whether then new menu is already shown or not.
					curNode.nodeTimer = setTimeout(menuName + ".menuNodes['" + curNode.id +
						"'].parentNode = " + menuName + ".menuNodes['" + theNode.id + "'];" +
						menuName + ".menuNodes['" + curNode.id + "'].showNode();",
						childNode == null ? switchDelay : showDelay);
				}
				shownMenu.length = 0;
			}
		}
	}
	
	/** Activates the hideNode() function after the given delay.
	 */
	this.out = function(nodeEvent) {
		clearTimeout(theNode.menuObj.nodeTimer);
		theNode.menuObj.nodeTimer = setTimeout(theNode.menuObj.menuName +
			".menuNodes['" + initId + "'].hideNode()", theNode.menuObj.hideDelay);
	}
	
	// Set up the object reference if this is not the root.
	if (initId != "root") {
		this.objectRef = getObject(initId);
		this.styleRef = getObject(initId).style;
		if (this.objectRef != null) {
		
			// Assign the menu node events so that they will execute when the mouse
			// hover on the menu.
			addHandler(this.objectRef, "mouseover", this.over);
			addHandler(this.objectRef, "mouseout", this.out);
		}
	}
}

/** Displays a menu node to the screen.
 */
HierarchyMenuNode.prototype.showNode = function() {
	with (this) with (menuObj) {
	
		// Must have these.
		if (objectRef == null) {
			return;
		}
		// Hide the old node.
		if (parentNode.childNode && (parentNode.childNode != this)) {
			parentNode.childNode.hideNode();
		}
		parentNode.childNode = this;
		
		// Light up the root.
		var rootOffset = argArray[1];
		
		if (rootOffset != null) {
			rootOffset.className = litClass;
		}
		isVisible = true;
		styleRef["display"] = "block";
	}
}

/** Hides a hierarchy menu node from the screen.
 */
HierarchyMenuNode.prototype.hideNode = function() {
	with (this) with (menuObj) {
		
		// Must have these.
		if (objectRef == null) {
			return;
		}
		if (argArray[1] != null) {
			argArray[1].className = null;
		}
		// Change the visiblity on the child nodes and then this node.
		if (childNode != null) {
			childNode.hideNode();
		}
		isVisible = false;
		styleRef["display"] = "none";
		
		// Switch the nodes.
		if (parentNode != null && (parentNode.childNode == this)) {
			parentNode.childNode = null;
			parentNode = null;
		}
	}
}

/** Starts the hierarchy menu system so that it can be used on a page.
 */
HierarchyMenu.prototype.startMenu = function(initId, childArrow) {

	// Get the root menu element.
	var menuRoot = getObject(initId);
	
	// Must support DOM and have a root.
	if (!isDom || menuRoot == null) {
		return;
	}
	// The "ul" tags.
	var menuParts = menuRoot.getElementsByTagName("ul");
	
	var menuPanel;	// A "ul" element.
	var menuItem;		// A "li" element.
	var trigAnchor;	// A "a" element.
	
	// The identifier of the menu item.
	var idCount = 1;
	
	// Find all of the menu elements.
	for (mpIndex = 0; mpIndex < menuParts.length; mpIndex++) {
		menuItem = menuPanel = menuParts[mpIndex];
		
		// Find the menu items.
		while (menuItem != null) {
			if (menuItem.nodeName.toLowerCase() != "li") {
				menuItem = menuItem.parentNode;
			} else {
				break;
			}
		}
		if (menuItem == null) {
			continue;
		}
		// Find the anchors.
		trigAnchor = null;
		for (var aIndex = 0; aIndex < menuItem.childNodes.length; aIndex++) {
			if (menuItem.childNodes[aIndex].nodeName.toLowerCase() == "a") {
				trigAnchor = menuItem.childNodes[aIndex];
			}
		}
		// Ensure that there is an anchor at the item.
		if (trigAnchor == null) {
			continue;
		}
		var menuId = this.menuName + '-' + idCount++;
		
		if (menuPanel.id) {
			menuId = menuPanel.id;
		} else {
			menuPanel.setAttribute("id", menuId);
		}
		// Add the event handlers.
		addHandler(trigAnchor, "mouseover", new Function("mOverEvent", this.menuName +
			".showMenu('" + menuId + "', this);"));
		addHandler(trigAnchor, "mouseout", new Function("mOutEvent", this.menuName +
			".hideMenu('" + menuId + "');"));
		
		// Add the arrow that indicate whether a child menu is present.
		var childArrowSpan = document.createElement ? document.createElement("span") : null;
		if (childArrowSpan != null) {
			childArrowSpan.appendChild(document.createTextNode(childArrow));
			childArrowSpan.className = "childArrow";
			trigAnchor.appendChild(childArrowSpan);
		}
	}
}

