/**
 * @fileoverview EasyGUI MenuTree Script
 *
 * This Class creates whether a fully functional TreeCtrl or MenuCtrl
 *
 * @author Gaetan Lauff <glauff@plansoft.de>
 * @package 	js.widgets
 * 
 * @version	$Id: class.menu.js 260 2007-04-26 13:13:42Z glauff $
 */
var zIndex= 100000;

/**
 * @class	EasyGUI_MenuTree
 * @constructor
 * @param	{string}	id	ID of Widget to create
 * @returns	void
 * @access	public
 */
var EasyGUI_Menu = Class.create();

Object.extend( Object.extend( EasyGUI_Menu.prototype, EasyGUI_widget.prototype), 
{
	/**
	 * @private
	 */
	activeButton: null,
	
	/**
	 * @private
	 */
	activeContextMenu: null,
	
	/**
	 * @private
	 */
	cmi: null,
	
	/**
	 * @type boolean
	 * @private
	 */	
	activateOnMouseover: null,
	
	/**
	 * @type string
	 * @private
	 */
	orientation: 'horizontal',
	
	/**
	 * @type string
	 * @private
	 */
	isContextMenu: null,
	
	/**
	 * @type string
	 * @private
	 */
	defaulticon: null,
	
	/**
	 * @type string
	 * @private
	 */
	icons: null,
	
	/**
	 * @type	object
	 * @private
	 */
	submitHandler: null,
	
	/**
	 * @private
	 */
	render: function()
	{
		this.activateOnMouseover 	= Element.getAttributeValue( this.element, 'activateonmouseover' ),
		this.orientation 			= Element.getAttributeValue( this.element, 'orientation', this.orientation ),
		this.isContextMenu 			= Element.getAttributeValue( this.element, 'contextmenu' ),
		this.defaulticon 			= Element.getAttributeValue( this.element, 'defaulticon', ek_path + '/gfx/blank.gif' ),
		this.icons 					= Element.getAttributeValue( this.element, 'icons' );
		
		if ( isEmptyValue(this.element.className) ) {
			this.element.className = 'easygui-menu';
		}
		
		if ( !this.isContextMenu ) {
			this.menubuttons = [];
			this.menubar = this.buildMenubar();
			this.element.parentNode.appendChild( this.menubar );
		} else {
			this.buildContextMenu();
		}
		
		Event.observe(document, 'mousedown', this.pageMousedown.bindAsEventListener(this) );
		
		if ( this.element.onclick ) {
			this.submitHandler = this.element.onclick;
			this.element.onclick = null;
		} else {
			this.submitHandler = navigate;
		}
	},
	
	/**
	 * Builds a Context Menu
	 * @private
	 */
	buildContextMenu: function()
	{
		this.buildMenu( this.element, true, this.id );
		
		if ((contextElementId = Element.getAttributeValue(this.element, 'contextelement') ) == false ) {
			this.contextElement = document;
			this.cmi = this.id;
		} else {
			this.contextElement = $(contextElementId);
			this.contextElement.setAttribute('contextmenuid', this.id );
		}
		
		Event.observe( this.contextElement, "contextmenu", this.displayContextMenu.bindAsEventListener( this ) );
		Event.observe( this.contextElement, "click", this.hideContextMenu.bindAsEventListener( this ) );
	},
	
	/**
	 * Builds the Menubar
	 *
	 * @returns	object
	 * @private
	 */
	buildMenubar: function ()
	{
		var menubar = document.createElement( 'DIV' );
		document.body.appendChild( menubar );
		
		menubar.className 	= this.getStyleDefinition('menubar');
		
		var position = this.element.style.position;
		var width = this.element.style.width;
			
		menubar.style.position = position;
		menubar.style.width = width;
		menubar.style.margin = '0px';
		
		Element.setPosition( menubar, this.element.style.top, this.element.style.left );
		
		var menubuttons = Element.getChildNodesByTagName( this.element, 'DIV' );
		
		/*
		 Kleiner Denkanstoß
		 
		$A(menubuttons).each( function( menubutton ) {
			if ( getItemDepth( menubutton, 'DIV', 'Menu' ) == 0 ) {
				menubutton = Element.getFirstChildByTagName( menubutton, 'A' );
			}
		});
		*/
		for (var i=0; i < menubuttons.length; i++) {
			if (Element.getDepth( menubuttons[i], 'DIV', 'Menu' ) == 0) {
				menubutton = Element.getFirstChildByTagName( menubuttons[i], 'A');
			
				menubutton.className = this.getStyleDefinition('menubutton');
				menubutton.menuId = menubutton.id + '_MENU';
				
				if (this.orientation == 'vertical') {
					//menubutton.style.display = 'block';
				}
				
				//menubutton.onfocus = function() { this.blur() };
				Event.observe(menubutton, "focus", this.onFocus.bindAsEventListener(this) );
				Event.observe(menubutton, 'click', this.openMenu.bindAsEventListener(this), false);
				Event.observe(menubutton, 'mouseover', this.menuButtonOver.bindAsEventListener(this), false);
				
				menubar.appendChild( menubutton );
				
				if (is.ie5) {
					menubutton.style.width = '10px';
				}
	
				this.buildMenu( menubuttons[i], true, menubutton.id );
			}
		}
		
		return menubar;
	},
	
	/**
	 * Function to Menu from MenuStructure
	 * Called Recursive*
	 * @param	{object}	menuitem
	 * @param	{bool}		isButton
	 * @param	{string}	parentId
	 * @param	{string}	parentMenu
	 * @returns void
	 * @private
	 */
	buildMenu: function ( menuitem, isButton, parentId, parentMenu )
	{
		if (! Element.hasChildNodesWithTagName( menuitem, 'DIV' )) {
			return;
		}
		
		if (!isButton) {
			var parentMenuItem = Element.getFirstChildByTagName( menuitem, 'A');
			var menuItemIcon = this.getIcon( menuitem );
			
			var menuId = parentMenuItem.id + '_MENU';				
			var menuItemText = document.createElement('span');
							
			menuItemText.className = this.getStyleDefinition('menuitem') + '-text';
			menuItemText.menuId = menuId;
							
			var menuItemArrow = document.createElement('span');
						
			menuItemArrow.className = this.getStyleDefinition('menuitem') + '-arrow';
			menuItemArrow.menuId = menuId;
							
			menuItemText.innerHTML = parentMenuItem.innerHTML;
			
			if ( is.ie5up ) {
				menuItemArrow.innerHTML = '<b>></b>';
			} else {
				menuItemArrow.innerHTML = '<b>&#9658;</b>';
			}
			
			parentMenuItem.innerHTML = '';
			
			if (menuItemIcon) {
				parentMenuItem.appendChild(menuItemIcon);
			}
				
			parentMenuItem.appendChild(menuItemText);
			parentMenuItem.appendChild(menuItemArrow);
	
			parentMenuItem.menuId = menuId;
			
			Event.observe( parentMenuItem, 'mouseover', this.menuItemOver.bindAsEventListener( this) );
			Event.observe( parentMenu, 'mouseover', this.menuOver.bindAsEventListener( this ) );
		}
	
		var menu = document.createElement('DIV');
		
		menu.style.lineHeight = '2.5ex';
		menu.style.zIndex = zIndex++;
						
		menu.id = parentId + '_MENU';
						
		menu.className 	= this.getStyleDefinition('menu');
		menu.setAttribute('isMenu', 'true');
		
		var cNodes  = Element.getChildNodesByTagName( menuitem, 'DIV' );
		
		for (var i=0; i < cNodes.length; i++) {
			menuitem = Element.getFirstChildByTagName( cNodes[i], 'A');
			var sep =  Element.getAttributeValue(menuitem, 'separator');
	
			if ( sep ) {
				menu.appendChild(this.getSeparator());
				continue;
			}
			
			//menuitem.onfocus = function() { this.blur(); };
			Event.observe(menuitem, "focus", this.onFocus.bindAsEventListener(this) );
			this.buildMenu(cNodes[i], false, menuitem.id, menu);
			menuitem.className = this.getStyleDefinition('menuitem');
			
			if (! Element.hasChildNodesWithTagName(menuitem, 'SPAN') ) {
				var menuItemIcon = this.getIcon( cNodes[i] );
				var menuItemText = document.createElement('span');
				var menuItemLabel = document.createTextNode( Element.getInnerText(menuitem) );
				
				menuItemText.className = this.getStyleDefinition('menuitem') + '-text';
				menuitem.innerHTML 		= '';
				menuItemText.appendChild( menuItemLabel );
				menuItemText.itemId 	= menuitem.id;
				
				if (menuItemIcon) {
					menuitem.appendChild( menuItemIcon );
				}
					
				menuitem.appendChild( menuItemText );
				
				Event.observe( menuitem, 'click', this.onClick.bindAsEventListener( this ) );
			}
			
			menu.appendChild( menuitem );
		}
		
		document.body.appendChild(menu);
		this.correctMenu(menu);
	},
	
	onFocus : function( evt )
	{
		var element = $GE(evt);
		element.blur();
	},
	
	/**
	 * Enables a menuitem
	 * @param	element		DOM Element or ID
	 * @public
	 */
	enable: function( element )
	{
		var element = $( element );
		element.disabled = false;
	},
	
	/**
	 * Disables a menuitem
	 * @param	element		DOM Element or ID
	 * @public
	 */
	disable: function( element )
	{
		var element = $( element );
		element.disabled = true;
	},
	
	/**
	 * @param	{object} menuitem	DOM Element
	 * @returns	an Icon for menu
	 * @private
	 */
	getIcon: function(menuitem)
	{
		if (!this.icons) {
			return false;
		}
		
		var menuItemIcon = document.createElement('span');
		menuItemIcon.className = this.getStyleDefinition('menuitem') + '-icon';
			
		var iconImg = document.createElement('img');	
		var icon = Element.getAttributeValue(menuitem, 'icon', this.defaulticon);
			
		iconImg.src 			= icon;
		iconImg.border 			= 0;
		
		iconImg.style.position = 'relative';
		Element.setDimension( iconImg, '16px', '16px');
		
		iconImg.height 	= 16;
		iconImg.width 	= 16;
		
		menuItemIcon.appendChild( iconImg );
		
		return menuItemIcon;
	},
	
	/**
	 * Corrects the Menu dimensions
	 * @param	{object}	menu	DOM Element
	 * @returns	void
	 * @private
	 */
	correctMenu: function ( menu )
	{
		var itemList = menu.getElementsByTagName("A");
		
		if (itemList.length > 0) {
			itemWidth = itemList[0].offsetWidth;
		} else {
			return;
		}
		
		for (i = 0; i < itemList.length; i++) {
			spanList = itemList[i].getElementsByTagName("SPAN");
			
			textEl  = null;
			arrowEl = null;
			
			for (j = 0; j < spanList.length; j++) {
		  		if ( Element.hasClassName(spanList[j], this.getStyleDefinition("menuitem") + "-text")) {
		  			textEl = spanList[j];
		  		}
		  			
		  		if ( Element.hasClassName(spanList[j], this.getStyleDefinition("menuitem") + "-arrow")) {
		    		arrowEl = spanList[j];
		  		}
		  	}
			
			if (textEl != null && arrowEl != null) {
	  			textEl.style.paddingRight = (itemWidth - ( textEl.offsetWidth  + arrowEl.offsetWidth)) + "px";
			
	  			if (is.opera5up) {
	    			arrowEl.style.marginRight = '0px';
	  			}
			}
			
		}
		
		if (is.ie5up) {
			w = itemList[0].offsetWidth;
			itemList[0].style.width = w + 'px';
			
			dw = itemList[0].offsetWidth - w;
			w -= dw;
			
			itemList[0].style.width = w + 'px';
			
			menu.iframeEl = menu.parentNode.insertBefore( Util.getIframe(), menu);
			
			Element.hide( menu.iframeEl );
			menu.iframeEl.style.position = 'absolute';
			menu.iframeEl.style.zIndex = 10000;
		}
		
		menu.isInitialized = true;
	},
	
	/**
	 * @param	{object} menuitem	DOM Element
	 * @returns	a separator for Menu
	 * @private
	 */
	getSeparator: function( menuitem )
	{
		var separator = document.createElement( 'DIV' );
		separator.className = this.getStyleDefinition('menuitem') + '-separator';
		return separator;
	},
	
	/**
	 * Opens Menu
	 * This method is called when the user clicks on a menuutton
	 *
	 * @param	{object} evt	Current Event Object
	 * @returns	void
	 * @private
	 */
	openMenu: function( evt )
	{
		var button = $GE( evt );
		button.blur();
	
		if ( this.activeButton != null ) {
			this.resetButton( this.activeButton );
		}
		
		if ( button != this.activeButton ) {
			this.activeButton = button;
			this.menuButtonOut();
		} else {
			this.activeButton = null;
		}
	},
	
	/**
	 * Handles Mousover on Button
	 * @param	{object}	evt		Current Event Object
	 * @returns	void
	 * @private
	 */
	menuButtonOver: function( evt )
	{
		var button = $GE( evt );
		
		if ( this.activateOnMouseOver) {
			if ( this.activeButton == null ) {
				this.openMenu( evt );
				return;
			}
		}
		
		if ( this.activeButton != null && this.activeButton != button ) {
			this.openMenu( evt );
		}
	},
	
	/**
	 * Handles Mouseout on Button
	 * @param	{object}	button	DOM Element
	 * @returns	void
	 * @private
	 */
	menuButtonOut: function()
	{
		var x, y;
		var button = this.activeButton;
		
		button.className += ' ' + this.getStyleDefinition("menubutton") + "-active";
		var menu = $(button.menuId);
		
		if (this.activateOnMouseover) {
			Event.observe( button, 'mouseout', buttonOrMenuMouseout, false );
			
			if ( menu != null )
	  			Event.observe( menu, 'mouseout', buttonOrMenuMouseout, false );
		}
	
		var pos = Position.cumulativeOffset( button );
		x = pos[0];
		y = pos[1];
		
		if (button.style.display == 'block') {
			x += button.offsetWidth;
		} else {
	  		y += button.offsetHeight;
		}
		
	  	if (menu != null) {
	  		Element.setPosition( menu, y, x );
	  		Element._show( menu );
	
	  		if (menu.iframeEl != null) {
	    		Element.setPosition( menu.iframeEl, y , x );
	    		Element.setDimension( menu.iframeEl, menu.offsetWidth, menu.offsetHeight );
	    		Element.show( menu.iframeEl );
	  		}
		}
	},
	
	/**
	 * Resets Button to normal state
	 * @param	{object}	button	DOM Element
	 * @returns	void
	 * @private
	 */
	resetButton: function( button )
	{
		Element.removeClassName( button, this.getStyleDefinition("menubutton") + '-active' );
		var menu = $(button.menuId);
		
		if ( menu != null ) {
			this.closeSubMenu( menu );
			
			menu.style.visibility = "hidden";
		    	
			if (menu.iframeEl != null) {
		  		menu.iframeEl.style.display = "none";
			}
		}
	},
	
	/**
	 * Handles Menu Over
	 * @param	{object}	evt		Current Event Object
	 * @returns	void
	 * @private
	 */
	menuOver: function( evt )
	{
		var menu = $GE(evt);
		
		if (menu.nodeName != 'DIV') {
			menu = Element.getParentElementByTagName( menu, 'DIV');
		}
		
	  	if (menu.activeItem != null) {
	    	this.closeSubMenu(menu);
	  	}
	},
	
	/**
	 * Handler for MenuItemMouseOver
	 * @param	{object}	evt		Current Event Object
	 * @returns	void
	 * @private
	 */
	menuItemOver: function( evt )
	{
		var x, y;
		var element = $GE(evt);
	
		var item = Element.getParentElementByTagName( element, 'A');
		var menu = Element.getParentElementByTagName( item, 'DIV' );
		
	  	if (menu.activeItem != null)
	    	this.closeSubMenu(menu);
	  	
	    if (menu.activeItem == item )
	    	return;
	    	
	    menu.activeItem = item;
	    
	  	item.className += " " + this.getStyleDefinition("menuitem") + "-over";
	  	
	  	if (item.subMenu == null)
	    	item.subMenu = $(item.menuId);
	    	
	    if (this.activateOnMouseover) {
	    	if (item.subMenu.onmouseout == null) {
	    		Event.observe( item.subMenu, 'mouseout', this.buttonOrMenuMouseout.bindAsEventListener(this) );
	    	}
	    }
	    
	    var itempos = Position.cumulativeOffset( item );
	    
	  	x = itempos[0] + item.offsetWidth;
	  	y = itempos[1]
	  	
	  	var maxX, maxY;
	
	  	if (is.ie5up) {
	    	maxX = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft) +
	      		(document.documentElement.clientWidth != 0 ? document.documentElement.clientWidth : document.body.clientWidth);
	    	maxY = Math.max(document.documentElement.scrollTop, document.body.scrollTop) +
	      		(document.documentElement.clientHeight != 0 ? document.documentElement.clientHeight : document.body.clientHeight);
	  	}
	  	
	  	if (is.opera5up) {
	    	maxX = document.documentElement.scrollLeft + window.innerWidth;
	    	maxY = document.documentElement.scrollTop  + window.innerHeight;
	  	}
	  	
	  	if (is.nav6up || is.gecko) {
	   		maxX = window.scrollX + window.innerWidth;
	    	maxY = window.scrollY + window.innerHeight;
	  	}
	  	
	  	maxX -= item.subMenu.offsetWidth;
	  	maxY -= item.subMenu.offsetHeight;
	
	  	if (x > maxX) {
	    	x = Math.max(0, x - item.offsetWidth - item.subMenu.offsetWidth + (menu.offsetWidth - item.offsetWidth));
	  	}
	  		
	    y = Math.max(0, Math.min(y, maxY));

	    
	  	item.subMenu.style.left       = x + "px";
	  	item.subMenu.style.top        = y + "px";
	  	item.subMenu.style.visibility = "visible";
		
	  	if (item.subMenu.iframeEl != null) {
	    	item.subMenu.iframeEl.style.left    = item.subMenu.style.left;
	    	item.subMenu.iframeEl.style.top     = item.subMenu.style.top;
	    	item.subMenu.iframeEl.style.width   = item.subMenu.offsetWidth + "px";
	    	item.subMenu.iframeEl.style.height  = item.subMenu.offsetHeight + "px";
	    	item.subMenu.iframeEl.style.display = "";
	  	}
	  	
		Event.stop( evt );
	},
	
	/**
	 * Closes SubMenu
	 * @param	{object}	menu
	 * @returns	void
	 * @private
	 */
	closeSubMenu: function( menu )
	{
		if (menu == null || menu.activeItem == null) {
	    	return;
		}
	
	  	if (menu.activeItem.subMenu != null) {
	    	this.closeSubMenu(menu.activeItem.subMenu);
	
	    	menu.activeItem.subMenu.style.visibility = "hidden";
	    	
			if (menu.activeItem.subMenu.iframeEl != null) {
	      		menu.activeItem.subMenu.iframeEl.style.display = "none";
			}
	      		
	    	menu.activeItem.subMenu = null;
	  	}
	
	  	Element.removeClassName(menu.activeItem, this.getStyleDefinition("menuitem") + "-over");
	  	menu.activeItem = null;
	},
	
	/**
	 * Detects Mousedown Event on Page and closes Menu if necesarry
	 * @param	{object} evt	Current Event Object
	 * @returns	void
	 * @private
	 */
	pageMousedown: function( evt )
	{
		var el = $GE(evt);
		
		if (this.activeButton == null) {
	    	return;
		}
	    	
		if (el == this.activeButton) {
			return;
		}
	
		if (!Element.hasParentWithAttribute( el, 'isMenu')) {
			this.resetButton( this.activeButton );
		    this.activeButton = null;
		}
	},
	
	/**
	 * Close Menu when Mouse leaves Menu
	 * @param	{object} evt	Current Event Object
	 * @returns	void
	 * @private
	 */
	buttonOrMenuMouseout: function( evt ) 
	{
		if (this.activeButton == null) {
	    	return;
	  	}
	    
	    var el = getTargetElement(evt);
	 
	  	if (!Element.hasParentWithAttribute( el, 'isMenu')) {
	    	this.resetButton( this.activeButton );
	    	this.activeButton = null;
	  	}
	},
	
	/**
	 * Close Menu on Mousedown in frame
	 * @param	{object} evt	Current Event Object
	 * @returns	void
	 * @private
	 */
	frameMousedown: function( evt )
	{
		if (this.activeButton == null) {
	    	return;
		}
	    	
		this.resetButton( this.activeButton );
		this.activeButton = null;
	},
	
	/**
	 * Hides Context Menu
	 * @param	{object}	evt		Current Event Object
	 * @returns	void
	 * @private
	 */
	hideContextMenu: function( evt )
	{
		if (this.activeContextMenu != null ) {
			this.activeContextMenu.style.visibility = 'hidden';
		}
		
		Event.stop( evt );
		return false;
	},
	
	/**
	 * Displays ContextMenu
	 * @param	{object}	evt		Current Event Object
	 * @returns	void
	 * @private
	 */
	displayContextMenu: function( evt ) 
	{
		if ( this.activeContextMenu != null ) {
			Element.show( this.activeContextMenu );
		}
		
		var element = $GE( evt );
		var contextMenuId = Element.getAttributeValue( element, 'contextmenuid' );
	
		if ( !contextMenuId ) {
			contextMenuId = this.cmi;
		}
		
		var contextMenu = $( contextMenuId + '_MENU' );
	
		x = Event.pointerX( evt );
		y = Event.pointerY( evt );
		
		x -= 2; y -= 2;
	
		Element.setPosition( contextMenu, y, x );
		Element._show( contextMenu );
		Event.stop( evt );
		
		this.activeContextMenu = contextMenu;
		return false;
	},
	
	/**
	 * Handles Click on MenuItem
	 * @param	{object}	evt		Current Event Object
	 * @returns	void
	 * @private
	 */
	onClick: function( evt )
	{	
		var element = Element.getParentElementByTagName( $GE(evt), 'A' );
		
		if ( element.disabled ) {
			return;
		}
		
		this.submitHandler.call( this, element );
		this.pageMousedown( this.id );
		Event.stop( evt );
	},
	
	/**
	 * Shows the Widget
	 *
	 */
	show: function()
	{
		Element.show( this.menubar );
	},
	
	/**
	 * Hides the Widget
	 *
	 */
	hide: function()
	{
		Element.hide( this.menubar );
	}
});