/**
 * jFHMenu - Freshheads style menu with jQuery
 *   http://freshheads.com
 *
 * Copyright (c) 2009 Stefan Moonen (Freshheads)
 *
 * Built on top of the jQuery library
 *   http://jquery.com
 */

(function($) {

	$.fn.jfhmenu = function(o) {
			return this.each(function() {
					new $jfhm(this, o);
			});
	};

	var defaults = {
		animations: {
			show: {
				fixed:    "fadeIn",
				duration: "medium"
			},
			hide: {
				fixed:    "fadeOut",
				duration: "medium"
			},
			innerShow: {
				fixed:    "show",
				duration: 0
			},
			innerHide: {
				fixed:    "hide",
				duration: 0
			}
		},

		eventtype: 'mouseover'
	};

	$.jfhmenu = function(e, o) {
		$e = $(e);

		this.options = $.extend({}, defaults, o || {});

		this.activeChild = null;
		this.activeSubmenu = null;
		this.container = $e.is('ul') ? $e : $e.find('ul');
		this.empty = false;
		this.id = this.container.selector;
		this.initialChild = null;
		this.locked = false;
		this.parent = null;
		this.submenus = [];
		this.timer = null;

		if (!this.container.is('ul'))
		{
			this.empty = true;

			return false;
		}

		this.setup();
	};

	// Shortcut for internal use
	var $jfhm = $.jfhmenu;

	$jfhm.fn = $jfhm.prototype = {
			jfhmenu: '1.0'
	};

	$jfhm.fn.extend = $jfhm.extend = $.extend;

	$jfhm.fn.extend({
		setup:          function() {
			var menu = this;

			// Find and save associated submenu's for every menu-item
			this.container.find('li a').each(function(i, e) {
				var $e = $(e);

				var elmid = $e.attr('id');
				var subid = $e.attr('rel');

				if (elmid && subid)
				{
					var submenu = new $jfhm($('#' + subid), menu.options);
					submenu.parent = menu;

					menu.submenus[elmid] = submenu;
				}

				if ($e.hasClass('active') || $e.hasClass('selected'))
				{
					menu.initialChild = $e;

					menu.activeChild = $e;
					menu.activeSubmenu = submenu;
				}
			});

			// Bind Events for this menu
			switch (this.options.eventtype) {
				case "click":
					this.container.find('li a').bind('click', { menu: menu }, menu.childMouseOver);
					break;

				case "mouseover":
					this.container.bind('mouseover', { menu: menu }, menu.mouseOver);
					this.container.bind('mouseout', { menu: menu }, menu.mouseOut);

					this.container.find('li a').bind('click', { menu: menu }, menu.childClick);
					this.container.find('li a').bind('mouseover', { menu: menu }, menu.childMouseOver);
					this.container.find('li a').bind('mouseout', { menu: menu }, menu.childMouseOut);
					break;
			}
		},

		childClick:     function(event) {
			var menu = event.data.menu;
			var $target = $(event.target);
			if ($target.is('a'))
				menu.locked = true;
		},

		childMouseOver: function(event) {
			var menu = event.data.menu;
			var $target = $(event.target);
			var targetid = $target.attr('id');

			if (menu.locked) return;

			if (targetid)
			{
				if (menu.activeChild) {
					if (targetid == menu.activeChild.attr('id')) return;

					menu.activeChild.removeClass('selected');
				}
				menu.activeChild = $target;
				$target.addClass('selected');

				menu.hideActiveMenu(menu.submenus[targetid].empty);
				menu.showSubmenu(!menu.activeSubmenu || menu.activeSubmenu.empty, menu.submenus[targetid]);
			}

			event.preventDefault();
		},

		childMouseOut:  function(event) {
			// Unused
		},

		mouseOver:      function(event) {
			var menu = event.data.menu;

			menu.resetTimeout();
		},

		mouseOut:       function(event) {
			var menu = event ? event.data.menu : this;

			if (menu.locked) return;

			if (menu.parent)
				menu.parent.mouseOut();

			if (!menu.activeChild) return;

			menu.timer = setTimeout(function() {
				if (!menu.initialChild) {
					menu.hideActiveMenu(true);

					menu.activeChild.removeClass('selected');
					menu.activeChild = null;
					menu.activeSubmenu = null;
				}
				else if (menu.activeChild.attr('id') != menu.initialChild.attr('id')) {
					menu.initialChild.trigger('mouseover');
				}
			}, 500);
		},

		showSubmenu:     function(animate, submenu) {
			if (submenu) {
				submenu.container.stop(false, true);

				if (animate)
					this.animate(submenu.container, 'show');
				else
					this.animate(submenu.container, 'innerShow');

				this.activeSubmenu = submenu;
			}
		},

		hideActiveMenu:  function(animate) {
			if (this.activeSubmenu && !this.activeSubmenu.empty) {
				this.activeSubmenu.container.stop(false, true);

				if (animate)
					this.animate(this.activeSubmenu.container, 'hide');
				else
					this.animate(this.activeSubmenu.container, 'innerHide');
			}
		},

		animate:        function(elm, type) {
				var animation = this.options.animations[type];
				var $elm = $(elm);

				if (animation.fixed) {
					$elm[animation.fixed](animation.duration);
				}
				else if (animation.custom) {
					$elm.animate(animation.custom, animation.duration, animation.easing, animation.callback);
				}
		},

		resetTimeout:   function() {
			if (this.timer)
				clearTimeout(this.timer);

			if (this.parent)
				this.parent.resetTimeout();
		}
	});

	$jfhm.extend({
		defaults: function(d) {
			return $.extend(defaults, d || {});
		}
	});

	// Autoloading for elements with rel="jfhmenu"
	$(function() {
		$('[rel="jfhmenu"]').jfhmenu();
	});

})(jQuery);

