/* 
Dropout menu navigation script
Copyright Hi-Fi Design Pty Ltd 2002
laurence@hifidesign.com.au
*/

// constants, globals
var arrMenuItems = new Array();
var cssProperties = new CssProperties();
var t; // timeout thread
var menuLoaded = false;
var linkTopLevel = false; // determines whether the top level items are links

// configurable parameters - overwrite if necessary
var linkTarget = '_self';
var delay = 200; // milliseconds

/* Object constructors */

// menu item object
function Item(id, parentId, name, path, imgNormal, imgOver) {
	this.id = id;
	this.parentId = parentId;
	this.name = name;
	this.path = path;
	this.objElement = null;
	this.objStyle = null;
	// optional image information
	if (imgNormal != null) {
		this.imgNormal = new Image();
		this.imgNormal.src = imgNormal;
	}
	if (imgOver != null) {
		this.imgOver = new Image();
		this.imgOver.src = imgOver;
	}
}

// css properties object
function CssProperties() {
	this.topLevel = new Array();
	this.otherLevel = new Array();
}

/* Initialisation functions */

// add a menu Item
function addMenuItem(id, parentId, name, path, imgNormal, imgOver) {
	arrMenuItems[arrMenuItems.length] = new Item(id, parentId, name, path, imgNormal, imgOver);
}

// draw the menu
function drawMenu(top, left, right, orientation) {
	if (!menuLoaded) {
		// filter arguments
		if (isNaN(parseInt(top))) top = 0;
		if (isNaN(parseInt(left))) left = null;
		if (isNaN(parseInt(right))) right = null;
		if (orientation != 'horizontal' && orientation != 'vertical') orientation = 'horizontal';
		// get css properties
		getCSSProperties();
		// draw the menu
		drawMenuTree(top, left, right, orientation, 0, null, 1);
		menuLoaded = true;
	} else {
		// make sure the rollovers and submenus are reset
		for (var i=0; i < arrMenuItems.length; i++) {
			outItem(arrMenuItems[i]);
		}
	}
}

// get the properties from the stylesheet into the cssProperties object
function getCSSProperties() {
	var objSS = getStyleSheet('menu_')
	var arrProperties = new Array ("width", "height", "backgroundColor", "marginTop", "marginLeft", "marginBottom", "marginRight", "paddingTop", "paddingLeft", "paddingBottom", "paddingRight", "borderTopWidth", "borderLeftWidth", "borderBottomWidth", "borderRightWidth");
	for (var i=0; i < arrProperties.length; i++) {
		cssProperties.topLevel[arrProperties[i]] = getCssProperty(objSS, 'menuTopLevel', arrProperties[i]);
		cssProperties.otherLevel[arrProperties[i]] = getCssProperty(objSS, 'menuOtherLevel', arrProperties[i]);
	}
}

function drawMenuTree(top, left, right, orientation, parentId, parentHeight, level) {
	var firstItem = true;
	// determine directional paramaters
	var start, end, incr;
	if (left == null && orientation == 'horizontal') {
		start = arrMenuItems.length - 1; end = arrMenuItems.length; incr = -1; // start from last
	} else {
		start = 0; end = arrMenuItems.length; incr = 1; // start from first
	}
	// draw the menu items
	for (var i=start; 0<=i && i<end; i+= incr) {
		var objMenuItem = arrMenuItems[i];
		if (objMenuItem.parentId == parentId) {
			// draw the item html
			drawItemHtml(objMenuItem, top, left, right, level);
			// if the first subitem, adjust the position so it it aligns to the bottom of the parent item
			if (level > 1 && firstItem && parentHeight != null) {
				top += parentHeight - objMenuItem.height;
				objMenuItem.objStyle.top = top + ((ns4) ? "" : "px");
				firstItem = false;
			}
			// draw subitems
			if (hasChild(objMenuItem)) {
				var subTop = (orientation == 'horizontal') ? top + objMenuItem.height : top;
				var subLeft = (left == null) ? null : left + ((orientation == 'horizontal') ? 0 : objMenuItem.width);
				var subRight = (right == null) ? null : right + ((orientation == 'horizontal') ? 0 : objMenuItem.width);
				var parentHeight = (orientation == 'horizontal') ? null : objMenuItem.height;
				drawMenuTree(subTop, subLeft, subRight, 'vertical', objMenuItem.id, parentHeight, level + 1);
			}
			// increment position counters
			if (orientation == 'horizontal') {
				left = (left == null) ? null : left + objMenuItem.width;
				right = (right == null) ? null : right + objMenuItem.width;
			} else {
				top += objMenuItem.height;
			}
		}
	}
}

