/*
 * jQuery decorated plugin
 *
 * version 1.0 (6/25/2007)
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 */

/*
 * The decorate() method provides a simple way of styling select box.  
 *
 * We assume we have a container which contain a single multiple-select box.
 * Decorating this container will replace this container's content by a decorated version of the multiple-select box.
 * The decorated select box is composed of 2 select box, the one on left contains element that won't be selected, and the ones on right will be selected.
 * This way, we can manage long select box easily.
 *
 * Configuration parameters are :
 * - size : (default -1)
 * 		if value is greater than 0, than it will be the size of the select box. If it's -1, the size define in html will be use
 * - rtSearch : (default true)
 *		true or false, to know if we display the text box to make selection in non-selected element easier
 * - navByDblClick : (default true)
 *		true or false, to know if we bind the (un)select action with double click element
 *		! it seems that it isn't working on safari
 * - navByArrows : (default true)
 *		true or false, to know if we bind the (un)select action with arrow navigation (right or left) on element
 *		! it seems that it isn't working on safari
 * - navByButtons : (default true)
 *		true or false, to know if we display and bind the (un)select action with buttons
 * - addBreaker : (default true)
 *		true or false, to know if we add <br class="breaker" /> at the end of the containers. It can be useful if all containers are float elements ...
 * - lblCurrentElement : (default value of contained label)
 *		Label for selected elements select box
 * - lblSearch : (default "State a name or choose from list")
 *		Label for unselected elements filter
 * - lblLeftSelected : (default "<-")
 *		Label for selected elements go to left
 * - lblLeftSelected : (default "<--")
 *		Label for all elements go to left
 * - lblLeftSelected : (default "->")
 *		Label for selected elements go to right
 * - lblLeftSelected : (default "-->")
 *		Label for all elements go to right
 *
 * @name decorated
 * @type jQuery
 * @return jQuery
 * @author Romain Gonord (romain.gonord.opensource@neteyes.org)
 */
