/**
 * =========================
 *   DYNAMIC EXPANDER MENU
 *    (c) Zero One - 2003
 *   Author: Gary Jacobson
 * http://www.zero-one.co.za
 * =========================
 */

/*
Usage:
-	Create all your MenuItems using the ZO_Menu constructor below.
	It takes its variable name as a parameter, and an array containing
	constructor data (id, parentId, label, href) for all the MenuItems.
	(see ZO_MenuItem constructor)
	E.g.	var myCoolMenu = new ZO_Menu( 'myCoolMenu',
			[ 3, null, 'Home', 'index.html',
			84, 3, 'News', 'news.html',
			3783, 3, 'FAQ', 'faq.html' ] );
 - If you are working with a single root item, for example in a PB menuList, add the
   parameter true to the ZO_Menu constructor to ignore the root item.
 - Set <body onLoad="myCoolMenu.arrangeMenus()" onResize="myCoolMenu.arrangeMenus()">
 - Call myCoolMenu.initialize()
 - Call myCoolMenu.drawRootMenu() in the location that you want the root menu to appear.
 - Just inside the body (either right after <body>, or right before </body>),
   call myCoolMenu.drawSubMenus() - this is to maximise Netscape 4 compatibility.
*/

function ZO_Menu( name, menuItemVarArray, ignoreRoot )
{
	this.name = name;
	this.menuItems = [];
	this.ignoreRoot = ignoreRoot;
	
	this.menuTimerId = null;
	this.formTimerId = null;
	this.rootMenu = [];
	
	this.menuLoaded = false;
	
	// these will be set correctly onLoad
	this.windowWidth = 800;
	this.windowHeight = 600;

	for (var i = 0; i + 3 < menuItemVarArray.length; i += 4)
	{
		this.menuItems[ 'menuItem' + menuItemVarArray[i] ] = new ZO_MenuItem( this,
				menuItemVarArray[i], menuItemVarArray[i+1], menuItemVarArray[i+2], menuItemVarArray[i+3] );
	}
	this.arrangeMenus = ZO_arrangeMenus;
	this.menuOver = ZO_menuOver;
	this.menuOut = ZO_menuOut;
	this.closeAllMenus = ZO_closeAllMenus;
	this.menuExpand = ZO_menuExpand;
	this.menuCollapse = ZO_menuCollapse;
	this.menuDisplay = ZO_menuDisplay;
	this.highlightMenuItem = ZO_highlightMenuItem;
	this.getTagWithId = ZO_getTagWithId;
	this.classSwap = ZO_classSwap;
	this.initialize = ZO_initialize;
	this.drawRootMenu = ZO_drawRootMenu;
	this.drawSubMenus = ZO_drawSubMenus;
	this.drawSubMenu = ZO_drawSubMenu;
	this.drawMenuTable = ZO_drawMenuTable;
	this.setMenuProperties = ZO_setMenuProperties;
	this.isMenuHorizontal = ZO_isMenuHorizontal;
	this.getBorderColorForMenu = ZO_getBorderColorForMenu;
	this.hideFormElements = ZO_HideFormElements;
	this.showFormElements = ZO_ShowFormElements;
}

/*
MenuItem object
=============================================

properties supplied to constructor
----------------------------------
menuContainer	the ZO_Menu object containing this ZO_MenuItem
id				unique identifier
parentId		id of parent menu item, or null for root items
label			text displayed
href			page this menu item points to ('#' if there is no page)

properties created in constructor
---------------------------------
subMenu			array of sub menu items
isExpanded		true if menu item is currently expanded
isHighlighted	true if menu item is currently highlighted
parentItem		parent menu item, or null for root items
depth			menu level - root is 0, 1st level sub menus are 1, etc
hasSubMenu		true if this item has a sub menu
parentMenu		menu (array of menu items) that this menu item is in

properties supplied by setMenuProperties method
-----------------------------------------------
width			width of the menu item cell
height			height of the menu item cell
cssClass		stylesheet class applied to the menu item cell and link
				note that onMouseOver, the class is changed from x to xHover
subMenuImage	image to display when the menu item has a sub menu
textAlign		alignment of text inside the cell (left, center, right)

=============================================
*/
function ZO_MenuItem( menuContainer, id, parentId, label, href )
{
	this.menuContainer = menuContainer;
	this.id = id;
	this.parentId = parentId;
	this.label = label;
	this.href = href;
	this.subMenu = [];
	this.isExpanded = false;
	this.isHighlighted = false;
	this.parentItem = null;
	this.depth = 0;
	this.hasSubMenu = false;
	this.parentMenu = menuContainer.rootMenu;
	if (parentId != null)
	{
		this.parentItem = menuContainer.menuItems[ 'menuItem' + parentId ];
		this.parentMenu = this.parentItem.subMenu;
		this.parentItem.hasSubMenu = true;
		this.depth = this.parentItem.depth + 1;
	}
	this.parentMenu[ this.parentMenu.length ] = this;

	this.width = 100;
	this.height = 20;
	this.cssClass = 'menu';
	this.subMenuImage = '';
	this.textAlign = 'left';
}

