/*

=================================================================================================
>> EASYMENU - XHTML/CSS/DHTML Semantically correct drop down menu
=================================================================================================
Author: 	Sam Hampton-Smith
Site: 		http://www.hampton-smith.com

Description:	This script takes a nested set of <ul>s and turns it into a fully functional
		DHTML menu. All that is required is the correct use of class names, and
		the application of some CSS. For the latest version of this script, go to
		http://www.easymenu.co.uk

Use:		Use of this code is free for all non-commercial applications. If you would like to
		use the code on a commercial website, a link back to http://www.easymenu.co.uk is
		required. You are free to make alterations to the code as required.


Copyright:	This script is copyright 2004-2005 hampton-smith limited. All rights reserved.


--------------------------------------------------------------------------------------------------
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
--------------------------------------------------------------------------------------------------
Credits: 	Inspiration/Code borrowed from Dave Lindquist (http://www.gazingus.org)
		Menu hide functionality was aided by some code I found on http://www.jessett.com/
		Konqueror functionality was aided by some code Scott Wehrenberg emailed over
--------------------------------------------------------------------------------------------------
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
--------------------------------------------------------------------------------------------------

==================================================================================================
>> REVISION HISTORY
==================================================================================================
Date		Version		Changes/Bug Fixes/New functionality added
--------------------------------------------------------------------------------------------------
10/01/2005	1.01		Fixed known issue where hovering over a sub-menu, then returning to
				its parent menu not via the "starter" item on that menu, where the
				new item moused over is a "starter" caused the two sub-menus
				to overlay each other until a further movement of the mouse.
				Fixed known issue where returning to parent menu via a non-"starter"
				menu item on the parent menu would not hide the child menu
08/01/2005	1.00		First full release of easymenu.
				Stylesheets now loaded in through JavaScript to improve accessibility.
01/12/2004	0.9		Base code inherited from client project
				Added suggestion from Scott Wehrenberg enabling Konqueror functionality
--------------------------------------------------------------------------------------------------

*/

//-- check for browser version start ----------------------------------

function lib_bwcheck() { //Browsercheck (needed)
	this.ver=navigator.appVersion
	this.agent=navigator.userAgent
	this.dom=document.getElementById?1:0
	this.opera5=(navigator.userAgent.indexOf("Opera")>-1 && document.getElementById)?1:0
	this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
	this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
	this.ie7=(this.ver.indexOf("MSIE 7")>-1 && this.dom && !this.opera5)?1:0;
	this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
	this.ie=this.ie4||this.ie5||this.ie6||this.ie7
	this.mac=this.agent.indexOf("Mac")>-1
	this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
	this.ns4=(document.layers && !this.dom)?1:0;
	this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.ns7 || this.opera5)
	return this
}

//-- check for browser version end ------------------------------------

var bw = lib_bwcheck()

//alert(this.ie);
// Load up the stylesheet for the menus. This code is here rather than in the html
// document to allow for non-javascript browsers to render a seperately styled non-
// interactive list rather than the DHTML menu

// load different style sheet with different browser, IE, Firefox
if (bw.ie == 0) {
	document.write("<link rel='stylesheet' href='/js/cssmenu-firefox.css' type='text/css' />");
} else {
	document.write("<link rel='stylesheet' href='/js/cssmenu-ie.css' type='text/css' />");
}

var currentMenu = null;
var lastMenuStarter = null;
var mytimer = null;
var timerOn = false;
var opera = window.opera ? true : false;
var startx;
var endx;

if (!document.getElementById)
	document.getElementById = function() { return null; }


//-- initialiseDummy START --------------------------------------------

function initialiseDummy(dummy, root) {
	dummy.onmouseover = function() {
		containingMenu = this.parentNode.parentNode;
		for (var x=0;x<containingMenu.childNodes.length;x++) {
			if (containingMenu.childNodes[x].nodeName.toUpperCase()=="LI") {
				if (containingMenu.childNodes[x].getElementsByTagName("ul").length>0) {
					containingMenu.childNodes[x].getElementsByTagName("UL").item(0).style.visibility = 'hidden';
				}
			}
		}
	}
	dummy.onfocus = function() {
		dummy.onmouseover();
	}
}

//-- initialiseDummy END ----------------------------------------------


//-- initialiseMenu START ---------------------------------------------

