(function($){
	var TREESELECT_BLUR							= "treeselect:blur";
	var TREESELECT_CHANGE						= "treeselect:change";
	var TREESELECT_OPTIONCLICK					= "treeselect:optionclick";
	var TREESELECT_FOCUS						= "treeselect:focus";
	
	var TREESELECT_OPTGROUP_VALUE_ATTR			= "data-treeselect-value";
	var TREESELECT_ICON_ATTR					= "data-treeselect-icon";
	var TREESELECT_ICON_POSITION_ATTR			= "data-treeselect-icon-position";
	var TREESELECT_ICON_POSITION_BEFORE_LABEL	= "before-label";
	var TREESELECT_ICON_POSITION_AFTER_LABEL	= "after-label";
	var TREESELECT_ICON_POSITION_BEFORE_INPUT	= "before-input";
	var TREESELECT_ICON_POSITION_AFTER_INPUT	= "after-input";

	
	function extendOptions(options) {
		this.options = $.extend(true, {
			mode: (this.element.prop("multiple") ? "checkbox" : "radio"),
			valuesSeparator:"/",
			removeLeafsContainer: true,
			removeSelectOptions: true,
			removeMultipleAttr: true,
			displaySummaryOption: true,
			displayNbItemsInSummary: true,
			displaySelectedItemsInSummary: false,
			treeSelectHtmlWrapperTemplate: "<div>",
			treeSelectHtmlWrapperClass: "treeselect_wrapper",
			treeSelectHtmlMaskTemplate: "<div>",
			treeSelectHtmlMaskClass: "treeselect_mask",
			treeSelectHtmlOptionsContainerTemplate: "<ul>",
			treeSelectHtmlOptionsContainerClass: "treeselect_treeoptions",
			treeSelectHtmlOptgroupOptionLabelTemplate: "<span>",
			treeSelectHtmlOptionOptionLabelTemplate: "<label>",
			treeSelectHtmlOptionTemplate: "<li>",
			treeSelectHtmlOptionTemplateDisabledClass: "treeselect_disabled",
			treeSelectHtmlOptionTemplateIconDisabledOpacity: 0.5,
			depthGap: 10,
			labels: {
				NB_ITEMS: "item(s)",
				NO_ITEM: null,
				SELECTED_ITEMS_SEPARATOR: ": "
			}
		}, options || {});
	};
	
	var ALL_TREE_SELECTS = [];

	function TreeSelect(element, options) {
		this.element = element;
		this.element.data("treeselect", this);
		extendOptions.call(this, options);
		createWrapper.call(this);
		createMask.call(this);
		createTreeOptionsContainer.call(this);
		bindListeners.call(this);
		this.displaySummary();
	};
	
	function createWrapper() {
		this.wrapper = this.element.wrap(this.options.treeSelectHtmlWrapperTemplate).parent();
		this.wrapper.addClass(this.options.treeSelectHtmlWrapperClass);
		
		this.wrapper.css({
			position:"relative",
			float: this.element.css("float")
		});		
	};
	
	function createMask() {
		var pos = this.element.position();
		var cssMask = {
			left: pos.left + parseInt(this.element.css("margin-left")) + "px",
			top: pos.top + parseInt(this.element.css("margin-top")) + "px",
			width: (this.element.outerWidth()) + "px",
			height: (this.element.outerHeight()) + "px",
			position:"absolute",
			opacity:0
		};
		
		this.mask = $(this.options.treeSelectHtmlMaskTemplate);
		this.mask.addClass(this.options.treeSelectHtmlMaskClass);
		this.mask.css( cssMask );
		this.element.after(this.mask);
	};
	
	function createTreeOptionsContainer() {
		this.treeOptionsContainer = $(this.options.treeSelectHtmlOptionsContainerTemplate);
		this.treeOptionsContainer.addClass(this.options.treeSelectHtmlOptionsContainerClass);
		var pos = this.element.position();
		this.treeOptionsContainer.css({
			"display": "none",
			"position": "absolute",
			"left": pos.left + parseInt(this.element.css("margin-left")) + "px",
			"top": (pos.top + parseInt(this.element.css("margin-top")) + this.element.height() + parseInt(this.element.css("border-top-width")) + parseInt(this.element.css("border-bottom-width"))) + "px"
		});
		this.element.after(this.treeOptionsContainer);
		this.treeOptionsContainer.css("min-width", this.element.outerWidth() - this.treeOptionsContainer.outerWidth(true) - this.treeOptionsContainer.width());

		this.element.children().each($.proxy(createTreeOptionItem, this));
		
		if(this.options.removeLeafsContainer) {
			this.treeOptionsContainer.find(".treeselect_treeoptions").each(function(){
				if($(this).children().length == 0) {
					$(this).remove();
				}
			});
		}
		if(this.options.removeSelectOptions) {
			this.element.children().remove();
		}
		
		if(this.options.removeMultipleAttr) {
			this.element.removeAttr("multiple");
			if(this.options.displaySummaryOption) {
				this.summary = $("<option selected=\"selected\"></option>");
				
				this.element.prepend(this.summary);
			}
		}
		
	};
	
	function bindListeners() {
		this.mask.click($.proxy(onTreeselectMaskClicked, this));
		this.treeOptionsContainer.click(function(e){
			e.stopPropagation();
		});
		$(document).click($.proxy(onDocumentClicked, this));
		this.treeOptionsContainer.find("input").change($.proxy(onOptionsChanged, this));
		this.treeOptionsContainer.find("input").click($.proxy(onOptionsClicked, this));
	};
	
	function onOptionsClicked(e) {
		var clickEvent = $.Event(TREESELECT_OPTIONCLICK, {treeselect: this, originalEvent: e} );
		this.element.trigger(clickEvent);
		if(clickEvent.isDefaultPrevented()) {
			e.preventDefault();
		}
	};
	
	function onOptionsChanged(e) {
		var changeEvent = $.Event(TREESELECT_CHANGE, {treeselect: this});
		this.element.trigger(changeEvent);
		this.displaySummary();
	};

	function createTreeOptionItem(index, optionElement) {
		var treeOptionItem = null;
		switch(optionElement.nodeName.toUpperCase()) {
		case "OPTGROUP":
			createItemFromOptgroup.call(this, optionElement);
			break;
		case "OPTION":
			createItemFromOption.call(this, optionElement);
			break;
		default:
			throw "[wedia.ui.treeSelect.TreeSelect#createTreeOptionItem] unsupported node type : " + element.nodeName;
		}
	};
	
	function createItemFromOptgroup(optgroupElement) {
		var optGroupVal = $(optgroupElement).attr(TREESELECT_OPTGROUP_VALUE_ATTR);
		var path = [], value = optGroupVal;
		if(typeof optGroupVal !== "undefined") {
			path	= optGroupVal.split(this.options.valuesSeparator);
			value	= path.pop();
		}
		var parent	= findParent.call(this, path);
		var label	= $(this.options.treeSelectHtmlOptgroupOptionLabelTemplate);
		label.css("padding-left", (path.length) * this.options.depthGap + "px");
		label.text($(optgroupElement).attr("label"));
		var icon = createIcon.call(this, optgroupElement);
		if(icon != null) {
			switch($(optionElement).attr(TREESELECT_ICON_POSITION_ATTR)) {
			case TREESELECT_ICON_POSITION_AFTER_LABEL :
				label.after(icon);
				break;
			case TREESELECT_ICON_POSITION_BEFORE_LABEL :
			default :
				label.before(icon);
				break;
			}
		}
		var treeOptionItem = $(this.options.treeSelectHtmlOptionTemplate);
		treeOptionItem.append(label);
		appendSubContainer.call(this, treeOptionItem, value);
		parent.append(treeOptionItem);
		
		$(optgroupElement).children().each($.proxy(createTreeOptionItem, this));
	};
	
	function createItemFromOption(optionElement) {
		var path	= optionElement.value.split(this.options.valuesSeparator);
		var value	= path.pop();
		var parent	= findParent.call(this, path);
		var label	= $(this.options.treeSelectHtmlOptionOptionLabelTemplate);
		label.css("padding-left", (path.length + 1) * this.options.depthGap + "px");
		var input	= $("<input type=\"" + this.options.mode + 
							"\" name=\"" + this.element.attr("name") + 
							"\" value=\"" + value + "\">");
		if(optionElement.selected) {
			input.prop("checked", true);
		}
		label.text(optionElement.text);
		label.prepend(input);
		var icon = createIcon.call(this, optionElement);
		if(icon != null) {
			switch($(optionElement).attr(TREESELECT_ICON_POSITION_ATTR)) {
			case TREESELECT_ICON_POSITION_AFTER_LABEL :
				label.after(icon);
				break;
			case TREESELECT_ICON_POSITION_BEFORE_LABEL :
				label.before(icon);
				break;
			case TREESELECT_ICON_POSITION_BEFORE_INPUT :
				input.before(icon);
				break;
			case TREESELECT_ICON_POSITION_AFTER_INPUT :
			default :
				input.after(icon);
				break;
			}
		}
		var treeOptionItem = $(this.options.treeSelectHtmlOptionTemplate);
		if($(optionElement).prop("disabled")) {
			input.prop("disabled", true);
			treeOptionItem.addClass(this.options.treeSelectHtmlOptionTemplateDisabledClass);
			if(icon != null) {
				icon.css("opacity", this.options.treeSelectHtmlOptionTemplateIconDisabledOpacity);
			}
		}
		treeOptionItem.append(label);
		appendSubContainer.call(this, treeOptionItem, value);
		parent.append(treeOptionItem);
	};
	
	function appendSubContainer(container, value) {
		var subContainer = $(this.options.treeSelectHtmlOptionsContainerTemplate);
		subContainer.attr("id", "treeselect_children_" + value);
		subContainer.addClass(this.options.treeSelectHtmlOptionsContainerClass);
		container.append(subContainer);
	};
	
	function createIcon(sourceElement) {
		var iconUrl = $(sourceElement).attr(TREESELECT_ICON_ATTR);
		if(iconUrl != null && iconUrl != "") {
			var img = $("<img src=\"" + iconUrl + "\">");
			if(this.options.iconWidth) {
				img.attr("width", this.options.iconWidth);
			}
			if(this.options.iconHeight) {
				img.attr("height", this.options.iconHeight);
			}
			return img;
		} else {
			return null;
		}
	};

	function findParent(path) {
		var parent	= this.wrapper.find("#treeselect_children_" + path.join(" #treeselect_children_"));
		if(parent.length == 0) {
			parent = this.treeOptionsContainer;
		}
		return parent;
	}
	
	function toggleOptionsContainer() {
		if(this.isOpened()) {
			this.hide();
		} else {
			this.show();
		}
	};
	
	function showOptionsContainer(e) {
		var focusEvent = $.Event(TREESELECT_FOCUS, {treeselect: this});
		this.element.trigger(focusEvent);
		if(! focusEvent.isDefaultPrevented() ) {
			this.treeOptionsContainer.show();
		}
	};
	
	function hideOptionsContainer() {
		var blurEvent = $.Event(TREESELECT_BLUR, {treeselect: this});
		this.element.trigger(blurEvent);
		if(! blurEvent.isDefaultPrevented()) {
			this.treeOptionsContainer.hide();
		}
		
	};

	function displaySummary() {
		if(this.options.displaySummaryOption) {
			var str = "";
			var nbSelected = this.treeOptionsContainer.find(":checked").length;
			if(nbSelected == 0 && this.options.labels.NO_ITEM != null) {
				str = this.options.labels.NO_ITEM;
			} else {
				if(this.options.displayNbItemsInSummary) {
					str += nbSelected + " " + this.options.labels.NB_ITEMS;
					if(this.options.displaySelectedItemsInSummary) {
						str += this.options.labels.SELECTED_ITEMS_SEPARATOR;
					}
				}
				if(this.options.displaySelectedItemsInSummary) {
					var labels = "";
					this.treeOptionsContainer.find(":checked").parent("label").each(function(idx, label){
						if(idx > 0) {
							labels += ", " + $(this).text();
						} else {
							labels = $(label).text();
						}
					});
					str += labels;
				}
			}
			this.summary.text(str);
		}		
	}
	function isOptionContainerOpened() {
		return this.treeOptionsContainer.is(":visible");
	};
	
	function getSelectedValues() {
		var values = [];
		this.treeOptionsContainer.find(":checked").each(function(){
			values.push(this.value);
		});
		return values;
	};

	TreeSelect.prototype.isOpened	= isOptionContainerOpened;
	TreeSelect.prototype.show		= showOptionsContainer;
	TreeSelect.prototype.hide		= hideOptionsContainer;
	TreeSelect.prototype.toggle		= toggleOptionsContainer;
	TreeSelect.prototype.displaySummary = displaySummary;
	TreeSelect.prototype.getSelectedValues = getSelectedValues;
		
	function onTreeselectMaskClicked(e) {
		e.stopPropagation();
		if(this.isOpened()) {
			this.hide();
		} else {
			$.each(ALL_TREE_SELECTS, function() {
				if(this.isOpened()) {
					this.hide();
				}
			});
			this.show();
		}
	};
	
	function onDocumentClicked() {
		if(this.isOpened()) {
			this.hide();
		}
	};

	
	$.fn.treeSelect = function(options) {
		this.each(function() {
			var ts = new TreeSelect($(this), options);
			ALL_TREE_SELECTS.push(ts);
		});
		return this;
	};
})(jQuery);

