////////////////////////////////////////////////////////////////////////////
// Menu script v 1.4
// Written by Justin Gan
// 4/10/05
////////////////////////////////////////////
//		Menu object

/* 
 * Menu::constructor
 *
 * Parameters
 * ID : string - unique string identifier for this menu
 * closedwidth : integer - width of this menu when it is closed (non-rolled over) (pixels)
 * fullwidth : integer - width of this menu when it is rolled out (pixels)
 * title : string - text to be displayed in the menu header
 * description : string - text to be displayed in the status bar when this menu is rolled over
 * hdnonrolloverimg : string - URL of the non-rollover image. May be "" for no image.
 * hdrolloverimg : string - URL of the rollover image. May be "" for no image.
 * ftimg : string - URL of the menu footer image. May be "" for no image.
 * ftheight : integer - height of the menu footer (pixels)
 * target : string - ID of the target window that the link will be displayed in
 * url : string - URL of the menu link
 * timerDelay : integer - Time for menu to slide down (ms). Defaults to mainmenu.defaultTimerDelay if ""
 * borderWidth : integer - Width of menu border (pixels)
 * textClass : string - name of the class (defined in menustyles.css) for this menu. 
 			If "", defaults to the "menu" style.
 * rolloverScript : string - javascript to be run when this menu is rolled over
 * rolloutScript : string - javascript to be run when the mouse rolls out of this menu
 * clickScript : string - javascript to be run when this menu is clicked
 */
function Menu (ID, closedwidth, fullwidth, title, description, hdnonrolloverimg, hdrolloverimg, ftimg, ftheight, target, url, timerDelay, borderWidth, textClass, rolloverScript, rolloutScript, clickScript) {
	if (arguments.length > 0)
		this.init (ID, closedwidth, fullwidth, title, description, hdnonrolloverimg, hdrolloverimg, ftimg, ftheight, target, url, timerDelay, borderWidth, textClass, rolloverScript, rolloutScript, clickScript);
};

/*
 * Menu::init
 * Initialises all the storage for this menu and caches any images.
 */
 Menu.prototype.init = function (ID, closedwidth, fullwidth, title, description, hdnonrolloverimg, hdrolloverimg, ftimg, ftheight, target, url, timerDelay, borderWidth, textClass, rolloverScript, rolloutScript, clickScript) {
	// Object Properties
	this.ID = ID;
	this.left = 0;
	this.top = 0;
	this.fullwidth = fullwidth;
	this.closedwidth = closedwidth;
	this.fullheight = 0;
	this.closedheight = 0;
	this.curheight = 1;
	this.ftheight = ftheight;
	this.title = title;
	this.description = description;
	this.showing = false;
	this.zindex = 2;
	if (hdnonrolloverimg != "") {
		this.hdnonrolloverimg = new Image ();
		this.hdnonrolloverimg.src = hdnonrolloverimg;
	}
	else
		this.hdnonrolloverimg = null;
	if (hdrolloverimg != "") {
		this.hdrolloverimg = new Image ();
		this.hdrolloverimg.src = hdrolloverimg;
	}
	else
		this.hdrolloverimg = null;
	if (ftimg != "") {
		this.ftimg = new Image ();
		this.ftimg.src = ftimg;
	}
	else
		this.ftimg = null;
	this.target = target;
	this.url = url;
	this.timerDelay = (timerDelay == "" || timerDelay < 0 ? mainMenu.getTimerDelay () : timerDelay);
	this.timerDelayStep = 10;
	this.timerID = null;
	this.parent = null;
	this.borderWidth = (borderWidth == "" ? mainMenu.getBorderWidth () : borderWidth);
	if (textClass != "")
		this.textClass = textClass;
	else
		this.textClass = "menu";
	this.menuitems = new Array ();

	this.rolloverScript = rolloverScript;
	this.rolloutScript = rolloutScript;
	this.clickScript = clickScript;
};

/*
 * Menu::getWidth
 * Returns the closed width of this menu (pixels)
 */
Menu.prototype.getWidth = function () {
	return this.closedwidth;
};

/*
 * Menu::getHeight
 * Returns the full height of this menu (pixels)
 */
Menu.prototype.getHeight = function () {
	return this.fullheight;
};

/*
 * Menu::getClosedHeight
 * Returns the closed height of this menu (pixels)
 */
Menu.prototype.getClosedHeight = function () {
	return this.closedheight;
};

/*
 * Menu::setClosedHeight
 * Sets the closed height of this menu (pixels). Also sets the current menu height to closedHeight.
 */
Menu.prototype.setClosedHeight = function (closedHeight) {
	this.curheight = closedHeight;
	this.closedheight = closedHeight;
};

/*
 * Menu::getLeft
 * Returns the left offset of this menu (pixels)
 */
Menu.prototype.getLeft = function () {
	return this.left;
};

