// Menu Generator v1.2
//
// Dymanically generate drop-down menus
// Matt Churchyard - May 2003

// create menu generator object
function menuGenerator()
{
	// our config variables
	// set setConfig for descriptions
	this.version = "Userve Menu Generator v1.2";
	this.offclass = 'menuitem-off';
	this.onclass = 'menuitem-on';
	this.itemwidth = 150;
	this.itemheight = 20;
	this.moves = 0;
	this.banner = "Userve Menu Generator v1.1";
	this.divider = '';
	this.dividerheight = 0;
	this.menuend = '';
	this.menuendheight = 0;
	this.submenuicon = '';
	this.submenuleftoffset = 0;
	this.submenutopoffset = 0;
	this.allowreversemenus = 1;
	this.submenufollowparent = 1;
	this.submenudynamic = 1;
	this.timer = 0;
	this.timeout = 0;
	this.disabled = 0;
	
	// mouse position
	this.mouseX = 0;
	this.mouseY = 0;

	// set state flags
	if( document.layers )
	{
		this.visible = 'show';
		this.hidden = 'hide';
	}
	else
	{
		this.visible = 'visible';
		this.hidden = 'hidden';
	}

	// set menu items
	this.menus = Array();
	this.menunames = Array();
	
	// set functions
	this.setConfig = setConfig;				// set configuration value
	this.setMousePos = setMousePos;			// sets mouse position
	this.setMouseControl = setMouseControl;	// control menu using mouse position
	this.addMenu = addMenu;					// create a menu
	this.addMenuItem = addMenuItem;			// add an item to a menu
	this.addMenuDivider = addMenuDivider;	// add a divider to a menu
	this.addParentMenu = addParentMenu;		// set a menu as a parent of another
	this.buildMenus = buildMenus;			// build menu layers
	this.runMenuEvents = runMenuEvents;		// run menu click,mouseover,mouseout events
	this.openMenu = openMenu;				// display a menu
	this.openSubMenu = openSubMenu;			// display a submenu (calulates position)
	this.closeMenu = closeMenu;				// close single menu (after timeout)
	this.closeMenuNow = closeMenuNow;		// close single menu now
	this.closeMenus = closeMenus;			// close all menus
	this.updateClass = updateClass;			// updates the class of an object
	this.findObject = findObject;			// finds an object in the html dom
	this.getClientWidth = getClientWidth;	// gets width of client browser
	this.getClientHeight = getClientHeight;	// gets height of client browser
	this.dumpMenus = dumpMenus;				// dump menu spec
	
	// save reference to this object
	window.MGmenuGenerator = this;

	// capture mouse events
	if( document.layers )
	{
		document.captureEvents(Event.MOUSEMOVE);
	}
	
	document.onMouseMove = this.setMousePos;

	return this;
}

// saves current mouse position
function setMousePos(e)
{
	if( document.layers )
	{
		this.mouseX = e.PageX;
		this.mouseY = e.PageY;
	}
	else if( document.all )
	{
		this.mouseX = window.event.x;
		this.mouseY = window.event.y;
	}
	else if( document.getElementById )
	{
		this.mouseX = e.pageX;
		this.mouseY = e.PageY;
	}
	
	window.status = this.mouseX + " -- " + this.mouseY;
	
	return true;
}

