/*
menubar.js - created by Brendan Ratter 15/03/2007
This file contains the functions to build a generic menu bar
This file should not be edited - if you want to access menu properties, use the specific object instance
*/

/*to do's:
	get rid of the global array - put timeouts as object properties if possible, otherwise stick to a single superglobals array - do timeouts as closures or object properties
	scrap the status monitor
	write ability to load from xml
	add multiple menu tiers
	add picture dotpt
*/


//declare a global array to hold certain parameters
var menuglobal = new Array();

//function to build menu bar
function buildMenuBar(bar_id,menu_array)
{
	//create a new menubar
	var navbar = new menuBar(bar_id);
	
	//only start if there are some headings to put in the menu bar
	if (menu_array['mh'].length > 0) {
	
		//loop through each heading section in the array, and build the menu bar - stop at the smallest value to avoid errors
		for (var i = 0; i < menu_array['mh'].length; i++) {
			//add heading
			navbar.addHeading(menu_array['mh'][i],menu_array['mh_href'][i]);
			
			//if there are some menu items, add a menu
			if (menu_array['ml'].length > i && menu_array['ml_href'].length > i) {
				if (menu_array['ml'][i].length > 0) {
					navbar.headings[i].addMenu();
					//loop through all the menu items and put into object
					
					for (var j = 0; j < menu_array['ml'][i].length; j++) {
						navbar.headings[i].menu.addItem(menu_array['ml'][i][j],menu_array['ml_href'][i][j]);
					}
				}
			}
		}
		//write menu bar
		document.write(navbar.writeMenuBar());
	}
	
	return navbar;
}

//---------------------------------------------object templates for menu bar---------------------------------------------//

//create the object template for a menu bar
function menuBar(id)
{
	//-----public properties-----//
	
	//stores the height of the bar in specified units
	this.height = 15;
	this.heightunits = 'px';
	//stores the class
	this.classname = 'menu_bar';
	//store the time in ms that menus stay before disappearing (use 10 for instant)
	this.menuLag = 10;
	
	//-----private properties-----//
	
	//counter for number of headings
	this.count = 0;
	//id for the menubar
	this.id = id;
	//to hold array of heading objects
	this.headings = new Array();
	//to hold the status monitor
	this.monitor;
	
	//-----methods-----//
	
	//method to insert a heading into the menu bar
	this.addHeading = addHeading;
	//method to write html string of menu bar
	this.writeMenuBar = writeMenuBar;
}

//create the object template for a menu heading
function menuHeading(id_no)
{
	//-----public properties-----//
	
	//stores the width of the heading in specified units
	this.width = 150;
	this.widthunits = 'px';
	//stores the class
	this.classname = 'menu_heading';
	
	//-----private properties-----//
	
	//id for the heading
	this.parentbar;
	this.id_no = id_no;
	this.id= 'mh' + id_no;
	//label for the heading
	this.label = '';
	//link to follow if the heading is clicked
	this.href = '';
	
	//checks to see if the heading has a child menu
	this.hasMenu = false;
	//stores the menu object if present
	this.menu;
	
	//-----methods-----//
	
	//method to add a menu that drops down from the heading
	this.addMenu = addMenu;
	//method to write the html of a heading
	this.writeHeading = writeHeading;
}

//create the oject template for the menu
function menuList(id_no)
{
	//-----public properties-----//
	
	//property to hold the css class of the container div
	this.classname = 'menu_list';
	//stores the width of the list in specified units
	this.width = 200;
	this.widthunits = 'px';
	
	//-----private properties-----//
	
	//counter for number of items
	this.count = 0;
	//id for the menu
	this.parentbar;
	this.id_no = id_no;
	this.id = 'ml' + id_no;
	//to hold array of item objects
	this.items = new Array();
	
	//-----methods-----//
	
	//method to add an item to the menubar
	this.addItem = addItem;
	//method to write the html of a menu list
	this.writeList = writeList;
}

//create the oject template for a menu item
function menuItem(id_no,list_id_no)
{
	//-----public properties-----//
	this.classname = 'menu_item';
	
	//-----private properties-----//
	
	//id for the item
	this.parentbar;
	this.id_no = id_no;
	this.id = 'mi' + list_id_no + '_' + id_no;
	//holds the width of the parent list - list width controls all cell widths
	this.width;
	this.widthunits;
	//label for the item
	this.label = '';
	//link to follow if the item is clicked
	this.href = '';
	
	//-----methods-----//
	
	//method to write html string of table cell
	this.writeItem = writeItem;
}

//---------------------------------------------object methods for menu bar---------------------------------------------//