/*
 * Menu::setLeft
 * Sets the left offset of this menu (pixels)
 */
Menu.prototype.setLeft = function (left) {
	this.left = left;
	document.getElementById (this.ID + "_head").style.left = left;
	document.getElementById (this.ID).style.left = left;
};

/*
 * Menu::shiftX
 * Moves the left offset of this menu and all submenus by xshift
 */
Menu.prototype.shiftX = function (xshift) {
	document.getElementById (this.ID).style.left += xshift;
	document.getElementById (this.ID + "_head").style.left += xshift;
	for (j = 0; j < this.menuitems.length; j++) {
		if (this.menuitems [j].isSubmenu ())
			this.menuitems [j].submenu.shiftX (xshift);
	}
};

/*
 * Menu::getTop
 * Returns the top offset of this menu (pixels) = top offset + closed height
 */
Menu.prototype.getTop = function () {
	return this.top + this.closedheight;
};

/*
 * Menu::setTop
 * Sets the top offset of this menu (pixels)
 */
Menu.prototype.setTop = function (top) {
	this.top = top;
};

/*
 * Menu::getBorderWidth
 * Returns the width of the border for this menu (pixels)
 */
Menu.prototype.getBorderWidth = function () {
	return this.borderWidth;
};

/*
 * Menu::getID
 * Returns the unique ID for this menu
 */
Menu.prototype.getID = function () {
	return this.ID;
};

/*
 * Menu::addMenuItem
 * Adds a menuitem to this menu.
 * Sets the parent of the menuitem to this
 * Sets the style of the menuitem
 * Sets the width of the menuitem to the full width of this menu
 */
Menu.prototype.addMenuItem = function (mitem) {
	mitem.setWidth (this.fullwidth);
	mitem.parent = this;
	mitem.setStyles ();
	this.menuitems [this.menuitems.length] = mitem;
};

/*
 * Menu::getMenuItem
 * Returns the [index] menuitem in this menu
 */
Menu.prototype.getMenuItem = function (index) {
	return this.menuitems [index];
};

/*
 * Menu::findMenuItem
 * Recursively searches through this menu and the associated submenus looking for a menuitem ID and returns that menuitem
 */
Menu.prototype.findMenuItem = function (ID) {
	var done = false;
	var i = 0;
	var menuitem = null;
	while (!done && i < this.menuitems.length) {
		if (this.menuitems [i].ID == ID) {
			menuitem = this.menuitems [i];
			done = true;
		}
		else if (this.menuitems [i].isSubmenu ()) {
			// check for submenus
			menuitem = this.menuitems [i].submenu.findMenuItem (ID);
			done = menuitem != null;
		}
		i++;
	}
	return menuitem;
};

/*
 * Menu::findMenu
 * Recursively searches through this menu looking for a menu or submenu ID and returns that menu
 */
Menu.prototype.findMenu = function (ID) {
	if (this.ID == ID)
		return this;
	var j = 0;
	var done = false;
	var menu = null;
	while (!done && j < this.menuitems.length) {
		if (this.menuitems [j].ID == ID) {
			menu = this.menuitems [j];
			done = true;
		}
		else if (this.menuitems [j].isSubmenu ()) {
			menu = this.menuitems [j].submenu.findMenu (ID);
			done = menu != null;
		}
		j++;
	}
	return menu;
};

/*
 * Menu::getNrMenuItems
 * Returns the number of menuitems in this menu
 */
Menu.prototype.getNrMenuItems = function () {
	return this.menuitems.length;
};

/*
 * Menu::onMouseOver
 * Code run when the mouse is rolled over this menu
 */
Menu.prototype.onMouseOver = function () {
	this.setShowing (true);
	this.displayMenu ();
};

/*
 * Menu::onMouseOut
 * Code run when the mouse rolls out of this menu
 */
Menu.prototype.onMouseOut = function () {
	this.setShowing (this.checkShowing ());
	this.displayMenu ();
	if (!this.isShowing ())
		// Check to see if parents are still showing
		if (this.parent != null)
			this.parent.onMouseOut ();
};

/*
 * Menu::onClick
 * Code run when the mouse is left-clicked on this menu
 */
Menu.prototype.onClick = function () {
	if (this.url != "")
		document.getElementById (this.target).src = this.url;
};

/*
 * Menu::checkShowing
 * Returns true if this menu should be showing
 * Browser independent
 */
