
var emp = emp || {};



emp.createApp = function(vars, i18n) {  
	return {
		vars: vars || {},
		i18n: i18n || {},
		dom: {}
		}
}



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.ID = {
	id: 1,
	get: function() {return this.id++}
}



emp.cookie = {
	set: function(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=/";
	},
	get: function(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;
	},
	unset: function(name) {
		this.set(name, "", -1);
	}
}


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.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)
			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() {
	html = $("html");
	body = $("body");

	return {
		window: {
			width: window.innerWidth || document.body.clientWidth,
			height: window.innerHeight || document.body.clientHeight
			},
		document: {
			width: html.width(),
			height: html.height()
		},
		scroll: {
			top: body.scrollTop(),
			left: body.scrollLeft()
			}
		}
}



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



emp.showInPosition = function(element, target, vertical, horizontal, offsetLeft, offsetTop) {
	var elementPosition = {}

	target = target || $('body');
	horizontal = horizontal || "center";
	vertical = vertical || "center";			
	offsetLeft = ( typeof offsetLeft == "number" ? offsetLeft : 0 );
	offsetTop = ( typeof offsetTop == "number" ? offsetTop : 0 ); 

	element
		.css({position: "absolute", left: 0, top: 0}) //, opacity: 0
		.appendTo($('body'));

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

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

	element.css(elementPosition).css({opacity: 1});	
}



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


emp.Movable = function(o) {
	var o = $.extend({
		target: $(),
		handler: $(),
		onStart: function(self) { },
		onStop: function(self) { },
		onMove: function(self) { }
		}, o);

	var self = this;

	function bind() {
		(o.handler || o.target).bind("mousedown.Movable", function(e) {
			var e = e || window.event;
			var pageSizes = emp.getPageSizes();
			var origin = {
				target: {
					left: o.target.offset().left,
					top: o.target.offset().top
					},
				mouse: {
					left: e.screenX,
					top: e.screenY
					}
				}

			o.onStart(origin.target, self);

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

			$(window).bind("mousemove.Movable", function(e) {
				var e = e || windows.event;

				position = {
					left: ( (a = origin.target.left - (origin.mouse.left - e.screenX)) < 0 ? 0 : a ),
					top:  ( (a = origin.target.top - pageSizes.scroll.top - (origin.mouse.top - e.screenY)) < 0 ? 0 : a )
					}

				o.target.css(position);

				o.onMove(position, origin.target, self);

				return false;
			});

			$(window).bind("mouseup.Movable", function() {
				$("body").css("cursor", "default !important");

				$(this).unbind("mousemove.Movable");
				$(this).unbind("mouseup.Movable");

				o.onStop(o.target.offset(), origin.target, self);
			})

			return false;
		});
	}


	function unbind() {
		$(this).unbind("mousemove.movable");
		$(this).unbind("mouseup.movable");
		$(o.handler || o.target).unbind("mousemove.movable");
	}

	this.unbind = unbind;

	bind();
}



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

	var dom = null;
	var offset = {top:0, left:0};
	var timer = null;


	function init() {
		dom = $('<div>').css({position: "fixed", zIndex: 100000, width: 300}).append($('<div class="emp-caption">').append(o.content)).hide().prependTo(o.target);

		o.target.bind("mouseenter.Caption", function(e) {
			timer = setTimeout(function() {
				dom.fadeIn(200);
				offset = dom.offsetParent().offset();
			}, 300);
		});

		o.target.bind("mousemove.Caption", function(e) {
			dom.css({top: e.pageY + 10  - offset.top, left: e.pageX + 15 - offset.left});
		});

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

	this.dom = function() {return dom;}

	init();

}



