// ---------------------------------------------------------------
// Class DynamicMenu
// (C) Copyright by Andreas Doelling (www.a-doelling.de)
// This file is part of the JS-Pocket-Lib.
// The JS-Pocket-Lib is licenced under the CC-GNU LGPL 
// (http://creativecommons.org/licenses/LGPL/2.1/).
//
// Version: 1.0
// Date: 2005-12-16
// Author: Andreas Doelling (doelling@a-doelling.de)
//
// Creates dynamic menu from nested UL list.
// ---------------------------------------------------------------

function DynamicMenu(elementId) {
	// -----------------------------------------------------
	// Properties
	// -----------------------------------------------------
	var self = this;
	self.rootObj = document.getElementById(elementId);
	self.visibleNodes = new Array();
	self.showListTimeout = null;
	self.hideAllTimeout = null;
	
	
	// -----------------------------------------------------
	// Method applyParentCssClass
	// Gives all LI items which contain a UL node the given 
	// CSS class.
	// -----------------------------------------------------
	self.applyParentCssClass = function(className) {
		var liColl = self.rootObj.getElementsByTagName('LI');
		for(var i=0; i<liColl.length; i++) {
			var sublistNodesColl = liColl[i].getElementsByTagName('UL');
			if(sublistNodesColl.length > 0) {
				liColl[i].className = className;
			}
		}
	}
	
	
	// -----------------------------------------------------
	// Method mouseover
	// Handles mouseover events propagated by a Controller object.
	// -----------------------------------------------------
	self.mouseover = function(evt) {
		var srcElement = (evt.srcElement)? evt.srcElement : evt.target;
		if(self.isResponsible(srcElement)) {
			if(self.showListTimeout != null) { window.clearTimeout(self.showListTimeout); self.showListTimeout = null; }
			if(self.hideAllTimeout != null) { window.clearTimeout(self.hideAllTimeout); self.hideAllTimeout = null; }
			var activeListItem = self.getActiveObj(srcElement);
			var methodReference = self.showChild(activeListItem);
			if(activeListItem.parentNode == self.rootObj) {
				self.showListTimeout = window.setTimeout(methodReference, 500);
			} else {
				self.showListTimeout = window.setTimeout(methodReference, 300);
			}
			return false;
		} else {
			if(self.showListTimeout != null) { window.clearTimeout(self.showListTimeout); self.showListTimeout = null; }
			if(self.visibleNodes.length > 0 && self.hideAllTimeout == null) {
				var methodReference = self.hideAll();
				self.hideAllTimeout = window.setTimeout(methodReference, 800);
			}
			return true;
		}
	}
	
	
	// -----------------------------------------------------
	// Method click
	// Handles click events propagated by a Controller object.
	// -----------------------------------------------------
	self.click = function(evt) {
		var srcElement = (evt.srcElement)? evt.srcElement : evt.target;
		if(self.isResponsible(srcElement)) {
			srcElement.blur();
			return true;
		} else {
			if(self.showListTimeout != null) { window.clearTimeout(self.showListTimeout); self.showListTimeout = null; }
			if(self.hideAllTimeout != null) { window.clearTimeout(self.hideAllTimeout); self.hideAllTimeout = null; }
			if(self.visibleNodes.length > 0) {
				var methodReference = self.hideAll();
				self.hideAllTimeout = window.setTimeout(methodReference, 100);
			}
			return true;
		}
	}
	
	
	// -----------------------------------------------------
	// Method isResponsible
	// Checks if the current DynamicMenu instance is responsible for
	// handling the propagated event, i.e. if the source elements
	// is a child node of rootObj.
	// -----------------------------------------------------
	self.isResponsible = function(srcElement) {
		if(self.rootObj == null) return false;
		if (!self.rootObj.contains) {
			return !!(self.rootObj.compareDocumentPosition(srcElement) & 16);
		} else {
			return self.rootObj.contains(srcElement);
		}
	}
	
	
	// -----------------------------------------------------
	// Method getActiveObj
	// Returns the current list element (e.g. if the
	// event was fired by a STRONG node within the 
	// LI node).
	// -----------------------------------------------------
	self.getActiveObj = function(srcElement) {
		var parent = srcElement.parentNode;
		while(parent.tagName != 'LI') {
			parent = parent.parentNode;
		}
		return parent;
	}
	
	
	// -----------------------------------------------------
	// Method showChild
	// Displays the answer node of the active question node
	// and hides the previously active answer node.
	// This method returns an anonymous inner function which 
	// is used by a timeout initialized in method click().
	// -----------------------------------------------------
	self.showChild = function(activeListItem) {
		return function() {
			try {
				var childListCollection = activeListItem.getElementsByTagName('ul');
				if(self.visibleNodes.length > 0) { self.hideChildren(activeListItem); }
				if(childListCollection.length > 0) {
					var childObj = childListCollection[0];
					var posX = activeListItem.offsetWidth;
					var posY = activeListItem.offsetTop;
					if(document.all && activeListItem.parentNode == self.rootObj) posY += 50;	// extremely dirty hack for IE which positions the second level submenu to high for some unknown reason
					//childObj.style.left = (posX - 8) + 'px';
					//childObj.style.top = (posY + 24) + 'px';
					childObj.style.display = 'block';
				}
				self.visibleNodes[self.visibleNodes.length] = activeListItem;
			} catch(err) { alert(err); }
		}
	}
	
	
	// -----------------------------------------------------
	// Method hideAll
	// Hides all visible sub menus.
	// This method returns an anonymous inner function which 
	// is used by a timeout initialized in method click().
	// -----------------------------------------------------
	self.hideAll = function() {
		return function() {
			try {
				for(var i=self.visibleNodes.length-1; i>=0; i--) {
					var childListCollection = self.visibleNodes[i].getElementsByTagName('ul');
					if(childListCollection.length > 0) {
						childListCollection[0].style.display = 'none';
					}
					self.visibleNodes.pop();
				}
				if(self.showListTimeout != null) window.clearTimeout(self.showListTimeout);
			} catch(err) { alert(err); }
		}
	}
	
	
	// -----------------------------------------------------
	// Method hideChildren
	// Hides all sub menus but the current one and its parent
	// nodes.
	// -----------------------------------------------------
	self.hideChildren = function(activeObj) {
		try {
			for(var i=self.visibleNodes.length-1; i>=0; i--) {
				if(self.visibleNodes[i] != activeObj.parentNode.parentNode) {	// activeObj is a LI element, its parent an UL element, its grandparent is the LI element, we need to check
					var childListCollection = self.visibleNodes[i].getElementsByTagName('ul');
					if(childListCollection.length > 0) {
						childListCollection[0].style.display = 'none';
					}
					self.visibleNodes.pop();
				} else {
					break;
				}
			}
		} catch(err) { alert(err); }
	}

}

