//menu that is currently open (deepest)
var m_oCurrentSubMenu = null;

//contains the menu that should be opened for showing menu's based on a timer
var m_oProposedSubMenu = null;

//contains the menu where the automatic hiding should stop
var m_oProposedSubMenuHideUntil = null;

//contains the current menu that is fading in
var m_oCurrentFadeIn = null;

//contains an array of menus that is fading out
var m_oCurrentFadeOut = null;

//the delay for showing a menu
var m_iShowSubMenuDelay = 100;
var m_iHideSubMenuDelay = 50;

//the interval for the fading timer
var m_iFadeInterval = 10;

//id of the timer
var m_iCurrentTimerID = -1;
var m_iCurrentHideTimerID = -1;

//id of the interval timer
var m_iCurrentFadeInIntervalID = -1;
var m_iCurrentFadeOutIntervalID = -1;

//current opacity used for fading
var m_iCurrentFadeIn = -1;
var m_iCurrentFadeOut = -1;

//handles the MouseDown event of the document
function Document_MouseUp(oEvent)
{
	//if there is a submenu showing
	if (m_oCurrentSubMenu != null)
	{
		var oSubMenu = GetEventMenu(oEvent);
		
		if (m_oCurrentSubMenu == oSubMenu)
		{
			return;
		}

		if (IsParentMenu(m_oCurrentSubMenu, oSubMenu)) 
		{
			return;
		}
	
		//finish fading in
		if (UseAnimation())
		    FinishFadeIn();
		
		//hide all submenus
		HideSubMenu(m_oCurrentSubMenu, null);
	}

	m_bPreventHideOnMouseUp = false;
}

//Gets the source of the event
function GetEventSource(oEvent)
{
	if (oEvent.target)
	{
		return oEvent.target;
	}
	else
	{
		return oEvent.srcElement;
	}
}

//Gets the direct parent of a menu
function GetParentMenu(oSubMenu)
{
	if (oSubMenu == null) return null;
	
	var tmp_oParent = oSubMenu.parentNode;
	while (tmp_oParent != null && tmp_oParent.tagName != "UL")
	{
		tmp_oParent = tmp_oParent.parentNode;
	}
	
	if (tmp_oParent != null && tmp_oParent.tagName == "UL") return tmp_oParent;
	else return null;
}

//Determines if the 2nd parameter is a parent menu of the 1st parameter
function IsParentMenu(oSubMenu, oMenuToCheck)
{
	var tmp_oParent = oSubMenu.parentNode;
	while (tmp_oParent != null)
	{
		if (tmp_oParent == oMenuToCheck)
		{
			return true;
		}
		else
		{
			tmp_oParent = tmp_oParent.parentNode;
		}
	}
	return false;
}

//shows a new submenu
function ShowSubMenu(oSubMenu)
{
	//if no submenu was given, its possible that we we're called by a timer, so get the proposed submenu
	if (oSubMenu == null)
	{
		oSubMenu = m_oProposedSubMenu;
	}
	
	//it is possible that the menu is fading out, remove it from the list
	if (m_oCurrentFadeOut != null)
	{
		for (var i=0; i<m_oCurrentFadeOut.length; i++)
		{
			if (m_oCurrentFadeOut[i] == oSubMenu)
			{
				m_oCurrentFadeOut[i] = null;
				break;
			}
		}
	}
	
	//if some menu is open
	if (m_oCurrentSubMenu != null)
	{
		//unless the parent menu is the main menu, hide all other menus
		if (!IsRootMenu(GetParentMenu(oSubMenu)))
		{
			//hide every submenu until we hit the parent of the new submenu
			HideSubMenu(m_oCurrentSubMenu, GetParentMenu(oSubMenu));
		}
		else
		{
			//just hide the current sub menu
			HideSubMenu(m_oCurrentSubMenu, null);
		}
	}
	
	if (UseAnimation())
	{

	    FinishFadeIn();

	    //show the submenu and save it to the variable
	    //if (m_iCurrentFadeInIntervalID != -1) clearInterval(m_iCurrentFadeInIntervalID);
	    ClearHideTimer();
	    m_oCurrentSubMenu = oSubMenu;
	    m_oCurrentFadeIn = oSubMenu;
	    m_iCurrentFadeIn = 0;
	    SetOpacity(m_oCurrentFadeIn, m_iCurrentFadeIn);

	    SetExpanded(m_oCurrentSubMenu, true);
	    m_oCurrentSubMenu.style.display = "block";
	    m_iCurrentFadeInIntervalID = setInterval("FadeIn()", m_iFadeInterval);	
	}
	else
	{
	    m_oCurrentSubMenu = oSubMenu;
	    SetExpanded(m_oCurrentSubMenu, true);
	    m_oCurrentSubMenu.style.display = "block";
	}
}

