var Popup = function (trigger, popup, settings) {
	this.settings = $.extend({
		timeout: 100,
		onShow: null,
		onHide: null,
		showFx: 'show',
		hideFx: 'hide',
		hideCollectionOnShow: true
	}, settings);

	this.trigger = $(trigger);
	this.popup = $(popup);

	var triggerElem = this.trigger.get(0),
		popupElem = this.popup.get(0);
	for (var i = 0; i < Popup.collection.length; i++) {
		if (Popup.collection[i].trigger == triggerElem && Popup.collection[i].popup == popupElem) {
			return;
		}
	}
	Popup.collection.push({ trigger: triggerElem, popup: popupElem });

	this.init();
}

Popup.collection = [];

Popup.prototype = {
	init: function() {
		this.trackHover(this.trigger);
		this.trackHover(this.popup);

		var $this = this;
		var hide = function () {
			window.setTimeout(function() { $this.hidePopup.apply($this); }, $this.settings.timeout);
		};
		this.trigger.hover(
			function() {
				$this.showPopup();
			}, hide
		);
		this.popup.mouseleave(hide);
	},

	showPopup: function() {
		if (this.trigger.data('popup_hover') || this.popup.data('popup_hover')) {
			typeof(this.settings.showFx) == 'string' ? this.popup[this.settings.showFx]() : this.settings.showFx(this.popup);
			if (this.settings.hideCollectionOnShow) {
				this.hideCollection(this.popup.get(0));
			}
			if (this.settings.onShow) {
				this.settings.onShow(this.trigger, this.popup);
			}
		}
	},

	hidePopup: function() {
		if (!this.trigger.data('popup_hover') && !this.popup.data('popup_hover')) {
			typeof(this.settings.hideFx) == 'string' ? this.popup[this.settings.hideFx]() : this.settings.hideFx(this.popup);
			if (this.settings.onHide) {
				this.settings.onHide(this.trigger, this.popup);
			}
		}
	},

	hideCollection: function(except) {
		for (var i in Popup.collection) {
			if (Popup.collection[i].popup != except) {
				$(Popup.collection[i].popup).hide();
			}
		}
	},

	trackHover: function(elem) {
		return elem.hover(function() {
			$(this).data('popup_hover', true);
		}, function() {
			$(this).data('popup_hover', false);
		}).data('popup_hover', false);
	}
};

