/**
 * GEO Mega Menu
 * 
 * @author Brian Coit <brian@line.uk.com>
 */
(function($)
{
	var timeout;
	
	var nav,
		megaMenu;
	
	$(document).ready(function()
	{
		if(!$('#nav').length)
			return;
		
		setUp();
	});
	
	var maxH = 0;
	
	$(window).load(function()
	{
		if(!$('#nav').length)
			return;
		
		// position mega menu
		var top = $('#header').next()
			.offset().top;
		
		positionMenu(top);
		
		maxH = calculateMaxMenuHeight();
		
		applyBindings();
		
		deNestNavigation();
		
		megaMenu.hide();
	});
	
	function calculateMaxMenuHeight()
	{
		var maxH = 0;
		
		megaMenu.show();
		megaMenu.find('ul, div').css('display', 'block');
		megaMenu.find('ul, .menu-puff').each(function()
		{
			$(this).show();
			
			if($(this).hasClass('menu-puff'))
			{
				var hTot = $(this).outerHeight() + parseInt($(this).css('margin-top')) + parseInt($(this).css('margin-bottom'))
				if(hTot > maxH)
				{
					maxH = hTot;
				}
			}
			else
			{
				if($(this).height() > maxH)
				{
					maxH = $(this).height();
				}
			}
		});
		
		return maxH;
	}
	
	function calculateMenuHeight()
	{
		var _h = 0;
		
		var hidden = megaMenu.find('.megaMenu-box').not(':hidden').find('ul').not(':visible');
		
		hidden.show();
		
		megaMenu.find('.megaMenu-box').not(':hidden').find('ul').each(function()
		{
			if($(this).height() > _h)
			{
				_h = $(this).height();
			}
		});
		
		hidden.hide();
		
		return _h;
	}
	
	/**
	 * Sets the height, based on the height of the tallest <ul>
	 * 
	 * @return void
	 */
	function setMenuHeight()
	{
		megaMenu.find('> .megaMenu-inner > div:visible').height('auto');
		megaMenu.find('ul').height('auto');
		
		var _h = maxH;
		
		megaMenu.find('> .megaMenu-inner > div:visible').height(_h);
		megaMenu.find('ul').height(_h);
	}
	
	// placeholder - we could use this to 'grow/shrink the menu height'
	function smoothResizeMenuHeight()
	{
		return setMenuHeight();
	}
	
	function applyAnimationBindings()
	{
		var currentIndex = 0;
		
		nav.find('> ul > li').each(function()
		{
			var _li = $(this);
			
			if(typeof _li.data('megaMenuIndex') != 'undefined')
			{
				var isNavHovered;
				
				var _fnOver = function()
				{
					currentIndex = _li.data('megaMenuIndex');

					clearTimeout(timeout);

					var submenus = megaMenu.find('> div > .megaMenu-box');

					submenus.hide();
					$(submenus.get(currentIndex)).show();

					_li.addClass('megaMenu-hover').siblings()
						.removeClass('megaMenu-hover');
					
					open();
				};
				
				var _fnOut = function(e)
				{
					var currentTarget = $(e.relatedTarget);
					
					var parent = currentTarget.parent('#megaMenu');
					
					timeout = setTimeout(function()
					{
						if(!parent.length)
						{
							_li.removeClass('megaMenu-hover');
							close();
						}
					}, 200);
				};

				_li.mouseover(function()
				{
					clearTimeout(timeout);
				});

				_li.hoverIntent({    
					 over: _fnOver,
					 timeout: 200,   
					 out: $.noop
				});
				
				_li.mouseleave(_fnOut);
				
				megaMenu.mouseenter(function(e)
				{
					clearTimeout(timeout)
				});
				
				megaMenu.mouseleave(function(e)
				{
					isNavHovered = $(e.relatedTarget).is('#nav > ul > li')
						&& typeof $(e.relatedTarget).data('megaMenuIndex') != 'undefined';
					
					
					
					if(isNavHovered)
					{
						return;
					}
					
					close();
				});
				
			}
		});
	}
	
	function open()
	{
		megaMenu.fadeIn(200);
		smoothResizeMenuHeight();
	}
	
	function close()
	{
		$('#nav > ul > li').removeClass('megaMenu-hover');
		megaMenu.fadeOut(300);
	}
	
	function applyBindings()
	{
		// bind hover states (if we do this before we re-nest the elements, then these should still stay attached - handy)
		var els = megaMenu.find('li');
		
		els.find('ul').hide();
		els.filter('.active').find('> ul').show();
		
		megaMenu.find('.sub-menu').hoverIntent({    
			 over: $.noop,  
			 timeout: 200,  
			 out: resetState
		});

		var _fnOver = function()
		{
			$(this).siblings().filter('ul').show();
			
			// hide <ul>'s from adjacent <li>'s
			$(this).parent().siblings().find('ul').hide();
			
			// show adjacent <ul>
			$(this).siblings('ul').show();
		}
		
		els.find('> a').hoverIntent({    
			 over: _fnOver, 
			 timeout: 200,
			 out: $.noop
		});
	}
	
	/**
	 * Resets the menu states (anything that was active will be shown again)
	 * 
	 * @return void
	 */
	function resetState()
	{
		megaMenu.find('li > ul').hide();
		megaMenu.find('li.active > ul').show();
	}
	
	/**
	 * Loops through the navigation and sets css classes on parent <ul> elements
	 * 
	 * @return void
	 */
	function deNestNavigation()
	{
		var subMenu = megaMenu.find('.sub-menu');
		var depth = 0;

		function _loop(el)
		{
			if(!el.length)
				return false;
			
			depth++;
			
			el.each(function()
			{
				$(this)
					.addClass('column')
					.addClass('level-' + depth)
					.data('level', depth);
			});
			_loop(el.find('> li > ul'));
		}
		_loop(subMenu);
	}
	
	/**
	 * Sets up containing elements
	 * 
	 * @return void
	 */
	function setUp()
	{
		nav = $('#nav');
		
		// mark items which have no children
		nav.find('li').each(function()
		{
			if(!$(this).find('li').length)
				$(this).addClass('no-children');
		});
		
		megaMenu = $('<div />')
			.attr('id', 'megaMenu')
			.appendTo('body');
			
		var megaMenuInner = $('<div />')
			.addClass('megaMenu-inner');
			
		var i = 0;
			
		// apply data to each element
		nav.find('li').each(function()
		{
			var li = $(this);
			var submenu = li.find('.sub-menu');
			
			if(submenu.length)
			{
				var idx = i++;
				
				var div = $('<div />')
					.addClass('megaMenu-box')
					.data('megaMenuIndex', idx)
					.appendTo(megaMenuInner);
					
				li.find('.sub-menu, .menu-puff')
					.appendTo(div);
				
				li.data('megaMenuIndex', idx);
			}
		});
		
		applyAnimationBindings();
		
		megaMenuInner.appendTo(megaMenu);
	}
	
	/**
	 * Sets the menu position (px from top)
	 * 
	 * @return void
	 */
	function positionMenu(topValue)
	{
		megaMenu.css({
			position: 'absolute',
			top: topValue + 'px',
			left: 0
		});
	}
})
(jQuery);
