//<script language="javascript">
// Load XML into a dom on the page and transform it using XSL on the fly
// author: daniel@klixo.net.nz (c) Klixo Limited 2006. All rights reserved. http://klixo.net.nz/ 
// modified by: dan@klixo.net.nz
// depends on klixo.js
// Klixo customers may use and modify this code as long as this copyright statement is left intact.

// Notes:
// Global constants can be reset before MenuInit()

// Global variables
var moMenu = new Menu();
var moMenuXML = null;
var moMenuXSL = null;

// Global constants
var mlMENU_EXPAND_DELAY = 350;	// How long to wait before expanding a sub-menu (in milliseconds)
var mlMENU_HIDE_DELAY = 550;		// How long to wait before hiding the entire menu
var msMENU_PARENT_ID_PREFIX = "_pid_";
var msMENU_ID_PREFIX = "_id_";

// Menu object is used to hold properties of a menu during a draw or hide
function Menu(sId)
{
	// Id of the document element of the menu
	this.elementId = sId;
	// The timer handle allows a timer to be cancelled. A timer is used to delay
	// showing or hiding a menu allowing smoother navigation and a better user experience
	this.timerHandle = 0;
	// The page ID to which the menu links
	this.pageId = "";
	// The page ID to which the menu's parent links
	this.parentPageId = 0;
	// Screen position offsets from parent menu
	this.offsetLeft = 0;
	this.offsetTop = 0;
	this.offsetWidth = 0;
	this.offsetHeight = 0;
	// If the menu is waiting to hide
	this.hiding = false;
	// If the menu is actually hidden; used to prevent attempts to hide the menu again
	this.hidden = false;
	// default properties
	this.className = "menu";
	this.display = "block";
	this.parentElement = document.body;
	this.tagName = "div";
	this.idPrefix = "divMenu";
	
	if (sId == "divTopMenu") this.idPrefix = "divTopMenu";

	// If we've got an element ID..
	if (this.elementId)
	{
		// ..try and derive the page ID from it
		var lPrefixIndex = this.elementId.indexOf(msMENU_ID_PREFIX);
	
		if (lPrefixIndex >= 0)
		{
			var lPrefixLength = msMENU_ID_PREFIX.length;
			this.pageId = this.elementId.substring(lPrefixIndex + lPrefixLength, this.elementId.length);
			this.idPrefix = this.elementId.substring(0, this.elementId.indexOf(msMENU_PARENT_ID_PREFIX));
		}
		else
		{
			// It's the root menu so doesn't have one
			this.pageId = "";
		}
		
		// Set the element property to the document element
		this.element = document.getElementById(this.elementId);
		// If we didn't find it
		if (this.element == null)
		{
			// See if what we're looking for doesn't have a parent ID
			var lStartIndex = this.elementId.indexOf(msMENU_PARENT_ID_PREFIX) + msMENU_PARENT_ID_PREFIX.length;
			var lEndIndex = this.elementId.indexOf(msMENU_ID_PREFIX);
			var tempid = this.elementId.substring(0, lStartIndex) + this.elementId.substring(lEndIndex, this.elementId.length);
			if (document.getElementById(tempid))
			{
				this.elementId = tempid;
				this.element = document.getElementById(this.elementId);
			}
		}
		// If this element already exists, set the element property
		if (this.element)
		{
			// Get the offsets
			this.offsetLeft = this.element.offsetLeft;
			this.offsetTop = this.element.offsetTop;
			this.offsetWidth = this.element.offsetWidth;
			this.offsetHeight = this.element.offsetHeight;
		}
	}
	

	// Create Child - creates a child menu object
	this.CreateChild = function(sMenuId)
	{
		// Derive an id
		var sId = 
			this.idPrefix
			+ msMENU_PARENT_ID_PREFIX
			+ this.pageId.toString() 
			+ msMENU_ID_PREFIX
			+ sMenuId;
		// Create a new menu object
		var oMenu = new Menu(sId);
		// Set its parent menu id to this menu's id
		oMenu.parentPageId = this.pageId;
		// Set its parentElement to this menu's element
		oMenu.parentElement = this.element;
		// Return the new menu item
		return oMenu;
	}

	// Draw - creates a menu html element and appends it to the parentElement
	this.Draw = function(bShow)
	{
		// If we haven't yet loaded the XML or XSL try again in a little while
		if ((moMenuXML == null) || (moMenuXSL == null))
		{
			this.Show();
			return;
		}
		// Check to see if the document element for this menu has already been created
		if (!this.element)
		{
			// Create the menu fragment by transforming a fragment of the menu XML into HTML using
			// an XSL template

			// Get a page node
			var oNode = moMenuXML.selectSingleNode("//pages[page/id = '" + this.pageId + "']");
			// If we couldn't get one we can't create a menu so quit
			if (!oNode) return;
			oNode.setAttribute("prepTxt", this.idPrefix);
			// Transform it
			var sHTML = TransformXML(oNode, moMenuXSL);
			// create a new HTML element to contain the menu, set the id and classname, load the
			// HTML fragment and append to the menu parent element
			this.element = document.createElement(this.tagName);
			this.element.id = this.elementId;
			this.element.className = this.className;
			this.element.innerHTML = sHTML;
			this.element.style.display = "none";
			this.element.style.position = "absolute";
			if (this.parentElement) this.parentElement.appendChild(this.element);
			// Remove any specified pages
			if (RemoveSpecificMenus) RemoveSpecificMenus(this.element);			
		}
		// If we're trying to draw it
		if (bShow == true)
		{
			this.element.style.left = this.offsetLeft.toString() + "px";
			this.element.style.top = this.offsetTop.toString() + "px";
			this.element.style.display = this.display;
		}
		// Otherwise we're hiding it
		else
		{
			this.element.style.display = "none";
		}
	}
	
	// Show - shows a menu after a delay
	this.Show = function()
	{
		// Stop any current action
		this.CancelTimerAction();
		// Say we're not hiding
		this.hiding = false;
		this.hidden = false;
		// Kick off the timer
		this.timerHandle = StartTimeout(mlMENU_EXPAND_DELAY, MenuShowCallBack);
	}

	// Cancel show - cancels the current timer action whatever it may be
	this.CancelTimerAction = function()
	{
		// We're not hiding
		this.hiding = false;
		this.hidden = false;
		// Stop the timer
		StopTimeout(moMenu.timerHandle);
	}
	
	// Hide the menu after a delay
	this.HideAllMenus = function()
	{
		// Stop any current action
		this.CancelTimerAction();
		// Say we are waiting to hide the menu
		this.hiding = true;
		this.hidden = false;
		// Kick off the timer
		this.timerHandle = StartTimeout(mlMENU_HIDE_DELAY, MenuHideAllCallBack);
	}
	
	// Hide the current menu's children after a delay
	this.HideChildren = function()
	{
		this.CancelTimerAction();
		this.timerHandle = StartTimeout(mlMENU_EXPAND_DELAY, MenuHideChildrenCallBack);
	}
	
	// Hide the children of this menu
	this.HideChildrenNow = function()
	{
		// hide all child menus
		var sPrefix = this.idPrefix + msMENU_PARENT_ID_PREFIX + this.pageId;
		var oMenus = document.getElementsByTagName(this.tagName);
		// iterate through all menus
		for (var i = 0; i < oMenus.length; i++)
		{
			if (oMenus[i].id.indexOf(sPrefix) == 0)
			{
				if (oMenus[i].id.length > sPrefix.length)
				{
					oMenus[i].style.display = "none";
					// recursively hide the children
					var oMenu = new Menu(oMenus[i].id);
					oMenu.HideChildrenNow();
				}
			}
		}
	}
	
	// Hide the siblings of this menu
	this.HideSiblings = function()
	{
		// hide all sibling menus
		var sPrefix = this.idPrefix + msMENU_PARENT_ID_PREFIX + this.parentPageId;
		var oMenus = document.getElementsByTagName(this.tagName);
		// iterate through all menus
		for (var i = 0; i < oMenus.length; i++)
		{
			if (oMenus[i].id.indexOf(sPrefix) == 0)
			{
				if (oMenus[i].id.length > sPrefix.length)
				{
					oMenus[i].style.display = "none";
					// recursively hide the children
					var oMenu = new Menu(oMenus[i].id);
					oMenu.HideChildrenNow();
				}
			}
		}
	}
}