function initialiseMenu(menu, starter, root) {
	var leftstarter = false;

	if (menu == null || starter == null) return;
		currentMenu = menu;

	starter.onmouseover = function() {
		if (currentMenu) {
			if (this.parentNode.parentNode!=currentMenu) {
				currentMenu.style.visibility = "hidden";
				hideAllMenus(currentMenu, root);

			}
			if (this.parentNode.parentNode==root) {
				while (currentMenu.parentNode.parentNode!=root) {
					currentMenu.parentNode.parentNode.style.visibility = "hidden";
					currentMenu = currentMenu.parentNode.parentNode;
				}
			}
			currentMenu = null;
			this.showMenu();
			}
	}

	menu.onmouseover = function() {
		if (currentMenu) {
			currentMenu = null;
			this.showMenu();
			}
	}

	starter.showMenu = function() {
		startx = parseInt(this.offsetLeft);
		if (!opera) {
			if (this.parentNode.parentNode==root) {
				menu.style.left = this.offsetLeft + "px";
				menu.style.top = this.offsetTop + this.offsetHeight + "px";
				if (menu.offsetWidth < this.offsetWidth) {
					menu.style.width = this.offsetWidth;
				}
			}
			else {
				menu.style.left = this.offsetLeft + this.offsetWidth + "px";
				menu.style.top = this.offsetTop + "px";
			}
		}
		else {
			var rootOffset = root.offsetLeft;
			if (this.parentNode.parentNode==root) {
				menu.style.left = this.offsetLeft + "px";
				menu.style.top = this.offsetTop + this.offsetHeight + "px";
				if (menu.offsetWidth < this.offsetWidth) {
					menu.style.width = this.offsetWidth;
				}
			}
			else {
				menu.style.left = this.offsetLeft + this.offsetWidth + "px";
				menu.style.top = this.offsetTop + "px";
				//menu.style.top = menu.style.top - menu.style.offsetHeight + "px";
			}
		}
		endx = parseInt(menu.style.left);

		menu.style.visibility = "visible";
		for (i=startx;i<=endx;i++) {
			menu.style.left = i + "px";
			menu.style.visibility = "visible";
			//clearInterval(5000);
		}
		currentMenu = menu;
	}

	starter.onfocus	 = function() {
		starter.onmouseover();
	}

	menu.onfocus	 = function() {
	//	currentMenu.style.visibility="hidden";
	}

	menu.showMenu = function() {
		menu.style.visibility = "visible";
		currentMenu = menu;
		stopTime();
	}

	menu.hideMenu = function()  {
		if (!timerOn) {
			mytimer = setInterval("killMenu('" + this.id + "', '" + root.id + "');", 500);
			timerOn = true;
			for (var x=0;x<menu.childNodes.length;x++) {
				if (menu.childNodes[x].nodeName=="LI") {
					if (menu.childNodes[x].getElementsByTagName("UL").length>0) {
						menuItem = menu.childNodes[x].getElementsByTagName("UL").item(0);
						menuItem.style.visibility = "hidden";
					}
				}
			}
		}
	}

	menu.onmouseout = function(event) {
		this.hideMenu();
	}
	menu.onblur = function() {
		this.hideMenu();
	}
	starter.onmouseout = function() {
		for (var x=0;x<menu.childNodes.length;x++) {
			if (menu.childNodes[x].nodeName=="LI") {
				if (menu.childNodes[x].getElementsByTagName("UL").length>0) {
					menuItem = menu.childNodes[x].getElementsByTagName("UL").item(0);
					menuItem.style.visibility = "hidden";
				}
			}
		}
		menu.style.visibility = "hidden";
	}
}

//-- initialiseMenu END -----------------------------------------------

//-- killMenu START ---------------------------------------------------

function killMenu(menu, root) {
	var menu = document.getElementById(menu);
	var root = document.getElementById(root);
	menu.style.visibility = "hidden";
	for (var x=0;x<menu.childNodes.length;x++) {
		if (menu.childNodes[x].nodeName=="LI") {
			if (menu.childNodes[x].getElementsByTagName("UL").length>0) {
				menuItem = menu.childNodes[x].getElementsByTagName("UL").item(0);
				menuItem.style.visibility = "hidden";
			}
		}
	}
	while (menu.parentNode.parentNode!=root) {
		menu.parentNode.parentNode.style.visibility = "hidden";
		menu = menu.parentNode.parentNode;
	}
	stopTime();
}

//-- killMenu END -----------------------------------------------------

//-- stopTime START ---------------------------------------------------

function stopTime() {
	if (mytimer) {
		 clearInterval(mytimer);
		 mytimer = null;
		 timerOn = false;
	}
}

//-- stopTime END -----------------------------------------------------

window.onload = function() {
	var root = document.getElementById("menuList");
	var rootOffset = root.offsetLeft;
	getMenus(root, root);
}

