/*
 * 	
 * jQuery extensions by plentySystems
 * 
 *
 * 
 * HowTo ...
 * 
 * ...definine a custom function:
 * 
 * jQuery.fn.FUNCTIONNAME = function()
 * 							{
 * 								return jQuery(this).each(
 * 									function()
 * 									{
 * 										// "jQuery(this)" is the jquery object
 * 										jQuery(this).doSomething();
 * 									});
 *							};
 * 
 */


/*
 * Lets element(s) blink
 */
jQuery.fn.blink =  	function(iBlinkCount)
					{
						return jQuery(this).each(
							function()
							{
								// speed in ms
								var speed = 250;
								
								// count of blinks
								if(iBlinkCount > 0)
								{
									var count = iBlinkCount;
								}
								else
								{
									var count = 3;
								}
								
								for(var i=0;i<count;i++)
								{
									this.fadeOut(speed).fadeIn(speed);
								}
							});
					};

/*
 * Move element(s) to center (chainable), centers both on param unset
 */
jQuery.fn.center =	function (from)
					{
						return jQuery(this).each(
							function()
							{
								// top pos
								var top		= (jQuery(window).height() - jQuery(this).height()) / 2 + jQuery(window).scrollTop() + "px";
								// left pos
								var left	= (jQuery(window).width() - jQuery(this).width()) / 2 + jQuery(window).scrollLeft() + "px";
								
								switch(from)
								{
								// adjust top
								case 'top':
									jQuery(this).css("top", top);
									break;
									// adjust left
								case 'left':
									jQuery(this).css("left", left);
									break;
									// default adjust both
								default:
									jQuery(this).css("top", top);
								jQuery(this).css("left", left);
								break;
								}
							});
					};

/*
 * Applies a for the document unique id to element(s)
 */
jQuery.fn.setUniqueId =	function(prefix)
						{
							return jQuery(this).each(
								function()
								{
									var sUniqueId = '';
									var sUniqueId = '';
									var iMultiplier = 3;
									var iRandomNum 	= 0;
									
									var elExists = true;
									
									// set default id
									if(!prefix)
									{
										prefix = 'id_';
									}
									
									do
									{
										// get more room for new IDs on repeat
										iMultiplier++;
										// get random number
										iRandomNum = Math.ceil(Math.random() * iMultiplier);
										
										// build new id
										sUniqueId = prefix + iRandomNum;
									}
									// repeat if id already exists
									while(jQuery('#'+sUniqueId).exists());
									
									// set id to element
									this.attr('id', sUniqueId);
								});
						};

/**
 * Extending the jQuery namespace by defining a new function jQuery.plentyRequest() for AJAX calls
 * (estafilarakis)
 */
jQuery.extend({
	plentyRequest : plentyAjaxRequest2
});

/**
 * 
 * Custom effect for tabs
 */
jQuery.tools.tabs.addEffect(	"plenty_tabs",
						function(tabIndex, done)
						{
							this.getPanes()
								// slide up all panes
								.slideUp("slow")
								// get the selected tab
								.eq(tabIndex)
								// slide down the selected
								.slideDown("slow");
							
							// effect is done
							done.call();
						});

/*
 * Custom datepicker
 */
jQuery.fn.plentyDateInput = 	function() 
								{
									return this.each(	function()
														{
															 jQuery(this).dateinput({
																 				format: "dd.mm.yyyy ",
																 				selectors: true,             	
																 				min: -1
																 				});
														});
								};


/**
 * New plugin 'plentyPortlet'.
 * 
 * The HTML structur should be:
 * <div class="PlentyGuiHeaderPane">
 *     <div class="PlentyGuiHeader">...</div>
 *     <div class="PlentyGuiContent">...</div>
 * </div>
 * 
 * The javascript call to build the portlet is:
 * jQuery(".PlentyGuiHeaderPane").plentyPortlet();
 * 
 * The plugin adds a button with the CSS class 'PlentyGuiPortletButton'
 * to open and close the content of the portlet.
 * 
 * @author estafilarakis@plentySystems
 * 
 */