// mouse over menu item
function ZO_menuOver( id )
{
	if (!this.menuLoaded)
		return false;

	var menuItem = this.menuItems[ 'menuItem' + id ];
	window.status = menuItem.label;
//	ZO_HideFormElements();
	if (this.menuTimerId != null)
		clearTimeout( this.menuTimerId );
	if (this.formTimerId != null)
		clearTimeout( this.formTimerId );

	this.menuCollapse( this.rootMenu );
	this.menuExpand( menuItem );
	this.menuDisplay( this.rootMenu );
	return true;
}

// mouse out menu item
function ZO_menuOut( id )
{
	if (!this.menuLoaded)
		return;

	if (this.menuTimerId != null)
		clearTimeout( this.menuTimerId );

	this.menuTimerId = setTimeout( this.name + '.closeAllMenus()', 60 );

	if (this.formTimerId != null)
		clearTimeout( this.formTimerId );

	this.formTimerId = setTimeout( 'ZO_ShowFormElements()', 100 );
}

function ZO_closeAllMenus()
{
	window.status = '';
	this.menuCollapse( this.rootMenu );
	this.menuDisplay( this.rootMenu );
}

function ZO_menuExpand( menuItem )
{
	menuItem.isExpanded = true;
	if (menuItem.parentItem != null)
		this.menuExpand( menuItem.parentItem );
}

function ZO_menuCollapse( menu )
{
	for (var i = 0; i < menu.length; i++)
	{
		menu[i].isExpanded = false;
		this.menuCollapse( menu[i].subMenu );
	}
}

function ZO_menuDisplay( menu )
{
	for (var i = 0; i < menu.length; i++)
	{
		this.highlightMenuItem( menu[i] );
		if (menu[i].hasSubMenu)
			setDivProperty( 'subMenuItem' + menu[i].id, 'visibility',
					(menu[i].isExpanded ? 'visible' : 'hidden') );
		this.menuDisplay( menu[i].subMenu );
	}
}

function ZO_highlightMenuItem( menuItem )
{
	if (menuItem.isExpanded)
	{
		if (menuItem.isHighlighted)
			return;
		this.classSwap( menuItem.id, menuItem.cssClass + 'Hover' );
		menuItem.isHighlighted = true;
	}
	else
	{
		if (!menuItem.isHighlighted)
			return;
		this.classSwap( menuItem.id, menuItem.cssClass );
		menuItem.isHighlighted = false;
	}
}

function ZO_getTagWithId( id )
{
	if (document.all)
		return document.all[id];
	if (document.getElementById)
		return document.getElementById(id);
	return null;
}

function ZO_classSwap( id, className )
{
	var td = this.getTagWithId( 'menuCell' + id );
	if (td != null)
		td.className = className;
	td = this.getTagWithId( 'menuLink' + id );
	if (td != null)
		td.className = className;
}

// must be called after all menu items have been created, but before any functions are called
function ZO_initialize( menu )
{
	if (menu == null)
	{
		if (this.ignoreRoot)
			this.rootMenu = this.rootMenu[0].subMenu;
		menu = this.rootMenu;
	}
	for (var i = 0; i < menu.length; i++)
	{
		if (this.ignoreRoot)
			menu[i].depth--;
		this.setMenuProperties( menu[i] );
		this.initialize( menu[i].subMenu )
	}
}

// recursive function to position all menus correctly on screen - called by body onLoad
function ZO_arrangeMenus( menu )
{
	if (menu == null)
	{
		menu = this.rootMenu;

		// get window dimensions
		if (document.body && document.body.scrollWidth)
		{
			this.windowWidth = Math.max( document.body.scrollWidth, document.body.clientWidth );
			this.windowHeight = Math.max( document.body.scrollHeight, document.body.clientHeight );
		}
		else if (window.innerWidth)
		{
			this.windowWidth = window.innerWidth;
			this.windowHeight = window.innerHeight;
		}
	}

	for (var i = 0; i < menu.length; i++)
	{
		if (!menu[i].hasSubMenu)
			continue;
		var subMenuLayer = getLayer( 'subMenuItem' + menu[i].id );
		var subMenuWidth = getWidth( subMenuLayer );
		var subMenuHeight = getHeight( subMenuLayer );
		var xOffset, yOffset;
		if (this.isMenuHorizontal( menu[i].depth )) // if the menu is horizontal, align submenus below it
		{
			xOffset = getImageX( 'imgPosTL' + menu[i].id ) - 1;
			yOffset = getImageY( 'imgPosRB' + menu[i].id ) + 1;
			if (xOffset + subMenuWidth > this.windowWidth)
				xOffset = Math.max( 0, getImageX( 'imgPosRB' + menu[i].id ) + 2 - subMenuWidth - 100 );
			if (yOffset + subMenuHeight > this.windowHeight)
				yOffset = Math.max( 0, getImageY( 'imgPosTL' + menu[i].id ) - subMenuHeight );
		}
		else
		{
			xOffset = getImageX( 'imgPosRB' + menu[i].id ) + 1;
			yOffset = getImageY( 'imgPosTL' + menu[i].id ) - 1;
			if (xOffset + subMenuWidth > this.windowWidth)
				xOffset = Math.max( 0, getImageX( 'imgPosTL' + menu[i].id ) - subMenuWidth );
			if (yOffset + subMenuHeight > this.windowHeight)
				yOffset = Math.max( 0, getImageY( 'imgPosRB' + menu[i].id ) + 2 - subMenuHeight );
		}
		setDivProperty( 'subMenuItem' + menu[i].id, 'left', xOffset );
		setDivProperty( 'subMenuItem' + menu[i].id, 'top', yOffset );

		this.arrangeMenus( menu[i].subMenu );
	}
	if (menu == this.rootMenu)
		this.menuLoaded = true;
}