function drawItemHtml(objMenuItem, top, left, right, level) {
	var id = objMenuItem.id;
	var content = (objMenuItem.imgNormal != null) ? "<img id='img" + id + "' name='img" + id + "' src='" + objMenuItem.imgNormal.src + "' alt='' border=0>" : objMenuItem.name;
	var className = (level == 1) ? 'menuTopLevel' : 'menuOtherLevel';
	var visibility = (level == 1) ? 'visible' : 'hidden';
	var objCssProps = (level == 1) ? cssProperties.topLevel : cssProperties.otherLevel;
	if (ns4) {
		if (left == null) left = 0; // ns4 can only draw from left
		// get the layer width
		var width = parseInt(objCssProps.width);
		if (isNaN(width)) width = 50;
		// create the new layer element
		var objElement = objMenuItem.objElement = new Layer(width);
		objElement.bgColor = objCssProps.backgroundColor;
		objElement.top = top;
		objElement.left = left;
		objElement.visibility = visibility;
		// write the content
		if ((level > 1 || linkTopLevel) && objMenuItem.path != "") {
			var str = "<div class='" + className + "'><a href='" + objMenuItem.path + "' target='" + linkTarget + "'>" + content + "</a></div>";
		} else {
			var str = "<div class='" + className + "'>" + content + "</div>";
		}
		objElement.document.write(str);
		objElement.document.close();
		// append the event handlers
		objElement.onMouseOver = evtOver;
		objElement.onMouseOut = evtOut;
		// set the style object (same as element for ns4)
		var objStyle = objMenuItem.objStyle = objElement;
		// update the item dimensions and position from the created element
		objMenuItem.width = objStyle.clip.right + parseInt(objCssProps.marginLeft) + parseInt(objCssProps.marginRight);
		objMenuItem.height = objStyle.clip.height + parseInt(objCssProps.marginTop) + parseInt(objCssProps.marginBottom) - 4;
		if (left == 0) {
			left = window.innerWidth - right - objMenuItem.width + parseInt(objCssProps.marginLeft) + parseInt(objCssProps.marginRight);
			objElement.left = left;
		}
		// adjust the clip (workaround for extra top space)
		if (objMenuItem.imgNormal == null) {
			objMenuItem.objElement.clip.top = 4;
		}
	} else {
		if (ns6) {
			// create & insert the new element
			var objDiv = document.createElement("div");
			var objElement = objMenuItem.objElement = document.body.appendChild(objDiv);
			objElement.className = className;
			objElement.id = objElement.name = "menu" + id;
			var objStyle = objMenuItem.objStyle = objElement.style;
			objStyle.position = "absolute";
			objStyle.visibility = visibility;
			objStyle.zIndex = level;
			objStyle.top = top + "px";
			if (left != null) objStyle.left = left + "px";
			if (right != null) objStyle.right = right + "px";
			objElement.innerHTML = content;
			// add event listeners
			objElement.addEventListener("mouseover", evtOver, false);
			objElement.addEventListener("mouseout", evtOut, false);
			if (level > 1 || linkTopLevel) {
				objElement.addEventListener("click", evtClick, false);
			}
			// adjust the width & height to exclude padding and border widths
			if (objCssProps.width != 'auto') {
				var newWidth = parseInt(objCssProps.width) - parseInt(objCssProps.paddingLeft) - parseInt(objCssProps.paddingRight) - parseInt(objCssProps.borderLeftWidth) - parseInt(objCssProps.borderRightWidth);
				objStyle.width = newWidth + "px";
			} else {
				// workaround for incorrect placement of right aligned items
				//objStyle.width = getStyleProperty(objElement, "width", "width");
			}
			if (objCssProps.height != 'auto') {
				var newHeight = parseInt(objCssProps.height) - parseInt(objCssProps.paddingTop) - parseInt(objCssProps.paddingBottom) - parseInt(objCssProps.borderTopWidth) - parseInt(objCssProps.borderBottomWidth);
				objStyle.height = newHeight + "px";
			}
		} else if (ie) {
			// ie 4+
			var strHtml = "<div class='" + className + "' id='menu" + id + "' style='position:absolute;visibility:" + visibility + ";z-index:" + level + ";"
					 + "top:" + top + "px;" + ((left == null) ? "" : "left:" + left + "px;") + ((right == null) ? "" : "right:" + right + "px;")
					 + "' onmouseover='evtOver()' onmouseout='evtOut()'"
					 + ((level > 1 || linkTopLevel) ? " onmouseup='evtClick()'>" : ">")
					 + content
					 + "</div>\n";
			document.body.insertAdjacentHTML("beforeEnd", strHtml);
			var objElement = objMenuItem.objElement = getElementById(id);
			var objStyle = objMenuItem.objStyle = objElement.style;
		}
		// update the item dimensions from the created element
		objMenuItem.width = objElement.offsetWidth + parseInt(objCssProps.marginLeft) + parseInt(objCssProps.marginRight);
		objMenuItem.height = objElement.offsetHeight + parseInt(objCssProps.marginTop) + parseInt(objCssProps.marginBottom);
	}
}