// set config option for menus
function setConfig(key, value)
{
	// get config key and set correct value
	if( key == 'class-off' )
		// class for menu item when mouse is off
		this.offclass = value;
	else if( key == 'class-on' )
		// class for menu item when mouse is over
		this.onclass = value;
	else if( key == 'item-width'  )
		// width of menu item
		this.itemwidth = value;
	else if( key == 'item-height' )
	 	// height of menu item
		this.itemheight = value;
	else if( key == 'moves' )
		// if your menu is centered in the page and moves
		// with browser resize, this should be the overall width
		// of your content and menu left figures should be relative to
		// the edge of your content
		this.moves = value;
	else if( key == 'banner' )
		// set the banner displayed in status bar
		this.banner = value;
	else if( key == 'divider' )
		// set the divider graphic
		this.divider = value;
	else if( key == 'divider-height' )
		// set the divider graphic height
		this.dividerheight = value;
	else if( key == 'menu-end' )
		// menu end
		this.menuend = value;
	else if( key == 'menu-end-height' )
		// menu end height
		this.menuendheight = value;
	else if( key == 'submenu-icon' )
		// add icon
		this.submenuicon = value;
	else if( key == 'submenu-leftoffset' )
		// the left offset of submenus
		// if 0 they appear immediatley to the right of the parent
		// range -(itemwidth) to +1
		// numbers above 1 are allowed but are advised against 
		// as the gap between menus is offputting
		this.submenuleftoffset = value;
	else if( key == 'submenu-topoffset' )
		// the top offset of submenus
		// if 0 they appear top aligned with their parent item
		// range -(itemheight) to +(itemheight)
		// again any value is allowed but may affect menu functionaility
		this.submenutopoffset = value;
	else if( key == 'submenu-allowreverse' )
		// defaults to on!!
		// set this to allow submenus to display on the left of parent
		// menus when they would otherwise go off the edge of the page
		this.allowreversemenus = value;
	else if( key == 'submenu-followparent' )
		// defaults to on!!
		// if set, submenus will continue to be rendered left
		// of their parent once the menu reaches the page edge
		// if not set, you will get a 'ladder' effect down the side
		// of the page
		this.submenufollowparent = value;
	else if( key == 'submenu-dynamic' )
		// defaults to on!!
		// if set, the position of the submenus is calculated
		// if not set, the specified values are used
		this.submenudynamic = value;
	else if( key == 'menu-timeout' )
		// defaults to 0
		// milliseconds the menu should stay open after the mouse moves off
		this.timeout = value;
	else
	{
		// alert error
		alert(this.version + " (setConfig): Invalid config key: " + key);
	}

	return true;
}

// add a menu to the array
function addMenu(name, top, left)
{
	// check if menu exists
	if( this.menus[name] )
	{
		alert(this.version + " (addMenu): menu already exists with name '" + name + "'");
		return false;
	}

	// create containers
	var menuDetails = Array();
	var menuKeepOpen = Array();
	var menuItems = Array();
	var myMenuAlive = Array(name, -1);
	
	// add ourself to keep alive
	menuKeepOpen[0] = myMenuAlive;
	
	// store menu details
	menuDetails[0] = name;					// menu name
	menuDetails[1] = top;					// top position
	menuDetails[2] = left;					// left position
	menuDetails[3] = menuItems;				// array of items
	menuDetails[4] = menuKeepOpen;			// parents of this menu
	menuDetails[5] = 0;						// real left
	menuDetails[6] = 0;						// no left calculations required (auto submenu)
	menuDetails[7] = 0;						// menu is being displayed reverse (on left of parent)
	menuDetails[8] = 0;						// menu controlled by mouse
	
	// add to menus array
	this.menus[name] = menuDetails;
	this.menunames[this.menunames.length] = name;
	
	return true;
}

function setMouseControl(menu)
{
	// check menu
	if( !this.menus[menu] )
	{
		alert(this.version + " (setMouseControl): the menu '" + menu + "' does not exist!");
		return false;
	}
	
	// set flag
	this.menus[menu][8] = 1;
	
	return true;
}

function addMenuItem(menu, text, url, submenu)
{
	// check menu
	if( !this.menus[menu] )
	{
		alert(this.version + " (addMenuItem): the menu '" + menu + "' does not exist!");
		return false;
	}
	
	// check submenu
	if( submenu && !this.menus[submenu] )
	{
		alert(this.version + " (addMenuItem): cannot set '" + submenu + "' as submenu. menu does not exist");
		return false;
	}
	
	// create store variables
	var itemDetails = Array();
	
	// save details
	itemDetails[0] = text;					// text for item
	itemDetails[1] = url;					// url
	itemDetails[2] = submenu;				// name of this items submenu
	
	// save item
	this.menus[menu][3][(this.menus[menu][3].length)] = itemDetails;

	// if this menu has a submenu, update submenu
	// to keep us showing
	// we also tell the submenu to keep this item
	// active when its showing
	if( submenu )
	{
		this.addParentMenu(submenu, menu, this.menus[menu][3].length-1);
	}

	return true;
}

