(function ($) {
	
	/*
	 * Global plugin variables
	 */
	
	$.dropdown = {
		active: []
	};
	
	/*
	 * Dropdown class
	 */
	
	$.Dropdown = function ($wrapper, settings) {
		var base = this;
		
		base.$wrapper = $wrapper;
		base.$link = $wrapper.children(settings.link);
		base.$sub = $wrapper.children(settings.sub);
		base.settings = settings;
		base.status = 'closed';
		
		base.open = function () {
			switch (base.status) {
				case 'open':	return true;
				case 'hold':	base.status = 'open'; return true;
				default:		break;
			}
		
			// Close any other dropdown that is not a parent of this one
			for (var k in $.dropdown.active) {
				var elem = $.dropdown.active[k];
				if (!elem.$sub.has(base.$link).length) {
					elem.close();
				}
			}

            // Make link active
            base.$link.addClass(base.settings.activeClass);
			
			// Initialize positioning
			base.position();
			$(window).resize(function (e) { return base.position(); });
			
			// Show this dropdown
			base.$sub.show();
			base.status = 'open';
			
			// Call open-handler
			if (base.settings.onOpen != undefined) {
				base.settings.onOpen(base);
			}
			
			// Push active
			$.dropdown.active.push(base);
			
			return true;
		};
		
		base.close = function () {
			switch (base.status) {
				case 'closed':	return true;
				default:		break;
			}
			
			// Defer close when an element inside the dropdown is focused
			if (base.$sub.find(document.activeElement).length) {
				base.status = 'hold';
				$(document.activeElement).bind('blur.dropdown', function () {
					if (base.status == 'hold') {
						base.close();
					}
					$(this).unbind('blur.dropdown');
				});
				return false;
			}
					
			// Hide this popup
			base.$link.removeClass("active");
			base.$sub.hide();
			base.status = 'closed';
			
			// Call close-handler
			if (base.settings.onClose != undefined) {
				base.settings.onClose(base);
			}
			
			// Remove active
			for (var i = 0; i < $.dropdown.active.length; i++) {
				var elem = $.dropdown.active[i];
				if (elem == base) {
					$.dropdown.active.splice(i, 1);
					break;
				}
			}
			
			return true;
		};
		
		base.position = function () {
			// Setup position
			if (base.settings.position != undefined) {
				var position = base.settings.position;
				
				// Find the triggers bounding-box
				var pos = base.$link.position();
				var box = {
					left: pos.left, 
					top: pos.top, 
					right: pos.left + base.$link.outerWidth(), 
					bottom: pos.top + base.$link.outerHeight()
				};
				
				// Extract position tokens
				var my = position.my.split(' ');
				var at = position.at.split(' ');
				var ofs = position.offset != undefined ? position.offset.split(' ') : [ 0, 0 ];
				var offset = [ parseFloat(ofs[0]), parseFloat(ofs[1]) ];
				
				if (my[0] == 'right') {
					offset[0] -= base.$sub.outerWidth();
				}
				
				if (my[1] == 'bottom') {
					offset[1] -= base.$sub.outerHeight();
				}
				
				// Set position
				base.$sub.css({
					position: 'absolute', 
					left: (box[at[0]] + offset[0]) + 'px', 
					top: (box[at[1]] + offset[1]) + 'px', 
					right: 'auto', 
					bottom: 'auto'
				});
			}
			
			return true;
		};
		
		// Assign event handlers
		base.$wrapper.hoverIntent({
			sensitivity: base.settings.sensitivity, 
			interval: base.settings.interval, 
			timeout: base.settings.timeout, 
			over: base.open, 
			out: base.close
		});
	};
	
	/*
	 * Inject plugin functions
	 */
	
	$.fn.extend({
		
		/**
		 * Plugin main
		 */
		dropdown: function (settings) {
			// Merge default settings
			settings = $.extend({
				
				// Structure
				link: 'a', 
				sub: '.sub', 
				
				// hoverIntent settings
				sensitivity: 2,
				interval: 100, 
				timeout: 300, 
				
				// Styles
				activeClass: 'active', 
				
				// Handlers
				onOpen: function () {}, 
				onClose: function () {}
				
			}, settings);
			
			return $(this).each(function () {				
				(new $.Dropdown($(this), settings));
			});
		}
		
	});
	
})(jQuery);
