/*=============================================================================

			 	 TITLE:		NetMediaOne - Drop Down Menu System
		  MODIFIED:		2007.02.21
		 AUTHOR(S): 	Graham Wheeler - NetMediaOne - www.netmediaone.com
		  REQUIRES:		NetMediaOne Core 1.1 w/Prototype 1.5.0

=============================================================================*/

NMO.DDMenuController = {
	
	menus: $A( new Array() ),
	activeMenuStack: $A( new Array() ),
	menuStackLevel: 900,
	hideDelay: 400,
	thinkTimer: "",
	menuOffsetX: 0,
	menuOffsetY: 40,
	shadowOffsetX: 5,
	shadowOffsetY: 5,
	menuOpacity: 1.0,
	shadowOpacity: 0.20,
	useDivShadow: false,

	init: function() {

		// Default state (Menus included via server-side processing)
		//NMO.DDMenuController.menuContainer = $(NMO.layoutWrapper);
		
		// Use Ajax to insert an external file containing the menus
		// (Useful for sites where menu cannot be included via server-side code)
		new Insertion.Top( $(NMO.layoutWrapper), '\n<div id="nmoMenuContainer">\n</div>' );
		NMO.DDMenuController.menuContainer = $("nmoMenuContainer");
		new Ajax.Updater( NMO.DDMenuController.menuContainer, NMO.rootPath + "menus.html", { method: "get", onComplete: function(rObj) {
			$$(".DropDownMenu").each( function(m) {
				NMO.DDMenuController.menus.push( new NMO.DropDownMenu(m) );
			} );
		} } );
		
		NMO.DDMenuController.think();
		
	},
	
	showMenu: function(menu) {
		// Immediately hide all menus
		NMO.DDMenuController.menus.each( function(m) {
			m.isActive = false;
			m.hide();
		} );
		// Rebuild the active menu stack
		NMO.DDMenuController.activeMenuStack.clear();
		NMO.DDMenuController.menuStackLevel = 900;
		var menuList = menu.getAncestors( $A( new Array() ) );	
		
		// Show menus in correct order
		NMO.DDMenuController.activeMenuStack = menuList.reverse();
		NMO.DDMenuController.activeMenuStack.each( function(m) {
			m.show();
		} );
	},

	getMenuByID: function(menuID) {
		return NMO.DDMenuController.menus.detect( function(menu) {
			return ( menu.container.id == menuID );
		} );
	},
	
	think: function() {
		clearTimeout( NMO.DDMenuController.thinkTimer );
		if ( NMO.DDMenuController.activeMenuStack.length > 0 ) {			
			var menu = NMO.DDMenuController.activeMenuStack.last();
			if ( !menu.checkFocus() ) {
				menu.isActive = false;
				menu.hideTimer = setTimeout( function() { this.hide(); }.bind(menu), NMO.DDMenuController.hideDelay );
			} else {
				menu.isActive = true;
			}
		}
		NMO.DDMenuController.thinkTimer = setTimeout( function() { NMO.DDMenuController.think(); }, 50 );
	}

};


NMO.DropDownMenu = Class.create();
NMO.DropDownMenu.prototype = {

	initialize: function(elementRef) {
		this.hideTimer = "";
		this.isActive = false;
		this.boundingElements = $A( new Array() );
		this.container = $(elementRef);
		this.boundingElements.push(this.container);
		this.boundTo = $( this.container.getAttribute("bindto") );
		if ( NMO.DDMenuController.useDivShadow && !NMO.isMac ) {
			this.shadow = document.createElement("div");
		} else {
			this.shadow = document.createElement("iframe");
			this.shadow.setAttribute( "frameborder", "0" );
			this.shadow.setAttribute( "scrolling", "no" );
			this.shadow.setAttribute( "src", NMO.rootPath + "menushadow.html" );
		}
		this.shadow = $(this.shadow);
		this.shadow.addClassName("DropDownMenuShadow");
		NMO.DDMenuController.menuContainer.appendChild(this.shadow);
		this.container.setStyle( { opacity: NMO.DDMenuController.menuOpacity } );
		this.shadow.setStyle( { opacity: NMO.DDMenuController.shadowOpacity } );
		this.container.style.width = Number( this.container.getAttribute("menuwidth") || 160 ) + "px";
		this.leftOffset = Number( this.container.getAttribute("leftoffset") || NMO.DDMenuController.menuOffsetX );
		this.topOffset = Number( this.container.getAttribute("topoffset") || NMO.DDMenuController.menuOffsetY );	
		this.parent = NMO.DDMenuController.getMenuByID(	 this.container.getAttribute("parent") );
		this.group = this.container.getAttribute("menugroup") || "default";
		if ( this.boundTo != null ) {
			Event.observe( this.boundTo, "mouseover", function(e) { NMO.DDMenuController.showMenu(this); }.bind(this), false );
			this.boundingElements.push(this.boundTo);
		}

		// Squash layout disruption in Gecko browsers
		this.container.style.display = "block";
		this.shadow.style.display = "block";
		this.container.style.display = "none";
		this.shadow.style.display = "none";
	},
	
	show: function() {
		clearTimeout( this.hideTimer );
		NMO.DDMenuController.menuStackLevel += 10;
		this.shadow.style.zIndex = NMO.DDMenuController.menuStackLevel;
		this.container.style.zIndex = NMO.DDMenuController.menuStackLevel + 1;
		this.container.style.display = "block";
		this.shadow.style.display = "block";
		if ( this.boundTo != null ) {
			Position.clone( this.boundTo, this.container, { setWidth: false, setHeight: false, offsetTop: this.topOffset, offsetLeft: this.leftOffset } );
			Position.clone( this.container, this.shadow, { offsetTop: NMO.DDMenuController.shadowOffsetY, offsetLeft: NMO.DDMenuController.shadowOffsetX } );
			if ( !Element.hasClassName( this.boundTo, "Hovered" ) ) {
				Element.addClassName( this.boundTo, "Hovered" );
			}
		}
		this.isActive = true;
	},
	
	getAncestors: function(menuList) {
		menuList.push(this);
		if ( this.parent != null ) {
			menuList = this.parent.getAncestors(menuList);
		}
		return menuList;
	},
	
	checkFocus: function() {
		// Check to see if the mouse cursor is somewhere inside the active menu's bounding box
		var be = this.boundingElements.detect( function(el) {	return Position.within( el, NMO.mouseX, NMO.mouseY ); } );
		return ( (be != null)?true:false );
	},
	
	hide: function() {
		clearTimeout( this.hideTimer );
		if ( !this.isActive ) {
			NMO.DDMenuController.activeMenuStack.pop();
			NMO.DDMenuController.menuStackLevel = NMO.DDMenuController.menuStackLevel - 10;
			this.shadow.style.display = "none";
			this.container.style.display = "none";
			if ( this.boundTo != null && Element.hasClassName( this.boundTo, "Hovered" ) ) {
				Element.removeClassName( this.boundTo, "Hovered" );
			}
		}
	}

};

Event.observe( window, "load", NMO.DDMenuController.init, false );