Menu.prototype.checkShowing = function () {
	var show = false;
	// Check mouse position and this menu
	if (document.layers) {
		// NN4
		mouseX = lastEvent.pageX;
		mouseY = lastEvent.pageY;
	}
	else if (document.all) {
		// IE
  		mouseX = window.event.clientX + document.body.scrollLeft;
	  	mouseY = window.event.clientY + document.body.scrollTop;
	}
	else if (document.getElementById) {
		// NN6
		mouseX = lastEvent.pageX;
		mouseY = lastEvent.pageY;
	}	

	show = 	(mouseX <= this.getLeft () + this.closedwidth && mouseX >= this.getLeft () + 2 && 
			mouseY >= this.top + 2 && mouseY <= this.getTop ()) || 
		(mouseX <= this.getLeft () + this.fullwidth && mouseX >= this.getLeft () + 2 && 
			mouseY >= this.getTop () && mouseY <= this.getTop () + this.fullheight);

	if (!show)
		// Check to see if any submenus are showing
		show = this.checkChildrenShowing ();
	return show && this.showing;
};

/*
 * Menu::checkChildrenShowing
 * Returns true if any of this menu's submenus are showing
 */
Menu.prototype.checkChildrenShowing = function () {
	var show = false;
	for (i = 0; i < this.menuitems.length; i++) {
		var menuitem = this.menuitems [i];
		if (menuitem.isSubmenu ()) {
			show = show || menuitem.submenu.isShowing ();
			if (menuitem.submenu.isShowing ())
				show = show || menuitem.submenu.checkChildrenShowing ();
		}
	}
	return show;
};

/*
 * Menu::isShowing
 * Returns whether this menu should be showing or not
 */
Menu.prototype.isShowing = function () {
	return this.showing;
};

/*
 * Menu::setShowing
 * Sets whether this menu should be showing or not
 */
Menu.prototype.setShowing = function (show) {
	this.showing = show;
};

/*
 * Menu::displayMenu
 * Code called to display or hide this menu.
 */
Menu.prototype.displayMenu = function () {
	// timer delay type function...
	if (this.showing) {
		// Sets the window status bar text
		if (window.status == mainMenu.defaultStatusBar)
			window.status = this.description;
		// Sets this menu as visible
		document.getElementById (this.ID).style.visibility = "visible";
		// Sets the rollover image or style name = textClass_rollover
		if (this.hdrolloverimg != null)
			document.images [(this.ID + "_HD")].src = this.hdrolloverimg.src;
		else
			document.getElementById (this.ID+"_M").className = this.textClass + "_rollover";
		// initialises the rollout timer
		this.rolloutTimerEvent ();
	}
	else {
		// Sets the window status bar text
		window.status = mainMenu.defaultStatusBar;
		// Sets the rollover image or style name to textClass_nonrollover
		if (this.hdnonrolloverimg != null)
			document.images [(this.ID + "_HD")].src = this.hdnonrolloverimg.src;
		else
			document.getElementById (this.ID+"_M").className = this.textClass + "_nonrollover";
		// kills the rollout timer
		this.killTimerEvent ();
		// hides the menu
		document.getElementById (this.ID).style.height = 1;
		document.getElementById (this.ID).style.visibility = "hidden";
		this.curheight = 1;
	}
};

/*
 * Menu::closeMenu
 * Closes the menu
 */
Menu.prototype.closeMenu = function () {
	mouseX = 0;
	mouseY = 0;
	this.showing = false;
	this.displayMenu ();
};

/*
 * Menu::generateHTML
 * Generates the HTML for this menu
 */
Menu.prototype.generateHTML = function () {
	// generate menu head
	var str = "<DIV ID=\"" + this.ID + "_head\" STYLE='position: absolute;";
	str += " width: " + this.closedwidth + "; height: " + this.closedheight + "; overflow: hidden;";
	str += " z-index: " + this.zindex + "; left: " + this.left + "; top: " + this.top + "; border-width: 0;'";
	str += " onMouseOver=\"mainMenu.findMenu ('" + this.ID + "').onMouseOver (); " + this.rolloverScript + "\"";
	str += " onMouseOut=\"mainMenu.findMenu ('" + this.ID + "').onMouseOut (); " + this.rolloutScript + "\"";
	str += ">\n<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0 WIDTH=100%>\n<TBODY>\n<TR STYLE='height: " + this.closedheight + ";'>\n";
	str += "<TD STYLE='height: " + this.closedheight + "; width: " + this.closedwidth + ";'";
	str += " ID=\"" + this.ID + "_M\"";
	if (this.url != "")
		str += " onClick=\"mainMenu.findMenu ('" + this.ID + "').onClick (); " + this.clickScript + "\"";
	str += " CLASS=\"" + this.textClass + "_nonrollover\">";
	if (this.hdnonrolloverimg != null) {
		str += "<IMG STYLE=\" cursor: hand; cursor: pointer; height: " + (this.closedheight - 2*this.borderWidth) + ";";
		str += " width: " + (this.closedwidth - 2*this.borderWidth) + ";\" BORDER=0 ALT=\"" + this.description + "\" ";
//str += "SRC=\"" + this.hdnonrolloverimg.src + "\" ";
		str += "ID=\"" + this.ID + "_HD\">";
	}
	else {
		str += this.title;
	}
	str += "</TD>\n</TR>\n";
	str += "</TBODY></TABLE></DIV>\n";

	// generate menu body
	str += "<DIV ID=\"" + this.ID + "\" style='position: absolute;";
	str += " width: " + this.fullwidth + "; height: 1; overflow: hidden; visibility: hidden;";
	str += " z-index: " + this.zindex + "; left: " + this.left + "; top: " + (this.top + this.closedheight) + "; border-width: 0;'";
	str += " onMouseOver=\"mainMenu.findMenu ('" + this.ID + "').onMouseOver ();\"";
	str += " onMouseOut=\"mainMenu.findMenu ('" + this.ID + "').onMouseOut ();\"";
	str += " >\n<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0>\n<TBODY>\n";

	for (i = 0; i < this.menuitems.length; i++)
		str += this.menuitems [i].generateHTML ();
	if (this.ftimg != null) {
		str += "<TR style='height: " + this.ftheight + ";'>\n";
		str += "<TD style='height: " + this.ftheight + "; width: " + this.fullwidth + "'>";
		str += "<IMG STYLE='height: " + this.ftheight + "; width: " + this.fullwidth + ";' BORDER=0 ALT=\"" + this.description + "\" ";
//str += "SRC=\"" + this.ftimg.src + "\" ";
		str += "ID=\"" + this.ID + "_FT\">";
		str += "</TD>\n</TR>\n";
	}
	str += "</TBODY></TABLE></DIV>\n";
//alert (str);
	return str;
};

