jss.module.menu = function (element) {
	var HOVER = "hover";
	var HOVEROFF = "hoveroff";

	// If element is a string, then find the object
	if (jss.object.isString(element)) { element = $(element); }

	// Load the skin - if there is no skin then use the default
	var skin = jss.skin.menu;
	var jssSkin = element.getAttribute(jss.keywords.jssSkin);
	if (!jss.object.isEmpty(jssSkin)) {
		if (!jss.object.isEmpty(jss.skin[jssSkin]))
		{
			skin = jss.skin[jssSkin].menu;
		}
	}

	// Timeouts
	var timeout_hoverCheck = null;

	// Keep track of the currently open menu
	var _currentMenu = null;
	var _parentUL = null;
	var _ynOpen = false;

	// Reset the menu
	var resetMenu = function () {
		if (!skin.ynHoverOpen) {
			jss.css.addClass(_parentUL, HOVEROFF);
		}
		_ynOpen = false;
	}
	
	// If cursor is no longer on the menu, finish closing it
	var finishMenuClose = function () {
		if (_currentMenu == null) {
			resetMenu();
		}
	}

	// Open the selected menu
	var openMenu = function (element) {
		closeCurrentMenu();

		_currentMenu = element;

		jss.css.addClass(element, HOVER);
		jss.css.addClass(element.parentNode.parentNode, HOVER);
	}

	// Close the selected menu
	var closeCurrentMenu = function () {
		if (_currentMenu != null) {
			jss.css.removeClass(_currentMenu, HOVER);
			jss.css.removeClass(_currentMenu.parentNode.parentNode, HOVER);
			_currentMenu = null;
		}
		timeout_hoverCheck = setTimeout(finishMenuClose, 10);
	}

	var traverseDOM = function (element, name, depth) {
		var aryChildNodes = element.childNodes;
		var liCount = 0;

		for (var i=0; i<aryChildNodes.length; i++) {
			var childNode = aryChildNodes[i];
			if (childNode.nodeType == jss.constants.node.ELEMENT_NODE) {
				switch (childNode.tagName.toLowerCase()) {
					case "li":
						if (skin.ynHoverOpen || depth > 0) {
							childNode.onmouseover = function(e) {
								openMenu($$(e).parentNode);
							};
						}

						if (skin.ynClickOpen) {
							if (childNode.getElementsByTagName("UL").length > 0) {
								childNode.firstChild.href = "javascript:void(0);";
								var oFunction = function(e) {
									if (!_ynOpen) {
										openMenu($$(e).parentNode);
										jss.css.removeClass(_parentUL, HOVEROFF);
										
										var setOpen = function () { _ynOpen = true; }

										setTimeout(setOpen, 10);
									}
								};

								$$add(childNode, "click", oFunction);
							}
						}

						if (skin.ynClickClose) {
							if (childNode.getElementsByTagName("UL").length > 0) {
								childNode.firstChild.href = "javascript:void(0);";
								var oFunction = function(e) {
									if (_ynOpen) {
										resetMenu();
										_ynOpen = false;
									}
								};

								$$add(childNode, "click", oFunction);
							}
						}

						if (skin.ynHoverClose) {
							childNode.onmouseout = function(e) {
								closeCurrentMenu();
							};
						}

						childNode.id = name + "_" + liCount++;
						traverseDOM(childNode, childNode.id, depth + 1);
						break;
					case "ul":
						if (_parentUL == null) {
							_parentUL = childNode;
						}

						resetMenu();

						traverseDOM(childNode, name, depth + 1);
						break;
				}
			}
		}
	};

	traverseDOM (element, element.id, 0);

	// IE fix - the menu won't load without this
	var IE_fix = function(e) { element.className = HOVER; element.className = ""; };
	setTimeout(IE_fix, 10);
};