// write root menu items
function ZO_drawRootMenu()
{
	this.drawMenuTable( this.rootMenu );
}

// write sub menus
function ZO_drawSubMenus()
{
	for (var i = 0; i < this.rootMenu.length; i++)
		this.drawSubMenu( this.rootMenu[i] );
}

// write sub menus recursively
function ZO_drawSubMenu( menuItem )
{
	if (!menuItem.hasSubMenu)
		return;

	if (document.layers)
		docWrite( '<layer name="subMenuItem' + menuItem.id + '" top="0" left="0" visibility="hide">' );
	else
		docWrite( '<div id="subMenuItem' + menuItem.id + '" style="position:absolute;top:0px;left:0px;z-index:2000;visibility:hidden">' );

	this.drawMenuTable( menuItem.subMenu );

	if (document.layers)
		docWrite( '</layer>' );
	else
		docWrite( '</div>' );

	docFlush();

	for (var i = 0; i < menuItem.subMenu.length; i++)
		this.drawSubMenu( menuItem.subMenu[i] );
}

// create a table from the menu items, using the supplied parameters
function ZO_drawMenuTable( menu )
{
	docWrite( '<table border="0" cellpadding="0" cellspacing="0" bgcolor="' +
			this.getBorderColorForMenu( menu ) + '">' +
			'<tr><td>' +
			'<table border="0" cellpadding="0" cellspacing="1">' +
			'<tr>' );
	for (var i = 0; i < menu.length; i++)
	{
		with (menu[i])
		{
			if (i > 0 && !this.isMenuHorizontal( depth ))
				docWrite( '</tr><tr>' );
			docWrite( '<td id="menuCell' + id + '" class="' + cssClass + '" onMouseOut="' +
					this.name + '.menuOut(' + id + ')" onMouseOver="' +
					this.name + '.menuOver(' + id + ')" onClick="window.open( \'' + href + '\', \'_self\' )">' +
					'<table border="0" cellpadding="0" cellspacing="0" width="' +
					width + '" height="' + height + '">' +
					'<tr>' +
					'<td width="1%" valign="top">' +
					'<img name="imgPosTL' + id + '" src="images/pixel.gif" width="1" height="1" border="0" />' +
					'</td>' +
					(textAlign == 'right' ? '<td width="1%">' + (hasSubMenu ? subMenuImage : '') + '</td>' : '') +
					'<td width="97%" align="' + textAlign + '">' +
					'<a id="menuLink' + id + '" class="' + cssClass + '" href="' + href +
					'" onMouseOut="' + this.name + '.menuOut(' + id + ')" onMouseOver="return ' +
					this.name + '.menuOver(' + id + ')" >' +
					(textAlign == 'left' ? '&nbsp;&nbsp;' : '') +
					label +
					(textAlign == 'right' ? '&nbsp;&nbsp;' : '') +
					'</a>' +
					'</td>' +
					(textAlign == 'left' ? '<td width="1%">' + (hasSubMenu ? subMenuImage : '') + '</td>' : '') +
					'<td width="1%" valign="bottom">' +
					'<img name="imgPosRB' + id + '" src="images/pixel.gif" width="1" height="1" border="0" />' +
					'</td>' +
					'</tr></table></td>' );
		}
	}
	docWrite( '</tr></table></td></tr></table>' );
	docFlush();
}

// show all form elements when all menus close
function ZO_ShowFormElements()
{
	if (!document.layers)
	{
		for (var i = 0; i < document.forms.length; i++)
			for (var j = 0; j < document.forms[i].elements.length; j++)
				document.forms[i].elements[j].style.visibility = 'visible';
	}
}

// hide all form elements when a menu opens
function ZO_HideFormElements()
{
	if (!document.layers)
	{
		for (var i = 0; i < document.forms.length; i++)
			for (var j = 0; j < document.forms[i].elements.length; j++)
				document.forms[i].elements[j].style.visibility = 'hidden';
	}
}
