(function($){
	var alog = window.console ? console.log : alert;
	
	$.fn.supermenu = function(options){
	
		var sm = $.fn.supermenu,
				classes = sm.classes,
				$arrow = $(['<span class="', classes.arrowClass,'"> &#187;</span>'].join('')),
				over = function(){
					var $this = $(this),
							menu = getMenu($this);
					clearTimeout(menu.timer);
					$this.showMenu(menu).siblings().hideMenu(menu);
				},
				out = function(){
					var $this = $(this),
							menu = getMenu($this),
							opts = sm.options;
					clearTimeout(menu.timer);
					menu.timer = setTimeout(function(){
						opts.retainPath = ($.inArray($this[0], opts.$path) > -1);
						$this.hideMenu(menu);
						if(opts.$path.length && $this.parents(['li.', opts.hoverClass].join('')).length < 1){ over.call(opts.$path); }
					}, opts.delay);
				},
				getMenu = function($menu){
					var menu = $menu.parents(['ul.', classes.menuClass, ':first'].join(''))[0];
					sm.options = sm.opts[menu.serial];
					return menu;
				},
				addArrow = function(arrow){ arrow.addClass(classes.anchorClass).append(arrow.clone()); };
		
		return this.each(function(index){
			var serial = this.serial = sm.opts.length;
			var opts = $.extend({}, sm.defaults, options);
			var sub = this.sub = opts.sub[index];
			opts.$path = $(['li.', opts.pathClass].join(''), this).slice(0, opts.pathLevels).each(function(){
				$(this).addClass([opts.hoverClass, classes.breadcrumb].join(' ')).filter('li:has(ul, ol, li:has('+sub+')').removeClass(opts.pathClass);
			});
			sm.opts[serial] = sm.options = opts;
			
			$('li:has(ul, ol, '+sub+')', this)[($.fn.hoverIntent && !opts.disableHI) ? 'hoverIntent' : 'hover'](over, out).each(function(){
				if(opts.autoArrows) addArrow( $('>a:first-child', this) );
			}).not('.'+classes.breadcrumb).hideMenu(this);
			
			var $a = $('a', this);
			$a.each(function(i){
				var $li = $a.eq(i).parents('li');
				$a.eq(i).focus(function(){ over.call($li); }).blur(function(){ out.call($li); });
			});
			opts.onInit.call(this);
		}).each(function(){
			var menuClasses = [classes.menuClass];
			if(sm.options.dropShadows && !($.browser.msie && $.browser.version < 7)) menuClasses.push(classes.shadowClass);
			$(this).addClass(menuClasses.join(' '));
		});
	};
	
	var sm = $.fn.supermenu;
	sm.opts = [];
	sm.options = {};
	sm.IE7fix = function(){
		var opts = sm.options;
		if ($.browser.msie && $.browser.version > 6 && opts.dropShadows && opts.animate.opacity != undefined)
			this.toggleClass(sm.classes.shadowClass+'-off');
	};
	
	sm.classes = {
		breadcrumb	: 'sm-breadcrumb',
		menuClass		: 'sm-enabled',
		anchorClass	: 'sm-anchor',
		arrowClass	: 'sm-indicator',
		shadowClass	: 'sm-shadow'
	};
	
	sm.defaults = {
		sub							: [],
		hoverClass			: 'hover',
		pathClass				: 'replace',
		pathLevels			: 1,
		delay						: 800,
		showAnimation		: false,
		showAnimate 		: {opacity :'toggle'},
		showSpeed				: 'fast',
		hideAnimation		: false,
		hideSpeed				: 'fast',
		autoArrows			: false,
		dropShadows 		: false,
		disableHI				: false,		// true disables hoverIntent detection
		onInit					: function(){}, // callback functions
		beforeShow			: function(){},
		onShow					: function(){},
		beforeHide			: function(){},
		onHide					: function(){}
	};
	
	$.fn.extend({
		hideMenu : function(menu){
			var opts = sm.options,
				not = (opts.retainPath===true) ? opts.$path : '';
			opts.retainPath = false;
			
			var $ul = $(['li.', opts.hoverClass].join(''), this).add(this).not(not).removeClass(opts.hoverClass).find('>ul, >'+menu.sub);
			opts.beforeHide.call($ul);
			
			if(opts.hideAnimation || opts.hideAnimation == 'true'){
				$ul.fadeOut(opts.hideSpeed, function(){ sm.IE7fix.call($ul); opts.onHide.call($ul); });
			} else {
				$ul.hide();
				sm.IE7fix.call($ul);
				opts.onHide.call($ul);
			}
			
			return this;
		},
		showMenu : function(menu){
			var opts = sm.options,
				sh = sm.classes.shadowClass+'-off',
				$ul = this.addClass(opts.hoverClass).find('>ul:hidden, >div#'+menu+':hidden');
			sm.IE7fix.call($ul);
			
			opts.beforeShow.call($ul);
			if(opts.showAnimation || opts.showAnimation == 'true'){
				$ul.animate(opts.showAnimate, opts.showSpeed, function(){ sm.IE7fix.call($ul); opts.onShow.call($ul); });
			} else {
				$ul.show();
				sm.IE7fix.call($ul);
				opts.onShow.call($ul);
			}
			
			return this;
		}
	});
})(jQuery);
