
/********************
 Menu item objects
 ********************/

var topMenuItems = new Object();
var allMenuItems = new Object();
var menuItemRefs = new Array();
var current_topmenu_id = 0;
var current_topparent_id = 0;

var divDebug = null;
//var divDebug = initDebug();

Event.observe(window, 'load', initMenuItems);

/****************************************
 Constructor and Factory method
 ****************************************/

function createMenuItem(menu_id, parent_id)
{
	menuItemRefs.push(new MenuItemRef(menu_id, parent_id));
}

var MenuItemRef = Class.create();
MenuItemRef.prototype =
{
	initialize: function(menu_id, parent_id)
	{
		this.menu_id = menu_id;
		this.parent_id = parent_id;
	},

	destroy: function() {},

	create: function()
	{
		var menuItem = new MenuItem(this.menu_id, this.parent_id);
		allMenuItems[this.menu_id] = menuItem;
		//alert(menu_id + ': ' + allMenuItems[this.menu_id]);
		if (this.parent_id == 0)
			topMenuItems[this.menu_id] = menuItem;
		if (current_topmenu_id == 0)
			setCurrentTopMenu(menuItem); // Show first menu by default
	}
}

function initMenuItems()
{
	for (var i = 0; i < menuItemRefs.length; ++i)
	{
		menuItemRefs[i].create();
	}
}

var MenuItem = Class.create();
MenuItem.prototype =
{
	initialize: function(menu_id, parent_id)
	{
		this.menu_id = menu_id;
		
		this.inMenuLabel = false;
		this.inMenuDiv = false;
		
		this.divH = $(document.getElementById("divSubMenu_" + menu_id));
		if (this.divH)
			this.initDiv();
		
		this.children = new Object();
		
		if (parent_id != null && parent_id != 0)
		{
			//alert(parent_id);
			//alert(allMenuItems[parent_id]);
			this.parent = allMenuItems[parent_id];
			if (this.parent)
				this.parent.addChild(this);
			//else
			//	alert('error: parent element for menu item ' + parent_id + ' not found');
		}
	},
	
	destroy: function()
	{
	},
	
	addChild: function(child)
	{
		this.children[child.menu_id] = child;
	},
	
	// Initialises this div and sets display properties
	initDiv: function()
	{
		this.divH.menu_id = this.menu_id;
		Event.observe(this.divH, 'mouseover', enterMenuDiv);
		Event.observe(this.divH, 'mouseout', leaveMenuDiv);
		
		if (this.menu_id == current_menuitem_id || this.menu_id == current_topparent_id)
			setCurrentTopMenu(this);
		else
			unsetCurrentTopMenu(this);
		
		this.td = document.getElementById("tdMenu_" + this.menu_id);
		this.td.menu_id = this.menu_id;
		Event.observe(this.td, 'mouseover', enterMenuLabel);
		Event.observe(this.td, 'mouseout', leaveMenuLabel);
		
		/*
		if (this.divH.style.position == 'absolute')
		{
			this.divH.style.top = findTop(this.td) + this.td.offsetHeight;
			this.divH.style.left = findLeft(this.td);
		}
		else
		{
			document.getElementById('divHorizontalMenu').appendChild(this.divH);
		}
		*/
	},
	
	// Hide this menu, and all children, and each ancestor that isn't currently
	// in menu
	hideMenu: function()
	{
		if (this.divH)
			this.divH.style.display = 'none';
		
		for (var id in this.children)
		{
			this.children[id].hideMenu();	
		}
		
		var ancestor = this.parent;
		while (ancestor)
		{
			if (!ancestor.isInMenu)
				ancestor.hideMenu();
			ancestor = ancestor.parent;
		}
	},
	
	showMenu: function()
	{
		if (this.divH)
			this.divH.style.display = 'block';
	},
	
	// Returns true if the mouse is in this menu, or its child div, or if any
	// child has isInMenu = true.
	isInMenu: function()
	{
		return this.inMenuDiv || this.inMenuLabel || this.isInChildMenu();
	},
	
	// Returns true if any child has isInMenu = true.
	isInChildMenu: function()
	{
		for (var id in this.children)
		{
			if (this.children[id].isInMenu())
				return true;
		}
		
		return false;
	},
	
	// Returns the highest ancestor of this menu item.
	getTopMenuItem: function()
	{
		var ancestor = this;
		while (ancestor.parent)
			ancestor = ancestor.parent;
		return ancestor;
	}
}

/****************************************
 Set top
 ****************************************/

