var emp = emp || {};


emp.layers = {
	fog: 90000,
	dialog: 90001,
	movable: 90010,
	loader: 99999
}


emp.keys = {
	"ESC": 27,	"ENTER": 13, "DOWN": 40, "UP": 38, "LEFT": 37, "RIGHT": 39, "SPACE": 32, "BACKSPACE": 8,
	"CTRL": 17, "ALT": 18, "SHIFT": 16, "DEL": 46, "HOME": 36, "END": 35, "PGUP":33, "PGDOWN": 34, "TAB": 9
}


emp.patterns = {
	text:		new RegExp(".+"),
	datetime:	new RegExp("^[0-9]{4}-[0-9]{2}-[0-9]{2}( [0-9]{2}:[0-9]{2}(:[0-9]{2})?)?$"),
	number:		new RegExp("^[0-9]+(,|.[0-9]*)?$"),
	password:	new RegExp("^[a-z0-9.*/?!@_-]{5,}$", "i"),
	email:		new RegExp("^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$","i"),
	url:		new RegExp("^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/", "i")
}


emp.animations = {
	"fadeIn": {from: {opacity: 0}, to: {opacity: 1}},
	"fadeOut": {from: {}, to: {opacity: 0}, ease: "linear"},

	"scaleIn": {from: {opacity: 0, transform: "scale (0.1)"}, to: {opacity: 1, transform: ""}},
	"scaleOut": {from: {}, to: {opacity: 0, transform: "scale (0.1)"}, ease: "linear"},

	"spinIn": {from: {opacity: 0, transform: "scale(0.8)"}, to: {opacity: 1, transform: ""}},
	"spinOut": {from: {}, to: {opacity: 0, transform: "scale(0.9)"}, ease: "linear"}
}



emp.ID = function() {
	var id = 1;

	return {
		get: function() {return id++}
	}

}()



emp.relocate = function(url) {
	window.location.href = emp.url(url);
}



emp.url = function(url) {
	//return ( url.substr(0,4) == "http" ? url : conf.url + "/" + url);
	return ( url.substr(0,4) == "http" ? url : url);
}



emp.thisUrl = function() {
	return location.href.substr(0, location.href.length - location.hash.length);
}



emp.formatNumber = function(number) {
	if (!number)
		return 0;

	return number;
}



emp.removeAccents = function(string, lowercase) {
	clearedString = (lowercase ? string.toLowerCase() : string)
		.replace(/[àáâãäå]/g, "a")
		.replace(/[č]/g,"c")
		.replace(/[ď]/g,"d")
		.replace(/[èéêë]/g,"e")
		.replace(/[ìíîï]/g,"i")
		.replace(/[ľĺ]/g,"l")
		.replace(/[ň]/g,"n")
		.replace(/[òóôõö]/g,"o")
		.replace(/[ŕ]/g,"r")
		.replace(/[š]/g,"s")
		.replace(/[ť]/g,"t")
		.replace(/[ùúûü]/g,"u")
		.replace(/[ýÿ]/g,"y")
		.replace(/[ž]/g,"z");

	if (!lowercase)
		clearedString = clearedString
			.replace(/[ÀÁÂÃÄÅ]/g, "A")
			.replace(/[Č]/g,"C")
			.replace(/[Ď]/g,"D")
			.replace(/[ÈÉÊË]/g,"E")
			.replace(/[ÌÍÎÏ]/g,"I")
			.replace(/[ĽĹ]/g,"L")
			.replace(/[Ň]/g,"N")
			.replace(/[ÒÓÔÕÖ]/g,"O")
			.replace(/[Ŕ]/g,"R")
			.replace(/[Š]/g,"S")
			.replace(/[Ť]/g,"T")
			.replace(/[ÙÚÛÜ]/g,"U")
			.replace(/[ÝŸ]/g,"Y")
			.replace(/[Ž]/g,"Z");

	return clearedString;
	}



emp.getHrefHash = function(hash, parseActions) {
	var actions = {}

	if ((pos = hash.indexOf("#")) < 0)
		return parseActions ? {} : null;

	hash = hash.substr(pos + 1);

	if (!parseActions)
		return hash;

	$.each(hash.split("/"), function() {
		if (!this.length)
			return true;
		else if ((pos = this.indexOf(":")) > -1)
			actions[this.substr(0, pos)] = this.substr(pos + 1);
		else
			actions[this] = true;
	});

	return actions;
}



emp.formatTime = function(time) {
	parts = time.split(":");
	units = ["d", "h", "m", "s"];
	output = [];

	for (var i = 0; i < parts.length; i++) {
		if ((parts[i] = parseInt(parts[i], 10)) > 0)
			output.push(parts[i].toString() + units[i]);

	}

	return output.join(" ");
}



emp.parseTime = function(time) {
	parts = time.split(":");
	return parseInt(parts[0], 10) * 24 * 60 * 60 + parseInt(parts[1], 10) * 60 * 60 + parseInt(parts[2], 10) * 60 + parseInt(parts[3], 10);
}



emp.parseDate = function(dateString) {
	parts = /^(\d{4})\-(\d{2})\-(\d{2}) (\d{2})\:(\d{2})\:(\d{2})$/.exec(dateString);
	parts.shift();

	for (var i = 0; i < parts.length; i++)
		parts[i] = parseInt(parts[i], 10);

	return new Date(parts[0], parts[1] - 1, parts[2], parts[3], parts[4], parts[5], 0).getTime();
}



emp.filter = function(array, key, val) {
	for (var i in array) {
		if (array[key] == val)
			return array;
	}

	return null;
}



emp.getPageSizes = function() {
	return {
		window: {
			width: $(window).width(),
			height: $(window).height()
			},

		document: {
			width: $(document).width(),
			height: $(document).height()
			},

		scroll: {
			top: $(window).scrollTop(),
			left: $(window).scrollLeft()
			}
		}
}



emp.isDebug = function() {
	return true;
}