/*
 * Menu::loadMenuImages
 * Preloads all the images in the menu and associated submenus into the cache
 */
Menu.prototype.loadMenuImages = function () {
	if (this.hdnonrolloverimg != null)
		document.getElementById (this.ID + "_HD").src = this.hdnonrolloverimg.src;
	if (this.ftimg != null)
		document.getElementById (this.ID + "_FT").src = this.ftimg.src;
	for (r = 0; r < this.menuitems.length; r++)
		this.menuitems [r].loadMenuImages ();
};

/*
 * Menu::generateSubMenuHTML
 * Recursively generates the HTML for this menus submenus
 */
Menu.prototype.generateSubMenuHTML = function () {
	var str = "";
	for (k = 0; k < this.menuitems.length; k++)
		str += this.menuitems [k].generateSubMenuHTML ();
	return str;
};

/*
 * Menu::calculateMenuHeights
 * Recursively calculates the menu and submenu top offsets and heights of all menus and submenus
 */
Menu.prototype.calculateMenuHeights = function () {
//	this.curheight = 0;
	var topoffset = 0;
//	if (this.hdrolloverimg != null || this.title != "")
//		topoffset += this.closedheight;
	for (var i = 0; i < this.menuitems.length; i++) {
		if (this.menuitems [i].isSubmenu ()) {
			this.menuitems [i].submenu.setTop (topoffset + this.getTop () + this.menuitems [i].submenu.getTop ());
			this.menuitems [i].submenu.calculateMenuHeights ();
		}
		this.menuitems [i].ypos = topoffset;
		topoffset += this.menuitems [i].getHeight ();
	}
	if (this.ftimg != null)
		this.fullheight = topoffset + this.ftheight;
	else
		this.fullheight = topoffset;
};

/*
 * Menu::rolloutTimerEvent
 * Callback function - called on every timer event tick
 * Rolls out the menu to its full height
 */
Menu.prototype.rolloutTimerEvent = function () {
	if (this.timerDelay != 0) {
		this.curheight += this.fullheight * (this.timerDelayStep / this.timerDelay);
		if (this.curheight >= this.fullheight) {
			this.curheight = this.fullheight;
			this.timerID = null;
		}
		document.getElementById (this.ID).style.height = this.curheight;
		if (this.curheight < this.fullheight)
			this.timerID = window.setTimeout ("mainMenu.findMenu ('" + this.ID + "').rolloutTimerEvent ()", this.timerDelayStep);
	}
	else {
		this.curheight = this.fullheight;
		document.getElementById (this.ID).style.height = this.curheight;
	}
};

/*
 * Menu::killTimerEvent
 * Kills the timer object for this menu
 */
Menu.prototype.killTimerEvent = function () {
	window.clearTimeout(this.timerID);
	this.timerID = null;
};

/*
 * Menu::toString
 * Returns a string containing the list of parameters for this menuitem
 */
Menu.prototype.toString = function (index) {
	var str = "";
	for (j = 0; j < index; j++)
		str += "\t";
	str += this.ID + "\n";
	var i = 0;
	for (i = 0; i < this.menuitems.length; i++) {
		for (j = 0; j < index; j++)
			str += "\t";
		str += this.ID + "." + this.menuitems [i].toString (index + 1) + "\n";
	}
	return str;
};