function setCurrentTopMenu(topMenuItem)
{
	if (current_topmenu_id != 0)
	{
		var oldTopMenuItem = topMenuItems[current_topmenu_id];
		unsetCurrentTopMenu(oldTopMenuItem);
	}
	
	current_topmenu_id = topMenuItem.menu_id;
	if (hideWhenNotInMenu)
		topMenuItem.divH.style.display = 'none';
	else
		topMenuItem.divH.style.display = 'block';
}

function unsetCurrentTopMenu(topMenuItem)
{
	topMenuItem.divH.style.display = 'none';
}

/********************
 Event handlers
 ********************/

var MENU_CLOSE_TIME = 100;

function startMenuCloseTimer(menu_id)
{
	window.setTimeout("closeMenu('" + menu_id + "');", MENU_CLOSE_TIME);
}

function closeMenu(menu_id)
{
	if (menu_id == null)
		return;
	var menuItem = allMenuItems[menu_id];
	
	if (!menuItem.isInMenu())
	{
		menuItem.hideMenu();
		if (window.iqSwapImgRestore && document.getElementById('menuImage_' + menu_id))
			iqSwapImgRestore('menuImage_' + menu_id); // TODO: remove tight coupling to MenuItemCustomMenuLink
	}
	
	// Check if all menus are hidden, if so, show current_topmenu_id
	if (!hideWhenNotInMenu)
	{
		var allMenusHidden = true;
		for (var id in topMenuItems)
		{
			if (topMenuItems[id].isInMenu())
			{
				allMenusHidden = false;
				break;
			}
		}
		
		if (allMenusHidden)
			doEnterMenu(current_topmenu_id);
	}
}

function enterMenuLabel(e)
{
	var menu_id = getMenuIDTarget(e);
	if (menu_id == null)
		return;
	
	doEnterMenuLabel(menu_id);
}

function doEnterMenuLabel(menu_id)
{
	if (menu_id == null)
		return;	
	
	var menuItem = allMenuItems[menu_id];
	menuItem.inMenuLabel = true;
	menuItem.showMenu();
	
	// close all other menus
	var top_menu_id = menuItem.getTopMenuItem().menu_id;
	for (other_menu_id in topMenuItems)
	{
		if (top_menu_id != other_menu_id)
		{
			var other_topMenuItem = topMenuItems[other_menu_id];
			other_topMenuItem.inMenuDiv = false;
			other_topMenuItem.inMenuLabel = false;
			other_topMenuItem.hideMenu();
		}
	}
}

function leaveMenuLabel(e)
{
	var menu_id = getMenuIDTarget(e);
	if (menu_id == null)
		return;
	
	allMenuItems[menu_id].inMenuLabel = false;
	startMenuCloseTimer(menu_id);
}

function enterMenuDiv(e)
{
	var menu_id = getMenuIDTarget(e);
	if (menu_id == null)
		return;
	
	allMenuItems[menu_id].inMenuDiv = true;
	if (window.iqSwapImg && document.getElementById('menuImage_' + menu_id))
	{
		iqSwapImg('menuImage_' + menu_id); // TODO: remove tight coupling to MenuItemCustomMenuLink
	}
}

function leaveMenuDiv(e)
{
	var menu_id = getMenuIDTarget(e);
	if (menu_id == null)
		return;
	
	allMenuItems[menu_id].inMenuDiv = false;
	startMenuCloseTimer(menu_id);
}

function getMenuIDTarget(e)
{
	var menu_id = null;
	if (e.currentTarget)
	{
		menu_id = e.currentTarget.menu_id;
	}
	else if (e.srcElement)
	{
		var target = e.srcElement;
		while (target != null && target.menu_id == null)
			target = target.parentNode;
		if (target != null)
			menu_id = target.menu_id;
	}
	return menu_id;
}

/*****************
 Utility functions
 *****************/

function findLeft(obj)
{
	var curleft = 0;
	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			curleft += obj.offsetLeft
			obj = obj.offsetParent;
		}
	}
	else if (obj.x)
		curleft += obj.x;
	return curleft;
}

function findTop(obj)
{
	var curtop = 0;
	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			curtop += obj.offsetTop
			obj = obj.offsetParent;
		}
	}
	else if (obj.y)
		curtop += obj.y;
	return curtop;
}

/*****************
 Debugging
 *****************/
 
function debug(str)
{
	if (divDebug)	
		divDebug.innerHTML = str + "<br>" + divDebug.innerHTML;
}

function initDebug()
{
	var divDebug = document.createElement('div');
	document.body.appendChild(divDebug);
	divDebug.style.position = 'absolute';
	divDebug.style.top = 250;
	divDebug.style.left = 700;
	divDebug.style.width = 200;
	divDebug.style.height = 300;
	divDebug.style.overflow = 'auto';
	//divDebug.style.backgroundColor = 'yellow';
	return divDebug;
}