// add a divider to a menu
function addMenuDivider(menu)
{
	// check menu
	if( !this.menus[menu] )
	{
		alert(this.version + " (addMenuItem): the menu '" + menu + "' does not exist!");
		return false;
	}
	
	// check the divider graphic
	if( !this.divider )
	{
		alert(this.version + " (addMenuDivider): cannot add divider - set divider in configuration first!");
		return false;
	}
	
	// create objects
	var itemDetails = Array();
	
	// save details
	itemDetails[0] = 'MG-DIVIDE';
	itemDetails[1] = '';
	itemDetails[2] = 0;
	
	// save item
	this.menus[menu][3][(this.menus[menu][3].length)] = itemDetails;
	
	return true;	
}

// adds a parent to a menu so that the parent
// stays visible while the mouse is over child menu
function addParentMenu(child, parent, parentitem)
{
	// counter variable
	var i;
	// details
	var parentDetails = Array();
	
	// save details
	parentDetails[0] = parent;
	parentDetails[1] = parentitem;

	// check both menus
	if( !this.menus[parent] || !this.menus[child] )
	{
		// internal function, no notify
		return false;
	}
	
	// add the parent to the menu
	this.menus[child][4][(this.menus[child][4].length)] = parentDetails;
	
	// loop through items in submenu
	// if this has any submenus, we need to add the parent to them also (RECURSIVE)
	for(i=0;i<(this.menus[child][3].length);i++)
	{
		// check for submenu
		if( this.menus[child][3][i][2] )
		{
			// update menu
			this.addParentMenu(this.menus[child][3][i][2], parent, parentitem);
		}
	}
	
	return true;
}

