/**
 * Popup Block
 *
 * @author Stepan Reznikov [stepan.reznikov@gmail.com], Vladislav Yakovlev [red.scorpix@gmail.com]
 * @version 2.1.4 (2009-07-26)
 * @requires jQuery
 *
 * @changelog version 2.1.4
 * Оптимизирован код.
 *
 * @changelog version 2.1.3
 * <ul>
 *   <li>Добавлены комментарии.</li>
 *   <li>Параметр <code>showFunction</code> удален.</li>
 *   <li>Добавлены параметры <code>beforeShow</code>, <code>afterShow</code>, <code>beforeHide</code>, <code>afterHide</code>.</li>
 * </ul>
 *
 * @changelog version 2.1
 * <ul>
 *   <li>Флаг <code>keep</code> заменен на <code>event.stopPropagation().</code></li>
 *   <li>Форма появляется и исчезает плавно (под IE появляется/исчезает мгновенно в виду проблем с <code>filter</code>).</li>
 *   <li>Добавлен параметр <code>showFunction</code> - функция, выполняемая после показа popup'а.</li>
 * </ul>
 *
 * @param {Object} options Настройки:
 * <ul>
 *   <li>container - контейнер попап-блока,</li>
 *   <li>fader - блок тени (необязательный параметр),</li>
 *   <li>link - блоки для показа/скрытия попапа (необязательный параметр),</li>
 *   <li>close - блоки для закрытия попапа (необязательный параметр),</li>
 *   <li>beforeShow - функция, выполняемая перед открытием (необязательный параметр),</li>
 *   <li>afterShow - функция, выполняемая после открытия (необязательный параметр),</li>
 *   <li>beforeHide - функция, выполняемая перед закрытием (необязательный параметр),</li>
 *   <li>afterHide - функция, выполняемая после закрытия (необязательный параметр).</li>
 * </ul>
 * @return {Object} Функции:
 * <ul>
 *   <li>hide</li>
 *   <li>cancel</li>
 *   <li>show</li>
 *   <li>toggle</li>
 * </ul>
 */
var PopupBlock = (function() {

	var
		documentClickHandler,
		documentKeyDownHandler,
		options;

	function cancel(event) {
		var code = event.keyCode ? event.keyCode : event.which ? event.which : null;
		code === 27 && hide(event);
	}

	function hide(event) {
		if (options.container.hasClass('hidden')) return;

		options.beforeHide && options.beforeHide();
		options.fader && options.fader.addClass('hidden');
		options.container.addClass('hidden');
		$(document)
			.unbind('click', documentClickHandler)
			.unbind('keydown', documentKeyDownHandler);

		options.afterHide && options.afterHide();

		if (event) {
			event.preventDefault();
			event.stopPropagation();
		}
	}

	function show(event) {
		if (!options.container.hasClass('hidden')) return;

		options.beforeShow && options.beforeShow();
		options.fader && options.fader.removeClass('hidden');

		$.browser.msie ? options.container.removeClass('hidden') : options.container.css('opacity', 0).removeClass('hidden').animate({ opacity: 1 }, 300, function() {
			options.container.css('opacity', '');
			options.afterShow && options.afterShow();
		});

		documentClickHandler = hide;
		documentKeyDownHandler = cancel;

		$(document)
			.click(documentClickHandler)
			.keydown(documentKeyDownHandler);

		$.browser.msie && options.afterShow && options.afterShow();

		if (event) {
			event.preventDefault();
			event.stopPropagation();
		}
	}

	function toggle(event) {
		event.preventDefault();
		event.stopPropagation();
		options.container.hasClass('hidden') ? show(event) : hide(event);
	}

	return function(inOptions) {
		options = inOptions;
		options.container.click(function(event) {
			event.stopPropagation();
		});
		options.link && options.link.click(toggle);
		options.close && options.close.click(toggle);

		return {
			cancel: cancel,
			hide: hide,
			show: show,
			toggle: toggle
		};
	};
})();