/*
Product: INB Menubar
Version: 1.0.1
Modified: 07/11/2007 (MM/dd/yyyy)
Author: Andre Rafael Barboza (bispenho@bispenho.com - www.bispenho.com)
Company: INB - Industrias Nucleares do Brasil (www.inb.gov.br)

Description: INB Menubar is a dynamic menu like others but it's tableless based

Browser tested:
- Opera 9.10
- Firefox 1.5.0.9: ok
- IE 6, 7: ok
*/

var m_TCurrentMenu = null; //Only one menu is allowed to be showed, so this property control the menu changes

function TINBMenubar(){
	var m_SubMenu; //it's the child menu, UL element
	var m_SubMenuPrevious; //UL element
	var m_Root;
	var m_RootPrevious;
	var m_ObjectAuthor; //who fired the event. It's an anchor
	var m_ItemMenu; //It's an anchor with sub-menu
	var m_ItemDeep;
	var m_TopCorrection = 0; //It's optional if you want to change for some reason the top align
	var m_TopCorrectionForIE = false; //Apply the correction only to IE
	var m_isIE = (navigator.appName.indexOf("Microsoft") != -1);
	var m_isGecko = (navigator.appName.indexOf("Netscape") != -1);
	var m_isOpera = (navigator.appName.indexOf("Opera") != -1);
	var m_ID; //identify of menu

//****************************
//public methods and properties
//****************************
	this.Show = _Show;
	this.Menu = function(){return m_Root};
	
//****************************
//constructor
//****************************
if(arguments.length > 0){
	m_ID = arguments[0];
	if(arguments.length >= 2){
		m_TopCorrection = arguments[1];
	}
	if(arguments.length == 3){
		m_TopCorrectionForIE = arguments[2];
	}
	AddEvent(window, "load", ParseItens);
}

//****************************
//implements
//****************************
	function _Show(Object, Align){
	//Object: Who fired the event. It's an anchor
		if(!m_TCurrentMenu){
			m_TCurrentMenu = this;
		}
		else if(m_TCurrentMenu != this){//The current menu was changed
			Hide(m_TCurrentMenu.Menu(), true);
			m_TCurrentMenu = this;
		}
		
		m_ItemMenu = null;
		m_ObjectAuthor = Object;
		m_SubMenu = GetSubMenu(m_ObjectAuthor);
		m_ItemDeep = GetItemDeep(m_ObjectAuthor);
		
		if(m_ItemDeep == 1){//update root menu
			m_Root = m_ObjectAuthor;
			if(!m_RootPrevious){
				m_RootPrevious = m_Root;
			}
			if(m_RootPrevious != m_Root){//root changed
				Hide(m_RootPrevious, true);
				m_RootPrevious = m_Root;
			}
		}
		if(!m_SubMenuPrevious && m_SubMenu){
			m_SubMenuPrevious = m_SubMenu;
		}
		
		if(m_SubMenu){
			if(GetItemDeep(m_SubMenuPrevious) >= m_ItemDeep && m_SubMenuPrevious != GetMenu(m_ObjectAuthor)){//a sub menu from current menu had been showed and must be hide
				Hide(GetMenu(m_ObjectAuthor), true);
			}
			m_ItemMenu = m_ObjectAuthor;
			ShowHide(m_SubMenu, "Show");
			Hide(m_SubMenu, true);
			SetPosition(Align);
			m_SubMenuPrevious = m_SubMenu;
		}
		else if(m_SubMenuPrevious){
			if(GetItemDeep(m_SubMenuPrevious) >= m_ItemDeep){//a sub menu from current menu had been showed and must be hide
				Hide(GetMenu(m_ObjectAuthor), true);
			}
		}
		
		AddEvent(document, "click", Hide);
	}

//****************************
//private methods
//****************************
	function Hide(){
	/*
	1- if the arguments.length <=1, all menus will be hide
	2- if the method was called by an event, the method will hide last submenu showed until root
	3- else the menu to hide was specified and the method will hide it until root
	4- if the arguments.length = 2 and the arguments[1] = true, the method will hide each menu under the specified element
	5- if the arguments.length = 2 and the arguments[1] = false, the method will hide only the specified menu
	*/
		var StartHiddingFrom = (arguments[0].type)?m_SubMenuPrevious:arguments[0];
		var Menu, colMenus;
		
		if(!StartHiddingFrom)return;
		
		if(arguments.length == 2){
			if(arguments[1] == true){//#4
				if(StartHiddingFrom.nodeName == "UL"){//the Show method send the current menu
					Menu = StartHiddingFrom;
				}
				else{
					Menu = GetSubMenu(StartHiddingFrom);
					if(!Menu)return;
					ShowHide(Menu, "Hide");
				}
				colMenus = Menu.getElementsByTagName("UL");
				for(i=colMenus.length-1; i>=0; i--){//it's necessary check from in to out because IE has difficult to control the render
					if(colMenus[i].className == "Visible"){
						ShowHide(colMenus[i], "Hide");
					}
				}
			}
			else if(arguments[1] == false){//#5
				ShowHide(StartHiddingFrom, "Hide");
			}
		}
		else{//#1, #2, #3
			while(StartHiddingFrom.nodeName != "DIV"){
				if(StartHiddingFrom.className == "Visible")
					ShowHide(StartHiddingFrom, "Hide");
					StartHiddingFrom = StartHiddingFrom.parentNode;
			}
		}
		
		RemoveEvent(document, "click", Hide);
	}
	function ShowHide(Item, Action){
		if(Action == "Show"){
			Item.className = "Visible";
			Item.style.display = "block";
			Item.style.visibility = "visible";
		}
		else if(Action == "Hide"){/*IE has a problem with hidding elements only using css class*/
			Item.className = "Hidden";
			Item.style.display = "none";
			Item.style.visibility = "hidden";
		}
	}
	function GetSubMenu(Anchor){
	//Return a sub menu
		if(!Anchor.tagName){
			alert("It's not a HTML element");
			return false;
		}
		
		var childNode, colUnorderedList;
		
		childNode = Anchor.parentNode;
		while((childNode) && childNode.nodeName != "DIV" && childNode.nodeName != "LI")childNode = childNode.parentNode;
		colUnorderedList = childNode.getElementsByTagName("UL");
		
		if(colUnorderedList.length == 0){
			if(childNode.nextSibling)
				childNode = JumpTextNode(childNode, '+');
		}
		else{
			//in IE6 the close tag LI doesn't work, so the tag UL is a child of LI
			childNode = colUnorderedList[0];
		}
		if(childNode){
			if(childNode.nodeName == "LI"){
				return null;
			}
			else if(childNode.nodeName == "UL"){
				return childNode;
			}
		}
		else{
			return null;
		}
	}
	function GetItemMenu(UnorderedList){
	//UnorderedList: an UL element
		var Item = UnorderedList.parentNode;
		var colAnchors;
		
		if(Item.nodeName == "DIV")return null;
		if(Item.nodeName == "LI"){
		//UnorderedList is a child of LI
			colAnchors = Item.getElementsByTagName("A");
		}
		else if(Item.nodeName == "UL"){
			Item = JumpTextNode(UnorderedList, '-');
			colAnchors = Item.getElementsByTagName("A");
		}
		return colAnchors[0];
	}
	function HasSubMenu(Item){
		return (GetSubMenu(Item))?true:false;
	}
	function GetMenu(Anchor){
		if(!Anchor)return;
	
		var Menu = Anchor.parentNode;
		while((Menu) && Menu.nodeName != "DIV"){
			if(Menu.nodeName == "UL")break;;
			Menu = Menu.parentNode;
		}
		return Menu;
	}
	function GetItemDeep(Item){
		var i = 0;
		var Div = Item;
		while(Div){
			Div = Div.parentNode;
			if(Div.nodeName == "DIV")break;
			if(Div.nodeName == "UL")i++;
		}
		return i;
	}
	function SetPosition(Align){
		var LeftPos, TopPos;
		switch(Align){
			case 'b':
				var TopCorrection = -1;
				if(!m_isIE){
				/*Other browsers don't consider padding to calculate offsetTop as a child 
				item they also don't consider border but in this case it's not necessary*/
					TopCorrection = parseInt(GetStyle(m_ItemMenu, "padding-top"), 10);
				}
				//LeftPos = element_left(m_ItemMenu) + document.body.scrollLeft - ((m_isIE)?parseInt(GetStyle(m_ItemMenu, "padding-left"), 10):0);
				if(!m_isIE){
					var CurrentMenu = document.getElementById(m_ID);
					var parentEl = CurrentMenu.offsetParent;
					
					LeftPos = m_ItemMenu.offsetLeft;
					
					if(parentEl.nodeName == "TD")
						LeftPos += element_left(parentEl);
				}
				else{
					LeftPos = null;
				}
								
				if(m_TopCorrectionForIE && !m_isIE){
					m_TopCorrection = 0;
				}
				TopPos = element_top(m_ItemMenu) + m_ObjectAuthor.offsetHeight + TopCorrection - (m_TopCorrection);
			break;
			case 'l':
				if(m_ItemDeep > 1){//it's to sub of sub menu
					LeftPos = m_ItemMenu.offsetWidth + parseInt(GetStyle(m_ItemMenu, "padding-left"), 10);
					//TopPos = GetItemPosition(m_ItemMenu); //for IE is necessary to calculate (padding + border width) minus offsetTop
					TopPos = GetItemPosition(m_ItemMenu);
				}
				else{
					//LeftPos = element_left(m_ItemMenu) + m_ItemMenu.offsetWidth - ((m_isIE)?parseInt(GetStyle(m_ItemMenu, "padding-left"), 10):0);
					LeftPos = m_ItemMenu.offsetWidth + parseInt(GetStyle(m_ItemMenu, "padding-left"),10);
					TopPos = element_top(m_ItemMenu);
					if(m_isIE){
						TopPos = TopPos - (parseInt(m_ItemMenu.currentStyle.borderWidth, 10) + parseInt(m_ItemMenu.currentStyle.paddingTop, 10));
					}
				}
			break;
		}
		if(LeftPos)m_SubMenu.style.left = LeftPos + "px";
		m_SubMenu.style.top = TopPos + "px";
	}
	function GetItemPosition(Item){
	//return the sum height item to get the position of the element into the list
		var Menu = GetMenu(Item);
		var IECorrection;
		
		IECorrection = 0;
		if(Menu){
			if(m_isIE){//IE consider border and padding to offsetTop
				var ul = Item.parentNode.parentNode;
				if(ul.childNodes.length > 0){
					if(ul.childNodes[0] == Item.parentNode){//This fix is only to first element
						IECorrection = parseInt(Item.currentStyle.borderWidth, 10) + parseInt(Item.currentStyle.paddingTop, 10);
					}
				}
			}
			return Item.parentNode.offsetTop - IECorrection;
		}
		else{
			alert("GetItemPosition error: Item not found");
		}
		return null;
	}
	function element_top(el){
		var et = 0;
		while(el){
			et += el.offsetTop;
			el = el.offsetParent;
		}
		return et;
	}
	function element_left(el){
		var et = 0;
		while(el){
			et += el.offsetLeft;
			el = el.offsetParent;
		}
		return et;
	}
	function AddEvent(el, evname, func) {
		if(m_isIE){
			el.attachEvent("on" + evname, func);
		}else{
			el.addEventListener(evname, func, true);
		}
	}
	function RemoveEvent(el, evname, func){
		if(m_isIE){
			el.detachEvent("on" + evname, func);
		}else{
			el.removeEventListener(evname, func, true);
		}
	}
	function JumpTextNode(ObjectNode, Direction){
		var oNode = ObjectNode;
		if(Direction == '' || arguments.length < 2){
			alert("Parameter Direction was not found");
			return null;
		}
		if(Direction == '+'){
			oNode = oNode.nextSibling;
		}
		else if(Direction == '-'){
			oNode = oNode.previousSibling;
		}
		while(oNode && (oNode.nodeType != 1)){
			if(Direction == '+'){
				oNode = oNode.nextSibling;
			}
			else if(Direction == '-'){
				oNode = oNode.previousSibling;
			}
		}
		return oNode;
	}
	function GetStyle(oElm, strCssRule){
	/*
	This method came from http://www.robertnyman.com/2006/04/24/get-the-rendered-style-of-an-element/
	This script has been tested to work in the following web browsers:
   - IE 5.5+
   - Firefox
   - Safari
   - Opera 8.5
	*/
		var strValue = "";
		if(document.defaultView && document.defaultView.getComputedStyle){
			strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
		}
		else if(oElm.currentStyle){
			strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
				return p1.toUpperCase();
			});
			strValue = oElm.currentStyle[strCssRule];
		}
		return strValue;
	}
	function ParseItens(){
		var Menu = document.getElementById(m_ID);
		if(!Menu){
			alert('Menu parser error: Object was not found');
			return;
		}
		var colAnchors = Menu.getElementsByTagName("A");
		var Direction = Menu.className.indexOf("Horizontal");
		var Align, ItemMenu;
		
		if(m_isGecko || m_isOpera)document.body.className+= " INBMenubarNotIE";
				
		Direction = (Direction > -1)?'h':'v';
		
		for(i=0; i<colAnchors.length; i++){
			ItemMenu = colAnchors[i];
			Align = (GetItemDeep(ItemMenu) == 1 && Direction == 'h')?'b':'l';
			
			if(!m_isIE){//IE does not recognize events specified by setAttribute method
				ItemMenu.setAttribute("onmouseover", "o" + m_ID + ".Show(this,'" + Align + "');");
			}
			else{
				if(Align == 'b'){
					ItemMenu.onmouseover = function(){eval("o" + m_ID).Show(this, 'b');}
				}
				else if(Align == 'l'){
					ItemMenu.onmouseover = function(){eval("o" + m_ID).Show(this, 'l');}
				}
			}
			if(HasSubMenu(ItemMenu) || ItemMenu.getAttribute("disabled"))
					ItemMenu.onclick = function(){return false}
		}
	}
}