jQuery.fn.plentyPortlet = function(conf) {
	if(typeof(conf) != "object")
	{
		conf = { opened : false };
	}
	return this.each(function(){
		var button = jQuery('<div class="PlentyGuiPortletButton">&nbsp;</div>');
		var portlet = jQuery(this);
		var portletContent = portlet.find('> .PlentyGuiContent');
		if(conf.opened == true || conf.opened == "true")
		{
			portletContent.addClass("PortletFirstOpened");
		}
		portlet.
			addClass('PlentyGuiPortlet').
			find('> .PlentyGuiContent').
				addClass('PlentyGuiPortletContent').
				end().
			find('> .PlentyGuiHeader').
				addClass('PlentyGuiPortletHeader').
				before(button);
		button.toggle(
				function(){
					jQuery(this).addClass('PlentyGuiPortletOpened');
					portletContent.slideDown();
					if(typeof(conf.onOpen) == 'function')
					{
						conf.onOpen(portlet.find('> .PlentyGuiPortletContent'));
					}
				},
				function(){
					jQuery(this).removeClass('PlentyGuiPortletOpened');
					portletContent.slideUp();
					if(typeof(conf.onClose) == 'function')
					{
						conf.onClose(portlet.find('> .PlentyGuiPortletContent'));
					}
				}
		);
		if(conf.opened == true || conf.opened == "true")
		{
			button.click();
		}
	});
}

/**
 * New Plugin 'plentyOverlay'.
 * 
 * This plugin combines the Tools-Plugin 'overlay' with the UI-Plugin 'draggable'.
 * So you get a draggable overlay.
 * 
 * @author estafilarakis@plentySystems
 * 
 */
jQuery.fn.plentyOverlay = function(conf){
	return this.each(function(){
		// Bilde Overlay (über den Trigger)
		jQuery(this).
			overlay({	onLoad : conf.onLoad,
						onBeforeLoad : conf.onBeforeLoad,
						oneInstance : (conf.oneInstance ? conf.oneInstance : false),
						left : conf.left ? conf.left : '20%',
						top : conf.top ? conf.top : '10%',
						closeOnClick : (conf.closeOnClick ? true : false)
					});
		// Mache das Overlay verschiebbar
		jQuery(jQuery(this).attr("rel")).
			draggable({	appendTo : 'body',
						//containment : 'window',
						scroll : true,
						stack : '.plenty_overlay',
						handle : '> .title_bar'
					});
	});
}

/**
 * New Plugin 'plentyDateInput'
 * 
 * This Plugin uses the jQuery Tools dateinput-Plugin and fixes
 * the problems with multiple dateinput instances in different
 * AJAX loaded contents (e.g. portlets).
 * 
 * @author estafilarakis@plentySystems
 * 
 */
jQuery.fn.plentyDateInput = function(conf){
	return this.each(function(){
		jQuery(this).
			bind("focus",function(){
				jQuery(this).after(jQuery("#calroot"));
			}).
			dateinput(conf);
	});
}

/**
 * New Plugin 'plentyQFAMS'
 * 
 * @author estafilarakis@plentySystems
 */
jQuery.fn.plentyQFAMS = function(conf)
{
	return this.each(function(){
		var leftSelect = jQuery(this).find(".QFAMSLeftSelect").eq(0);
		var rightSelect = jQuery(this).find(".QFAMSRightSelect").eq(0);
		var addFunction = function()
		{
			var newOptions = leftSelect.find("option:selected");
			/*if(newOptions.length > 0)
			{
				rightSelect.find("option.emptyOption").remove();
			}*/
			rightSelect.append(newOptions);
		}
		var removeFunction = function()
		{
			var newOptions = rightSelect.find("option:selected");//.filter(":not(.emptyOption)");
			leftSelect.append(newOptions);
			/*if(rightSelect.find("option").length == 0)
			{
				rightSelect.append("<option value=\"\" class=\"emptyOption\">&nbsp;</option>");
			}*/
		}
		/*if(rightSelect.find("option").length==0)
		{
			rightSelect.append("<option value=\"\" class=\"emptyOption\">&nbsp;</option>");
		}*/
		leftSelect.dblclick(addFunction);
		rightSelect.dblclick(removeFunction);
		jQuery(this).
			find(".QFAMSAddIcon").
				click(addFunction).
				end().
			find(".QFAMSRemoveIcon").
				click(removeFunction).
				end();
	});
}

/**
 * New Plugin 'plentyFarbtastic'
 * 
 * @author estafilarakis@plentySystems
 * 
 * @uses The jQuery farbtastic plugin 
 */