emp.Box = function(o) {
	var o = $.extend({
		position: "center",
		width: "auto",
		height: "auto",
		holder: $("body"),
		dockedTo: $(),
		content: $(),
		fixed: false,
		padding: 4,
		holdPosition: false,
		css: ""
	}, o);

	var dom = $('<div class="emp-box">').addClass(o.css).css({position: ( o.fixed ? "fixed" : "absolute" )})
	var items = { };

	var getPosition = function(position) {
		pageSizes = emp.getPageSizes();

		switch(position) {
			case "center":
				return {
					left: ( (a = Math.round((pageSizes.window.width - ( o.width == "auto" ? dom.outerWidth() : o.width )) / 2)) < 0 ? 0 : a ),
					top: ( (a = Math.round((pageSizes.window.height - ( o.height == "auto" ? dom.outerHeight() : o.height )) / 2 * 0.65)) < 0 ? 0 : a )
					};

			case "under":
				offset = o.dockedTo.offset();
				offset.top += o.dockedTo.outerHeight() + o.padding;

				return offset;

			case "over":
				offset = o.dockedTo.offset();
				offset.top -= dom.outerHeight() + o.padding;

				return offset;

			default:
				return position;
		}
	}


	var resize = function(position) {
		dom.stop().css(getPosition(position || o.position));
	}


	var show = function(position) {
		dom.css({top:0, left: -99999}).append(o.content).appendTo(o.holder).css(getPosition(position || o.position));

		if (o.holdPosition)
			$(window).bind("resize.Box", function() {resize(position)});
	}


	var hide = function() {
		dom.detach();

		if (o.holdPosition)
			$(window).unbind("resize.Box");
	}

	this.dom = function() {return dom;}
	this.items = function() {return items;}

	this.show = show;
	this.hide = hide;

}



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

		width: 450,
		height: "auto",
		modal: false,
		autoOpen: true,

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

	var self = this;
	var content = null;
	var layers = 0;
	var ID = emp.ID.get();

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

	var loader = new emp.Box({
		css: "emp-dialog"
		});

	var box = new emp.Box({
		width: o.width,
		fixed: true,
		css: "emp-dialog"
		});


	function generateButtons(map) {
		var buttons = $();

		$.each(map, function(text, callback) {  
			var button = $('<button class="emp-button">');
			
			if (/\:focus$/.test(text)) {
				text = text.replace(/\:focus$/, "");
				o.focus = button;
			}
			
			button.html(text).click((function(callback) {
				return function() {
					if (callback === true)
						return submit();
					if (callback === false)
						return close();
					
					return callback(self);
				}
			})(callback));
			
			buttons = buttons.add(button);
		});

		return buttons;
	}


	function init() {
		box.dom().css({width: o.width, height: o.height}).append(
			box.items().header = $('<header>')
				.append(o.title)
				.append($('<span class="close emp-icon emp-icon-delete">').click(close)),
			box.items().content = $('<div>'),
			box.items().footer = $('<footer>')
				.append(generateButtons(o.buttons)));
			
		box.dom().movable(box.items().header);

		if (box.items().footer.is(":empty"))
			box.items().footer.hide();

		fog.css({position: "fixed", top: 0, left: 0}).click(function() {
			if(!o.modal && o.onCancel(box))
				close();
		});

		if (o.autoOpen)
			open();
	}


	function bindClosable() {
		$(window).bind("keyup.Dialog", function(e) {
			if ((e || window.event).keyCode == emp.keys.ESC && o.onCancel(self)) {
				close();
				return false;
			}
		});
	}


	function unbindClosable() {
		$(window).unbind("keyup.Dialog");
	}


	function showLoader() {
		loader.dom.html('<span class="emp-loader">Otváram... <br/></span>').css({zIndex: 9999 + layers});
		loader.show();
	}


	function hideLoader() {
		loader.hide();
	}


	function showFog() {
		fog.css({width: $(document).width(), height: $(document).height(), zIndex: 9998 + layers}).appendTo("body");
	}


	function hideFog() {
		fog.detach();
	}


	function checkLayers() {
		layers = $(".-dialog-fog").length;
	}


	function open() {
		checkLayers();
		showFog();
		bindClosable();

		$(window).bind("resize.Dialog", showFog);

		// ak uz mame nahraty obah, zobrazime ho
		if (content != null) {
			display();
			return;
		}

		// v opacnom pripade sa pozrieme ci bol zadany zobrazitelny obsah
		if (o.content instanceof jQuery || typeof o.content == "string") {

			content = o.content;
			display();

		// alebo ci si ho mame nahrat z nejakej url lokality
		} else {

			showLoader();

			emp.ajax(o.content.url, { }, function(responce) {
				content = responce
				hideLoader();
				display();
			}, html);
				
		}

	}


	function display() {
		box.items().content.append(content);
		box.dom().css({zIndex: 9999 + layers});
		box.show();
		
		if (o.focus !== false && (o.focus == null || !o.focus.length))
			o.focus = box.dom().find("input, button").eq(0);
		
		o.focus.focus();

		o.onOpen(self);
	}


	function close() {
		box.items().content.children().detach();
		box.hide();

		if (!o.cache)
			content = null;

		hideLoader();
		hideFog();
		unbindClosable();

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


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


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

	this.dom = function() {return box.dom();}
	this.items = function() {return box.items()}
	this.content = function() {return content;}
	
	this.open = open;
	this.close = close;
	this.submit = submit;
	this.cancel = cancel;

	init();
}



