jQuery(function() {
	jQuery('ul.jd_menu').jdMenu();
});

(function(jQuery){
	jQuery.jdMenu = {
		settings: 	[],
		getSettings: 	function( element ) {
							var t = jQuery(element).parents('ul.jd_menu:eq(0)')[0];
							return this.settings[ t && t.jQueryjdSettings ? t.jQueryjdSettings : 0 ];	
						}
	};
	
	function activateMenu(ul) {
		var ul = jQuery(ul);
		var li = ul.parent();
		ul	.trigger('jdMenuShow')
			.positionBy({ 	target: 	li[0], 
							targetPos: 	( li.parent().is('.jd_menu') ? 3 : 1 ), 
							elementPos: 0 
							});
		li	.addClass('jdm_active')
			// Hide any adjacent menus
			.siblings('li').find('ul:eq(0):visible')
				.each(function(){
					hideMenu( this ); 
				});
	}
	
	function hideMenu(ul) {
		jQuery(ul)
			.filter(':not(.jd_menu)')
			.find('> li ul:eq(0):visible')
				.each(function() {
					hideMenu( this );
				})
			.end()
			.hide()
			.trigger('jdMenuHide')
			.parents('li:eq(0)')
				.removeClass('jdm_active jdm_hover')
			.end()
				.find('> li')
				.removeClass('jdm_active jdm_hover');
	}
	
	function getSettings(element) {
		return jQuery.data( jQuery(element).is('.jd_menu') ? element : jQuery(element).parents('ul.jd_menu')[0], 'jdMenuSettings');;
	}
	
	// Public methods
	jQuery.fn.jdMenu = function(settings) {
		var settings = jQuery.extend({	activateDelay: 	500,
					showDelay: 		300, 
					hideDelay: 		1200
					}, settings);
		return this.filter('ul.jd_menu').each(function() {
			jQuery.data(this, 'jdMenuSettings', settings);
			jQuery('li', this)
				.bind('mouseenter.jdmenu', function() {
					jQuery(this).addClass('jdm_hover');
					var ul = jQuery('ul:eq(0)', this);
					if ( ul.length == 1 ) {
						var me = this;
						clearTimeout( this.jQueryjdTimer );
						this.jQueryjdTimer = setTimeout(function() {
							activateMenu( ul );
						}, getSettings(this).showDelay );
					}
				})
				.bind('mouseleave.jdmenu', function(){
					jQuery(this).removeClass('jdm_hover');
					var ul = jQuery('ul:eq(0)', this);
					if ( ul.length == 1 ) {
						var settings = jQuery.jdMenu.getSettings( this );
						var me = this;
						clearTimeout( this.jQueryjdTimer );
						this.jQueryjdTimer = setTimeout(function() {
							hideMenu( ul );
						}, getSettings(this).hideDelay );
					}
				})
				.bind('click.jdmenu', function(evt) {
					var ul = jQuery('> ul', this);
					if ( ul.length == 1 ) {
						activateMenu( ul );
						return true;
					}
					
					// The user clicked the li and we need to trigger a click for the a
					if ( evt.target == this ) {
						var link = jQuery('> a', evt.target).not('.accessible');
						if ( link.length > 0 ) {
							var a = link[0];
							if ( !a.onclick ) {
								window.open( a.href, a.target || '_self' );
							} else {
								jQuery(a).trigger('click');
							}
						}
					}
					jQuery(this).parent().jdMenuHide();
					evt.stopPropagation();
				})
				.bind('keydown.jdmenu', function(e) {
					if ( e.which == 27 ) {
						if ( !jQuery(this).parent().is('.jd_menu') ) {
							hideMenu( jQuery(this).parent()[0] );
						}
						jQuery(this).parents('li:eq(0)').find('a:eq(0)').trigger('focus');
						return false;
					}
				})
				.find('> a')
					.bind('focus.jdmenu', function() {
						jQuery(this).parents('li:eq(0)').addClass('jdm_hover');
					})
					.bind('blur.jdmenu', function() {
						jQuery(this).parents('li:eq(0)').removeClass('jdm_hover');
					})
					.filter('.accessible')
						.bind('click.jdmenu', function(evt) {
							evt.preventDefault();
						});
		});
	};
	
	jQuery.fn.jdMenuUnbind = function() {
		jQuery('li', this)
			.unbind('mouseenter.jdmenu mouseleave.jdmenu click.jdmenu keydown.jdmenu')
			.find('> a').unbind('focus.jdmenu blur.jdmenu click.jdmenu');
		return this;
	};
	
	jQuery.fn.jdMenuHide = function() {
		return this.filter('ul').each(function(){ hideMenu( this ); });
	};

	// Private methods and logic
	jQuery(window)
		// Bind a click event to hide all visible menus when the document is clicked
		.bind('click.jdmenu', function(){
			jQuery('ul.jd_menu ul:visible').jdMenuHide();
		});
})(jQuery);