// generates the html code for the menus
function buildMenus()
{
	// loop counters
	var i,j;
	// output and menu details
	var output, menuName, menuHeight, menuWidth, events;
	
	// check document.write
	if( !document.write )
	{
		alert(this.version + ' (buildMenus): Your browser does not support document.write. Build failed!');
		this.disabled = 1;
		return false;
	}

	// check for our object
	if( !window.MGmenuGenerator )
	{
		alert(this.version + ' (buildMenus): Cannot create global reference to menus. Build failed!');
		this.disabled = 1;
		return false;
	}
	
	// check timeouts
	if( this.timeout && (!setTimeout || !clearTimeout) )
	{
		alert(this.version + ' (buildMenus): Disabling menu timeouts - setTimeout or clearTimeout not supported');
		this.timeout = 0;
	}
	
	// loop through our menus
	for(i=0;i<this.menunames.length;i++)
	{		
		// save menu name
		menuName = this.menunames[i];
		
		// get the height for the menu
		menuHeight = 0;
		
		// add each menuitem to the height
		for(j=0;j<this.menus[menuName][3].length;j++)
		{
			// dividers have a different height to items
			if( this.menus[menuName][3][j][0] == 'MG-DIVIDE' )
				menuHeight = menuHeight + this.dividerheight;
			else
				menuHeight = menuHeight + this.itemheight;
		}
		
		// add height of menu end
		if( this.menuend && this.menuendheight )
			menuHeight = menuHeight + this.menuendheight;
			
		// get menu width
		menuWidth = this.itemwidth;
		// add submenu offset if > 0
		// if the submenu is not adjacent to the parent menu
		// the layer still needs to cover the gap so everything doesn't
		// disappear when the mouse moves between menus
		if( this.submenuleftoffset > 0 )
			menuWidth = menuWidth + this.submenuleftoffset;
	
		// create events for the div
		events = 'onMouseOver="window.MGmenuGenerator.runMenuEvents(\'' + menuName + '\', 0, 0, this);" ';
		events = events + 'onMouseOut="window.MGmenuGenerator.runMenuEvents(\'' + menuName + '\', 0, 1, this);"';
	
		// create a div for this menu
		// for the menus to work properly, submenus must be created in reverse order
		// (ie last menu first) so by using the menucount - currentmenuid as a zindex
		// the menus should lay correctly
		output = '<div id="' + menuName + '" ';
		output = output + 'style="position: absolute; z-index: ' + (this.menunames.length - i) + '; visibility: hidden; ';
		output = output + 'top: ' + this.menus[menuName][1] + 'px; left: ' + this.menus[menuName][2] + 'px; ';
		output = output + 'width: ' + menuWidth + 'px; height: ' + menuHeight + 'px;" ' + events + '>\n';
		
		// start the table to contain our menu items
		output = output + '  <table border="0" cellpadding="0" cellspacing="0" width="' + menuWidth + '">\n';
		
		// add the menu items
		for(j=0;j<this.menus[menuName][3].length;j++)
		{
			// check if its a divider
			if( this.menus[menuName][3][j][0] == 'MG-DIVIDE' )
			{
				// add divider
				output = output + '    <tr>\n';
				output = output + '      <td width="' + this.itemwidth + '" colspan="2" height="' + this.dividerheight + '">' + this.divider + '</td>\n';

				// add second column if menu needs to be wider
				if( this.submenuleftoffset )
					output = output + '      <td height="' + this.dividerheight + '" width="' + this.submenuleftoffset + '"></td>\n';
	
				output = output + '    </tr>\n';
			}
			else
			{
				// create event code
				events = 'onClick="window.MGmenuGenerator.runMenuEvents(\'' + menuName + '\', ' + j + ', 2, this);" ';
				events = events + 'onMouseOver="window.MGmenuGenerator.runMenuEvents(\'' + menuName + '\', ' + j + ', 3, this);" ';
				events = events + 'onMouseOut="window.MGmenuGenerator.runMenuEvents(\'' + menuName + '\', ' + j + ', 4, this);"';
			
				// add menu item
				output = output + '    <tr>\n';
				output = output + '      <td id="' + menuName + '' + j + '-left" width="' + (this.itemwidth-15) + '" class="' + this.offclass + '" height="' + this.itemheight + '" ' + events + '>\n';
				output = output + '        ' + this.menus[menuName][3][j][0] + '\n';
				output = output + '      </td>\n';
				
				// create event code
				events = 'onClick="window.MGmenuGenerator.runMenuEvents(\'' + menuName + '\', ' + j + ', 0, this);" ';
				events = events + 'onMouseOver="window.MGmenuGenerator.runMenuEvents(\'' + menuName + '\', ' + j + ', 3, this);" ';
				events = events + 'onMouseOut="window.MGmenuGenerator.runMenuEvents(\'' + menuName + '\', ' + j + ', 4, this);" ';
				
				// add right column
				// this contains the submenu graphic is the item has a submenu
				// has the same events as menuitem td because it must appear as one
				output = output + '      <td valign="middle" id="' + menuName + '' + j + '-right" class="' + this.offclass + '" width="15" ' + events + '>';

				// add graphic
				if( this.submenuicon && this.menus[menuName][3][j][2] )
					output = output + '<img src="' + this.submenuicon + '">\n';
				else
					output = output + '&nbsp;\n';
				

				// close td
				output = output + '      </td>\n';
				
				// add column if menu needs to be wider
				if( this.submenuleftoffset )
					output = output + '      <td width="' + this.submenuleftoffset + '" ' + events + '><img width="' + this.submenuleftoffset + '" height="1"></td>';
				
				// finish up row
				output = output + '    </tr>\n';
			}
		}
		
		// add menu end
		if( this.menuend && this.menuendheight )
		{
			output = output + '    <tr>\n';
			output = output + '      <td width="' + this.itemwidth + '" colspan="2" height="' + this.menuendheight + '">' + this.menuend + '</td>\n';
			
			// add column if menu needs to be wider
			if( this.submenuleftoffset )
				output = output + '      <td height="' + this.menuendheight + '" width="' + this.submenuleftoffset + '"></td>\n';
			
			output = output + '    </tr>\n';
		}
		
		// close table and div
		output = output + '  </table>\n';
		output = output + '</div>';
		
		// write menu to client
		document.write(output);
	}
	
	// write banner to window status
	if( window.status )
		window.status = this.banner;
	
	return true;
}