emp.showInPosition = function(o) {
	var o = $.extend({
		target: $(),
		holder: $(window),
		vertical: "center",
		horizontal: "center",
		offsetLeft: 0,
		offsetTop: 0,
		position: "absolute"
		}, o);

	var elementPosition = {}
	var dimensions = {}

	o.target
		.css({position: o.position, left: 0, top: 0})
		.appendTo($('body'))
		.show();

	if (o.holder.is($(window))) {
		dimensions.offset = {left: 0, top: 0}
		dimensions.width = o.holder.width();
		dimensions.height = o.holder.height();
	} else {
		dimensions.offset = o.holder.offset();
		dimensions.width = o.holder.outerWidth();
		dimensions.height = o.holder.outerHeight();
	}


	switch (o.horizontal) {
		case "center":elementPosition.left = dimensions.offset.left + (dimensions.width - o.target.outerWidth()) / 2;break;
		case "left":elementPosition.left = dimensions.offset.left;break;
		case "right":elementPosition.left = dimensions.offset.left + dimensions.width - o.target.outerWidth();break;
		case "onLeft":elementPosition.left = dimensions.offset.left - o.target.outerWidth();break;
		case "onRight":elementPosition.left = dimensions.offset.left + dimensions.width;break;
	}

	switch (o.vertical) {
		case "center":elementPosition.top = dimensions.offset.top + (dimensions.height - o.target.outerHeight()) / 2;break;
		case "top":elementPosition.top = dimensions.offset.top;break;
		case "bottom":elementPosition.top = dimensions.offset.top + dimensions.height - o.target.outerHeight();break;
		case "over":elementPosition.top = dimensions.offset.top - o.target.outerHeight() ;break;
		case "under":elementPosition.top = dimensions.offset.top + dimensions.height;break;
	}

	if (typeof o.offsetLeft == "string") {
		a = o.offsetLeft.match(/(-)?(\d+)(\%)?/);

		o.offsetLeft = parseInt(a[2], 10);

		if (a[3] == "%")
			o.offsetLeft = elementPosition.left / 100 * o.offsetLeft;

		if (a[1] == "-")
			o.offsetLeft = -o.offsetLeft;
	}

	if (typeof o.offsetTop == "string") {
		a = o.offsetTop.match(/(-)?(\d+)(\%)?/);

		o.offsetTop = parseInt(a[2], 10);

		if (a[3] == "%")
			o.offsetTop = elementPosition.top / 100 * o.offsetTop;

		if (a[1] == "-")
			o.offsetTop = -o.offsetTop;
	}


	elementPosition.top += o.offsetTop;
	elementPosition.left += o.offsetLeft;


	if (o.holder.is($(window))) {
		elementPosition.left = elementPosition.left < 0 ? 0 : elementPosition.left
		elementPosition.top = elementPosition.top < 0 ? 0 : elementPosition.top
	}

	o.target.css(elementPosition);

}



emp.editor = function (element, editorType) {

	if (!CKEDITOR) {
		error("CKEDITOR not loaded");
		return false;
	}

	element.each(function() {
		var editorId = "textarea-editor-" + emp.ID.get();

		var editorTypes = {
			optimal: {
				width: "690px",
				height: "400px",
				toolbar : [
					[
						'Format', 'Bold', 'Italic', 'Strike', '-',
						'Link', 'Unlink', '-',
						'Image', '-',
						'JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock', '-',
						'NumberedList', 'BulletedList', 'Outdent', 'Indent', '-', 'RemoveFormat'
					],
					[
						'Source'
					]
				]
			},
			small: {
				width: "500px",
				height: "250px",
				toolbar: [
					['Bold', 'Italic', '-', 'Link', 'Unlink', '-', 'NumberedList', 'BulletedList', '-', 'Image', '-', 'RemoveFormat'],
					['Source']
				]
			}
		}

		$(this).attr("id", editorId).siblings(".required").hide();

		CKEDITOR.replace( editorId, $.extend(editorTypes[editorType || "optimal"] || {}, {
			language: "sk",
			toolbarCanCollapse: false
		}));

	})

	return true;

}



emp.locker = function() {
	var locks = []

	function locked(owner) {
		for (var i = 0; i < locks.length; i++)
			if (locks[i] === owner)
				return true;

		return false;
	}

	function lock(owner) {
		for (var i = 0; i < locks.length; i++)
			if (locks[i] === owner)
				return false;

		locks.push(owner)
		return true;
	}

	function unlock(owner) {
		locks.removeItem(owner);
	}

	return {
		locked: locked,
		lock: lock,
		unlock: unlock
		}
}();



emp.fog = function() {

	var fog = $('<div class="emp-fog">').css({zIndex: emp.layers.fog});

	function show() {
		if (!fog.parent().length)
			fog.appendTo($('body')).cssAnimation("fadeIn");
	}

	function hide() {
		if (fog.parent().length)
			fog.cssAnimation("fadeOut", 250, function() {fog.detach()});
	}

	return {
		show: show,
		hide: hide
		}

}();



emp.loader = function() {

	var loader = $('<div class="emp-loader">').css({zIndex: emp.layers.loader});

	function show() {
		if (!loader.is(":visible"))
			loader.appendTo($("body"))
				.showInPosition({offsetTop: "-10%", position: "fixed"})
				.cssAnimation("scaleIn", 150);
	}

	function hide() {

		if (loader.is(":visible"))
		loader.cssAnimation("scaleOut", 150, function() {loader.detach()});
	}

	return  {
		show: show,
		hide: hide
		}

}();



emp.cookie = function() {

	function set(name, value, days) {
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		}
		else var expires = "";
		document.cookie = name+"="+value+expires+"; path=/";
	}

	function get(name) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
		}
		return null;
	}

	function unset(name) {
		this.set(name, "", -1);
	}

	return {
		set: set,
		get: get,
		unset: unset
	}

 }();




/***  EMP Classes  ************************************************************/


