function Layers() {

	// Add container after body
	function addContainer(id) {
		return jQuery(document.createElement('div')).attr("id", id).appendTo(jQuery("body"));
	}

	function ModalLayer () {	
		var container = addContainer("JSU_modalLayer");		
	}
	
	// PopupMenu Layer
	// uses clases .popupMenu, .popupMenuInvoker
	// Menu identified by IDs
	function PopupMenuLayer () {
		
		// Current invoker element
		var invokerElem = null;
		// Current popup menu
		var elem = null;
		// Timer for menu hiding
		var timer = 0;
		
		var container = addContainer("JSU_popupMenuLayer");

		// Schova aktualni menu okamzite
		function hideAllPopupMenuLayer() {
			var tmp = jLayers.popupMenu.elem; 
			jLayers.popupMenu.elem = null;
			jQuery(jLayers.popupMenu.invoker).removeClass("activated");
			jLayers.popupMenu.invoker = null;
			if (tmp) jQuery(tmp).hide();	// Schovat menu
		}
		
		// Procedura, ktera zapocne skryvani vsecha menu
		function cleanupPopupMenuLayer() {
			clearTimeout(jLayers.popupMenu.timer);
			jLayers.popupMenu.timer = setTimeout(hideAllPopupMenuLayer, 200);					
		}

		// Procedura, ktera zobrazi menu k volanemu invokeru
		jQuery.fn.showPopupMenu = function() {
			return this.each(function(){
				clearTimeout(jLayers.popupMenu.timer);
				if (jLayers.popupMenu.invoker != this) {
					hideAllPopupMenuLayer(); // Hide previous menu
					jLayers.popupMenu.invoker = this;
					jQuery(jLayers.popupMenu.invoker).addClass("activated");
					jLayers.popupMenu.elem = jQuery("#"+jQuery(jLayers.popupMenu.invoker).getClassParam("target")).get(0);
					// Show menu
					jQuery(jLayers.popupMenu.elem)
						.sameOffset(jQuery(jLayers.popupMenu.invoker), jQuery(this).getClassParam("style"))
						.sameOffset(jQuery(jLayers.popupMenu.invoker), jQuery(this).getClassParam("style"))
						.sameOffset(jQuery(jLayers.popupMenu.invoker), jQuery(this).getClassParam("style"))
						.show();
				}
			});				
		}

		// Invokers settings
		jQuery.fn.registerPopupMenuInvoker = function() {
			jQuery(this)
				.addHoverAbility()
				.hover(
					function(){ 
						jQuery(this).showPopupMenu() },
					cleanupPopupMenuLayer
				);
		}
		
		// Register element
		jQuery.fn.registerPopupMenu = function() {
			jQuery(this)
				.appendTo(container) // Presun do kontejneru
				.mouseover(function(){
					clearTimeout(jLayers.popupMenu.timer);
				})
				.mouseout(cleanupPopupMenuLayer)
				.each(function(){
					// For each popupMenu, do - vypocti vysku a sirku prvku
					var menuHeight = 0;
					var maxTextWidth = 0;
					jQuery(this).children().each(function(){
						maxTextWidth = Math.max(maxTextWidth, jQuery(this).text().length);
						menuHeight += (jQuery(this).css("line-height")).number();	
					});
					jQuery(this).css("width", (maxTextWidth * 0.8)+"em");
				});
		}
		
	}
	
	
	
	
	
	function FloatingBubbleLayer() {
		this.elem = null;
		this.invokerElem = null;
		var container = addContainer("JSU_floatingBubbleLayer");
		jQuery(".floatingBubble").each(function(){
			var parent = jQuery(this).parent();
			var elem = jQuery(this).appendTo(container);
			parent.data('floatingBubbleTarget', elem);
			parent.addClass('floatingBubbleInvoker');
			parent.addHoverAbility();
			parent.hover(
				function(){ jQuery(this).showFloatingBubble() },
				hideAllFloatingBubbleLayer
			);
		});
			
		// Schova aktualni bubble
		function hideAllFloatingBubbleLayer() {
			var tmp = jLayers.floatingBubble.elem; 
			jLayers.floatingBubble.elem = null;
			jQuery(jLayers.floatingBubble.invoker).removeClass("bubbleActivated");
			jLayers.floatingBubble.invoker = null;
			if (tmp) jQuery(tmp).hide();
		}

		// Procedura, ktera zobrazi bubble k volanemu invokeru
		jQuery.fn.showFloatingBubble = function() {
			return this.each(function(){
				if (jLayers.floatingBubble.invoker != this) {
					hideAllFloatingBubbleLayer(); // Hide previous menu
					jLayers.floatingBubble.invoker = this;
					jQuery(jLayers.floatingBubble.invoker).addClass("activated");
					jLayers.floatingBubble.elem = jQuery(this).data('floatingBubbleTarget');
					// Show menu
					jQuery(jLayers.floatingBubble.elem)
						.sameOffset(jQuery(jLayers.floatingBubble.invoker), 'bottom')
						.show();
				}
			});	
		}

		
	}
	
	
	
	
	// DetailPopup Layer
	function DetailPopupLayer () {
		this.elem = null;
		this.timer = 0;
		this.invokerElem = null;
		var container = addContainer("JSU_detailPopupLayer");

		jQuery(".detailPopup").each(function(){
			
			var parent = jQuery(this).parent();
			var elem = jQuery(this).appendTo(container);
			parent.data('detailPopupTarget', elem);
			parent.addClass('detailPopupInvoker');
			parent.addHoverAbility();

			elem
				.mouseover(function(){
					clearTimeout(jLayers.detailPopup.timer);
					})
				.mouseout(cleanupDetailPopupLayer);
			parent
				.hover(
					function(){ jQuery(this).showDetailPopup() },
					cleanupDetailPopupLayer
				);

		});



		// Schova aktualni menu okamzite
		function hideAllDetailPopupLayer() {
			var tmp = jLayers.detailPopup.elem; 
			jLayers.detailPopup.elem = null;
			jQuery(jLayers.detailPopup.invoker).removeClass("activated");
			jLayers.detailPopup.invoker = null;
			if (tmp) jQuery(tmp).hide();	// Schovat menu
		}
		
		// Procedura, ktera zapocne skryvani vsecha menu
		function cleanupDetailPopupLayer() {
			clearTimeout(jLayers.detailPopup.timer);
			jLayers.detailPopup.timer = setTimeout(hideAllDetailPopupLayer, 250);					
		}
		

		// Procedura, ktera zobrazi menu k volanemu invokeru
		jQuery.fn.showDetailPopup = function() {
			return this.each(function(){
				clearTimeout(jLayers.detailPopup.timer);
				if (jLayers.detailPopup.invoker != this) {
					hideAllDetailPopupLayer(); // Hide previous menu
					jLayers.detailPopup.invoker = this;
					jQuery(jLayers.detailPopup.invoker).addClass("activated");
					jLayers.detailPopup.elem = jQuery(this).data('detailPopupTarget');
					// Show menu
					
					jQuery(jLayers.detailPopup.elem)
						.sameOffset(jQuery(jLayers.detailPopup.invoker), jQuery(jLayers.detailPopup.elem).getClassParam("style"))
						.show();
				}
			});				
		}


	}
	
	
	
	// Keep z-order when initializing layers
	this.modal = new ModalLayer();
	this.popupMenu = new PopupMenuLayer();
	this.detailPopup = new DetailPopupLayer();
	this.floatingBubble = new FloatingBubbleLayer();

}

var jLayers;

jQuery(function(){
	
	jLayers = new Layers();
	
	// jLayers init
	jQuery(".popupMenu").registerPopupMenu();
	jQuery(".popupMenuInvoker").registerPopupMenuInvoker();

	// Invokers settings
	jQuery(".detailPopupInvoker").addHoverAbility();
	jQuery(".detailPopupInvoker").hover(
		function(){ jQuery(this).showDetailPopup() },
		jLayers.detailPopup.cleanupDetailPopupLayer
	);

});	