//menu bar method: add a heading to the menu bar
function addHeading(text,url)
{
	//the current value of count will be the number portion of the id
	var id_no = this.count;
	//increment the menu counter as we are adding another menu
	this.count += 1;
	
	//create a new instance of the heading object
	var current = this.headings[id_no] = new menuHeading(id_no);
	//add the label and hlink properties
	current.label = text;
	current.href = url;
	//set the parentbar property as the id of the menu bar
	current.parentbar = this.id;
	//return the menu heading
	return current;
}

//menu bar method: write html of the menu bar
function writeMenuBar()
{
	//str variable holds html for menu bar, mstr for menus
	var str = '', mstr = '';
		
	//open container div and table
	str += '<div id="' + this.id + '" class="' + this.classname + '">' +
	'<table id="' + this.id + 'tb" class="' + this.classname + '"><tr>';
	
	//create a status monitor
	this.monitor = new menuMonitor(this.count);
	this.monitor.make();
	
	//loop through all the headings and write them to menu bar
	for (var i = 0; i < this.count; i++) {
		str += this.headings[i].writeHeading();
		
		//if there is a corresponding menu list, then add its html to mstr
		if (this.headings[i].hasMenu == true) {
			mstr += this.headings[i].menu.writeList();
			//also, note that menu exists in the status monitor
			this.monitor.hasMenu[i] = true;
		}
	}
	//close table and div
	str += '</tr></table></div>';
	
	//concatenate the mstr onto the end of str to give one string for the entire menu
	str += mstr;
	
	//save the menu bar object to the global menu array for access
	menuglobal[this.id] = this;
	//also declare time variable to avoid terminating errors before a timeout has been set
	menuglobal['timer'];
	menuglobal['menuLag'] = this.menuLag;
	
	return str;
}

//menu heading method: add a menu list to the heading
function addMenu()
{
	//after adding a menu, the hasMenu poperty will be true
	this.hasMenu = true;
	
	//create a new instance of the menu object
	current = this.menu = new menuList(this.id_no);
	//set its parentbar property
	current.parentbar = this.parentbar;
	//return menu
	return current;
}

//menu heading method: write html of  a menu heading
function writeHeading()
{
	//str variable holds html
	var str = '';
	
	//write table cell
	str += '<td id="' + this.id + '" class="' + this.classname + '" ';
	//only put the link in if the href exists
	if (this.href != '' && this.href != undefined) {
		str += 'onClick="document.location.href=\'' + this.href + '\';" ';
	}
	str += 'onMouseOver="toggleHeading(\'' + this.parentbar + '\','  + this.id_no + ',true); ieHead(\'' + this.id + '\',1);" ' +
	'onMouseOut="toggleHeading(\'' + this.parentbar + '\','  + this.id_no + ',false); ieHead(\'' + this.id + '\',0);" ' +
	'style="width: ' + this.width + this.widthunits + ';">' + this.label + '</td>';
	
	return str;
}

//menu list method: add an item to the menu list
function addItem(text,url)
{
	//the current value of the count will be the number portion of the id
	var id_no = this.count;
	//increment the item counter
	this.count += 1;
	
	//create a new item object
	var current = this.items[id_no] = new menuItem(id_no,this.id_no);
	//set the width of the list item
	current.width = this.width;
	current.widthunits = this.widthunits;
	//add the label and hlink properties
	current.label = text;
	current.href = url;
	//set the parentbar property
	current.parentbar = this.parentbar;
}

//menu list method: write html of a menu list
function writeList()
{
	//str variable holds html
	var str = '';
	
	//check: if there is no items, then no point in writing anything (this method shouldn't be being called, but just a check)
	if (this.count != 0) {
		//open container div and start table
		str += '<div id="' + this.id + '" class="' + this.classname + '" ' +
		'onMouseOver="toggleList(\'' + this.parentbar + '\','  + this.id_no + ',true);" ' +
		'onMouseOut="toggleList(\'' + this.parentbar + '\','  + this.id_no + ',false);" ' + 
		'><table id="' + this.id + 'tb" class="' + this.classname + '">';
		
		//incorporate the html from all the list items
		for (var i = 0; i < this.count; i++) {
			str += this.items[i].writeItem();
		}
		
		//close the table and the table
		str += '</table></div>';
	}
	
	return str;
}

//menu item method: write html of table cell
function writeItem()
{
	//str variable holds string for cell creation
	var str = '';
	
	str += '<tr><td id="' + this.id + '" class="' + this.classname + '" ';
	//only put the link in if the hyperlink is set
	if (this.href != '' && this.href != undefined) {
		str += 'onClick="document.location.href=\'' + this.href + '\';" ' +
		'onMouseOver="ieItem(\'' + this.id + '\',1);" ' +
		'onMouseOut="ieItem(\'' + this.id + '\',0);" ';
		//had to change id formula to be able to access for on mouse overs. maybe try to access through dom tree as much as possible in later versions?
	}
	str += 'style="width: ' + this.width + this.widthunits + ';">' + this.label + '</td></tr>';
	
	return str;
}