emp.Confirm = function(o) {
	var o = $.extend({
		target: $(),
		title: '',
		content: '',
		yes: 'Yes',
		no: 'No'
	}, o)

	o.target.click(function() { 
		var location = $(this).attr("href");
		var buttons = {};

		buttons[o.no + ":focus"] = function(dialog) {dialog.close()};
		buttons[o.yes] = function() {window.location = location};

		new emp.Dialog({
			title: o.title,
			content: o.content,
			buttons: buttons
		});

		return false;
	 });
}



emp.Uploader = function(o) {
	var self = this;

	var o = $.extend({
		args: {},
		launcher: $(),
		queueHolder: $(),
		dropZone: $(),
		autoStart: true,
		multipleFiles: true,
		url: "/",
		filter: true,
		maxFileSize: 32 * 1024 * 1024,
		onInsert: function() {  },
		onStart: function() {  },
		onProgress: function(record, loaded, total) {  },
		onComplete: function(record) {  },
		onTotalyComplete: function(queue) {  },
		onDragStart: function() {  },
		onDragCancel: function() {  },
		onDragEnter: function() {  },
		onDragLeave: function() {  },
		onDrop: function() {  }
	}, o);

	var queue = [];
	var pointer = 0;
	var uploading = false;
	var counter = $('<span class="counter">');


	function prepareUrl(url, args) {
		var a = [];

		$.each(args, function(key, val) {
			a.push(key + "=" + val);
		});

		return url + ( a.length ? "?" : "" ) + a.join("&");
	}


	function getFileSizeFormatted(size) {
		var i = 0;

		while ((size /= 1024) > 1) i++;

		return (Math.round(size * 1024 * 10) / 10).toString() + " " + ["B", "kB", "MB", "GB", "TB", "PB"][i];
	}


	function cancelUpload(record) {
		record = record || queue[0];

		if (record) {
			record.xhr.abort();
			record.object.remove();
		}

		uploading = false;
	}


	function cancelAllUploads() {
		for (i in queue) {cancelUpload(queue[i])}
	}


	function onProgress(record, loaded, total) {

		percents = Math.round((loaded / total) * 100).toString();

		record.object.parts.percents.html(percents + "%");
		record.object.parts.progress.css({width: percents + "%"});

		o.onProgress(self, record, percents, loaded, total);
	}


	function onComplete(record) {
		record.object.parts.percents.html("100%");
		record.object.parts.progress.css({width: "100%"});
		record.object.parts.cancel.hide();

		setTimeout(function() {
			o.onComplete(self, record);
			uploading = false;

			if (queue[++pointer]) {
				record.object.removeClass("active").addClass("complete");
				startUpload();
			} else {
				onTotalyComplete();
			}
		 }, 100);

		 error("[Uploader] File '" + record.fileName + "' has been uploaded.");
	}


	function onTotalyComplete() {
		//o.queueHolder.empty();
		queue = [];
		pointer = 0;
		uploading = false;
		//counter.empty();

		o.onTotalyComplete(queue);
	}


	function startUpload(record) {

		if (uploading || (!record && !queue[pointer]) || o.onStart() === false)
			return false;

		uploading = true;
		updateCounter();

		record = record || queue[pointer];

		record.object.removeClass("waiting").addClass("active");
		record.object.parts.cancel.show();

		encodedFileName = encodeURIComponent(record.fileName);

//		jqXHR object zatial nepodporuje upload :(
//		record.xhr = $.ajax({
//			url: prepareUrl(o.url, $.extend({file: encodedFileName}, o.args)),
//			type: "POST",
//			processData: record.file,
//			header: {
//				"X-Requested-With": "XMLHttpRequest",
//				"X-File-Name": encodedFileName,
//				"Content-Type": "application/octet-stream"
//				},
//			success: function() {onComplete(record)},
//			error: function() {r("wwwwwww")},
//			beforeSend: function(xhr) {
//				xhr.upload.addEventListener("progress", function(e) {
//					if (e.lengthComputable)
//						onProgress(record, e.loaded, e.total);
//				});
//
//			}
//		});
		
		record.xhr.upload.onprogress = function(e) {
			if (e.lengthComputable)
				onProgress(record, e.loaded, e.total);
		};


		record.xhr.onreadystatechange = function() {
			if (this.readyState == 4)
				onComplete(record);
		}
		
		record.xhr.open("POST", prepareUrl(o.url, $.extend({file: encodedFileName}, o.args)), true);
		record.xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
		record.xhr.setRequestHeader("X-File-Name", encodedFileName);
		record.xhr.setRequestHeader("Content-Type", "application/octet-stream");
		record.xhr.send(record.file);

		r("[Uploader] Uploading of file '" + record.fileName + "' has started.");

	}


	function insertToQueue(file) {
		
		if (o.onInsert() === false)
			return false;

		var record = {}

		record.file = file;
		
		record.fileName = file.fileName || file.name;
		record.fileSize = file.fileSize || file.size;

		if (!o.multipleFiles && queue.length > 1) {
			error("[Uploader] Multiple files upload is disabled '" + record.fileName + "'.");
			return false;
		}

		if (o.filter !== true && o.filter.indexOf(record.fileName.substr(record.fileName.lastIndexOf(".") + 1)) < 0) {
			error("[Uploader] Bad extension of '" + record.fileName + "'.");
			return false;
		}

		if (record.fileSize > o.maxFileSize) {
			error("[Uploader] Ivalid filesize of '" + record.fileName + "'.");
			return false;
		}

		record.xhr = new XMLHttpRequest(); // TODO
		record.object = $('<div class="file waiting">').append(
			$('<span class="name">').html(record.fileName),
			$('<span class="size">').html(getFileSizeFormatted(record.fileSize)),
			$('<span class="percents">').html("0%"),
			$('<span class="progress-bar">').append(
				$('<span class="progress">')),
			$('<a class="cancel file-icon file-icon-cancel">').html("&nbsp;").hide().click(function() {cancelUpload(record);}),
			$('<span class="clear">')
			);

		record.object.parts = {
			percents: record.object.find(".percents"),
			progress: record.object.find(".progress"),
			cancel: record.object.find(".cancel")
			}

		if (!queue.length)
			o.queueHolder.find(".file");


		record.object.appendTo(o.queueHolder);
		queue.push(record);

		r("[Uploader] File '" + record.fileName + "' has been inserted to upload queue.");
		
		if (o.autoStart)
			startUpload(record);
	}


	function updateCounter() {
		//counter.html ((pointer + 1).toString() + "/" + queue.length.toString());
	}


	function validateFileDrag(event) {
		dataTransfer = event.originalEvent.dataTransfer || event.dataTransfer;
	}


	function bindDropZone() {
		$(document)
			.bind('dragenter', function(e) {
//				r(0);
				validateFileDrag(e);
				o.onDragStart(self, e);
				return false;
			})
			.bind('drageleave', function(e) {
				r(00);
				o.onDragCancel(self, e);
				return false;
			});

		o.dropZone
			.bind('dragover', function(e) {
//				r(1);
				return false;
			})
			.bind('dragenter', function(e) {
//				r(2);
				o.onDragEnter(self, e);
				return false;
			})
			.bind('dragleave', function(e) {
//				r(3);
				o.onDragLeave(self, e);
				return false;
			})
			.bind("click", function() {
				o.dropZone.fadeOut(200);
			})
			.bind('drop', function(e) {
//				r(4);
				validateFileDrag(e);
				e.dataTransfer = e.originalEvent.dataTransfer;

				if (o.onDrop(self, e) === false)
					return false;
				
				for (var i = 0; i < e.dataTransfer.files.length; i++) {
					insertToQueue(e.dataTransfer.files[i]);
				}

				return false;
			});
		
	}


	function bindUploader() {
		var input = $('<input>')
			.attr({multiple: o.multipleFiles ? "multiple" : false, type: "file", name: "file", value: ""})
			.css({position: "absolute", top: 0, right: 0, padding: 0, margin: 0, opacity: 0, width: o.launcher.outerWidth(), cursor: "pointer !important"})
			.change(function() {
				$.each(input[0].files, function() {
					insertToQueue(this);
				});
			});

		var launcher = $('<div>')
			.addClass("button")
			.css({display: "inline-block", direction:"ltr", position: "relative", overflow: "hidden", cursor: "pointer !important"})
			.html(o.launcher.html())
			.append(input)
			.insertAfter(o.launcher);

		o.launcher.hide();
		o.queueHolder.addClass("emp-uploader query").prepend(counter);

		if (o.dropZone.length)
			bindDropZone();
	}


	bindUploader();

	this.cancelAllUploads = cancelAllUploads;
	this.startUpload = startUpload;
	this.cancelUpload = cancelUpload;
	this.queryLength = function() {return query.length}
	this.currentUpload = function() {return;}
	this.setArgs = function(args) {o.args = args}

}



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.TabSwitcher = function(o) {
	var o = $.extend({
		buttons: $(),
		holder: $("body"),
		tabs: $()
		},o);
		
	if (!o.tabs.length)
		o.tabs = o.holder.find("[id^='tab-']");

	function switchToTab(tabName) {
		if (!(tab = o.tabs.filter("#tab-" + tabName)).length)
			return;
		
		o.tabs.hide();
		tab.show();
		
		o.buttons.filter(".selected").removeClass("selected");
		o.buttons.filter("[href$='#" + tabName + "']").addClass("selected");
	}

	o.buttons.click(function(e) { 
		switchToTab($(this).getHrefHash());
		
		return (!$(e.target).filter($(this)).length) ? true : false;
	});
	
	this.switchToTab = switchToTab;
}