// runs the events for a menu
function runMenuEvents(menu, menuitem, state, caller)
{
	var i, parentItem, itemID;

	// check menu exists and has [menuitem] items
	if( !this.menus[menu] || this.menus[menu][3].length <= menuitem )
	{
		alert(this.version + " (runMenuEvents): cannot run events for menu '" + menu + "'");
		return false;
	}
	
	// check state
	if( state == 0 )
	{
		// div onMouseOver
		// show all menus in keep alive array
		for(i=0;i<this.menus[menu][4].length;i++)
		{
			// make sure menu is visible
			this.openMenu(this.menus[menu][4][i][0], 1);
		}
	}
	else if( state == 1 )
	{
		// div onMouseOut				
		// close menus
		// any needed menus will be kept open by mouseover handler
		if( this.timeout )
			this.timer = setTimeout('window.MGmenuGenerator.closeMenus();', this.timeout);
		else
			this.closeMenus();
	}
	else if( state == 2 )
	{
		// item onClick
		// follow url
		if( this.menus[menu][3][menuitem][1] )
			document.location = this.menus[menu][3][menuitem][1];
	}
	else if( state == 3 )
	{
		// item onMouseOver
		// update class of menuitem (both sides)
		itemID = menu + '' + menuitem;
		this.updateClass(itemID + '-left', this.onclass);
		this.updateClass(itemID + '-right', this.onclass);

		// update window status
		if( window.status )
			window.status = this.banner + ': ' + this.menus[menu][3][menuitem][0];

		// close any submenus of this menu that are not of this item
		for(i=0;i<this.menus[menu][3].length;i++)
		{
			if( i != menuitem && this.menus[menu][3][i][2] )
			{
				this.closeMenuNow(this.menus[menu][3][i][2]);
			}
		}

		// show our submenu if we have one
		if( this.menus[menu][3][menuitem][2] )
		{
			// if dynamic, use openSubMenu to calculate position
			if( this.submenudynamic )
				this.openSubMenu(this.menus[menu][3][menuitem][2], menu, menuitem);
			else
				this.openMenu(this.menus[menu][3][menuitem][2]);
		}
	}
	else if( state == 4 )
	{
		// item onMouseOut
		// reset class of menuitem (both sides)
		itemID = menu + '' + menuitem;
		this.updateClass(itemID + '-left', this.offclass);
		this.updateClass(itemID + '-right', this.offclass);
		
		// close this items submenu
		if( this.menus[menu][3][menuitem][2] )
		{
			this.closeMenuNow(this.menus[menu][3][menuitem][2]);
		}
		
		// update window status
		if( window.status )
			window.status = this.banner;
	}
	else
	{
		// invalid state
		alert(this.version + " (runMenuEvents): invalid event state '" + state + "'");
		return false;
	}
	
	return true;
}

// opens a menu
function openMenu(menu, keepalive)
{
	var objMenu, menuLeft, menuRealLeft, clientWidth;
	
	// client calls this function
	// exit if we had to disable menus
	if( this.disabled )
		return false;
		
	// if menus arn't disabled, do quick check
	// on clientWidth because we can't do it in buildMenus
	if( this.moves && !this.getClientWidth() )
	{
		// disable menus
		alert(this.version + ' (openMenu): Cannot get width of your browser. Disabling menus!');
		this.disabled = 1;
		return false;
	}
	
	// cancel hide timer
	if( this.timeout )
		clearTimeout(this.timer);
	
	// get object ref
	objMenu = this.findObject(menu);
	
	if( !objMenu )
	{
		alert(this.version + " (openMenu): unable to locate menu '" + menu + "'");
		return false;
	}
	
	// get menu left
	menuLeft = this.menus[menu][2];
	
	// get clientwidth
	clientWidth = this.getClientWidth();

	// check for mouse menu
	if( this.menus[menu][8] )
	{	
		if( objMenu.style.visibility != this.visible )
		{
			objMenu.style.left = window.event.x;
			objMenu.style.top = window.event.y;
			this.menus[menu][1] = window.event.y;
			this.menus[menu][2] = window.event.y;
			this.menus[menu][5] = window.event.y;
		}
	}
	else
	{
		// update left if the menu moves and its not auto
		if( this.moves && clientWidth > this.moves && !this.menus[menu][6] )
		{
			menuRealLeft = clientWidth;
		
			if( this.moves < 1 )
				menuRealLeft = menuRealLeft * (1 - this.moves);	
			else
				menuRealLeft = menuRealLeft - this.moves;
			
			menuRealLeft = menuRealLeft / 2;
			menuLeft = menuRealLeft + menuLeft;
		}
	
		// update left of layer and update our record
		objMenu.style.left = menuLeft;
		this.menus[menu][5] = menuLeft;
	}

	// close all menus if not submenu
	if( !keepalive )
		this.closeMenus();

	// update all parent menus to select this menu
	for(i=0;i<this.menus[menu][4].length;i++)
	{
		if( this.menus[menu][4][i][1] >= 0 )
		{
			// get id of parent menuitem and update class
			parentItem = this.menus[menu][4][i][0] + '' + this.menus[menu][4][i][1];
			this.updateClass(parentItem + '-left', this.onclass);
			this.updateClass(parentItem + '-right', this.onclass);		
		}
	}
	
	// open our menu
	if( objMenu.visibility )
		objMenu.visibility = this.visible;
	else if( objMenu.style.visibility )
		objMenu.style.visibility = this.visible;
	
	return true;
}