emp.movable = function() {

	var Movable = function(o) {
		var self = this;
		var o = $.extend({
			items: $(),
			workaround: false,
			onGrab: function(movable) {  },
			onDrop: function(movable, target) {  },
			onMove: function(movable, offset) {  },
			handler: function(item) {
				return item;
			}
		}, o);


		var ID = emp.ID.get();
		var items = $();

		var draggedItem;
		var focusedElement;
		var itemGhost = $('<div class="emp-movable-ghost">');


		function cancelDrag(result) {
			$(window).unbind(".movable" + ID);
			$('body').css({cursor: ""});

			draggedItem
				.removeClass("emp-movable-moving")

			if (!result) {
				if (!getGhost())
					draggedItem.remove()
				else
					itemGhost.after(draggedItem);
			}

			setDraggedItem(null);

			if (focusedElement)
				focusedElement.first().focus();

			focusedElement = null;
		}


		function getItem() {
			return draggedItem;
		}


		function getGhost() {
			return itemGhost.parent().length ? itemGhost : false;
		}


		function getHandler(item) {
			return o.handler ? (typeof o.handler == "function" ? o.handler(self, item) : item.find(o.handler)) : item;
		}


		function setDraggedItem(item, addGhost) {
			if (draggedItem) {
				draggedItem.removeClass("emp-movable-moving")

				if (o.workaround)
					draggedItem.css({position: "", left: "", top: "", width: "", height: "", zIndex: ""});

				draggedItem = null;
				itemGhost.remove();
			}

			if (item) {
				draggedItem = item.addClass("emp-movable-moving")

				if (addGhost !== false)
					draggedItem.before(itemGhost);

				if (o.workaround)
					draggedItem.css({position: "fixed", width: item.width() || "", height: item.height() || "", zIndex: emp.layers.movable})
			}

			return draggedItem;

		}


		function init() {
			items.each(function() {
				getHandler($(this)).removeClass("emp-movable").unbind(".movable" + ID);
			});

			items = (typeof o.items == "function" ? o.items() : o.items).each(function() {
				var item = $(this);

				if (item.parent().css("position") == "static")
					item.parent().css("position", "relative");

				getHandler(item).addClass("emp-movable").bind("mousedown.movable" + ID, function(e) {
					focusedElement = $(':focus');

					if (e.button != 0)
						return true;

					var startOffset = {
						mouse: {top: e.pageY, left: e.pageX},
						item: null
						}

					startOffset.item = {
						top: item.offset().top - $(window).scrollTop(),
						left: item.offset().left - $(window).scrollLeft()
						}

					setDraggedItem(item);

					if (o.onGrab(self) === false) {
						cancelDrag();
						return false;
					}

					draggedItem.css(startOffset.item)

					$('body')
						.css("cursor", "move !important");

					$(window).bind("mousemove.movable" + ID, function(e) {
						var offset = {
							top: e.pageY - startOffset.mouse.top,
							left: e.pageX - startOffset.mouse.left
							}

						draggedItem.css({
							top: offset.top + startOffset.item.top,
							left: offset.left + startOffset.item.left
							});

						o.onMove(self, offset);

						return false;
					})

					$(window).bind("mouseup.movable" + ID + " keyup.movable" + ID, function(e) {
						if (e.type == "mouseup" || (e.type == "keyup" && e.keyCode == emp.keys.ESC)) {
							cancelDrag(!(o.onDrop(self, $(e.target)) === false));
							return false;
						}
					})

					return false;

				});

			});

		};


		init();

		this.getItem = getItem;
		this.getGhost = getGhost;
		this.cancelDrag = cancelDrag;
		this.setDraggedItem = setDraggedItem;
		this.init = init;

	}


	var create = function(o) {
		return new Movable(o);
	}


	return {
		create: create
		}


}();



emp.orderable = function() {

	var Orderable = function(o) {
		var self = this;

		var o = $.extend({
			holder: null,
			items: null,
			orientation: "vertical",
			placeholder: function(item) {
				return placeholder
					.width(item.outerWidth())
					.height(item.outerHeight());
			},
			onGrab: function(orderable) {

			},
			onDrop: function(orderable, target) {
				return orderable.getMovable().getItem().replaceAll(orderable.getPlaceholder());
			},
			onHelper: function(orderable, helper) {

			},
			onClean: function(orderable) {

			}
		}, o);


		var movable;
		var placeholder = $('<div class="emp-orderable-placeholder">');


		function createHelpers() {

			var items = getItems();

			var panelHelper = $('<div class="emp-orderable-panel-helper">')
				.css({zIndex: emp.layers.movable + 1})
				.bind("mouseenter.orderable", function() {
					if (!($(this)).parent().children().not(".emp–orderable-panel-helper").filter(items).length)
						$(this).parent().append(placeholder);
				});

			var helper = $('<div class="emp-orderable-helper">')
				.addClass("emp-orderable-helper-" + o.orientation)
				.css({zIndex: emp.layers.movable + 2})
				.bind("mouseenter.orderable", function() {
					if (o.onHelper(self, $(this)) !== false) {
						if ($(this).hasClass("reversed"))
							$(this).parent().before(placeholder)
						else
							$(this).parent().after(placeholder)
					}
				});

			placeholder = o.placeholder(movable.getItem());

			( typeof o.holder == "function" ? o.holder() : o.holder ).each(function() {
				var element = $(this);
				var firstItem = null;

				if (element.css("position") == "static")
					element.css("position", "relative");

				element.prepend(panelHelper.clone(true));

				$(this).children().not(".emp-movable-ghost").filter(items).each(function() {
					var element = $(this);

					if (element.is(movable.getItem()))
						return true;

					if (element.css("position") == "static")
						element.css("position", "relative");

					element.append(helper.clone(true));

					if (!firstItem)
						firstItem = element.append(helper.clone(true).addClass("reversed"))

				})
			})

		}


		function removeHelpers() {

			$('.emp-orderable-helper, .emp-orderable-panel-helper').remove();
			placeholder.remove();

		}


		function getHolder() {
			return (typeof o.holder == "function" ? o.holder() : o.holder || $());
		}


		function getItems() {
			return o.items ? (typeof o.items == "function" ? o.items() : o.items ) : getHolder().children();
		}


		(function() {
			var options = {
				items: function() {return ( typeof o.items == "function" ? o.items() : o.items || getItems() )},
				workaround: true,
				onGrab: function(movable) {
					if (o.onGrab(self, movable) === false)
						return false;

					createHelpers(movable);

					if (movable.getGhost())
						movable.getItem().after(o.placeholder(movable.getItem()));
				},
				onDrop: function(movable, target) {
					var result = false;

					if (placeholder.is(":visible") && o.onDrop(self, movable, target) !== false) {
						getPlaceholder().after(movable.getItem())
						result = true;
					}

					removeHelpers();
					movable.init();

					o.onClean(self);

					return result;
				},
				handler: function(movalbe, item) {return item}
			}

			if (o.handler)
				options.handler = o.handler;
//				options.handler = function(movable, item) {
//					return o.handler ? ( typeof o.handler == "function" ? o.handler(self, item) : item.find(o.handler) ) : item;
//				};

			if (o.onMove)
				options.onMove = function(movable, offset) {
					o.onMove(self, offset)
				}

			movable = emp.movable.create(options);

		})();


		this.getPlaceholder = function() {return placeholder;}
		this.getMovable = function() {return movable}
		this.getHolder = getHolder;
		this.getItems = getItems;

	}


	var create = function(o) {
		return Orderable(o);
	}


	return {
		create: create
		}

}();



