/**
 * Class for the dynamic menu.
 * 
 * Requires Prototype JS version 1.5.0 or greater. (Also supports version
 * 1.6.0.*, avoiding all deprecated methods) http://www.prototypejs.org/
 * 
 * Copyright 2007-2008 Charming Design, Niek Kouwenberg
 * http://www.charmingdesign.net/
 * 
 * Special thanks to CARE Internet Services B.V. http://www.care.nl/
 */
Menu = {

	/* Version of the Menu class */
	Version : "1.1",

	/*
	 * CONSTANTS
	 */

	/* Constant for a horizontal menu */
	HORIZONTAL : 1,

	/* Constant for a vertical menu */
	VERTICAL : 2,

	/*
	 * MENU
	 */

	/* Hold the ID of the menu */
	_menuId : null,

	/* Hold the menu UL node */
	_menuNode : null,

	/*
	 * TEMPORARY VARIABLES
	 */

	/* Hold the hide timer */
	_hideTimeout : null,

	/* Will hold the active A element */
	_activeLink : null,

	/* Will hold the active UL element */
	_activeSubMenu : null,

	/*
	 * OPTIONS
	 */

	/* Orientation of the menu (horizontal or vertical) */
	_orientation : 1,

	/* Time in milliseconds before hiding the sub menu */
	_hidePause : 1500,

	/* Opacity (0 = transparent, 1 = opaque) */
	_opacity : 1,

	_imgpath : '/img/menu/',

	/*
	 * METHODS
	 */

	/**
	 * Sets the time to wait before hiding the sub menu.
	 * 
	 * @param int
	 *            secs
	 * 
	 * @deprecated Please use the options argument for Menu.init() instead.
	 */
	setHidePause : function(secs) {
		Menu._hidePause = secs * 1000;

		/* deprecation warning */
		alert("Deprecated method Menu.setHidePause() used: Please use the options argument for Menu.init().");
	}, // function setHidePause

	/**
	 * Initializes the dynamic menu.
	 * 
	 * @param string
	 *            menuId
	 * @param object
	 *            options
	 * 
	 * Available options: - orientation (int, Menu.HORIZONTAL or Menu.VERTICAL) -
	 * hidePause (float, seconds) - opacity (float; 0 = transparent, 1 = opaque,
	 * transparency of the sub menu)
	 * 
	 * Example usage:
	 * 
	 * 
	 * This method can be called after document load, but it is preferred to be
	 * called directly from your page (HTML <head>, before document load). This
	 * way the menu loads faster and can be interacted with much sooner.
	 */
	init : function(menuId, options) {
		/* Save menu ID (fall back to the default ID "menu") */
        
		Menu._menuId = (typeof menuId == "string") ? menuId : "menu";
   
		/* Save options */
		if (options) {
			/* Orientation */
			if (options.orientation != undefined) {
				Menu._orientation = options.orientation;
			}
			/* Hide timeout in seconds */
			if (options.hidePause != undefined) {
				Menu._hidePause = options.hidePause * 1000;
			}
			/* Sub menu opacity */
			if (options.opacity != undefined) {
				Menu._opacity = options.opacity;
			}

			/* Sub menu opacity */
			if (options.imgpath != undefined) {
				Menu._imgpath = options.imgpath;
			}
		}

		/*
		 * Check if the document is already loaded. Prototype 1.6.0 introduces
		 * the document.loaded boolean, for 1.5*, check if we can retrieve an
		 * element from the DOM (fails when document is not loaded).
		 */
		if (document.loaded === true || $(Menu._menuId)) {
			Menu._doInit();
		}
		/* This is how it should work (init called before document load) */
		else {
			/*
			 * Do the actual initialization on document load. The "dom:loaded"
			 * event is prefered, but only available since 1.6.0 (with
			 * document.observe construction). Fallback to the window onload
			 * when not available.
			 */
			if (document.observe) {
				document.observe("dom:loaded", Menu._doInit);
			} else {
				Element.observe(window, "load", Menu._doInit);
			}
		}
	}, // function init

	/**
	 * Initializes the drop down menu.
	 * 
	 * Should be called on page load.
	 */
	_doInit : function() {
		/* After the DOM is loaded, save the menu node */
		Menu._menuNode = $(Menu._menuId);

		/* Find all first level menu nodes */
		var elements = (Element.select)
				? Menu._menuNode.select("li")
				: Menu._menuNode.getElementsBySelector("li");
		for (var i = 0; i < elements.length; i++) {

			/* Check if it has a sub menu */
			if (((Element.select)
					? elements[i].select("ul").length
					: elements[i].getElementsBySelector("ul").length) > 0) {

				/* Add expand/collapse listeners to the node link */
				var a = (Element.select)
						? elements[i].select("a")[0]
						: elements[i].getElementsBySelector("a")[0];
				Element.observe(elements[i], "mouseover", Menu._showSubMenu
								.bind(elements[i]));
				Element.observe(elements[i], "mouseout", Menu._hideSubMenu
								.bind(elements[i]));

				/* Add "submenu" class for this node link */
				Element.addClassName(a, "submenu");

			}
			/* No sub menu */
			else {
				/* Only hide any expanded sub menu when hovering this node */
				Element.observe(elements[i], "mouseout", Menu._changeImg);
				Element.observe(elements[i], "mouseover",
						Menu._quickHideSubMenu);
				

			}
		}
	}, // function _doInit
	_changeImg : function(e) {
		var img = $(Event.element(e));

		if (img.tagName.toLowerCase() == 'img' && img.name != "")
			$(img).src = Menu._imgpath + img.name + '.gif';
	},
	/**
	 * Shows the sub menu.
	 */
	_showSubMenu : function(e) {

		/* Get node link and sub menu */
		var a = (Element.select) ? this.select("a")[0] : this
				.getElementsBySelector("a")[0];
		var subMenu = (Element.select) ? this.select("ul")[0] : this
				.getElementsBySelector("ul")[0];

		if (subMenu.style.display != 'block') {

			/* Hide previous opened sub menu */
			Menu._quickHideSubMenu();

			/* Keep hover style as long as opened */
			Element.addClassName(a, "menu_open");

			var img = $(a).down('img');

			if ($(a).down('img')) {
				$(a).down('img').src = Menu._imgpath + img.name + '-over.gif';
			}

			/* Show sub menu */
			Element.setStyle(subMenu, {
						"display" : "block"
					});

			/* Set correct position */
			var pos = (Element.positionedOffset)
					? this.positionedOffset()
					: Position.positionedOffset(this);

			if (Menu._orientation == Menu.HORIZONTAL) {

				var menuoffset = Menu._menuNode.cumulativeOffset()[0]
						+ Menu._menuNode.getWidth();
				var switchoffset = 0;

				if (menuoffset < subMenu.cumulativeOffset()[0]
						+ subMenu.getWidth()) {
					var switchoffset = -(subMenu.getWidth() - a.getWidth());
				}

				if (subMenu.style.left == "") {
					subMenu.setStyle({
								"left" : pos[0] + switchoffset + "px",
								"top" : (pos[1] + this.getHeight()) + "px"
							});

					Event.observe(window, 'resize', function() {
								subMenu.style.left = "";
							});

				}
			} else if (Menu._orientation == Menu.VERTICAL) {
				subMenu.setStyle({
							"left" : (pos[0] + this.getWidth()) + "px",
							"top" : pos[1] + "px"
						});
			}

			/* Apply opacity if not fully opaque */
			if (Menu._opacity > 0 && Menu._opacity < 1) {
				subMenu.setOpacity(Menu._opacity);
			}

			/* Save submenu */
			Menu._activeLink = a;
			Menu._activeSubMenu = subMenu;
		}
	}, // function _showSubMenu

	/**
	 * Immediately hides the active menu.
	 */
	_quickHideSubMenu : function() {

		/* Clear possible timeout */
		if (Menu._hideTimeout) {
			window.clearTimeout(Menu._hideTimeout);
		}

		/* And hide the menu */
		Menu._doHideSubMenu(Menu._activeLink, Menu._activeSubMenu);
	}, // function _quickHideSubMenu

	/**
	 * Method for hiding the sub menu, takes
	 */
	_hideSubMenu : function() {

		/* Get node link and submenu */
		var a = (Element.select) ? this.select("a")[0] : this
				.getElementsBySelector("a")[0];
		var subMenu = (Element.select) ? this.select("ul")[0] : this
				.getElementsBySelector("ul")[0];

		/* No pause? Don't use the timeout */
		if (Menu._hidePause <= 0) {
			/* Hide the menu */
			Menu._doHideSubMenu(a, subMenu);
		} else {
			/* Hide in x (milli)seconds */
			Menu._hideTimeout = window.setTimeout(function() {
						Menu._doHideSubMenu(a, subMenu);
					}, Menu._hidePause);
		}
	}, // function _hideSubMenu
	/**
	 * Does the actual hiding the the sub menu.
	 * 
	 * @param node
	 *            a (A)
	 * @param node
	 *            subMenu (UL)
	 */
	_doHideSubMenu : function(a, subMenu) {
		/* Remove hover style */
		if (a) {
			Element.removeClassName(a, "menu_open");
			var img = $(a).down('img');
			if ($(a).down('img')) {
				$(a).down('img').src = Menu._imgpath + img.name + '.gif';
			}
		}
		/* Hide sub menu */
		if (subMenu) {
			Element.setStyle(subMenu, {
						"display" : "none"
					});
		}
	} // function _doHideSubMenu

}; // class Menu