//---------------------------------------------display functions---------------------------------------------//

//function that sets the status in the status monitor
function toggleHeading(parent_menu,id_no,status)
{
	//load the status monitor
	var monitor = menuglobal[parent_menu].monitor;
	//update relevant properties in status monitor
	monitor.mh_status[id_no] = status;
	
	//action depending on whether on or off
	if (status == true) {
		//actions for switching on		
		//hide all menus
		hideAllMenus(parent_menu,monitor);
		//change style of current menu ??? maybe just use :hover
		
		//show the attached menu list and clear timeout if there is one set
		showMenu(parent_menu,id_no,monitor);
		clearTimeout(menuglobal['timer']);
	} else {
		//actions for switching off
		
		//if the associated menu list exists and is toggled on, don't hide, otherwise, hide
		if (monitor.hasMenu[id_no] == true) {
			//set timeout for hiding menus - note must have global variables to pass to timeout
			arg1 = parent_menu;
			arg2 = id_no;
			arg3 = monitor;
			menuglobal['timer'] = setTimeout('hideMenu(arg1,arg2,arg3)',menuglobal['menuLag']);
		}		
	}
}

//function that turns the list on or off in the status monitor
function toggleList(parent_menu,id_no,status)
{
	//if the timeout has been called, then cancel it if status = true
	if (status == true) {
		clearTimeout(menuglobal['timer']);
	} else {
		//otherwise, hide the menu
		arg1 = parent_menu;
		arg2 = menuglobal[parent_menu].monitor;
		menuglobal['timer'] = setTimeout('hideAllMenus(arg1,arg2)',menuglobal['menuLag']);
	}
	//load the status monitor
	var monitor = menuglobal[parent_menu].monitor;
	//update relevant properties in status monitor
	monitor.ml_status[id_no] = status;
}

//function that shows the relevant menu when a mouseover is called
//pass the id of the menu bar over to allow access via menuglobal
function showMenu(menu_id,id_no,monitor)
{
	//set variables to the menu and the heading id being affected
	var mh_id = 'mh' + id_no, ml_id = 'ml' + id_no;
	
	//get and assign the left and top position of the heading if menu exists
	if (monitor.hasMenu[id_no] == true) {
		var list = getEl(ml_id).style;
		list.left = getElementLeft(mh_id) + 'px';
		list.top = getElementTop(mh_id) + getElementHeight(mh_id) + 'px';
		list.visibility = 'visible';
	}
}

//function to hide an individual menu
function hideMenu(parent_menu,id_no,monitor)
{
	//get menu list id
	ml_id = 'ml' + id_no;
	
	if (monitor.hasMenu[id_no] == true) {
		var list = getEl(ml_id).style;
		list.visibility = 'hidden';
	}
}

//function that ensure that all menus are hidden
function hideAllMenus(menu_id,monitor)
{
	//loop through all headings and ensure their menus are hidden
	for (var i = 0; i < monitor.length; i++) {
		if (monitor.hasMenu[i] == true) {
			hideMenu(menu_id,i,monitor);
		}
	}
}

//object prototype for the status monitor to track visibilities
function menuMonitor(length)
{
	//property to hold the number of headings in the menu
	this.length = length;
	//property to hold the hasMenu status of each menu
	this.hasMenu = new Array;
	//property to hold flag status of each heading
	this.mh_status = new Array;
	//property to hold flag status of each menu
	this.ml_status = new Array;
	
	//method to populate all the arrays with 'false'
	this.make = makeMonitor;
}

//makeMonitor method that populates status arrays
function makeMonitor()
{
	for (var i = 0; i < this.length; i++) {
		this.hasMenu[i] = false;
		this.mh_status[i] = false;
		this.ml_status[i] = false;
	}
}

//function to get mouseovers working in ie6 - otherwise would have used css:hover. May later versions change to setting all styles internally?
function ieHead(id,in_out)
{
	if (in_out == 1) {
		getEl(id).className = 'menu_heading_hover';
	} else {
		getEl(id).className = 'menu_heading';
	}
}

//fix function to get mouseovers working in ie6 - otherwise would have used css:hover. May later versions change to setting all styles internally?
function ieItem(id,in_out)
{
	if (in_out == 1) {
		getEl(id).className = 'menu_item_hover';
	} else {
		getEl(id).className = 'menu_item';
	}
}

var trackno = 0;
function track(msg)
{
	document.getElementById('tracker').innerHTML+= trackno + ': ' + msg + '<br />';
	trackno++;
}