/**
 * combo - jQuery jwwUI Copyright (c) 2013-2015 www.jeeww.com. All rights
 * reserved. Licensed under the GPL or commercial licenses
 */
(function($) {
	function getCbValues(target) {
		var values = [];
		var comboObj = $.data(target, "combo").combo;
		comboObj.find("input.combo-value").each(function() {
			values.push($(this).val());
		});
		return values;
	}
	;
	function setCbValues(target, values) {
		var cDefs = $.data(target, "combo").defs;
		var comboNowValues = getCbValues(target);
		var comboObj = $.data(target, "combo").combo;
		comboObj.find("input.combo-value").remove();
		var comboPropertyName = $(target).attr("comboName");
		if (values) {
			if (!(values instanceof Array)) {
				values = values.split(",");
			}
		} else {
			return;
		}
		for ( var i = 0; i < values.length; i++) {
			var comboValueHidden = $("<input type=\"hidden\" class=\"combo-value\">").appendTo(comboObj);
			if (comboPropertyName) {
				comboValueHidden.attr("name", comboPropertyName);
			}
			comboValueHidden.val(values[i]);
		}
		var tmp = [];
		for ( var i = 0; i < comboNowValues.length; i++) {
			tmp[i] = comboNowValues[i];
		}
		var aa = [];
		for ( var i = 0; i < values.length; i++) {
			for ( var j = 0; j < tmp.length; j++) {
				if (values[i] == tmp[j]) {
					aa.push(values[i]);
					tmp.splice(j, 1);
					break;
				}
			}
		}
		if (aa.length != values.length || values.length != comboNowValues.length) {
			if (cDefs.multiple) {
				cDefs.onChange.call(target, values, comboNowValues);
			} else {
				cDefs.onChange.call(target, values[0], comboNowValues[0]);
			}
		}
	}
	;
	function getCbText(target) {
		var comboObj = $.data(target, "combo").combo;
		return comboObj.find("input.combo-text").val();
	}
	;
	function setCbText(target, textValue) {
		var comboObj = $.data(target, "combo").combo;
		comboObj.find("input.combo-text").val(textValue);
		validate(target, true);
		$.data(target, "combo").previousValue = textValue;
	}
	;
	function getCbValue(comboObj) {
		var valueObjs = getCbValues(comboObj);
		return valueObjs[0];
	}
	;
	function setCbValue(comboObj, params) {
		setCbValues(comboObj, [ params ]);
	}
	;
	function setSize(target, sizeValue) {
		var cDefs = $.data(target, "combo").defs;
		var comboObj = $.data(target, "combo").combo;
		var cPanelObj = $.data(target, "combo").panel;
		var comboTextObj = comboObj.find("input.combo-text");
		var comboArrowObj = comboObj.find(".combo-arrow");
		var downArrowWidth = cDefs.hasDownArrow ? comboArrowObj._outerWidth() : 0;
		if (sizeValue && sizeValue != 'auto') {
			cDefs.width = sizeValue;
			comboObj._outerWidth(sizeValue);
		}
		var oWidth = comboObj._outerWidth();
		// comboTextObj._outerWidth(oWidth - downArrowWidth - 2);
		// var textWidth = (oWidth - downArrowWidth - 30) / oWidth;
		var textWidth = (oWidth - downArrowWidth - 10) / oWidth;
		textWidth = textWidth.toFixed(2) * 100;
		textWidth = textWidth + "%";
		comboTextObj.css({
			width : textWidth
		// height : comboObj.height() + "px",
		// lineHeight : comboObj.height() + "px"
		});
		comboArrowObj._outerHeight(comboObj.height());
		cPanelObj.panel("resize", {
		    width : (cDefs.panelWidth ? cDefs.panelWidth : oWidth),
		    height : cDefs.panelHeight
		});
		if (cDefs.border) {
			comboObj.addClass("combo-border");
		}
	}
	;
	function setArrowShowOrHide(target) {
		var cDefs = $.data(target, "combo").defs;
		var comboObj = $.data(target, "combo").combo;
		if (cDefs.hasDownArrow) {
			comboObj.find(".combo-arrow").show();
		} else {
			comboObj.find(".combo-arrow").hide();
		}
	}
	;
	function create(target, defs) {
		$(target).addClass("combo-f").hide();
		var comboObj = null;
		if (defs.cusCls) {
			comboObj = $("<span class=\"combo\"></span>").addClass(defs.cusCls).insertAfter(target);
		} else {
			comboObj = $("<span class=\"combo\"></span>").insertAfter(target);
		}
		var comboTextObj = $("<input type=\"text\" class=\"combo-text\">").appendTo(comboObj);
		$("<span class=\"combo-arrow\"></span>").appendTo(comboObj);
		$("<input type=\"hidden\" class=\"combo-value\">").appendTo(comboObj);
		var cPanelObj = $("<div class=\"combo-panel\"></div>").appendTo("body");
		cPanelObj.panel({
		    doSize : false,
		    closed : true,
		    cls : "combo-p",
		    style : {
		        position : "absolute",
		        zIndex : 10
		    },
		    onOpen : function() {
			    $(this).panel("resize");
		    }
		});
		var comboPropertyName = $(target).attr("name");
		if (comboPropertyName) {
			comboObj.find("input.combo-value").attr("name", comboPropertyName);
			$(target).removeAttr("name").attr("comboName", comboPropertyName);
		}
		comboTextObj.attr("autocomplete", "off");
		return {
		    combo : comboObj,
		    panel : cPanelObj
		};
	}
	;
	function destroy(target) {
		var comboTextObj = $.data(target, "combo").combo.find("input.combo-text");
		comboTextObj.inputbox("destroy");
		$.data(target, "combo").panel.panel("destroy");
		$.data(target, "combo").combo.remove();
		$(target).remove();
	}
	;
	function bindEvents(target) {
		var comboObj = $.data(target, "combo");
		var cDefs = comboObj.defs;
		var comboObjInner = $.data(target, "combo").combo;
		var cPanel = $.data(target, "combo").panel;
		var comboText = comboObjInner.find(".combo-text");
		var comboArrow = comboObjInner.find(".combo-arrow");
		$(document).unbind(".combo").bind("mousedown.combo", function(e) {
			var p = $(e.target).closest("span.combo,div.combo-panel");
			if (p.length) {
				return;
			}
			var cPanelObj = $("body>div.combo-p>div.combo-panel");
			cPanelObj.panel("close");
		});
		comboObjInner.unbind(".combo");
		cPanel.unbind(".combo");
		comboText.unbind(".combo");
		comboArrow.unbind(".combo");
		if (!cDefs.disabled) {
			comboText.bind("mousedown.combo", function(e) {
				$("div.combo-panel").not(cPanel).panel("close");
				e.stopPropagation();
			}).bind("keydown.combo", function(e) {
				switch (e.keyCode) {
				case 38:
					cDefs.keyHandler.up.call(target);
					break;
				case 40:
					cDefs.keyHandler.down.call(target);
					break;
				case 13:
					e.preventDefault();
					cDefs.keyHandler.enter.call(target);
					return false;
				case 9:
				case 27:
					hidePanel(target);
					break;
				default:
					if (cDefs.editable) {
						if (comboObj.timer) {
							clearTimeout(comboObj.timer);
						}
						comboObj.timer = setTimeout(function() {
							var q = comboText.val();
							if (comboObj.previousValue != q) {
								comboObj.previousValue = q;
								$(target).combo("showPanel");
								cDefs.keyHandler.query.call(target, comboText.val());
								validate(target, true);
							}
						}, cDefs.delay);
					}
				}
			});
			comboArrow.bind("click.combo", function() {
				if (cPanel.is(":visible")) {
					hidePanel(target);
				} else {
					$("div.combo-panel").panel("close");
					$(target).combo("showPanel");
				}
				comboText.focus();
			}).bind("mouseenter.combo", function() {
				$(this).addClass("combo-arrow-hover");
			}).bind("mouseleave.combo", function() {
				$(this).removeClass("combo-arrow-hover");
			}).bind("mousedown.combo", function() {
			});
			comboText.bind("click.combo", function() {
				if (cPanel.is(":visible")) {
					hidePanel(target);
				} else {
					$("div.combo-panel").panel("close");
					$(target).combo("showPanel");
				}
				comboText.focus();
			}).bind("mouseenter.combo", function() {
				$(this).addClass("combo-arrow-hover");
			}).bind("mouseleave.combo", function() {
				$(this).removeClass("combo-arrow-hover");
			}).bind("mousedown.combo", function() {
			});
		}
	}
	;
	function showPanel(target) {
		var cDefs = $.data(target, "combo").defs;
		var comboObj = $.data(target, "combo").combo;
		var cPanel = $.data(target, "combo").panel;
		if ($.fn.window) {
			cPanel.panel("panel").css("z-index", $.fn.window.defaults.zIndex++);
		}
		cPanel.panel("move", {
		    left : comboObj.offset().left,
		    top : getTopPx()
		});
		if (cPanel.panel("defs").closed) {
			cPanel.panel("open");
			cDefs.onShowPanel.call(target);
		}
		(function() {
			if (cPanel.is(":visible")) {
				cPanel.panel("move", {
				    left : getLeftPx(),
				    top : getTopPx()
				});
				setTimeout(arguments.callee, 200);
			}
		})();
		function getLeftPx() {
			var leftWidth = comboObj.offset().left;
			if (leftWidth + cPanel._outerWidth() > $(window)._outerWidth() + $(document).scrollLeft()) {
				leftWidth = $(window)._outerWidth() + $(document).scrollLeft() - cPanel._outerWidth();
			}
			if (leftWidth < 0) {
				leftWidth = 0;
			}
			return leftWidth;
		}
		;
		function getTopPx() {
			var top = comboObj.offset().top + comboObj._outerHeight();
			if (top + cPanel._outerHeight() > $(window)._outerHeight() + $(document).scrollTop()) {
				top = comboObj.offset().top - cPanel._outerHeight();
			}
			if (top < $(document).scrollTop()) {
				top = comboObj.offset().top + comboObj._outerHeight();
			}
			return top;
		}
		;
	}
	;
	function hidePanel(target) {
		var cDefs = $.data(target, "combo").defs;
		var cPanelObj = $.data(target, "combo").panel;
		cPanelObj.panel("close");
		cDefs.onHidePanel.call(target);
	}
	;
	function validate(target, validateFlag) {
		var comboDefs = $.data(target, "combo").defs;
		var comboInputObj = $.data(target, "combo").combo.find("input.combo-text");
		comboDefs.border = false;// delete inner border
		comboInputObj.inputbox(comboDefs);
		if (validateFlag) {
			comboInputObj.inputbox("validate");
		}
	}
	;
	function setDisabled(target, flag) {
		var cDefs = $.data(target, "combo").defs;
		var comboObj = $.data(target, "combo").combo;
		if (flag) {
			cDefs.disabled = true;
			$(target).attr("disabled", true);
			comboObj.find(".combo-value").attr("disabled", true);
			comboObj.find(".combo-text").attr("disabled", true);
		} else {
			cDefs.disabled = false;
			$(target).removeAttr("disabled");
			comboObj.find(".combo-value").removeAttr("disabled");
			comboObj.find(".combo-text").removeAttr("disabled");
		}
	}
	;
	function clear(target) {
		var cDefs = $.data(target, "combo").defs;
		var comboObj = $.data(target, "combo").combo;
		if (cDefs.multiple) {
			comboObj.find("input.combo-value").remove();
		} else {
			comboObj.find("input.combo-value").val("");
		}
		comboObj.find("input.combo-text").val("");
	}
	;
	function comboOnChange(comboObj) {
		var cDefs = $.data(comboObj, "combo").defs;
		var fn = cDefs.onChange;
		cDefs.onChange = function() {
		};
		if (cDefs.multiple) {
			if (cDefs.value) {
				if (typeof cDefs.value == "object") {
					setCbValues(comboObj, cDefs.value);
				} else {
					setCbValue(comboObj, cDefs.value);
				}
			} else {
				setCbValues(comboObj, []);
			}
			cDefs.originalValue = getCbValues(comboObj);
		} else {
			setCbValue(comboObj, cDefs.value);
			cDefs.originalValue = cDefs.value;
		}
		cDefs.onChange = fn;
	}
	;
	$.fn.combo = function(defs, param) {
		if (typeof defs == "string") {
			return $.fn.combo.methods[defs](this, param);
		}
		defs = defs || {};
		return this.each(function() {
			var comboObj = $.data(this, "combo");
			if (comboObj) {
				$.extend(comboObj.defs, defs);
			} else {
				var newDefs = $.extend({}, $.fn.combo.defaults, $.fn.combo.getDefs(this), defs);
				var r = create(this, newDefs);
				comboObj = $.data(this, "combo", {
				    defs : newDefs,
				    combo : r.combo,
				    panel : r.panel,
				    previousValue : null
				});
				$(this).removeAttr("disabled");
			}
			$("input.combo-text", comboObj.combo).attr("readonly", !comboObj.defs.editable);
			setArrowShowOrHide(this);
			bindEvents(this);
			comboOnChange(this);
			setDisabled(this, comboObj.defs.disabled);
			setSize(this, comboObj.defs.width);
			validate(this);
		});
	};
	$.fn.combo.methods = {
	    defs : function(jq) {
		    return $.data(jq[0], "combo").defs;
	    },
	    getText : function(jq) {
		    return getCbText(jq[0]);
	    },
	    setText : function(jq, v) {
		    return jq.each(function() {
			    setCbText(this, v);
		    });
	    },
	    getValues : function(jq) {
		    return getCbValues(jq[0]);
	    },
	    setValues : function(jq, v) {
		    return jq.each(function() {
			    setCbValues(this, v);
		    });
	    },
	    getValue : function(jq) {
		    return getCbValue(jq[0]);
	    },
	    setValue : function(jq, v) {
		    return jq.each(function() {
			    setCbValue(this, v);
		    });
	    },
	    clear : function(jq) {
		    return jq.each(function() {
			    clear(this);
		    });
	    },
	    disable : function(jq) {
		    return jq.each(function() {
			    setDisabled(this, true);
			    bindEvents(this);
		    });
	    },
	    enable : function(jq) {
		    return jq.each(function() {
			    setDisabled(this, false);
			    bindEvents(this);
		    });
	    },
	    panel : function(jq) {
		    return $.data(jq[0], "combo").panel;
	    },
	    textbox : function(jq) {
		    return $.data(jq[0], "combo").combo.find("input.combo-text");
	    },
	    destroy : function(jq) {
		    return jq.each(function() {
			    destroy(this);
		    });
	    },
	    resize : function(jq, width) {
		    return jq.each(function() {
			    setSize(this, width);
		    });
	    },
	    showPanel : function(jq) {
		    return jq.each(function() {
			    showPanel(this);
		    });
	    },
	    hidePanel : function(jq) {
		    return jq.each(function() {
			    hidePanel(this);
		    });
	    },
	    validate : function(jq) {
		    return jq.each(function() {
			    validate(this, true);
		    });
	    },
	    isValid : function(jq) {
		    var comboTextObj = $.data(jq[0], "combo").combo.find("input.combo-text");
		    return comboTextObj.inputbox("isValid");
	    },
	    reset : function(jq) {
		    return jq.each(function() {
			    var cDefs = $.data(this, "combo").defs;
			    if (cDefs.multiple) {
				    $(this).combo("setValues", cDefs.originalValue);
			    } else {
				    $(this).combo("setValue", cDefs.originalValue);
			    }
		    });
	    }
	};
	$.fn.combo.getDefs = function(target) {
		var t = $(target);
		return $.extend({}, $.fn.inputbox.getDefs(target), $.parser.getDefs(target, [ "width",
		        "height", "separator", {
		            panelWidth : "number",
		            editable : "boolean",
		            hasDownArrow : "boolean",
		            delay : "number"
		        } ]), {
		    panelHeight : (t.attr("panelHeight") == "auto" ? "auto" : parseInt(t.attr("panelHeight")) || undefined),
		    multiple : (t.attr("multiple") ? true : undefined),
		    disabled : (t.attr("disabled") ? true : undefined),
		    value : (t.val() || undefined)
		});
	};
	$.fn.combo.defaults = $.extend({}, $.fn.inputbox.defaults, {
	    cusCls : null,
	    width : "auto",
	    height : 22,
	    border : false,
	    multiple : false,
	    editable : true,
	    disabled : false,
	    hasDownArrow : true,
	    panelWidth : null,
	    panelHeight : 200,
	    separator : ",",
	    value : "",
	    delay : 200,
	    keyHandler : {
	        up : function() {
	        },
	        down : function() {
	        },
	        enter : function() {
	        },
	        query : function(q) {
	        }
	    },
	    onShowPanel : function() {
	    },
	    onHidePanel : function() {
	    },
	    onChange : function(target, v) {
	    }
	});
})(jQuery);