// dynamically position a submenu
function openSubMenu(menu, parent, parentitem)
{
	var i, dynLeft, dynTop, menuHeight;

	// check menus
	if( !this.menus[menu] || !this.menus[parent] || this.menus[parent][3].length < parentitem )
		return false;

	// get menu object
	objMenu = this.findObject(menu);
	
	if( !objMenu )
		return false;
	
	// get clientwidth
	clientWidth = this.getClientWidth();
	
	// get initial value for left
	dynLeft = this.menus[parent][5] + this.itemwidth + this.submenuleftoffset;

	// update left if we support reverse menus and are
	// getting too close to the right edge
	if( (this.allowreversemenus && 
		dynLeft > (clientWidth - (this.itemwidth + this.submenuleftoffset))) ||
		this.menus[parent][7] && this.submenufollowparent )
	{
		dynLeft = this.menus[parent][5] - this.itemwidth - this.submenuleftoffset;
		this.menus[menu][7] = 1;
	}
	else
	{
		this.menus[menu][7] = 0;
	}
	
	// set left if we are not using reverse menus
	// or if the menus have got to the left page edge
	if( this.menus[menu][7] && dynLeft < 0 )
	{
		dynLeft = this.menus[parent][5] + this.itemwidth + this.submenuleftoffset;
		this.menus[menu][7] = 0;
	}
	
	// calculate top
	dynTop = this.menus[parent][1] + this.submenutopoffset;
	
	// add item heights
	for(i=0;i<parentitem;i++)
	{
		// again, dividers have different heights
		if( this.menus[parent][3][i][0] == 'MG-DIVIDE' )
			dynTop = dynTop + this.dividerheight;
		else
			dynTop = dynTop + this.itemheight;
	}

	// update position and our copy
	objMenu.style.top = dynTop;
	objMenu.style.left = dynLeft;
	this.menus[menu][1] = dynTop;
	this.menus[menu][2] = dynLeft;
	
	// set this menu as auto
	this.menus[menu][6] = 1;
	
	// close all other menus
	this.closeMenus();
	
	// update all parent menus to select this menu
	for(i=0;i<this.menus[menu][4].length;i++)
	{
		if( this.menus[menu][4][i][1] >= 0 )
		{
			// get id of parent menuitem and update class
			parentItem = this.menus[menu][4][i][0] + '' + this.menus[menu][4][i][1];
			this.updateClass(parentItem + '-left', this.onclass);
			this.updateClass(parentItem + '-right', this.onclass);
		}
	}
	
	// show menu
	if( objMenu.visibility )
		objMenu.visibility = this.visible;
	else if( objMenu.style.visibility )
		objMenu.style.visibility = this.visible;
	
	return true;
}

// closes a menu after a timeout
function closeMenu(menu)
{
	// client calls this function
	// exit if we had to disable menus
	if( this.disabled )
		return false;

	// set timeout to close menu
	if( this.timeout )
		this.timer = setTimeout('window.MGmenuGenerator.closeMenuNow(\'' + menu + '\')', this.timeout);
	else
		this.closeMenuNow(menu);
	
	return true;
}