emp.dialog = function() {

	var self = this;
	var list = [];

	var Dialog = function(o) {

		var o = $.extend({
			title: "Emporium",
			content: "",
			params: {},
			cache: true,
			buttons: {"OK": true, "Storno": false},
			focus: true,

			css: null,
			width: null,
			height: null,

			onSubmit: function(self) {return true;},
			onCancel: function(self) {return true;},
			onOpen: function(self) { }
		}, o);

		var self = this;
		var content = null;
		var originalFocus = null;


		var holder = $('<div>');
		var dialog = $('<div class="emp-dialog">');
		var glass = $('<div>');


		function generateButtons(map) {
			if (map instanceof jQuery)
				return map;

			var buttons = $();

			$.each(map, function(text, callback) {
				var button = $('<button class="emp-button">');

				if (/\:focus/.test(text)) {
					text = text.replace(/\:focus/, "");

					if (o.focus === true)
						o.focus = button;
				}

				button.html(text).click((function(callback) {
					return function() {
						if (callback === true)
							return self.submit();
						if (callback === false)
							return self.cancel();

						return callback(self);
					}
				})(callback));

				buttons = buttons.add(button);
			});

			return buttons;
		}


		function init() {

			if (o.css)
				dialog.addClass(o.css);

			if (o.width)
				dialog.css({width: o.width});

			if (o.height)
				dialog.css({height: o.height});

			buttons = generateButtons(o.buttons);

			dialog.append(
				dialog.items().header = $('<header>')
					.append(o.title)
					.append($('<span class="close emp-icon emp-icon-delete">').click(function() {self.cancel()})),
				dialog.items().content = $('<div>'),
				dialog.items().footer = (buttons.length ? $('<footer>').append(buttons) : $())
			);

			holder
				.css({zIndex: emp.layers.dialog})
				.append(dialog);
				//.movable(dialog.items().header);

			emp.movable.create({
				items: holder,
				handler: dialog.items().header,
				onDrop: function() {return false}
			})

			glass
				.css({position: "fixed", width: "100%", height: "100%", top: 0, left: 0, zIndex: emp.layers.dialog})
				.click(function() {self.cancel();});

			self.open();

		}


		function close() {
			glass.detach();

			dialog
				.find(":focus").blur();

			dialog.cssAnimation("spinOut", 250, function() {
				holder.detach();
				dialog.detach()
			})

			if (!o.cache)
				content = null;

			emp.loader.hide();

			originalFocus.focus();

			removeDialog(self);
		}


		this.open = function() {

			if (!originalFocus)
				originalFocus = $(':focus').first().blur();

			// ak este nemame vybraty obsah...
			if (!content) {

				// overime si ci nemame natiahnut nejaku url
				if (typeof o.content == "string" && o.content.match(emp.patterns.url)) {

					emp.loader.show();

					$.post(o.content, {ajax: true}, function(response) {
						emp.loader.hide();
						content = response;
						self.open();
					}, "json");

					return;

				// inak tam hodime co sme dostali
				} else {

					content = o.content;

				}

			}


			dialog.items().content
				.append(content);

			o.focus = ( o.focus instanceof jQuery ? o.focus :
				( o.focus ? dialog.find("input, select, textarea, button").not(":disabled").first() : $() ) )

			holder.showInPosition({holder: $(window), position: "fixed", offsetTop: "-35%"})

			dialog.cssAnimation("spinIn", function() {
				dialog.vendorCss("transform", "")
			});

			o.focus.focus();

			glass.insertBefore(holder);

			o.onOpen(self);
		}


		this.submit = function() {
			if (typeof(o.onSubmit) == "function") {
				if ((result = o.onSubmit(self)) !== false)
					close();
				return result;
			} else if (typeof(o.onSubmit == "string")) {
				emp.relocate(o.onSubmit);
				return true;
			} else {
				return true;
			}
		}


		this.cancel = function() {
			if (typeof(o.onCancel) == "function") {
				if ((result = o.onCancel(self)) !== false)
					close();
				return result;
			} else {
				return true;
			}
		}


		this.close = function() {
			close();
		}


		this.minimize = function() {
			self.getDialog().addClass("minimized");
		}


		this.unminimize = function() {
			self.getDialog().removeClass("minimized");
		}


		this.getDialog = function() {
			return dialog;
		}


		this.getContent = function() {
			return content;
		}


		init();

	}


	function removeDialog(dialogObject) {
		for (var i = 0; i < list.length; i++)
			if (dialogObject === list[i])
				break;

		list.splice(i,1);

		refreshList();
	}


	function refreshList() {
		if (list.length) {
			emp.fog.show();

			for (var i = 0; i < list.length - 1; i++)
				list[i].minimize();

			list[list.length - 1].unminimize();

		} else {
			emp.fog.hide();

			$(window).unbind("keyup.Dialog");
		}
	}


	function open(o) {
		if (!list.length)
			$(window).bind("keyup.Dialog", function(e) {
				if (e.keyCode == emp.keys.ESC)
					removeDialog(list[list.length - 1].cancel());
			});

		list.push(a = new Dialog(o));

		refreshList();

		return a;
	}


	return {
		open: open
		}

}();



