// Initialization, you can leave this here or move this somewhere else
$(function(){
	$('ul.jd_menu').jdMenu({onShow: loadMenu, onHide: unloadMenu, offset: 4, onAnimate: onAnimate});
	$('ul.jd_menu_vertical').jdMenu({onShow: loadMenu, onHide: unloadMenu, offset: 1, onAnimate: onAnimate});
	$(document).bind('click', function() {
		$('ul.jd_menu,ul.jd_menu_vertical').find('ul:visible').jdMenuHide();
	});
});

function onAnimate() {
	$(this)
		.css('visibility', 'hidden').show()
			.css('width', $(this).innerWidth())
		.hide().css('visibility', 'visible')
	.slideDown('normal');
}

var MENU_COUNTER = 1;
function loadMenu() {
	if (this.id == 'dynamicMenu') {
		$('> ul > li', this).remove();

		var ul = $('<ul></ul>');
		var t = MENU_COUNTER + 10;
		for (; MENU_COUNTER < t; MENU_COUNTER++) {
			$('> ul', this).append('<li>Item ' + MENU_COUNTER + '</li>');
		}
	}
}

function unloadMenu() {
	if (MENU_COUNTER >= 30) {
		MENU_COUNTER = 1;
	}
}

/*
 * jdMenu 1.3 (2007-02-22)
 *
 * Copyright (c) 2006,2007 Jonathan Sharp (http://jdsharp.us)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://jdsharp.us/
 *
 * Built upon jQuery 1.1.1 (http://jquery.com)
 * This also requires the jQuery dimensions plugin
 */
