var ERMDropdown =
{
	iDropdownOffset: 6,			// Dropdown width offset imperically determined to be 6. This may need to change if you mess w/ the CSS
	pMenu: null,					// Pointer to current Menu DOM node
	pClickable: null,				// Pointer to current Clickable DOM node
	pSubMenu: null,				// Pointer to current Submenu DOM node
	pSubMenuItem: null,			// Pointer to current Submenu MenuItem DOM node (which is actually an <a> somewhere in pMenu)
	fEvtHide: null,				// Function to wrap event-based menu hiding

	show: function(sMenu, clickable, e)
	{
		if (!sMenu || !sMenu.length)
			return;

		var wrapper = document.getElementById(sMenu);
		if (!wrapper)
			return;

		var menu = wrapper.firstChild;
		if (!menu || !menu.className || menu.className.indexOf('active') > -1)
			return;

		// Begin messy code for detecting if we're clicking the <a> inside a SPMenu
		if (!e) var e = window.event;
		var targ;				// Get target node - http://www.quirksmode.org/js/events_properties.html	<3 QuirksMode
		if (e.target) targ = e.target;
		else if (e.srcElement) targ = e.srcElement;
		if (targ.nodeType == 3) targ = targ.parentNode; // defeat Safari bug
		if (targ && targ.nodeName == 'A' && targ.href) // If the targ is a hyperlink w/ href, that means we clicked it, so don't show menu
			return;
		// End code just for SPMenu

		// Hide any other menu, if there is one
		ERMDropdown.hide();

		// Show hoverable click, if we got one
		if (clickable)
			ERMDropdown.hover(clickable);

		menu.className = 'active';

		ERMDropdown.pMenu = menu;				// Store a pointer to the current menu
		ERMDropdown.pClickable = clickable;	// Store a pointer to the current clickable node - the node that causes us to show in the first place

		ERMDropdown.move(wrapper, clickable);		// Move the menu to the clickable
		ERMDropdown.resize(menu, clickable);		// Resize the menu

		// Define function to hide menu bar. We need to do this here so we can pass it as a pointer to setTimeout
		ERMDropdown.fEvtHide = function(e)
		{
			if (!e) var e = window.event;
			ERMDropdown.hide(e);
		};

		// Delay global click event registration a little bit so it doesn't fire for the event still being processed
		setTimeout(function() { ERM.attachEvent(document, 'click', ERMDropdown.fEvtHide); }, 200);
	},

	hide: function(e)
	{
		// If this function is triggered by an event, do some conditional checking
		if (e)
		{
			// Get target node - http://www.quirksmode.org/js/events_properties.html	<3 QuirksMode
			var targ;
			if (e.target) targ = e.target;
			else if (e.srcElement) targ = e.srcElement;
			if (targ.nodeType == 3) // defeat Safari bug
				targ = targ.parentNode;

			// We need to detect whether or not we're clicking inside our menu (and if we are, not on an <a>)
			if (ERMDropdown.pClickable && targ == ERMDropdown.pClickable) // If we clicked our clickable, just return
				return;
			else if (targ.nodeName != 'A')
			{
				var node = targ;
				while(node)
				{
					// If we clicked inside the menu (not on a hyperlink) or we clicked a child of our clickable, don't hide
					if (node == ERMDropdown.pMenu || (ERMDropdown.pClickable && node == ERMDropdown.pClickable))
						return;

					node = node.parentNode;
				}
			}
			else if (targ.className && targ.className.indexOf('submenu') > -1) // We are clicking an <a>
				return;
		}

		if (ERMDropdown.fEvtHide)
			ERM.removeEvent(document, 'click', ERMDropdown.fEvtHide);

		if (ERMDropdown.pMenu)
			ERMDropdown.pMenu.className = 'hidden';

		// if we have a hoverable, unhover it
		if (ERMDropdown.pClickable)
			ERMDropdown.unhover(ERMDropdown.pClickable);

		// First hide the submenu
		ERMDropdown.hideSubmenu();

		ERMDropdown.pMenu = null;					// clear pointer to the current menu
		ERMDropdown.pClickable = null;			// clear pointer to the current clickable
	},

	move: function(wrapper, clickable, bIsSubmenu)
	{
		if (!wrapper || !clickable)
			return;

		if (bIsSubmenu == null)
			bIsSubmenu = false;

		var left = 0;
		var top = 0;

		if (bIsSubmenu && clickable)
			left = clickable.offsetWidth + ERMDropdown.iDropdownOffset;
		else if (bIsSubmenu)
			left = ERMDropdown.pMenu.lastChild.offsetWidth;

		var x = clickable;
		while(x)
		{
			var l = x.offsetLeft;
			var t = x.offsetTop;

			if (l && !isNaN(l))
				left += l;
			if (t && !isNaN(t))
				top += t;

			// When we hit a position:relative, stop calculating
			var style = ERMDropdown.getComputedStyle(x, 'position');
			if (style == 'relative')
				break;

			x = x.offsetParent;
		}

		if (clickable)
		{
			if (bIsSubmenu)
			{
				var liner = clickable.parentNode;
				if(liner)
					top -= liner.scrollTop;
			}
			else if (clickable.offsetTop)
				top += clickable.offsetHeight;
		}

		// Finally, adjust for any specified offets
		if (clickable.edmOffsetLeft)
			left += clickable.edmOffsetLeft;

		if (clickable.edmOffsetTop)
			top += clickable.edmOffsetTop;

		wrapper.style.left = left + 'px';
		wrapper.style.top = top + 'px';
	},

	// Resizes the menu so that it is within the max/min limits and does not run offscreen
	resize: function(menu, clickable, bIsSubmenu)
	{
		if (!menu)
			return;

		var liner = menu.lastChild;

		// Smuggle the initial width and height values into other nodes
		if (typeof liner.edmMinWidth == 'undefined')
			liner.edmMinWidth = parseInt(liner.style.width.replace(/px/, '')); // Force integer
		if (typeof liner.edmMaxHeight == 'undefined')
			liner.edmMaxHeight = parseInt(liner.style.height.replace(/px/, '')); // Force integer

		// Reset the width and height
		liner.style.width = null;
		liner.style.height = null;

		// Enforce minWidth and make it match the clickable's width.
		if (clickable)
			liner.style.width = Math.max(clickable.offsetWidth, liner.edmMinWidth) - ERMDropdown.iDropdownOffset + 'px';
		else
			liner.style.width = liner.edmMinWidth - ERMDropdown.iDropdownOffset + 'px';

		// Enforce maxHeight. We need to do this through JS instead of CSS. Yes, trust me.
		liner.style.height = Math.min(liner.offsetHeight, liner.edmMaxHeight) - ERMDropdown.iDropdownOffset + 'px';

		// We need to set the width again because it might've changed with the height. Yes, we need to do it this way. Trust me. :(
		if (clickable)
			liner.style.width = Math.max(clickable.offsetWidth, liner.edmMinWidth) - ERMDropdown.iDropdownOffset + 'px';
		else
			liner.style.width = liner.edmMinWidth - ERMDropdown.iDropdownOffset + 'px';

		// Figure out if we need to scoot the menu left any because it's at the edge of the window
		var offsetleft = (menu.offsetLeft ? menu.offsetLeft : menu.offsetParent.offsetLeft);
		var offsetwidth = liner.offsetWidth;
		var browserwidth = ERM.getWindowWidth() - 16; // Why 16? We've empirically chosen it as an offset.
		var scrollwidth = ERM.getWindowScrollX();

		if (offsetwidth + offsetleft >= browserwidth + scrollwidth)
		{
			if (menu.className.indexOf('right') > -1)
				return;

			menu.className += ' right';

			if (bIsSubmenu)
			{
				menu.parentNode.style.left = (parseInt(menu.parentNode.style.left.replace(/px/, ''))
													+ clickable.offsetWidth + ERMDropdown.iDropdownOffset*2) + 'px';
			}
			else
				menu.parentNode.style.left = (parseInt(menu.parentNode.style.left.replace(/px/, '')) - clickable.offsetWidth) + 'px';
		}
		else if (menu.className.indexOf('right') > -1)
		{
			menu.className = menu.className.replace(/ right/, '');
			ERMDropdown.move(menu.parentNode, clickable, bIsSubmenu); // Need to call move again
		}


		// Lastly, figure out whether or not we need to scoot our menu up any because it's at the bottom of the window
		var offsettop = (menu.offsetTop ? menu.offsetTop : menu.offsetParent.offsetTop);
		var offsetheight = liner.offsetHeight;
		var browserheight = ERM.getWindowHeight();
		var scrollheight = ERM.getWindowScrollY();

		if (offsetheight + offsettop >= browserheight + scrollheight)
		{
			if (menu.className.indexOf('bottom') > -1)
				return;

			menu.className += ' bottom';

			if (bIsSubmenu)
			{
				menu.parentNode.style.top = (parseInt(menu.parentNode.style.top.replace(/px/, ''))
													+ clickable.offsetHeight + ERMDropdown.iDropdownOffset*2) + 'px';
			}
			else
				menu.parentNode.style.top = (parseInt(menu.parentNode.style.top.replace(/px/, '')) - clickable.offsetHeight) + 'px';
		}
		else if (menu.className.indexOf('bottom') > -1)
		{
			menu.className = menu.className.replace(/ bottom/, '');
			ERMDropdown.move(menu.parentNode, clickable, bIsSubmenu); // Need to call move again
		}
	},

	showSubmenu: function(sSubMenu, menuitem)
	{
		if (!sSubMenu || !sSubMenu.length)
			return;

		var wrapper = document.getElementById(sSubMenu);
		if (!wrapper)
			return;

		// Add CSS submenu class to the wrapper
		wrapper.className = 'ERMDropdownMenu ERMDropdownSubmenu';

		var submenu = wrapper.firstChild;
		if (!submenu || !submenu.className || submenu.className == 'active' || submenu.className == 'active bottom')
			return;

		// Hide the old submenu first
		ERMDropdown.hideSubmenu();

		submenu.className = 'active';
		menuitem.className = 'submenu active';

		ERMDropdown.pSubMenu = submenu;				// Store a pointer to the current submenu
		ERMDropdown.pSubMenuItem = menuitem;		// Store a pointer to the current submenu

		ERMDropdown.move(wrapper, menuitem, true);		// Move the submenu to the menuitem
		ERMDropdown.resize(submenu, menuitem, true);		// Resize the submenu
	},

	hideSubmenu: function(a)
	{
		if (!ERMDropdown.pSubMenu)
			return;

		// If we have an <a> tag that we're hovering, make sure it isn't actually in the submenu before hiding
		if (a && a.parentNode && a.parentNode.parentNode == ERMDropdown.pSubMenu)
			return;

		// Remove CSS submenu class from the wrapper
		ERMDropdown.pSubMenu.parentNode.className = 'ERMDropdownMenu';

		ERMDropdown.pSubMenu.className = 'hidden';
		ERMDropdown.pSubMenuItem.className = 'submenu';

		ERMDropdown.pSubMenu = null;
		ERMDropdown.pSubMenuItem = null;
	},

	// This controls the hover effect for the clickable, not the menu itself!
	hover: function(p, bHover)
	{
		if (!p || !p.className || (p.className != 'ERMDropdownSPButton' && p.className != 'ERMDropdownSPButtonHover'))
			return;

		if (ERMDropdown.pMenu && ERMDropdown.pMenu.className.indexOf('active') > -1)
			return;

		// If bHover isn't supplied, default to true
		if (bHover == null)
			bHover = true;

		// hide the old hover, if there is one. Leave the replace() code just in case we aren't on a ERMDropdownSPButton class
		if (ERMDropdown.pClickable)
			ERMDropdown.pClickable.className = ERMDropdown.pClickable.className.replace(/Hover/, '');

		p.className = 'ERMDropdownSPButton';
		if (bHover)
			p.className += 'Hover';
	},

	// Convenience function to make code a little cleaner
	unhover: function(p)
	{
		ERMDropdown.hover(p, false);
	},

	// Never scroll the page if we mousewheel in an open menu
	evtWheel: function(e)
	{
		if (!ERMDropdown.pMenu)
			return;

		if (!e) var e = window.event;

		// Get target node - http://www.quirksmode.org/js/events_properties.html	<3 QuirksMode
		var targ;
		if (e.target) targ = e.target;
		else if (e.srcElement) targ = e.srcElement;
		if (targ.nodeType == 3) // defeat Safari bug
			targ = targ.parentNode;

		// Determine whether we are scrolling up or down
		var delta = 0;
		if (e.wheelDelta)
		{
			delta = e.wheelDelta/120;
			if (window.opera)
				delta = -delta;
		}
		else if (e.detail)
			delta = -e.detail/3;

		if (delta == 0)
			return;

		var bShouldAbort = false;
		var cScrollDir = 'up';
		if (delta < 0)
			cScrollDir = 'down';

		// Now determine whether or not we scrolled in an open menu
		var node = targ;
		while(!bShouldAbort && node)
		{
			// If we scrolled inside the menu, or submenu, check to see if we should abort scrolling
			if (node == ERMDropdown.pMenu || node == ERMDropdown.pSubMenu)
			{
				// If we're scrolling up and have hit the top of the window, abort
				if (cScrollDir == 'up' && node.lastChild.scrollTop == 0)
					bShouldAbort = true;

				// Or if we're scrolling down and we hit the bottom
				if (cScrollDir == 'down' && (node.lastChild.scrollTop + node.lastChild.offsetHeight) > node.lastChild.scrollHeight)
				{
					bShouldAbort = true;
				}
			}

			node = node.parentNode;
		}

		if (bShouldAbort)
		{
			if (e.preventDefault)
				e.preventDefault();
			e.returnValue = false;
		}
	},

	// Thanks http://www.robertnyman.com/2006/04/24/get-the-rendered-style-of-an-element/
	getComputedStyle: function(oElm, strCssRule)
	{
		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;
	}
}

// Add wheel events to the entire page  - http://adomas.org/javascript-mouse-wheel/
if (window.addEventListener) window.addEventListener('DOMMouseScroll', ERMDropdown.evtWheel, false);	// Firefox
window.onmousewheel = document.onmousewheel = ERMDropdown.evtWheel;												// IE/Opera