emp.Caption = function(o) {
	var o = $.extend({
		target: $(),
		content: ""
		}, o);

	var element = $('<div class="emp-caption">').append(o.content).css({position: "fixed", zIndex: 999999});


	function init() {
		var timer;

		o.target.bind("mouseenter.Caption", function(e) {
			timer = setTimeout(function() {
				element.appendTo($('body')).fadeIn(100);
			}, 300);
		});

		$(window).bind("mousemove.Caption", function(e) {
			element.css({top: e.pageY + 10, left: e.pageX + 15});
		});

		o.target.bind("mouseleave.Caption", function() {
			clearTimeout(timer);

			element.fadeOut(100, function() {
				element.detach();
			});
		});
	}


	init();

}



emp.ContextMenu = function(o) {
	var o = $.extend({
		target: $("body"),
		content: []
	}, o)

	var ID = "ContextMenu" + emp.ID.get();
	var content;
	var box;


	function generateMenuList(menu) {
		var list = $('<ul>');
		var item = null;

		for (var i = 0; i < menu.length; i++) {
			if (typeof menu[i] == "string" && menu[i] == "-") {

				item = $('<li>').addClass("-context-menu-sep");

			} else {

				item = $('<li>').append($('<span>').addClass("-context-menu-item").append(menu[i].text));

				if (typeof menu[i].click == "function") {
					var onClick = menu[i].click;

					item.find(".-context-menu-item").eq(0).click(function(e) {
						if (onClick(e) !== false)
							close();

						return false;

						});
				}

				if (menu[i].children instanceof Array) {
					item.find("span").eq(0).append($('<span>').addClass("-context-menu-more").html("&rsaquo;"));
					item.append(generateMenuList(menu[i].children));
					}
			}

			item.appendTo(list);
		}

		list[0].oncontextmenu = function() {return false;}

		return list;
	}


	function open(position) {
		box.show(position);

		$(document)
			.bind('mousedown.' + ID, function(e) {
				if (!$(e.target).parents().andSelf().filter(box.dom()).length)
					close();
			}).bind('keydown.' + ID, function(e) {
				if (e.keyCode == emp.keys.ESC)
					close();
			});
	}


	function close() {
		box.hide();
		$(document).unbind("." + ID);
	}


	function bind() {
		content = generateMenuList(o.content);

		box = new emp.Box({
			content: content,
			css: "-context-menu"
			});

		o.target.bind('mouseup.' + ID, function(e) {
			if (e.button == 2) {
				open({
					left: e.pageX + 1,
					top: e.pageY + 1
					});

				return false;
			}
		});

		o.target[0].oncontextmenu = function() {return false;}

	}


	bind();

}



emp.tabs = function(o) {

		var o = $.extend({
			holder: $(),
			selected: 0,
			bookmarks: {},
			prefix: "tab"
		}, o)

		var bookmarks = $('<div class="emp-tabs">');
		var tabs;
		var selected;


		function select(tab) {
			if (!tab)
				tab = 0;

			if (!isNaN(parseFloat(tab)) && isFinite(tab))
				tab = tabs.eq(tab).attr("id").replace(new RegExp("^" + o.prefix + "-"), "");

			if (!tabs.filter('[id=' + o.prefix + '-' + tab + ']').length)
				return;

			tabs.hide().filter('[id=' + o.prefix + '-' + tab + ']').show();
			bookmarks.children().removeClass("selected").filter('[href=#' + tab + ']').addClass("selected");

			selected = tab;
		}

		o.prefix = $.trim(o.prefix, "-");

		tabs = $('[id^=' + o.prefix + '-]')

		$.each(o.bookmarks, function(tab, title) {
			$('<a href="#' + tab + '">').append(title).appendTo(bookmarks).click(function(e) {
				if (e.target.tagName == "INPUT") {
					e.stopPropagation();

				} else {
					if (!$(this).hasClass("selected"))
						select(tab);
					return false;
				}
			});
		})

		o.holder.append(bookmarks);

		select(o.selected);

		return {
			select: select,
			getSelected: function() {return selected}
			}

	}



emp.langTabs = function(o) {

		var o = $.extend({
			showLangName: true,
			published: false,
			selected: window.location.hash.substr(1)
		}, o);

		$.each(o.bookmarks || {}, function(lang, name) {
			o.bookmarks[lang] = (o.published ? '<input type="checkbox" name="published[' + lang + ']" value="1"' + ( o.published.indexOf(lang) > -1 ? ' checked="checked"' : '') + ' />' : '') +
				'<span class="emp-flag emp-flag-' + lang + '" title="' + name + '"></span>' + ( o.showLangName ? '&nbsp;' + name : '')
		})

		return emp.tabs(o);

	}