// closes a menu
function closeMenuNow(menu)
{
	var objMenu, i, itemID, parentMenu;

	// exit if we had to disable menus
	if( this.disabled )
		return false;

	// try to ref menu
	objMenu = this.findObject(menu);
	
	if( !objMenu )
	{
		alert(this.version + " (closeMenu): unable to locate menu '" + menu + "'");
		return false;
	}
	
	// find out if this menu has a parent
	parentMenu = (this.menus[menu][4].length > 1 ? 1 : 0);
	
	// update the immediate parent of this menu to deselect item
	for(i=0;i<=parentMenu;i++)
	{
		if( this.menus[menu][4][i][1] >= 0 )
		{
			// get id of parent menuitem and update class
			parentItem = this.menus[menu][4][i][0] + '' + this.menus[menu][4][i][1];
			this.updateClass(parentItem + '-left', this.offclass);
			this.updateClass(parentItem + '-right', this.offclass);
		}
	}
	
	// update layer state
	if( objMenu.visibility )
		objMenu.visibility = this.hidden;
	else if( objMenu.style.visibility )
		objMenu.style.visibility = this.hidden;
	
	return true;
}

// closes all menus
function closeMenus()
{
	var i;
	
	// loop through menus
	for(i=0;i<this.menunames.length;i++)
	{
		// close menu
		this.closeMenuNow(this.menunames[i]);
	}
	
	return true;
}

// updates the class of an object
function updateClass(object, newclass)
{
	// find object
	var objRef = this.findObject(object);

	// check we have a className method
	if( objRef && objRef.className )
		objRef.className = newclass;
		
	return true;
}

// finds an object in the dom and returns ref
function findObject(object)
{
	var objRef;

	if( document.getElementById )
		objRef = document.getElementById(object);
	if( document.all && !objRef )
		objRef = document.all[object];
	if( document.layers && !objRef )
		objRef = document.layers[object];
		
	return objRef;
}

// gets the width of the client browser
function getClientWidth()
{
	var clientWidth;
	
	// try document.body
	if( document.body )
		clientWidth = document.body.clientWidth;
	
	// try window
	if( !clientWidth )
		clientWidth = window.innerWidth;
	
	// last ditch
	// try document.documentElement but its doubtful
	if( !clientWidth && document.documentElement )
		clientWidth = document.documentElement.clientWidth;
	
	// return width
	return clientWidth;
}

// gets the height of the client browser
function getClientHeight()
{
	var clientHeight;
	
	// try document.body
	if( document.body )
		clientHeight = document.body.clientHeight;
	
	// last ditch
	// try document.documentElement but its doubtful
	if( !clientHeight && document.documentElement )
		clientHeight = document.documentElement.clientHeight;
	
	// return width
	return clientHeight;
}

// writes the menu structure out to the client
function dumpMenus()
{
	// variables
	var output;
	var i,j
	
	// header
	output = this.version + '\n';
	output = output + '© Unitron Systems 2003\n\n';
	output = output + 'Dumping Menu Structure\n\n';
	
	// loop through menus
	for(i=0;i<this.menunames.length;i++)
	{
		// output menu config
		output = output + 'Menu: ' + this.menus[this.menunames[i]][0] + '\n';
		output = output + 'Top: ' + this.menus[this.menunames[i]][1] + '\n';
		output = output + 'Left: ' + this.menus[this.menunames[i]][2] + '\n';
		output = output + 'Items\n';
		
		// loop through items
		for(j=0;j<this.menus[this.menunames[i]][3].length;j++)
		{
			output = output + '' + j + ' (name): ' + this.menus[this.menunames[i]][3][j][0] + '\n';
			output = output + '' + j + ' (url): ' + this.menus[this.menunames[i]][3][j][1] + '\n';
			output = output + '' + j + ' (submenu): ' + this.menus[this.menunames[i]][3][j][2] + '\n';
		}
		
		// add parent text
		output = output + 'Parent Menus\n';
		
		// loop through parent menus
		for(j=0;j<this.menus[this.menunames[i]][4].length;j++)
		{
			output = output + '' + j + ' (parent): ' + this.menus[this.menunames[i]][4][j][0] + '\n';
			output = output + '' + j + ' (parent-item): ' + this.menus[this.menunames[i]][4][j][1] + '\n';
		}
	}
	
	// return info
	return output;
}