/* Operational functions */

// event handlers
function evtOver(e) {
	var target = (ns6) ? e.currentTarget : (ns4) ? e.target : event.srcElement;
	var objMenuItem = getItemByElement(target);
	overItem(objMenuItem);
}

function evtOut(e) {
	var target = (ns6) ? e.currentTarget : (ns4) ? e.target : event.srcElement;
	var objMenuItem = getItemByElement(target);
	outItem(objMenuItem);
}

function evtClick(e) {
	var target = (ns6) ? e.currentTarget : (ns4) ? e.target : event.srcElement;
	var objMenuItem = getItemByElement(target);
	clickItem(objMenuItem);
}

// get the item id from the element object returned by the event
function getItemByElement(objElement) {
	for (var i=0; i < arrMenuItems.length; i++) {
		if (arrMenuItems[i].objElement == objElement || arrMenuItems[i].objElement == objElement.parentElement) return(arrMenuItems[i]);
	}
	return(null);
}

// event functions
function overItem(objMenuItem) {
	// set the rollover
	setRollover(objMenuItem, true);
	// show subitems
	clearTimeout(t);
	t = setTimeout("setSubItems(" + objMenuItem.id + ")", delay);
}

function outItem(objMenuItem) {
	// set the rollover
	setRollover(objMenuItem, false);
	// hide all subitems, unless cancelled by another 'over' event
	clearTimeout(t);
	t = setTimeout("setSubItems(0);", delay);
}

// called when a div is clicked on (not ns4!)
function clickItem(objMenuItem) {
	if (objMenuItem.path != "") {
		if (linkTarget.substring(0, 1) == "_") {
			window.open(objMenuItem.path, linkTarget);
		} else {
			window.frames[linkTarget].location.href = objMenuItem.path;
		}
	}
}

// set the rollover state for an item
function setRollover(objMenuItem, over) {
	var className = (objMenuItem.parentId == 0) ? (over) ? 'menuTopLevelOver' : 'menuTopLevel' : (over) ? 'menuOtherLevelOver' : 'menuOtherLevel';
	if (objMenuItem.imgNormal != null) {
		setImage(objMenuItem, (over) ? objMenuItem.imgOver.src : objMenuItem.imgNormal.src);
	} else {
		setClass(objMenuItem, className);
	}
	// set the top level parent rollover
	if (objMenuItem.parentId != 0) {
		var objAncestor = getAncestor(objMenuItem);
		setRollover(objAncestor, over);
	} 
}

// set a new image in a menu item
function setImage(objMenuItem, strImageSrc) {
	var objImage = getImageElement(objMenuItem);
	objImage.src = strImageSrc;
}

// set a new CSS class (for rollovers)
function setClass(objMenuItem, className) {
	var objElement = objMenuItem.objElement;
	if (ns4) {
		var str = "<div class='" + className + "'><a href='" + objMenuItem.path + "' target='" + linkTarget + "'>" + objMenuItem.name + "</a></div>";
		objElement.document.write(str);
		objElement.document.close();
	} else {
		objElement.className = className;
	}
}