emp.form = function() {

	var Form = function(o) {

		var self = this;
		var o = $.extend({
			form: $("form").eq(0),
			items: { },
			beforeCheck: function(form) {return true;},
			afterCheck: function(form) {return true;},
			onError: function(form) {
				form.getElement()
					.find(".error").first()
					.find("input, textarea, select").first()
					.focus();
			}
		}, o);

		var valid = true;
		var enable = true;
		var items;


		this.disableForm = function() {
			enable = false;
			o.form.find('[type=submit]').disable();
		}


		this.enableForm = function() {
			enable = true;
			o.form.find('[type=submit]').enable();
		}


		this.validate = function(raiseErrors) {
			if (!enable)
				return false;

			var valid = true;

			self.getItems(true);
			self.disableForm();

			o.form.find(".error")
				.removeClass("error");

			// funkcia beforeCheck
			if (o.beforeCheck(self) === false) {
				self.enableForm();
				return false;
			}


			// kontola poloziek cez zadane pravidla
			$.each(items, function() {
				if (self.validateItem(this) === false)
					valid = false;
			});


			// funkcia afterCheck
			if (!valid || o.afterCheck(self) === false) {
				if (raiseErrors) {
					$.each(items, function() {
						if (!this.valid)
							this.input.parents("div.input-field").first().addClass("error");
					});

					if (o.onError)
						o.onError(self);
				}

				self.enableForm();
				return false;
			}

			return valid;
		}


		this.validateItem = function(item) {
			// ak uz niekto nastavil validitu polozky, nekontrolujeme ju
			if (item.valid !== null) {

			// 'type' moze byt aj funkcia ktora urci validnost
			} else if (item.validator) {
				item.valid = ( item.validator(item, self) === false ? false : true );

			// ak je vtup typu text, textarea, radio, alebo select, kontrolujeme iba ci nie je prazdny
			} else if (item.type == null || item.type == "text" || item.type == "select" || item.type == "radio" || item.type == "textarea") {
				item.valid = ((item.value.length > 0) || !item.required);

			// ak je 'type' regularny vyraz rovno ho preverime
			} else if(item.type instanceof RegExp) {
				item.valid = (item.type.test(item.value) || (!item.required && item.value==''));

			// inak sa pozrieme do pola pomenovanych regexps ci tam nemame jeden s takymto klucov
			} else if(emp.patterns[item.type] != undefined) {
				item.valid = (emp.patterns[item.type].test(item.value) || (!item.required && (item.value == '')))

			// ako dalsiu moznost overime "zaskrtnutie" (checkbox, radio)
			} else if(item.type == "checkbox") {
				item.valid = (item.input.is(":checked") || !item.required);

			// niekedy potrebujeme zistit iba bool hodnotu polozky
			} else if(typeof item.type == "boolean") {
				item.valid = (item.value && (item.value != "false") && (item.value != "0") && (item.value != 0));

			// ak sme vycerpali vsetky moznosti nieco bude zle...
			} else {
				error("[Form] Uknown rule '" + item.type + "' for item '" + item.name + "'");
				item.valid = false;
			}

			if (!item.valid)
				error("[Form] Invalid entry on '" + item.name + "'")

			return item.valid;
		}


		// namapuje pozadovane polozky z formularu
		this.getItems = function(force) {

			if (!items || force) {
				items = {}

				$.each(o.items, function(name, options) {
					var element;

					if (typeof options == "function")
						options = {validator: options}

					if (!(element = o.form.find('[name=' + name + ']')).length) {
						error("[Form] Item '" + name + "' not found!");
						return true;
					}

					items[name] = $.extend({
						name: name,
						input: element,
						value: $.trim(element.val()),
						type: null,
						valid: null,
						required: true,
						msg: false,
						focus: true
					}, options)

				});

			}

			return items;
		}


		this.setItem = function(name, options) {
			o.items[name] = options;
		}


		this.setItems = function(items) {
			o.items = items;
			self.getItems(true);
		}


		this.getElement = function() {
			return o.form;
		}


		this.submit = function() {
			(o.form)[0].submit();
		}


		o.form.submit(function() {
			return self.validate(true);
		});


	}

	function create(o) {
		return new Form(o);
	}

	return {
		create: create
		}

}();



emp.Autocomplete = function(o) {
	var o = $.extend({
		target: $(),
		url: null,
		items: [],
		minLength: 0,
		wait: 300,
		createIndex: function(item) {return emp.removeAccents(item, true)},
		renderItem: function(item) {return item},
		selectItem: function(item) {return item}
	}, o);

	var timer;
	var indexes = [];
	var suggestions = [];
	var selected;
	var originalValue = "";

	var dom = $('<ul class="emp-autocomplete">').hide().insertAfter(o.target).css({
		position: "absolute",
		zIndex: 100,
		width: o.target.outerWidth(),
		top: o.target.position().top + o.target.outerHeight() + 3,
		left: o.target.position().left
	});


	function selectItem(item) {
		originalValue = o.selectItem(item);
		o.target.val(originalValue).focus();
		close();
	}


	function init() {
		o.target.attr("autocomplete", "off")
			.keydown(function(e) {
				if (e.keyCode == emp.keys.ENTER && dom.is(":visible")) {
					selectItem(suggestions[selected]);
					return false;
				}

				if (e.keyCode == emp.keys.ESC) {
					dom.hide();
					return false;
				}

				if (e.keyCode == emp.keys.TAB) {
					close();
					return;
				}

				if (e.keyCode == emp.keys.UP && dom.is(":visible")) {
					selected--;
					renderSuggestions();
					return false;
				}

				if (e.keyCode == emp.keys.DOWN) {
					if (dom.is(":visible")) {
						selected++;
						renderSuggestions();
					} else {
						originalValue = "";
						search();
					}

					return false;
				}
			})

			.keyup(function(e) {
				clearTimeout(timer);

				timer = setTimeout(function() {
					search();
				}, o.wait);
			});
	}


	function search() {
		value = o.target.val();
		indexedValue = emp.removeAccents($.trim(value), true);

		if (value != originalValue) {
			suggestions = [];
			selected = 0;
			originalValue = value;

			if (indexedValue.length > o.minLength) {

				if (o.url) {
					o.target.addClass("emp-autocomplete-loading");

					$.post(o.url, {q: value}, function(response) {
						o.target.removeClass("emp-autocomplete-loading");

						if (response)
							o.items = suggestions = response;

						renderSuggestions();
					}, "json");

				} else {

					if (!indexes.length) {
						for (var i = 0; i < o.items.length; i++)
							indexes.push({index: $.trim(o.createIndex(o.items[i])), item: o.items[i]});

						indexes.sort(function(a, b) {
							return a.index.toLowerCase() > b.index.toLowerCase() ? -1 : 1;
						});
					}


					for (var i = 0; i < indexes.length; i++) {
						if (indexes[i].index.indexOf(indexedValue) > -1) {
							suggestions.push(indexes[i].item);
						}
					}

					renderSuggestions();
				}

			}
		}
	}


	function renderSuggestions() {
		if (!suggestions.length) {
			dom.hide();
			return false;
		}

		selected = selected < 0 ? 0 : selected >= suggestions.length ? suggestions.length - 1 : selected;

		dom.empty();

		for (var i = 0; i < suggestions.length; i++) {
			itemText = o.renderItem(suggestions[i]);

			// todo: zvyraznovanie textu

			$('<li>').append(itemText).appendTo(dom).addClass(i == selected ? "selected" : "")
				.click((function(item) {return function() {selectItem(item);}})(suggestions[i]));
		}

		dom.show();

		$(window).bind('click.empAutocomplete', function(e) {
			if (!$(e.target).parents().andSelf().filter(dom).length && !$(e.target).filter(o.target).length)
				close();
		});
	}


	function close() {
		dom.hide();
		suggestions = [];
		$(window).unbind('.empAutocomplete');
	}


	init();

	}