(function($) {
	$.fn.contains = function(text) {
		return $(this).filter(":contains("+text+")");
	};

	$.fn.decorate = function(settings) {

		var defaults =  {
			size: -1,
			rtSearch: true,
			navByDblClick: true,
			navByArrows: true,
			navByButtons: true,
			addBreaker: true,
			lblCurrentElement: -1,
			lblSearch: "",
			lblLeftSelected: "<-",
			lblLeftAll: "<--",
			lblRightSelected: "->",
			lblRightAll: "-->"
		};

		return this.each(function(i,n){
			/* merge default with custom options */
			$.extend(defaults, settings);
		
			initDecoratedSelectBox(n);

			function buildButton(name, value){
				return "<input type=\"button\" name=\"" + name + "\" id=\"" + name + "\" value=\"" + value + "\" />";
			};
	
			function moveOption(select){
				var selectName = select.name;
				if (selectName.indexOf("_src") > 0){
					moveOptions(selectName, selectName.substring(0, selectName.length - 4), 0);
				} else {
					moveOptions(selectName, selectName + "_src", 0);
				}
			};
			
			function moveOptions(srcSelectId, dstSelectId, all){
				var searchPattern = "option";
				if (all == 0)
					searchPattern += "[@selected]";
				$("#" + dstSelectId).append($(searchPattern, $("#" + srcSelectId)));
			};
	
			function moveOptionsFromEvent(select, event){
				var selectName = select.name;
				var key = event.keyCode ? event.keyCode : event.charCode ? event.charCode : 0;
				switch(key) {
					case 37: 
						if (selectName.indexOf("_src") < 0){
							moveOption(select);
						}
						break;
					case 39: 
						if (selectName.indexOf("_src") > 0){
							moveOption(select);
						}
						break;
				}
			};

			
			function initDecoratedSelectBox(selectBoxContainer){
				var mySelect = $("select", selectBoxContainer).get(0);
				var prefix = mySelect.name;
				var prefixId = mySelect.id;
				var size = defaults.size > 0 ? defaults.size : mySelect.size;
	
				/* define elements */
				var container1 = $("<div class=\"decoratedSelectBoxContainer1\"></div>")
				var container3 = $("<div class=\"decoratedSelectBoxContainer3\"></div>")
				var srcSelect = $("<select name=\"" + prefix + "_src\" id=\"" + prefixId + "_src\" multiple=\"multiple\" size=\"" + size + "\"></select>");
				var dstDisplayedLabel = defaults.lblCurrentElement;
				if (dstDisplayedLabel == -1){
					dstDisplayedLabel = $("label", selectBoxContainer).html();
				}
				var dstlabel = $("<label for=\"" + prefix + "\">" + dstDisplayedLabel + "</label>");
				var dstSelect = $("<select name=\"" + prefix + "\" id=\"" + prefixId + "\" multiple=\"multiple\" size=\"" + size + "\"></select>");
				$("option", selectBoxContainer).each(function(i,n){
					if (n.selected){
						$(dstSelect).append(n);
					} else {
						$(srcSelect).append(n);
					}
				});
				if (defaults.rtSearch){
					var searchBoxLabel = $("<label for=\"" + prefixId + "_search\">" + defaults.lblSearch + "</label>");
					var searchBox = $("<input type=\"text\" name=\"" + prefixId + "_search\" id=\"" + prefixId + "_search\">");
					$(container1).append(searchBoxLabel);
					$(container1).append(searchBox);
				}
				$(container1).append(srcSelect);
				$(container3).append(dstlabel);
				$(container3).append(dstSelect);

				if (defaults.navByButtons){
					var container2 = $("<div class=\"decoratedSelectBoxContainer2\"></div>")
					var toTheLeft = $(buildButton("toTheLeft_" + prefixId, defaults.lblLeftSelected));
					var toTheRight = $(buildButton("toTheRight_" + prefixId, defaults.lblRightSelected));
					var allToTheLeft = $(buildButton("allToTheLeft_" + prefixId, defaults.lblLeftAll));
					var allToTheRight = $(buildButton("allToTheRight_" + prefixId, defaults.lblRightAll));
					$(container2).append(allToTheLeft);
					$(container2).append(toTheLeft);
					$(container2).append(toTheRight);
					$(container2).append(allToTheRight);
				}
	
				/* Build the block */
				$(selectBoxContainer).empty();
				$(selectBoxContainer).append(container1);
				$(selectBoxContainer).append(container2);
				$(selectBoxContainer).append(container3);
				if (defaults.addBreaker){
					$(selectBoxContainer).append("<br class=\"breaker\" />");
				}

				/* Bind events */
				if (defaults.rtSearch){
					$("#" + prefixId + "_search").keyup(function(){
						var searchStr = this.value;
						$("option", $("#" + prefixId  + "_src")).each(function(i,n){
							var elem = $(n);
							if (elem.contains(searchStr).length > 0){
								elem.show();
								elem.attr("selected","selected");
							} else {
								elem.hide();
								elem.removeAttr("selected");
							}
						});
					});
				}

				if (defaults.navByDblClick){
					$("select", selectBoxContainer).dblclick(function(){
						moveOption(this);
					})
				}

				if (defaults.navByButtons){
					$("#" + "toTheLeft_" + prefixId).click(function(){
						moveOptions(prefixId, prefixId + "_src", 0);
					});
					$("#" + "toTheRight_" + prefixId).click(function(){
						moveOptions(prefixId + "_src", prefixId, 0);
					});
					$("#" + "allToTheLeft_" + prefixId).click(function(){
						moveOptions(prefixId, prefixId + "_src", 1);					});
					$("#" + "allToTheRight_" + prefixId).click(function(){
						moveOptions(prefixId + "_src", prefixId, 1);
					});
				}

				if (defaults.navByArrows){
					$("#" + prefix + "_src").keydown(function(e) {
						moveOptionsFromEvent(this, e);
					})
					$("#" + prefix).keydown(function(e) {
						moveOptionsFromEvent(this, e);
					})
				}
	
				/* submit form */
				$(mySelect.form).submit(function(){
					$("#" + prefixId + "_src" + " option").each(function(i,n){
						$(n).removeAttr("selected");
					});
					var nbselect=document.getElementById(prefixId).length;
					
					for(var i = 0; i < nbselect; i++){
						document.getElementById(prefixId).options[i].selected = "selected";
					}
					
					var Obj = document.getElementById(prefixId + "_src");
					for (var i=0; i < Obj.length; i++){
						if(Obj.options[i].selected){
							$("#"+prefixId + "_src").options.removeAttr("selected");
						}
					}
			
				});
	
				/* reset form */
				$("input[@type = button]", mySelect.form).click(function(){
					$("#" + prefixId + "_src" + " option").each(function(i,n){
						$(n).removeAttr("selected");
					});
					var nbselect=document.getElementById(prefixId).length;
					
					for(var i = 0; i < nbselect; i++){
						document.getElementById(prefixId).options[i].selected = "selected";
					}
					
					var Obj = document.getElementById(prefixId + "_src");
					for (var i=0; i < Obj.length; i++){
						if(Obj.options[i].selected){
							$("#"+prefixId + "_src").options.removeAttr("selected");
						}
					}
			
				});
			};
		});
	};
})(jQuery);
