
//adapted from the horizontal-menu demo at:
//	http://www.sitepoint.com/examples/goodmenus/horizontal.html
//which was in turn adapted from The JavaScript Anthology, for:
//	http://blogs.sitepoint.com/2009/04/01/the-right-way-to-make-a-dropdown-menu/

//the only others comments in the code are those which relate 
//specifically to the footer-menu concept, not the general menu scripting


var branch,
	navid = 'navigation',
	isie = typeof document.uniqueID != 'undefined',
	oldie = isie && !/msie\s+8/i.test(navigator.userAgent),
	issafari = navigator.vendor == 'Apple Computer, Inc.',
	tree = document.getElementById(navid);

if(tree)
{
	branch = tree;
	
	var items = tree.getElementsByTagName('li');
	for(var i=0; i<items.length; i++)
	{
		dropdownTrigger(tree, items[i], navid, oldie);
	}
	
	if(typeof window.opera == 'undefined')
	{
		cleanUselessWhitespace(tree);
	
		var keyevent = issafari || isie ? 'keydown' : 'keypress';
		attachEventListener(document, keyevent, function(e)
		{
			if(e.cmdKey || e.metaKey) { return true; }
			var target = typeof e.target != 'undefined' ? e.target : e.srcElement;
			if(tree.contains(target) && target.getAttribute('href'))
			{
				if(/^(37|38|39|40)$/.test(e.keyCode.toString()))
				{
					arrowKeyNavigation(tree, target, e.keyCode);
					return false;
				}
			}
			return true;
		});
	}
	
	var eles = document.getElementsByTagName('*');
	for(i=0; i<eles.length; i++)
	{
		attachEventListener(eles[i], 'focus', function(e)
		{
			var target = typeof e.target != 'undefined' ? e.target : e.srcElement;
			if(!tree.contains(target))
			{
				resetSiblingBranches(items[0]);
			}
		});
	}
	
	attachEventListener(document, 'click', function()
	{
		clearMenus(tree);
		return true;
	});
	
	if(typeof tree.contains == 'undefined')
	{
		tree.contains = function(node)
		{
			if(node == null) { return false; }
			if(node == this) { return true; }
			else { return this.contains(node.parentNode); }
		};
	}
}




function dropdownTrigger(tree, li, navid, oldie)
{
	var opentime, 
		closetime,
		a = li.getElementsByTagName('a')[0],
		menu = (li.getElementsByTagName('ul').length > 0 ? li.getElementsByTagName('ul')[0] : null),
		issub = li.parentNode.id == navid;

	attachEventListener(a, 'focus', function(e)
	{
		clearTimeout(closetime);

		a.className += (a.className == '' ? '' : ' ') + 'hover';

		resetSiblingBranches(li);
		
		//get the associated menu from the footer, if there is one
		menu = getMenu(li);
		
		if(menu)
		{
			showMenu(menu, li, a, oldie);
		}
	});

	attachEventListener(li, 'mouseover', function(e)
	{
		if(unwantedTextEvent()) { return; }
		clearTimeout(closetime);
		
		if(branch == li) { branch = null; }
		a.className += (a.className == '' ? '' : ' ') + 'hover';

		var target = typeof e.target != 'undefined' ? e.target : window.event.srcElement;
		while(target.nodeName.toUpperCase() != 'LI')
		{
			target = target.parentNode;
		}
		if(target != li) { return; }

		//clear the current menus
		resetSiblingBranches(li);

		//get the associated menu from the footer, if there is one
		menu = getMenu(li);
				
		if(menu)
		{
			opentime = window.setTimeout(function()
			{
				//if(branch)
				//{
				//	clearMenus(branch);
				//	branch = null;
				//}
				//resetSiblingBranches(li);

				showMenu(menu, li, a, oldie);
				
			}, 250);
		}
	});

	attachEventListener(li, 'mouseout', function(e)
	{
		if(unwantedTextEvent()) { return; }

		var related = typeof e.relatedTarget != 'undefined' ? e.relatedTarget : window.event.toElement;
		if(!li.contains(related))
		{
			clearTimeout(opentime);
			
			branch = li;
			
			if(menu)
			{
				closetime = window.setTimeout(function()
				{
					a.className = a.className.replace(/ ?hover/g, '');

					//menu.style.left = '-100em';
					
					//clear the menu
					clearMenus(li);

				}, 600);
			}
		}
	});

	if(typeof li.contains == 'undefined')
	{
		li.contains = function(node)
		{
			if(node == null) { return false; }
			if(node == this) { return true; }
			else { return this.contains(node.parentNode); }
		};
	}
}


//look for a menu associated with a navbar item
function getMenu(li)
{
	//parse the ID to get a reference to the corresponding footer link section
	var links = document.getElementById(li.id.replace('navigation-', 'links-'));

	//look for a UL list inside it
	var list = links.getElementsByTagName('ul');
	if(list.length > 0) 
	{ 
		list = list[0]; 
		
		//now clone the list to create the menu 
		//and append it to the original item
		var menu = li.appendChild(list.cloneNode(true));
		
		//hide it, so you don't see it until it's been positioned
		menu.style.visibility = 'hidden';
		
		//clean its useless whitespace, so that we have 
		//predictable sibling relationships for the key navigation 
		cleanUselessWhitespace(menu);
		
		//return the reference
		return menu;
	}
	
	//if we get here return null for no menu
	return null;
}