function getMenus(elementItem, root) {
	var selectedItem;
	var menuStarter;
	var menuItem;
	for (var x=0;x<elementItem.childNodes.length;x++) {
		if (elementItem.childNodes[x].nodeName.toUpperCase()=="LI") {
			if (elementItem.childNodes[x].getElementsByTagName("ul").length>0) {
				// submenu exist
				menuStarter = elementItem.childNodes[x].getElementsByTagName("A").item(0);
				menuItem = elementItem.childNodes[x].getElementsByTagName("UL").item(0);
				getMenus(menuItem, root);
				initialiseMenu(menuItem, menuStarter, root);
			}
			else {
				initialiseDummy(elementItem.childNodes[x].getElementsByTagName("A").item(0), root);
			}
		}
	}
}
function hideAllMenus(elementItem, root) {
	for (var x=0;x<elementItem.childNodes.length;x++) {
		if (elementItem.childNodes[x].nodeName.toUpperCase()=="LI") {
			if (elementItem.childNodes[x].getElementsByTagName("ul").length>0) {
				elementItem.childNodes[x].getElementsByTagName("UL").item(0).style.visibility = 'hidden';
				hideAllMenus(elementItem.childNodes[x].getElementsByTagName("UL").item(0), root);
			}
		}
	}
}

//=====================================================================
// Accel[erated] [an]imation object
// change a property of an object over time in an accelerated fashion
//=====================================================================
// obj  : reference to the object whose property you'd like to animate
// prop : property you would like to change eg: "left"
// to   : final value of prop
// time : time the animation should take to run
// zip	: optional. specify the zippiness of the acceleration. pick a
//		  number between -1 and 1 where -1 is full decelerated, 1 is
//		  full accelerated, and 0 is linear (no acceleration). default
//		  is 0.
// unit	: optional. specify the units for use with prop. default is
//		  "px".
//=====================================================================
// bezier functions lifted from the lib_animation.js file in the
// 13th Parallel API. www.13thparallel.org
//=====================================================================

function Accelimation(from, to, time, zip) {
	if (typeof zip  == "undefined") zip  = 0;
	if (typeof unit == "undefined") unit = "px";

        this.x0         = from;
        this.x1		= to;
	this.dt		= time;
	this.zip	= -zip;
	this.unit	= unit;
	this.timer	= null;
	this.onend	= new Function();
        this.onframe    = new Function();
}



//=====================================================================
// public methods
//=====================================================================

// after you create an accelimation, you call this to start it-a runnin'
Accelimation.prototype.start = function() {
	this.t0 = new Date().getTime();
	this.t1 = this.t0 + this.dt;
	var dx	= this.x1 - this.x0;
	this.c1 = this.x0 + ((1 + this.zip) * dx / 3);
	this.c2 = this.x0 + ((2 + this.zip) * dx / 3);
	Accelimation._add(this);
}

// and if you need to stop it early for some reason...
Accelimation.prototype.stop = function() {
	Accelimation._remove(this);
}



//=====================================================================
// private methods
//=====================================================================

// paints one frame. gets called by Accelimation._paintAll.
Accelimation.prototype._paint = function(time) {
	if (time < this.t1) {
		var elapsed = time - this.t0;
	        this.onframe(Accelimation._getBezier(elapsed/this.dt,this.x0,this.x1,this.c1,this.c2));
        }
	else this._end();
}

// ends the animation
Accelimation.prototype._end = function() {
	Accelimation._remove(this);
        this.onframe(this.x1);
	this.onend();
}




//=====================================================================
// static methods (all private)
//=====================================================================

// add a function to the list of ones to call periodically
Accelimation._add = function(o) {
	var index = this.instances.length;
	this.instances[index] = o;
	// if this is the first one, start the engine
	if (this.instances.length == 1) {
		this.timerID = window.setInterval("Accelimation._paintAll()", this.targetRes);
	}
}

// remove a function from the list
Accelimation._remove = function(o) {
	for (var i = 0; i < this.instances.length; i++) {
		if (o == this.instances[i]) {
			this.instances = this.instances.slice(0,i).concat( this.instances.slice(i+1) );
			break;
		}
	}
	// if that was the last one, stop the engine
	if (this.instances.length == 0) {
		window.clearInterval(this.timerID);
		this.timerID = null;
	}
}

// "engine" - call each function in the list every so often
Accelimation._paintAll = function() {
	var now = new Date().getTime();
	for (var i = 0; i < this.instances.length; i++) {
		this.instances[i]._paint(now);
	}
}


// Bezier functions:
Accelimation._B1 = function(t) { return t*t*t }
Accelimation._B2 = function(t) { return 3*t*t*(1-t) }
Accelimation._B3 = function(t) { return 3*t*(1-t)*(1-t) }
Accelimation._B4 = function(t) { return (1-t)*(1-t)*(1-t) }


//Finds the coordinates of a point at a certain stage through a bezier curve
Accelimation._getBezier = function(percent,startPos,endPos,control1,control2) {
	return endPos * this._B1(percent) + control2 * this._B2(percent) + control1 * this._B3(percent) + startPos * this._B4(percent);
}


//=====================================================================
// static properties
//=====================================================================

Accelimation.instances = [];
Accelimation.targetRes = 10;
Accelimation.timerID = null;