emp.Form = function(o) {
	var o = $.extend({
		form: $("form").eq(0),
		items: { },
		beforeCheck: function(form, items) {return true;},
		afterCheck: function(form, items) {return true;},
		onError: function(items) {
			$.each(items, function() { 
				if (!this.valid) {
					this.input.focus();
					return false;
				}
			});
		}
	}, o);

	var valid = true;
	var enable = true;
	var self = this;


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


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


	function validateForm(raiseErrors) {
		var raiseErrors = (raiseErrors == undefined ? true : raiseErrors);
		var items = getItems();
		var valid = true;

		if (!enable)
			return false;

		disableForm();
		
		o.form.find("div.input-field.error").removeClass("error");

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

		// kontola poloziek cez zadane pravidla
		$.each(items, function() {
			if (validateItem(this, items) === false) {
				valid = false;
				
				if (raiseErrors && this.onError)
					this.onError(this);
			}
		});
		
		// funkcia afterCheck
		if (!valid || o.afterCheck(self, items) === false) {
			if (o.onError)
				o.onError(items);
			
			$.each(items, function() { 
				if (!this.valid)
					this.input.parents("div.input-field").eq(0).addClass("error");
			});
			
			enableForm();
			return false;
		}
		
		return valid;
	}


	function validateItem(item, items) {
		// ak uz polozka ma nastavenu validitu, nekontrolujeme (nastavil jej ju niekto z vonku)
		if (item.valid != null) {
		
		// 'type' moze byt aj funkcia ktora urci validnost 
		} else if (typeof item.type == "function") {
			item.valid = item.type(item, self, items || {});
			
		// 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(typeof(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;
		}

		return item.valid;
	}



	// skontroluje ci sa polozky nachadzaju vo formulari a namapuje ich
	function getItems() {
		var items = {}
		
		$.each(o.items, function(name, options) {
			var element;
			
			if ((element = o.form.find('[name=' + name + ']')).length) {
				items[name] = $.extend({
					name: name,
					input: element,
					value: $.trim(element.val()),
					type: null,
					valid: null,
					required: true,
					msg: false,
					focus: true,
					onError: function(item) { 
						error("[Form] Invalid entry on '" + item.name + "'");
					}
				}, options);
			} else {
				error("[Form] Item '" + name + "' not found!");
			}
		});
					
		return items;
	}


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

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

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

	this.addItem = function(itemName, options) {  
		if (itemName instanceof Object && !options)
			$.each(itemName, function(itemName, options) {  
				o.items[itemName] = options;
			});
		else
			o.items[itemName] = options;
	}
	
	this.validate = validateForm;

	this.enable = enableForm;
	
	this.disable = disableForm;
	

}



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(o) {
	var o = $.extend({
		input: $(),
		time: false,
		defaultDate: new Date(),
		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 dom = {}

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

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

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

		renderCalendar();

		dom.holder.showInPosition(o.input, "under", "center", 0, 3).hide().fadeIn(100);

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


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

		dom.monthYear.html(months[browseDate.getMonth()] + " " + browseDate.getFullYear());
		dom.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() {closeCalendar(date);return false;}})(renderDate))
				.appendTo(dom.calendar);
		}

	}


	function closeCalendar(setDate) {
		if (setDate)
			o.input.val(o.parseDate(setDate)).focus();
		
		dom.holder.fadeOut(100, function() {$(this).detach()} );
		$(window).unbind('.empCalendar');
	}


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

}



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

