/**
 * singleton class which manages the interactive behavior of main and sub navigation elements.
 * @requires jQuery
 */
Navigation = function () {
	/**
	 * @var jQuery selector to match the top navigation container
	 */
	this.topNavContainerSelector = '#topNavContainer';
	/**
	 * @var jQuery selector to match the sub navigation container
	 */
	this.subNavContainerSelector = '#subNavContainer';
	/**
	 * @var duration of "slide up"-effect to hide the sub navigation
	 */
	this.slideUpDuration = 300;
	/**
	 * @var duration of "slide down"-effect to show the sub navigation
	 */
	this.slideDownDuration = 200;

	
	/**
	 * @private
	 */
	this.animateNext = true;
	/**
	 * @private
	 */
	this.subNavs = new Array();
	/**
	 * @private
	 */
	this.topNavContainer = null;
	/**
	 * @private
	 */
	this.subNavContainer = null;


	/**
	 * performs basic initialization and cacheing
	 * 
	 * @param Object overrides a set of property overrides. should be used to adapt different container IDs or timings. defaults are used, if omitted.
	 */
	this.init = function (overrides) {
		if (overrides) {
			jQuery.extend(this, overrides);
		}
		
		this.topNavContainer = $j(this.topNavContainerSelector);
		this.subNavContainer = $j(this.subNavContainerSelector)
		
		this.subNavContainer.find('.subNavBox').each(function (index, elem) {
			$j(this).attr('_index', index);
			$j(this).hide();
			$j(this).removeClass('hidden');
		});

		this.topNavContainer.find('a').each(jQuery.proxy(function (index, elem) {
			$j(elem).attr('_index', index);

			this.subNavs[index] = $j(this.subNavContainerSelector).find('.subNavBox[_index='+index+']');
			
			if (!$j(elem).hasClass('noSub') && this.subNavs[index].length) {
				$j(elem).mouseenter(jQuery.proxy(this.mainNavElementMouseEnterHandler, this));
			} 

			$j(elem).mouseleave(jQuery.proxy(this.mainNavElementMouseLeaveHandler, this));
		}, this));

		
		this.topNavContainer.mouseleave(jQuery.proxy(this.mainNavMouseLeaveHandler, this));
		this.subNavContainer.mouseleave(jQuery.proxy(this.subNavContainerMouseLeaveHandler, this));
	};


	/**
	 * displays a specific sub nav menu
	 *  
	 * @param elem Object jQuery object of the sub menu container
	 * @param immediate boolean if set to true, omits the slide effect. default is false
	 */
	this.showSubNav = function (elem, immediate) {
		if (immediate) {
			elem.show();					
		} else {
			elem.slideDown(this.slideDownDuration);
			this.animateNext = false;
		}
	};

	/**
	 * hides the sub navigation
	 *  
	 * @param elem Object jQuery object of the sub menu container
	 * @param immediate boolean if set to true, omits the slide effect. default is false
	 */
	this.hideSubNav = function (immediate) {
		if (immediate) {
			this.subNavContainer.find('.subNavBox').hide();
		} else {
			this.animateNext = true;
			this.subNavContainer.find('.subNavBox').slideUp(this.slideUpDuration);
		}
	};

	
	
	/**
	 * @private
	 */
	this.mainNavMouseLeaveHandler = function (ev) {
		if (!$j(ev.relatedTarget).hasClass('subNavBox')) {
			this.topNavContainer.find('a').removeClass('selected');
			this.hideSubNav();
		}
	};

	/**
	 * @private
	 */
	this.subNavContainerMouseLeaveHandler = function (ev) {
		if (!$j(ev.relatedTarget).is(this.topNavContainerSelector)) {
			this.topNavContainer.find('a').removeClass('selected');
			this.hideSubNav();
		}
	};

	/**
	 * @private
	 */
	this.mainNavElementMouseEnterHandler = function (ev) {
		this.hideSubNav(true);

		var subNav = this.subNavs[parseInt($j(ev.currentTarget).attr('_index'))];
		
		if (subNav.length) {
			this.showSubNav(subNav, !this.animateNext);
		}

		this.topNavContainer.find('a').removeClass('selected');
		
		$j(ev.currentTarget).addClass('selected');
	};

	/**
	 * @private
	 */
	this.mainNavElementMouseLeaveHandler = function (ev) {
		var target = $j(ev.relatedTarget);
		
		if (!target.hasClass('subNavBox') && target.parents().is(this.topNavContainerSelector)) {
			var targetIndex = target.attr('_index');
			if (!targetIndex) {
				targetIndex = target.parent().attr('_index');
			}

			var targetHasSub = !(target.hasClass('noSub') || target.parent().hasClass('noSub')) && (this.subNavContainer.find('.subNavBox[_index='+targetIndex+']').length > 0);
			this.hideSubNav(targetHasSub);

			$j(ev.currentTarget).removeClass('selected');
		}
	};
};

/**
 * singleton extension for easy access and usage
 * 
 * @static
 * @private
 */
Navigation._instance = null;
/**
 * retrieves the Navigation singleton
 * 
 * @static
 */
Navigation.getInstance = function () {
	if (!Navigation._instance) {
		Navigation._instance = new Navigation();
	}

	return Navigation._instance;
};