// show the appropriate subitems based on the active item
function setSubItems(id) {
	var objMenuItem = getItemById(id);
	// check trough the tree for ancestors, siblings or children
	for (var i=0; i < arrMenuItems.length; i++) {
		arrMenuItems[i].objStyle.visibility = (arrMenuItems[i].parentId == 0 || isFamily(arrMenuItems[i], objMenuItem)) ? "visible" : "hidden";
	}
}

/* Item tree functions */

// get an item object with a given ID
function getItemById(id) {
	for (var i=0; i < arrMenuItems.length; i++) {
		if (arrMenuItems[i].id == id) return(arrMenuItems[i]);
	}
	return(null);
}

// find if an item has children
function hasChild(objMenuItem) {
	for (var i=0; i < arrMenuItems.length; i++) {
		if (arrMenuItems[i].parentId == objMenuItem.id) return(true);
	}
	return(false);
}

// check if two items belong to the same 'family tree'
function isFamily(objMenuItem1, objMenuItem2) {
	if (objMenuItem1 == null || objMenuItem2 == null) return(false);
	if (objMenuItem1.parentId == objMenuItem2.parentId || objMenuItem1.parentId == objMenuItem2.id) return(true);
	if (objMenuItem2.parentId == 0) {
		return(false);
	} else {
		var objParent = getItemById(objMenuItem2.parentId);
		return (isFamily(objMenuItem1, objParent));
	}
}

// get the top level ancestor of an item
function getAncestor(objMenuItem) {
	if (objMenuItem.parentId == 0) {
		return(objMenuItem);
	} else {
		var objParent = getItemById(objMenuItem.parentId);
		return(getAncestor(objParent));
	}
}

/* CSS functions */

function getStyleSheet(strFilename) {
	if (ns4) return(null);
	for (var i=0; i < document.styleSheets.length; i++) {
		if (document.styleSheets[i].href.indexOf(strFilename) >=0) return(document.styleSheets[i]);
	}
	return(null);
}

function getCssProperty(objSS, strRule, strProperty) {
	if (ns4) {
		return(document.classes[strRule].all[strProperty]);
	} else {
		var objRule = getRule(objSS, strRule);
		return(eval("objRule.style." + strProperty));
	}
}

function getRule(objSS, strRule) {
	var arrRules = ie ? objSS.rules : objSS.cssRules;
	if (ff) { //wp	
		arrRules = objSS.cssRules; //wp	
	} //wp		
	for (var i=0; i < arrRules.length; i++) {
		// parse the selector text to remove any non alpha characters
		var strThisRule = arrRules[i].selectorText.replace(/[^a-z]*/gi,'');
		if (strThisRule == strRule) return (arrRules[i]);
	}
	return(null);
}

// get an actual (inherited) style property for an element
function getStyleProperty(objElement, strAttrib, strCssProp) {
	if (ns6) return(document.defaultView.getComputedStyle(objElement, '').getPropertyValue(strCssProp));
	if (ie) return(objElement.currentStyle.getAttribute(strAttrib));
	if (ns4) return(null);
}

/* cross-browser functions */

// determine browser version
var ver=navigator.appVersion;
var dom=document.getElementById?1:0
var ie=(document.all)?1:0;
var ns6=(this.dom && parseInt(this.ver) >= 5)?1:0; 
var ns4=(document.layers && !this.dom)?1:0;
var ff = (navigator.userAgent.indexOf("Firefox") != -1)?1:0   //wp

// get the dhtml element corresponding to an item id
function getElementById(id) {
	if (ns6) return(document.getElementById("menu" + id));
	if (ie) return(document.all["menu" + id]);
	if (ns4) return(document.layers["menu" + id]);
}

// get the image object corresponding to an item id
function getImageElement(objMenuItem) {
	if (ns6) return(document.getElementById("img" + objMenuItem.id));
	if (ie) return(document.all["img" + objMenuItem.id]);
	if (ns4) return(objMenuItem.objElement.document.images["img" + objMenuItem.id]);
}