$(function() {

	$.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;
	}


	// za/odskrtne vsetky chceboxy predane selecotrom
	$.fn.checkAll = function(target) {
		$(this).click(function() {
			if($(this).attr("checked"))
				$(target).attr("checked", "checked")
			else
				$(target).removeAttr("checked");
		});
	}



	$.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.movable = function(o) {
		if (o instanceof jQuery)
			o = {handler: o}
		
		emp.Movable($.extend({
			target: $(this),
			handler: $(this),
			onMove: function() {},
			onStart: function() {},
			onStop: function() {}
			}, o));

		return this;
	}
	
	

	$.fn.sortable = function(o) {

		var parent = $(this);
		var elements = parent.children();

		var helpers = $();
		var mover = $();
		var flyer = $();

		var originalPos = {x: 0, y: 0};
		var mouseStartPos = {left:0, top:0};

		var bind = function() {
			elements
				.css({cursor: "move !important"})
				.bind("click.sortable", function() {return false})
				.bind("mousedown.sortable", function(e) {
					mover = $(this);
					helpers = $();

					flyer = mover.clone(false);
					flyer.vars = {element : mover};

					mouseStartPos = {x: e.screenX, y: e.screenY};
					originalPos = mover.offset();

					$("body").css({cursor: "move !important"});

					var arr = [];

					elements.each(function() {
						var element = $(this);
						offset = $(this).offset();

						var helper = $('<div class="jsHelper">').css({
							zIndex: 1001, position: "absolute", top: offset.top, left: offset.left,
							width: mover.outerWidth(), height: mover.outerHeight()
							});

						helper.bind("mouseenter.sortable", function() {
							thisIndex = $(this).index(".jsHelper");
							moverIndex = mover.index();

							if (thisIndex > moverIndex)
								elements.eq(moverIndex).insertAfter(elements.eq(thisIndex));
							else if (thisIndex < moverIndex)
								elements.eq(moverIndex).insertBefore(elements.eq(thisIndex));
							else
								return;

							elements = $(parent).children();
						});

						helpers = helpers.add(helper);
						helper.hide().appendTo("body");
					});

					mover.css({visibility: "hidden"});
					flyer.css({position: "absolute", top: originalPos.top, left: originalPos.left, zIndex: 1000}).appendTo(parent);

					helpers.show();


					$(window).bind("mousemove.sortable", function(e) {
						flyer.css({
							left: (a = originalPos.left + (e.screenX - mouseStartPos.x)) < 0 ? 0 : a,
							top: (a = originalPos.top + (e.screenY - mouseStartPos.y)) < 0 ? 0 : a
							});

						return false;
					});


					$(window).bind("mouseup.sortable", function() {
						var offset = mover.offset();

						flyer.animate({left:offset.left, top: offset.top}, 150, function() {
							mover.css({visibility: "visible"});

							flyer.remove();
							flyer = $();
							elements = $(parent).children();

							$(window).unbind("mouseup.sortable").unbind("mousemove.sortable");
							});

						helpers.remove();

						$("body").css({cursor: "default"});

						return false;
					});

					return false;
				});
		}


		var unbind = function() {
			elements
				.css({cursor: "auto"})
				.unbind("mousedown.sortable")
				.unbind("click.sortable");
		}


		if (o === false)
			unbind();
		else
			bind();


	}
	
	
	
	$.fn.showInPosition = function(target, vertical, horizontal, offsetLeft, offsetTop) {
		emp.showInPosition($(this), target, vertical, horizontal, offsetLeft, offsetTop);
		return $(this);
	}

});




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

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




/***  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);
}