// Set everything up for the menus to operate correctly. Must be called
// before they will work.
function MenuInit()
{
	var XMLURL = "page_page.xml";
	var XSLURL = "xsl/menu_frag.xsl";
	// load the menu XML
	moMenuXML = GetDocument(XMLURL);
	moMenuXSL = GetDocument(XSLURL);
}

// Call back function to draw a sub-menu
function MenuShowCallBack()
{
	var menu;
	switch (moMenu.idPrefix)
	{
	case	'divMenu':
		menu = new Menu("divTopMenu");
		break;
	case	'divTopMenu':
		menu = new Menu("divMenu");
		break;
	}
	menu.HideChildrenNow();
	// Hide the siblings first in case there are any other sub-menus open
	moMenu.HideSiblings();
	// Now draw the menu
	moMenu.Draw(true);
}

// Call back function to hide all menus
function MenuHideAllCallBack()
{
	moMenu = new Menu("divMenu");
	// Say the menu is now hidden
	moMenu.hidden = true;
	moMenu.HideChildrenNow();
	moMenu = new Menu("divTopMenu");
	// Say the menu is now hidden
	moMenu.hidden = true;
	moMenu.HideChildrenNow();
}

// Call back function to hide children of the current menu
function MenuHideChildrenCallBack()
{
	// Hide all the children
	moMenu.HideChildrenNow();
}