(function($){
	$.fn.parentsUntil = function(match) {
		var a = [];
		$(this[0]).parents().each(function() {
			a.push(this);
			return !$(this).is(match);
		});
		return this.pushStack(a, arguments);
	};
	
	// Public methods
	$.fn.jdMenu = function(inSettings) {
		var settings = $.extend({}, arguments.callee.defaults, inSettings);
		return this.each(function() {
			$(this).addClass('jd_menu_flag_root');
			this.$settings = $.extend({}, settings, {isVerticalMenu: $(this).is('.jd_menu_vertical')});
			addEvents(this);
		});
	};

	$.fn.jdMenu.defaults = {
		activateDelay: 0, //750
		showDelay: 0, //150
		hideDelay: 0, //550
		onShow: function() { return true; },
		onHide: function() { return true; },
		onAnimate: null,
		offset: 2,
		iframe: $.browser.msie
	};
	
	$.fn.jdMenuHide = function() {
		return this.each(function() {
			hideMenu.apply(this);
		});
	};
	$.fn.jdMenuShow = function() {
		return this.each(function() {
			showMenu.apply(this);
		});
	};

	// Returns our settings object for this menu
	function getSettings(el) {
		return $(el).parents('ul.jd_menu_flag_root')[0].$settings;
	}

	// Unbind any events and then rebind them
	function addEvents(ul) {
		removeEvents(ul);
		$('> li', ul).hover(hoverOver, hoverOut).bind('click', itemClick)
			.find('> a.accessible').bind('click', accessibleClick);
	};
	
	// Unbind all events we may have attached
	function removeEvents(ul) {
		$('> li', ul).unbind('mouseover').unbind('mouseout').unbind('click')
			.find('> a.accessible').unbind('click');
	};

	// Passed in a li
	function addHoverClass(li) {
		var c = 'jd_menu_hover' + ($(li).parent().is('.jd_menu_flag_root') ? '_toolbar' : '');
		$(li).addClass(c).find('> a').addClass(c);
	}
	
	// Triggered when hovering over a list item
	function hoverOver() {
		addHoverClass(this);
		
		if (this.$timer) {
			clearTimeout(this.$timer);
		}

		// Do we have a sub menu?
		if ($('> ul', this).size() > 0) {
			var settings = getSettings(this);
			
			// Which delay to use, the longer activate one or the shorter show delay if a menu is already visible
			var delay = ($(this).parents('ul.jd_menu_flag_root').find('ul:visible').size() == 0) 
							? settings.activateDelay : settings.showDelay;
			var t = this;
			this.$timer = setTimeout(function() {
				showMenu.apply(t);
			}, delay);
		}
	};
	
	function hoverOut() {
		$(this)	.removeClass('jd_menu_hover').removeClass('jd_menu_hover_toolbar')
			.find('> a')
				.removeClass('jd_menu_hover').removeClass('jd_menu_hover_toolbar');
		
		if (this.$timer) {
			clearTimeout(this.$timer);
		}

		// If we have a visible menu, hide it
		if ($(this).is(':visible') && $('> ul', this).size() > 0) {
			var settings = getSettings(this);
			var ul = $('> ul', this)[0];
			this.$timer = setTimeout(function() {
				hideMenu.apply(ul);
			}, settings.hideDelay);
		}
	};
	
	// "this" is a reference to the LI element that contains 
	// the UL that will be shown
	function showMenu() {
		var ul = $('> ul', this).get(0);
		// We are already visible, just return
		if ($(ul).is(':visible')) {
			return;
		}

		// Add hover classes, needed for accessible functionality
		addHoverClass(this);

		// Hide any existing menues at the same level
		$(this).parent().find('> li > ul:visible').not(ul).each(function() {
			hideMenu.apply(this);
		});

		// Get our settings object
		var settings = getSettings(this);

		// Clear our timer if it exists
		if (this.$timer) {
			clearTimeout(this.$timer);
		}

		// Call our callback
		settings.onShow.apply(this);
		addEvents(ul);

		// "Show" our menu so we can calculate its width, set left and top so that it does not accidentally
		// go offscreen and trigger browser scroll bars
		$(ul).css({visibility: 'hidden', left: 0, top: 0}).show();

		// border width
		var bw = parseInt($(this).parent().css('borderRightWidth'));
		var offset	= bw * settings.offset;

		// window width
		var ww = $(window).width();

		// outer width of UL element
		var ow = $(ul).outerWidth();

		var liOffset = $(this).offset({border: false});

		var x = 0, y = 0;
		// Are we the first drop down menu? If so special positioning code
		if ($(this).parentsUntil('ul.jd_menu_flag_root').filter('li').size() == 0) {
			if (settings.isVerticalMenu) {
				x = liOffset.left + $(this).outerWidth() - offset;
				y = liOffset.top;

				if (ww < (x + ow)) {
					x = liOffset.left + offset;
					y += $(this).outerHeight() - offset;
				}
			} else {
				x = liOffset.left;
				y = liOffset.top + $(this).outerHeight();
				if (ww < (x + ow)) {
					x = ww - ow;
					if (x < 0) {
						x = 0;
					}
				}
			}
		// We are a sub menu
		} else {
			y = liOffset.top - $(this).parent().offset().top;

			if ((ww < (liOffset.left + $(this).outerWidth() + ow))) {
				x = (-ow) + offset;
				if ((liOffset.left + x) < 0) {
					x = offset;
					y += $(this).outerHeight() - offset;
				}
			} else {
				x = $(this).outerWidth() - offset;
			}
		}

		if (settings.iframe) {
			$(ul).bgiframe();
		}

		if (settings.onAnimate) {
			$(ul).hide().css({left: x, top: y, visibility: 'visible'});
			// The onAnimate method is expected to "show" the element it is passed
			settings.onAnimate.apply(ul);
		} else {
			$(ul).css({left: x, top: y, visibility: 'visible'});
		}
	}

	// "this" is a reference to a UL menu to be hidden
	function hideMenu(recurse) {
		if (!$(this).is(':visible')) {
			return;
		}
		
		$('> li > ul:visible', this).each(function() {
			hideMenu.apply(this, [false]);
		});

		if ($(this).is('.jd_menu_flag_root')) {
			return;
		}

		var elms = $('> li', this).add($(this).parent());

		elms.removeClass('jd_menu_hover').removeClass('jd_menu_hover_toolbar')
			.find('> a')
				.removeClass('jd_menu_hover').removeClass('jd_menu_hover_toolbar');

		removeEvents(this);
		$(this).hide().find('> .bgiframe').remove();
		var settings = getSettings(this);
		settings.onHide.apply(this);

		// Recursively hide our parent menus
		if (recurse == true) {
			$(this).parentsUntil('ul.jd_menu_flag_root')
					.removeClass('jd_menu_hover').removeClass('jd_menu_hover_toolbar')
				.not('.jd_menu_flag_root').filter('ul')
					.each(function() {
						hideMenu.apply(this, [false]);
					});
		}
	}

	// Prevent the default (usually following a link)
	function accessibleClick(e) {
		if ($(this).is('.accessible')) {
			// Stop the browser from the default link action allowing the 
			// click event to propagate to propagate to our LI (itemClick function)
			e.preventDefault();
		}
	}

	// Trigger a menu click
	function itemClick(e) {
		e.stopPropagation();
		if ($('> ul', this).size() > 0) {
			showMenu.apply(this);
		} else {
			if ($(e.target).is('li')) {
				if ($('> a', e.target).not('.accessible').size() > 0) {
					var lnk = $('> a', e.target).not('.accessible').get(0);
					if (!lnk.onclick) {
						window.open(lnk.href, lnk.target || '_self');
					} else {
						$(lnk).click();
					}
				}
			}
			
			hideMenu.apply($(this).parent(), [true]);
		}
	}
})(jQuery);