jQuery.fn.plentyFarbtastic = function()
{
	/*
	 * Load the farbtastic script if not allready loaded.
	 */
	jQuery.getPlentyScriptOnce("/tpl/global/jquery/farbtastic/farbtastic.js");
	
	/*
	 * Split hexstring color to RGB array
	 */
	function getRGB(color)
	{
		if(color.length == 7 && color.substring(0,1) == "#")
		{
			return [parseInt('0x'+color.substring(1,3))/255, parseInt('0x'+color.substring(3,5))/255, parseInt('0x'+color.substring(5,7))/255];
		}
		else if(color.length == 4 && color.substring(0,1) == "#")
		{
			return [parseInt('0x'+color.substring(1,2))/15, parseInt('0x'+color.substring(2,3))/15, parseInt('0x'+color.substring(3,4))/15];
		}
		return [255,255,255];
	}
	
	/*
	 * Returns the foreground color for the given background color.
	 */
	function getFgColor(bgColor)
	{
		var r = bgColor[0], g = bgColor[1], b = bgColor[2];
		var min = Math.min(r, Math.min(g, b));
		var max = Math.max(r, Math.max(g, b));
		return (min+max)/2 > 0.5 ? '#000' : '#fff';
	}
	
	return this.each(function(){
		var picker = jQuery("<div class=\"plentyFarbtastic\" id=\""+jQuery(this).attr("id")+"_farbtastic\"></div>");
		
		jQuery(this).
			after(picker.hide()).
			focusin(function(){
				picker.farbtastic(this).show();
			}).
			focusout(function(){
				picker.farbtastic(this).hide();
			}).
			css({
				backgroundColor: jQuery(this).val(),
				color: getFgColor(getRGB(jQuery(this).val()))
			});
	});
}

/**
 * Loads a Javascript file with the given URL syncron.
 */
jQuery.getPlentyScript = function(url){
	jQuery.ajax({
		  url: url,
		  dataType: 'script',
		  async : false
		});
}

/*jQuery.fn.scrollTo =	function()
						{
							var x = $(this).offset().top - 100;
							$("html,body").animate({scrollTop: x}, 500);
							return jQuery(this);
						}*/

jQuery.fn.removeClassByPrefix = function(sPrefix)
{
	return this.each(function(){
		
		var regx = new RegExp('\\b' + sPrefix + '.*?\\b', 'g');
		this.className = this.className.replace(regx, '');
	    //return this;
		
	});
}
	

/**
 * Removes a tab added with jQuery.addNewTab() and reinitializes the tabs object.
 */
jQuery.removeTab = function()
{
	var tabTitle = $(this).closest("li").find("a.PlentyGuiTabTitle");
	var tabId = tabTitle.attr("id");
	var paneId = tabTitle.attr("href").substr(1,tabTitle.attr("href").length);
	
	var tabsSelectorId = tabTitle.closest("div.PlentyGuiTabs").attr("id");
	var tabsObj = $("#"+tabsSelectorId+" > .tabs");
	var options = tabsObj.data("options");
	
	$("#"+tabsSelectorId).find("div#"+paneId).remove();
	$(this).closest("li").remove();
	
	options.initialIndex = 0;
	tabsObj.tabs("> .pane",options);
	tabsObj.find("a.current").click();
}

/**
 * Adds a new tab in an existing tabs object and reinitializes it.
 * 
 * @param string	selector	The ID of the tabs object (PlentyGuiTabs->getID()).
 * @param string	id			The ID of the new tab title. This value will be submited to the AJAX class called with 'ajaxUrl'.
 * @param string	ajaxUrl		The URL to be called. This call should return the tab title and the tab pane for the new tab.
 * @param boolean	click		A flag indicating whether to imediatly open the new tab or not.
 * 
 * @return void
 */
jQuery.addNewTab = function(selector,id,ajaxUrl,click)
{
	var tab = $(selector);
	var selectorId = selector;
	var liId = id+"_liElement";
	var liElem = $("#"+liId);
	var ulElem = $("#"+selector+" > .tabs");
	
	if(typeof click != "boolean")
	{
		click = false;
	}
	
	/*
	 * Only if the tab does not already exist.
	 */
	if(liElem.length == 0)
	{
		var closeBtn = $("<img/>");
		liElem = $("<li></li>");
		
		/*
		 * The new close button.
		 */
		closeBtn.
			css({'position':'absolute', 'top':'10px', 'right':'5px'}).
			addClass("link").
			addClass("PlentyGuiIcon").
			addClass("TabCloseButton").
			attr("title","Close Tab").
			attr("id",liId+"_closeButton").
			attr("src","/images/icons/silk/tab_close.gif").
			bind("click",$.removeTab);
		
		/*
		 * The new tab title of the tabs object.
		 */
		liElem.
			css("position","relative").
			attr("id",liId);
		ulElem.append(liElem);
		
		/*
		 * The callback function, which adds the new tab and reinitializes the tabs object.
		 */
		var addCloseBtn = function()
		{
			var options = $("#"+selector+" > .tabs").data("options");
			options.initialIndex = ulElem.find('li').index(liElem);
			
			/*
			 * Add the close button
			 */
			liElem.append(closeBtn);
			
			/*
			 * Reinitialize the tabs object.
			 */
			ulElem.tabs("> .pane",options);
			
			/*
			 * Open the new tab, if requested.
			 */
			if(click)
			{
				ulElem.find("a.current").click();
			}
		}
		
		/*
		 * The AJAX call.
		 */
		ajaxUrl = ajaxUrl + '&Params[result_id][0]=' + liId + '&Params[result_id][1]=' + selectorId + '&Params[add_result_id][1]=1'+'&TabTitleId='+id;
		plentyAjaxRequest2(ajaxUrl,addCloseBtn);
	}
	else
	{
		/*
		 * The requested tab already exists, so only open it.
		 */
		$("#"+selector+" > .tabs").data("tabs").click(ulElem.find('li').index(liElem));
	}
}