function showMenu(menu, li, a, oldie)
{
	menu.style.left = (oldie ? li.offsetLeft + 'px' : 'auto');
	menu.style.top = a.offsetHeight + 'px';

	//make it visible
	menu.style.visibility = 'visible';
}


function resetSiblingBranches(trigger)
{
	clearMenus(trigger.parentNode);

	var links = trigger.parentNode.getElementsByTagName('a');
	for(var i=0; i<links.length; i++)
	{
		links[i].className = links[i].className.replace(/ ?hover/g, '');
	}
}


function cleanUselessWhitespace(node)
{
	for(var x=0; x<node.childNodes.length; x++)
	{
		var child = node.childNodes[x];
		if(child.nodeType == 3 && !/\S/.test(child.nodeValue))
		{
			node.removeChild(node.childNodes[x]);
			x--;
		}
		if(child.nodeType == 1)
		{
			cleanUselessWhitespace(child);
		}
	}
}


function mapKeyCode(keycode, type)
{
	switch (type)
	{
		case 0:
			if(keycode == 37) { keycode = 39; }
			else if(keycode == 39) { keycode = 37; }
			break;

		case 1:
			if(keycode % 2) { keycode++; }
			else { keycode--; }
			break;

		case 2:
			if(keycode == 38) { keycode = 37; }
			break;
	}

	return keycode;
}


function arrowKeyNavigation(tree, link, keycode)
{
	var li = link.parentNode,
		menu = (li.getElementsByTagName('ul').length > 0 ? li.getElementsByTagName('ul')[0] : null),
		parent = li.parentNode;

	if(menu)
	{
		if(getRoughPosition(menu, 'x') < getRoughPosition(li.parentNode, 'x'))
		{
			keycode = mapKeyCode(keycode, 0);
		}
	}
	else if(parent != tree)
	{
		if(getRoughPosition(parent.parentNode.parentNode, 'x') > getRoughPosition(parent, 'x'))
		{
			keycode = mapKeyCode(keycode, 0);
		}
	}

	if(parent == tree)
	{
		keycode = mapKeyCode(keycode, 1);
	}
	else if(parent.parentNode.parentNode == tree && li == li.parentNode.firstChild)
	{
		keycode = mapKeyCode(keycode, 2);
	}

	switch (keycode)
	{
		case 37:
			parent = parent.parentNode;
			if(tree.parentNode == parent) { parent = null; }
			if(parent)
			{
				parent.firstChild.focus();
			}
			break;

		case 38:
			var previous = li.previousSibling;
			if(!previous)
			{
				previous = li.parentNode.childNodes[li.parentNode.childNodes.length - 1];
			}
			previous.firstChild.focus();
			break;

		case 39:
			if(menu)
			{
				menu.firstChild.firstChild.focus();
			}
			break;

		case 40:
			var next = li.nextSibling;
			if(!next)
			{
				next = li.parentNode.childNodes[0];
			}
			next.firstChild.focus();
			break;
	}
}


function clearMenus(root)
{
	var menus = root.getElementsByTagName('ul');
	for(var i=0; i<menus.length; i++)
	{
		//menus[i].style.left = '-100em';
		
		//remove the menu
		menus[i].parentNode.removeChild(menus[i]);
	}
}


function unwantedTextEvent()
{
	return 
	(
		issafari
		&& 
		(event.target == event.relatedTarget.parentNode
			|| 
			(event.eventPhase == 3 && event.target.parentNode == event.relatedTarget)
		)
	);
}


function getRoughPosition(ele, dir)
{
	var pos = dir == 'x' ? ele.offsetLeft : ele.offsetTop;
	var tmp = ele.offsetParent;
	while (tmp != null)
	{
		pos += dir == 'x' ? tmp.offsetLeft : tmp.offsetTop;
		tmp = tmp.offsetParent;
	}
	return pos;
}


function getViewportSize()
{
	var size = [0,0];

	if(typeof window.innerWidth != 'undefined')
	{
		size = [
			window.innerWidth, 
			window.innerHeight
			];
	}
	else if(typeof document.documentElement != 'undefined'
			&& typeof document.documentElement.clientWidth != 'undefined'
			&& document.documentElement.clientWidth != 0)
	{
		size = [
			document.documentElement.clientWidth,
			document.documentElement.clientHeight
			];
	}
	else
	{
		size = [
			document.getElementsByTagName('body')[0].clientWidth,
			document.getElementsByTagName('body')[0].clientHeight
			];
	}

	return size;
}


function attachEventListener(element, eventname, userhandler)
{
	function eventhandler(e)
	{
		if(!userhandler(e))
		{
			try { e.preventDefault(); } catch(err) {}
			return false;
		}
		return true;
	}
	
	if(typeof document.addEventListener != 'undefined')
	{
		return element.addEventListener(eventname, eventhandler, false);
	}
	else if(typeof document.attachEvent != 'undefined')
	{
		return element.attachEvent('on' + eventname, eventhandler);
	}
}