function SetExpanded(oMenu, bExpanded)
{
    var tmp_oLink = null;
    
    for (var i=0; i<oMenu.parentNode.childNodes.length; i++)
    {
        if (oMenu.parentNode.childNodes[i].tagName == "A")
        {
            tmp_oLink = oMenu.parentNode.childNodes[i];
            break;
        }
    }
    
    if (tmp_oLink == null) return;
    
    if (bExpanded && (tmp_oLink.className.indexOf(" expanded") < 0)) tmp_oLink.className += " expanded";
    else if (!bExpanded && (tmp_oLink.className.indexOf(" expanded") >= 0)) tmp_oLink.className = tmp_oLink.className.replace(" expanded", "");
}

//Fades a array of menus out (1 step), and stops the fading timer when its done
function FadeOut()
{
	if (m_iCurrentFadeOut <= 0)
	{
		FinishFadeOut();
		return;
	}

	m_iCurrentFadeOut -= 0.1;

	for (var i=0;i<m_oCurrentFadeOut.length;i++)
	{
		if (m_oCurrentFadeOut[i] != null)
			SetOpacity(m_oCurrentFadeOut[i], m_iCurrentFadeOut);
	}
}

//Finishes the FadeOut process
function FinishFadeOut()
{
	//only finish if the interval timer is running
	if (m_iCurrentFadeOutIntervalID != -1)
	{
		//stop the interval timer
		clearInterval(m_iCurrentFadeOutIntervalID);
		m_iCurrentFadeOutIntervalID = -1;
		
		//and set all the fading menus to their final hidden state
		for (var i=0;i<m_oCurrentFadeOut.length;i++)
		{
			if (m_oCurrentFadeOut[i] != null)
			{
				SetOpacity(m_oCurrentFadeOut[i], 0);
				m_oCurrentFadeOut[i].style.display = "none";
			}
		}
	}
}

//Fades a menu in (1 step), and stops the fading timer when its done
function FadeIn()
{
	if (m_iCurrentFadeIn >= 1)
	{
		FinishFadeIn();
		return;
	}

	m_iCurrentFadeIn += 0.1;

	SetOpacity(m_oCurrentFadeIn, m_iCurrentFadeIn);
}

//Finishes the FadeIn process
function FinishFadeIn()
{
	//only finish if the interval timer is running
	if (m_iCurrentFadeInIntervalID != -1)
	{
		clearInterval(m_iCurrentFadeInIntervalID);
		m_iCurrentFadeInIntervalID = -1;
		
		SetOpacity(m_oCurrentFadeIn);
	}
}

//determines if the menu is the root menu
function IsRootMenu(oMenu)
{
	return (GetParentMenu(oMenu) == null);
}

//hides a submenu, optionally recursive so all the parent submenus are removed too
function HideSubMenu(oSubMenu, oUntilMenu)
{	
	//maybe we dont have to hide anything?
	if (oSubMenu == oUntilMenu) return;

	//finish any possible current fading out process
	if (UseAnimation())
    	FinishFadeOut()
    else
        oSubMenu.style.display = "none"
	
	//create a new array to store the menus to fade out
	m_oCurrentFadeOut = new Array();
	var tmp_iIndex = -1;

	//hide the submenu
	if (UseAnimation()) m_oCurrentFadeOut[++tmp_iIndex] = oSubMenu;
    SetExpanded(oSubMenu, false);
	//oSubMenu.style.display = "none"

	//clear the current submenu if this was the one
	if (m_oCurrentSubMenu == oSubMenu)
	{
	    //we clear everything
	    if (oUntilMenu == null) m_oCurrentSubMenu = null;
	    
	    //or just a few, where the oUntilMenu will be the deepest visible menu (if its not the root menu)
	    else if (!IsRootMenu(oUntilMenu)) m_oCurrentSubMenu = oUntilMenu;
	    
	    //in that case (its the root menu) clear the current menu too
	    else m_oCurrentSubMenu = null;
	    
	}
	
	//loop all the parents	
	while (oSubMenu != null)
	{
		//get the parent menu
		oSubMenu = GetParentMenu(oSubMenu);
		
		//exit when we hit our mark
		if (oSubMenu == oUntilMenu) break;
		
		//if it was found and its not the root, hide it
		if (oSubMenu != null && !IsRootMenu(oSubMenu))
		{
            if (UseAnimation()) 		
			    m_oCurrentFadeOut[++tmp_iIndex] = oSubMenu;
			else
			    oSubMenu.style.display = "none"
            SetExpanded(oSubMenu, false);
		}
	}

	if (UseAnimation())
	{
	    //Fade out the submenus
	    m_iCurrentFadeOut = 1;
	    m_iCurrentFadeOutIntervalID = setInterval("FadeOut()", m_iFadeInterval)
	}
}