jQuery.fn.iconselect = function(conf){
	return this.each(function(){
			$(this).change(function(){
				var option = $(this).find("option:selected");
				var url = option.css("background-image");
				if( url )
				{
					$(this).css("background-image",url);
				}
				else
				{
					$(this).css("background-image","none");
				}
			});
			$(this).css("background-repeat","no-repeat").
					css("height","19px").
					css("padding-left","25px");
			$(this).change();
		});
}

function PlentyElementCache()
{
	// Element sets are registered here
	this.oRegistry = new Object();
	// Singleton
	PlentyElementCache.oInstance = null;
}

/**
 * 
 * @returns {PlentyElementCache}
 * @todo if this class is in heavy use, we could think about a cache limit
 */
PlentyElementCache.getInstance = function()
{
	if(PlentyElementCache.oInstance == null)
	{
		PlentyElementCache.oInstance = new PlentyElementCache();
	}
	
	return PlentyElementCache.oInstance;
};

/**
 * 
 * @returns {void}
 */
PlentyElementCache.destroy = function()
{
	PlentyElementCache.oInstance = null;
};

/**
 * 
 * @param {String} sJQuerySelector
 * @param {String} sCacheNamespace
 * @returns {Object} jQuery element match
 */
PlentyElementCache.prototype.get = function(sJQuerySelector, sCacheNamespace)
{
	if(		sJQuerySelector.length > 0
		&&	this.exists(	sJQuerySelector,
							sCacheNamespace) == false)
	{
		// Allocate element set to the selector
		this.set(	sJQuerySelector,
					sCacheNamespace);
	}
	
	if(		$.isset(sCacheNamespace)
		&&	sCacheNamespace.length	> 0)
	{
		return this.oRegistry[sCacheNamespace][sJQuerySelector];
	}
	
	return this.oRegistry[sJQuerySelector];
}

/**
 * Check if matching elements are cached for a selector or a selector in a namespace
 * 
 * @param {String} sJQuerySelector
 * @param {String} sCacheNamespace
 * @returns {Boolean}
 */
PlentyElementCache.prototype.exists = function(sJQuerySelector, sCacheNamespace)
{
	if(		$.isset(sCacheNamespace)
		&&	sCacheNamespace.length > 0)
	{
		return		$.isset(this.oRegistry[sCacheNamespace])
				&&	$.isset(this.oRegistry[sCacheNamespace][sJQuerySelector]);
	}
	else
	{
		return		$.isset(this.oRegistry[sJQuerySelector]);
	}
}

/**
 * Sets a set of matched elements to the cache
 * 
 * @param {String} sJQuerySelector
 * @param {String} sCacheNamespace
 * @returns {void}
 */
PlentyElementCache.prototype.set = function(sJQuerySelector, sCacheNamespace)
{
	if(		$.isset(sCacheNamespace)
		&&	sCacheNamespace.length	> 0)
	{
		if($.isset(this.oRegistry[sCacheNamespace]) == false)
		{
			this.oRegistry[sCacheNamespace] = new Object();
		}
		
		this.oRegistry[sCacheNamespace][sJQuerySelector] = jQuery(sJQuerySelector);
	}
	else
	{
		this.oRegistry[sJQuerySelector] = jQuery(sJQuerySelector);
	}
}

/**
 * Unsets a set of matched elements in the cache.
 * 
 * Unset either for a selector, a selector in a namespace or a whole namespace (by leaving the first param blank)
 * 
 * @param {String} sJQuerySelector
 * @param {String} sCacheNamespace
 */
PlentyElementCache.prototype.unset = function(sJQuerySelector, sCacheNamespace)
{
	if(		$.isset(sCacheNamespace)
		&&	sCacheNamespace.length	> 0)
	{
		if(		$.isset(sJQuerySelector)
			&&	sJQuerySelector.length	> 0)
		{
			// unset selector in namespace
			delete this.oRegistry[sCacheNamespace][sJQuerySelector];
		}
		else
		{
			// unset whole namespace
			delete this.oRegistry[sCacheNamespace];
		}
	}
	else
	{
		if(		$.isset(sJQuerySelector)
			&&	sJQuerySelector.length > 0)
		{
			// unset selector
			delete this.oRegistry[sJQuerySelector];
		}
	}
}