emp.TableSorter = function(o) {
	var o = $.extend({
		table: $('table').eq(0),
		columns: {},
		sortBy: null,
		direction: "asc",
		parser: function(a) {return emp.removeAccents($(a).html(), true);}
		}, o);

	o.direction = (o.direction == "asc");

	var dom = {
		sortPointer: $('<span class="emp-sort-pointer emp-icon">')
			.css({position: "absolute", right: -27})
	}


	function sortTable(sortBy, direction) {
		if (direction == undefined)
			o.direction = ( sortBy == o.sortBy ? !o.direction : true );
		else
			o.direction = direction;

		o.sortBy = sortBy;

		var up = (o.direction ? -1 : 1)
		var down = up * -1;

		$(o.columns[o.sortBy].column)
			.sort(function(a,b) {
				return o.columns[o.sortBy].parser(a) > o.columns[o.sortBy].parser(b) ? down : up;
			})
			.each(function() {
				$(this).parent("tr").appendTo($(this).parent("tr").parent());
			});

		dom.sortPointer.removeClass("emp-icon-up emp-icon-down").addClass(o.direction ? "emp-icon-down" : "emp-icon-up");
		o.columns[o.sortBy].handler.append(dom.sortPointer);
	}


	$.each(o.columns, function(key) {
		if (!this.parser)
			this.parser = o.parser

		if (typeof this.column == "number")
			this.column = 'tr td:nth-child(' + this.column + ')';

		if (!this.handler)
			this.handler = o.table.find("th").eq(o.table.find(this.column).eq(0).index());

		this.handler.append($('<span>').append(this.handler.contents()).css({cursor: "pointer", position: "relative"}));
		this.handler = this.handler.find('span').eq(0).click((function(key) {return function() {sortTable(key);return false;}})(key));
	});

	if (o.sortBy)
		sortTable(o.sortBy, o.direction)

	this.sortTable = sortTable;

}



emp.calendar = function() {

	var Calendar = function(o) {
		var o = $.extend({
			target: $(),
			time: false,
			fillOnInit: true,
			parseDate: function(date) {
				fixNumber = function(number) {return (number < 10 ? "0" : "") + number.toString(10)}

				if (typeof date == "string") {
					date = /^(....)\-(..?)\-(..?)( (..?)\:(..?)\:(..?))?$/.exec($.trim(date));

					if (!date)
						date = new Date();
					else
						date = new Date(parseInt(date[1], 10), parseInt(date[2], 10)-1, parseInt(date[3], 10),
							parseInt(date[5], 10) || 0, parseInt(date[6], 10) || 0, parseInt(date[7], 10) || 0);

				} else if (typeof date == "object" && date instanceof Date) {

					date = fixNumber(date.getFullYear()) + "-" + fixNumber(date.getMonth() + 1) + "-" + fixNumber(date.getDate()) +
						(o.time ? " " + fixNumber(date.getHours()) + ":" + fixNumber(date.getMinutes()) + ":" + fixNumber(date.getSeconds()) : "");

				}

				return date;
			}
		}, o);

		var selectedDate;
		var browseDate;
		var today = new Date();

		var months = ["Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Október", "November", "December"];
		var days = ["Po", "Ut", "St", "Št", "Pi", "So", "Ne"];

		var holder = $('<div class="emp-calendar">');



		function open() {
			if (holder.is(":visible"))
				return;

			selectedDate = o.parseDate(o.target.val());
			browseDate = new Date(selectedDate);

			render();

			holder
				.showInPosition({holder: o.target, vertical: "under", horizontal: "center", offsetTop: 3})
				//.show(); //todo:animation

			$(window)
				.bind('keyup.empCalendar', function(e) {
					if (e.keyCode == emp.keys.ESC) close();
				})
				.bind('mousedown.empCalendar', function(e) {
					if (!$(e.target).andSelf().parents(holder).filter(holder).length && !$(e.target).filter(o.target).length)
						close();
				})
		}


		function render() {
			renderDate = new Date(browseDate);
			renderDate.setDate(1);
			renderDate.setDate(-((renderDate.getDay() || 7) - 1))

			holder.items().monthYear.html(months[browseDate.getMonth()] + " " + browseDate.getFullYear());
			holder.items().calendar.empty();

			compareDates = function(a,b) {
				return a.getFullYear() == b.getFullYear() && a.getMonth() == b.getMonth() && a.getDate() == b.getDate();
			}

			for (var i = 0; i < 42; i++) {
				renderDate.setDate(renderDate.getDate() + 1);

				$('<li>')
					.append(renderDate.getDate())
					.addClass(renderDate.getMonth() != browseDate.getMonth() ? "other-month" : "")
					.addClass(compareDates(renderDate, selectedDate) ? "selected" : "")
					.addClass(compareDates(renderDate, today) ? "today" : "")
					.click((function(date) {date = new Date(date);return function() {close(date);return false;}})(renderDate))
					.appendTo(holder.items().calendar);
			}

		}


		function close(setDate) {
			if (setDate)
				o.target.val(o.parseDate(setDate)).focus();

			holder.fadeOut(100, function() {$(this).detach()} );
			$(window).unbind('.empCalendar');
		}


		function init() {
			holder.append(
				$('<header>').append(
						$('<span class="next-month emp-icon emp-icon-right">')
							.click(function() {browseDate.setMonth(browseDate.getMonth() + 1);render();return false;}),
						$('<span class="prev-month emp-icon emp-icon-left">')
							.click(function() {browseDate.setMonth(browseDate.getMonth() - 1);render();return false;}),
						holder.items().monthYear = $('<span class="month-year">')
					),
					$('<ul class="days">').append('<li>' + days.join('</li><li>') + '</li>'),
					holder.items().calendar = $('<ul class="calendar">')
				);

			o.target.addClass("emp-calendar-icon")
				.attr("autocomplete", "off")
				.bind('click.empCalendar', function() {open()})
				.bind('focus.empCalendar', function() {open()})
				.bind('keydown.empCalendar', function(e) {if (e.keyCode == emp.keys.TAB) close();});

			if (o.fillOnInit && !o.target.val())
				o.target.val(o.parseDate(new Date()));
		}


		init();

	}

	function create(o) {
		return new Calendar(o)
	}

	return {
		create: create
		}

}();