//determines if a menu is visible
function IsVisible(oMenu)
{
	var tmp_bVisible = oMenu.style.display == "block";
	
	//if its visible, its possible that its fading out, return invisible then
	if (tmp_bVisible && m_iCurrentFadeOutIntervalID && m_oCurrentFadeOut != null)
	{
		for (var i=0; i<m_oCurrentFadeOut.length; i++)
		{
			if (m_oCurrentFadeOut[i] == oMenu)
				return false;
		}
		
	}
	
	return tmp_bVisible;
}

//Gets the menu that was the source of the mouse event
function GetEventMenu(oEvent)
{
	//get the element the mouse is hovering over
	var oElement = GetEventSource(oEvent);
	//only proceed when the element was found and it is a hyperlink
	if (oElement == null || oElement.tagName != "A") return null;

	//get the submenu the hyperlink is part of
	var oSubMenus = oElement.parentNode.getElementsByTagName("UL");
	//only proceed if the submenu can be found
	if (oSubMenus == null || oSubMenus.length == 0)
	{
		return null;
	}
	
	return oSubMenus[0];
}

//Handles the MouseDown event of a menu
function Menu_MouseDown(oEvent)
{
	var oSubMenu = GetEventMenu(oEvent);
	
	if (oSubMenu == null) return;

	//if the menu is not already visible, show it
	if (!IsVisible(oSubMenu))
	{
		if (m_iCurrentTimerID != -1) ClearTimer(m_iCurrentTimerID);
	
		ShowSubMenu(oSubMenu);
	}
}

//determines if the second parameters is an (indirect) child of the first parameter
function Contains(oParent, oChild)
{
    if (oParent == null || oChild == null) return false;
    
    for (var i=0; i<oParent.childNodes.length; i++)
    {
        if (oParent.childNodes[i] == oChild) return true;
        else if (Contains(oParent.childNodes[i], oChild)) return true;
    }
    
    return false;
}

//handles the MouseOut event of the whole menu system
function Menu_MouseOut(oEvent)
{
	//clear any current timers for showing a menu
	ClearTimer();
}

//handles the MouseOver event of the whole menu system
function Menu_MouseOver(oEvent)
{	
	var oSubMenu = GetEventMenu(oEvent);
	
	//if there is no submenu to activate
	if (oSubMenu == null)
	{   
	    //maybe there is a menu to deactivate
	    if (m_oCurrentSubMenu != null)
	    {
	        //clear any current close timers
	        ClearHideTimer();
	    
	        //get the element the mouse is hovering over
	        var oElement = GetEventSource(oEvent);
	        //only proceed when the element was found and it is a hyperlink
	        if (oElement == null || oElement.tagName != "A") return;

            //if the activated element is a child of the current menu, exit here
            if (Contains(m_oCurrentSubMenu, oElement.parentNode)) return;

            //get the parent menu of the active element, and store that so the hiding process stops there
            m_oProposedSubMenuHideUntil = GetParentMenu(oElement);

            //hide it after a short delay
			m_iCurrentHideTimerID = setTimeout("HideSubMenu(m_oCurrentSubMenu, m_oProposedSubMenuHideUntil)", m_iHideSubMenuDelay);
	    }
		return;
	}

	//if the menu is not already visible, show it
	if (!IsVisible(oSubMenu))
	{
		//show the menu
		if (m_iShowSubMenuDelay < 1)
		{
			ShowSubMenu(oSubMenu);
		}
		else
		{	
			//clear any current timers
			ClearTimer();

			//show after a short delay			
			m_oProposedSubMenu = oSubMenu;
			m_iCurrentTimerID = setTimeout("ShowSubMenu(null)", m_iShowSubMenuDelay);
		}
	}
}

//Clears the current timer for hiding menu's
function ClearHideTimer()
{
    if (m_iCurrentHideTimerID > 0)
    {
        clearTimeout(m_iCurrentHideTimerID);
        m_iCurrentHideTimerID = -1;
    }
}

//Clears the current timer
function ClearTimer()
{
	if (m_iCurrentTimerID > 0)
	{
		clearTimeout(m_iCurrentTimerID);
		m_iCurrentTimerID = -1;
	}
}

function UseAnimation()
{
    return (window.navigator.userAgent.indexOf("MSIE 7") < 0);
}

//Sets the opacity of an item
function SetOpacity(aElm,aOpac) 
{ 
	var noSet = (typeof aOpac == "undefined"); 
	if (typeof aElm.style.filter != "undefined") 
	{
		aElm.style.filter = (noSet) ? "" : "Alpha(opacity=" + (aOpac*100) + ")"; 
    }
	else if (typeof aElm.style.opacity != "undefined") 
	{
		aElm.style.opacity = (noSet) ? "" : aOpac; 
	}
	else if (typeof aElm.style.MozOpacity != "undefined") 
	{
		aElm.style.MozOpacity = (noSet) ? "" : aOpac; 
	}
} 