/**
 * 
 * Class registers paths to javascript files, so that the same script isn't loaded twice.
 */
function PlentyScriptRegistry()
{
	// Registry object, script's src tag's values are registered here
	this.oRegistry = new Object();
	PlentyScriptRegistry.oInstance = null;
}

/**
 * Singleton
 * 
 * @returns {PlentyScriptRegistry}
 */
PlentyScriptRegistry.getInstance = function()
{
	if(PlentyScriptRegistry.oInstance == null)
	{
		PlentyScriptRegistry.oInstance = new PlentyScriptRegistry();
	}
	
	return PlentyScriptRegistry.oInstance;
};

/**
 * Register script
 * 
 * @param {String} sSource The path to the script
 */
PlentyScriptRegistry.prototype.register = function(sSource)
{
	if(sSource.length > 0)
	{
		this.oRegistry[sSource] = true;
	}
}

/**
 * Is a script registered with that path?
 * 
 * @param {String} sSource The path to the script
 */
PlentyScriptRegistry.prototype.isRegistered = function(sSource)
{
	return 		$.isset(this.oRegistry[sSource])
			&&	this.oRegistry[sSource]			== true
}

/*
 * jQuery extensions.
 * 
 * Functions will be available via "$." or "jQuery." respectively.
 */
jQuery.extend({
	/**
	 * Takes use of the PlentyElementCache class.
	 * 
	 * All elements that are found via this function are cached by the selector as long as the page is not reloaded.
	 * 
	 * @param {String} sJQuerySelector
	 * @param {String} sCacheNamespace
	 * @returns {Object} A set of matching elements for the selector
	 */
    c: function(sJQuerySelector, sCacheNamespace) {
    	return	PlentyElementCache
					.getInstance()
						.get(sJQuerySelector, sCacheNamespace);
    },
    /**
     * Direct access to the PlentyElementCache instance.
     * 
     * Use this, for example, to unset parts of the cache.
     * 
     * @returns {PlentyElementCache}
     */
    getCache: function() {
    	return	PlentyElementCache
					.getInstance();
    },
    /**
     * Loads a script via ajax just once
     * 
     * @param {String} sSource
     */
    getPlentyScriptOnce: function(sSource) {
    	if(	PlentyScriptRegistry
    			.getInstance()
    				.isRegistered(sSource) === false)
    	{
    		// Load script via synchronous ajax
    		jQuery.getPlentyScript(sSource);
    		// Register script source
			PlentyScriptRegistry
				.getInstance()
					.register(sSource);
    	}
    },
    /**
     * Loads a CSS file via ajax
     * 
     * To load a CSS file just once, use $.getPlentyCssOnce()
     * 
     * @param {String} sSource
     */
    getPlentyCss: function(sSource)
    {
    	if(		$.isset(sSource)
    		&&	sSource.length > 0)
    	{
    		$('head').append('<link>');
    		css = $('head').children(':last');
    		css.attr({
    			rel:  'stylesheet',
    			type: 'text/css',
    			href: sSource
    		});
    	}
    },
    /**
     * Loads a CSS file just once
     * 
     * @param {String} sSource
     */
    getPlentyCssOnce: function(sSource)
    {
    	if(	PlentyScriptRegistry
    			.getInstance()
    				.isRegistered(sSource) === false)
    	{
    		// Register
    		PlentyScriptRegistry
    			.getInstance()
    				.register(sSource);
    		// Get
    		$.getPlentyCss(sSource);
    	}
    },
    /**
     * Returns true if param is not undefined and not null
     * 
     * @param {mixed}
     * @returns {Boolean}
     */
    isset: function(mixed)
    {
    	return		mixed	!== undefined
    			&&	mixed	!== null;
    },
    /**
     * Returns true if param is null
     * 
     * @param {mixed}
     * @returns {Boolean}
     */
    is_null: function(mixed)
    {
    	return mixed == null;
    },
    /**
     * Returns true if param is not undefined and not null
     * 
     * @param {mixed}
     * @returns {Boolean}
     */
    is_undefined: function(mixed)
    {
    	return mixed === undefined;
    },
    /**
     * Returns true if param is an object
     * 
     * @param {mixed}
     * @returns {Boolean}
     */
    is_object: function(mixed)
    {
        return typeof mixed == 'object';
    }
});