/***  jQuery Extensions  ******************************************************/


// TODO nahradit "items" "elements"
$.fn.items = function() {
		if (!this.__items)
			this.__items = {}

		return this.__items;
	}



$.fn.elements = function(key) {
	if (!this.__elements)
		this.__elements = {}

	if (key)
		return this.__elements(key);

	return this.__elements;
}



$.fn.getHrefHash = function(parseActions) {
	return emp.getHrefHash($(this).attr("href"), parseActions);
}



$.fn.defaultValue = function(defaultText) {
	return $(this)
		.focus(function() {if ($(this).val() == defaultText) $(this).val("");})
		.blur(function() {if ($(this).val() == "") $(this).val(defaultText);});
}



// prehodi css triedy objektu
$.fn.swapClass = function(c1, c2) {
	$(this).removeClass(c1).addClass(c2);
	return this;
}



// disable element
$.fn.disable = function(val) {
	$(this).attr("disabled", "disabled");
	if (val || false) $(this).val(val);

	return $(this);
}



// enable element
$.fn.enable = function(val) {
	$(this).removeAttr("disabled");
	if (val || false) $(this).val(val);

	return $(this);
}



// skontroluje / nastavi stav checkboxus
$.fn.checked = function(state) {
	if(typeof(state) == "undefined")
		return $(this).attr("checked");
	if(state)
		$(this).attr("checked", "checked");
	else
		$(this).removeAttr("checked");
	return state;
}



$.fn.scrollTo = function(speed, offset, easing) {
	scroll = $(this).offset().top - (offset || 10);
	$('html, body').animate({scrollTop: scroll > 0 ? scroll : 0}, speed || 200, easing || "swing");

	return $(this);
}



$.fn.dropdown = function(content, type) {
	$(this).click(function() {
		dom = $('<div>');

		for (var i in content)
			dom.append(content[i]);

		new	emp.DropDownMenu({
			position: type || "under",
			dockedTo: $(this),
			content: dom
		});
	 });
}



$.fn.caption = function(content) {
	emp.Caption({target: $(this), content: content});
	return this;
}



$.fn.showInPosition = function(o) {
	emp.showInPosition($.extend(o, {
		target: $(this)
			}));

	return $(this);
}



$.fn.cssAnimation = function(animation, duration, callback) {

	animation = typeof animation == "object" ? animation : emp.animations[animation];
	callback = typeof duration == "function" ? duration : callback;
	duration = typeof duration == "number" ? duration : 400;

	var element = $(this);

	if (element[0].cssAnimation)
		clearTimeout(element[0].cssAnimation);

	element
		.vendorCss("transition", "none")
		.vendorCss(animation.from)

	setTimeout(function() {
		element
			.vendorCss("transition", "all " + duration + "ms " + (animation.ease || ""))
			.vendorCss(animation.to)
	});

	element[0].cssAnimation = setTimeout(function() {
		element
			.vendorCss("transition", "");

		if (typeof callback == "function")
			callback.apply(element);

	}, duration + 50);

	return this;

}




	// CSS3 3D efekty
$.fn.vendorCss = function(property, value) {
	var element = $(this);

	if (typeof property == "object") {
		$.each(property, function(property, value) {element.vendorCss(property, value)});

	} else {
		var vendorProperties = ["transform", "transition", "animation", "perspective"];
		var vendorPrefixes = ["-webkit-", "-moz-", "-ms-", "-o-", ""];

		if (vendorProperties.indexOf(property) > -1)
			for (var i = 0; i < vendorPrefixes.length; i++)
				element.css(vendorPrefixes[i] + property, value);
		else
			element.css(property, value)

	}

	return $(this);
}




/***  Fix Array indexOf method  ***********************************************/


/***  Console reporter  *******************************************************/

if (typeof console == 'undefined') {
	var console = {
		log: function(msg) {return msg;}
	};
}

function r(data) {
	console.log(data);
}

function error(data) {
	if (emp.isDebug())
		console.error(data);
}



Array.prototype.indexOf = function(obj, start) {
	for (var i = (start || 0); i < this.length; i++) {
		if (this[i] == obj)
			return i;
	}

	return -1;
}


Array.prototype.removeItem = function(item) {
	var founded = false;

	for (var i = 0; i < this.length; i++)
		if (this[i] === item)
			founded = i;

	if (founded !== false) {
		this.splice(founded, 1);
		return true
	}

	return false;
}


String.prototype.removeAccents = function(lowercase) {
	return emp.removeAccents(this, lowercase);
}
