var Input = {
	Checkbox: function (id) {
		var el = Innect.$(id);
		var DIV = Innect.$("_" + el.id);
		return {
			Check: function (value) {
				el.checked = value;
				this.Checked = value;
				if(!Input.UseBrowserControls) this.Render();
			},
			Checked: (el.checked)?el.value:"",
			Disable: function () {
				el.disabled = true;
				this.Disabled = true;
				if(!Input.UseBrowserControls) this.Render();
			},
			Disabled: (el.disabled),
			Enable: function () {
				el.disabled = false;
				this.Disabled = false;
				if(!Input.UseBrowserControls) this.Render();
			},
			Node: el,
			Render: function () {
				var classes = "Checkbox" + ((el.checked)?" Checked":"") + ((el.disabled)?" Disabled":"");
				if(!DIV) {
					el.insertAdjacentHTML("beforeBegin", "<div class=\"" + classes + "\" id=\"_" + el.id + "\"></div>");
					DIV = el.previousSibling;
					EventManager.Add(DIV, "click", function () {
						EventManager.Fire(this.nextSibling, "click");
					});
					EventManager.Add(DIV, "keydown", function (e) {
						e = e || window.event;
						if(e.keyCode == 32) EventManager.Fire(this.nextSibling, "click");
					});
					if(window.IE7) IE7.FixFocus(DIV);
				}
				else {
					Innect.Class.Set(DIV, classes);
					DIV.tabIndex = (el.disabled)?-1:0;
				}
			},
			Value: el.value
		}
	},
	CheckboxGroup: function (name) {
		var els = Innect.$$(name);
		return {
			Check: function (values) {
				Array.forEach(els, function (el) {
					el.checked = (values.indexOf(el.value) != -1);
				});
				this.Checked = Input.Shared.Checked(els);
				if(!Input.UseBrowserControls) this.Render();
			},
			Checked: Input.Shared.Checked(els),
			Disable: function () {
				Array.forEach(els, function (el) {
					el.disabled = true;
				});
				if(!Input.UseBrowserControls) this.Render();
			},
			Enable: function () {
				Array.forEach(els, function (el) {
					el.disabled = false;
				});
				if(!Input.UseBrowserControls) this.Render();
			},
			Nodes: els,
			Render: function () {
				Array.forEach(els, function (el) {
					Input.Checkbox(el.id).Render();
				});
			}
		}
	},
	Coalesce: function (value, returnValue) {
		if(String(value).match(/^(?:null|undefined|-1)*$/) == null) return value;
		return returnValue;
	},
	Disable: function (id) {
		var el = Innect.$(id);
		el.disabled = true;
		if(!Input.UseBrowserControls) Input.Render(el);
	},
	Enable: function (id) {
		var el = Innect.$(id);
		el.disabled = false;
		if(!Input.UseBrowserControls) Input.Render(el);
	},
	Errors: {
		Add: function (error, id) {
			var Errors = Input.Errors.Get(id);
			if(Errors.Index == -1) Input.Errors.Collection.push([id, error]);
			else if(Errors.Collection.indexOf(error) == -1) Input.Errors.Collection[Errors.Index].push(error);
			Input.Errors.Show(id);
		},
		Clear: function () {
			Input.Errors.Collection = [];
		},
		Collection: [],
		Get: function (id) {
			var errors = null;
			var i = -1;
			Input.Errors.Collection.forEach(function (el, index) {
				if(el[0] == id) {
					errors = el.slice(1);
					i = index;
				}
			});
			return {
				Collection: errors,
				Index: i
			}
		},
		Hide: function () {
			Input.Errors.Clear();
			cssQuery("div.Errors").forEach(function (el) {
				el.parentNode.removeChild(el);
			});
		},
		Remove: function (error, id) {
			var Errors = Input.Errors.Get(id);
			if(Errors.Index != -1) {
				var i = Errors.Collection.indexOf(error);
				if(i != -1) {
					if(Errors.Collection.length > 1) Input.Errors.Collection[Errors.Index].splice((i + 1), 1);
					else Input.Errors.Collection.splice(Errors.Index, 1);
					Input.Errors.Show(id);
				}
			}
		},
		Show: function (id) {
			if(!Input.UseBrowserControls) {
				var Errors = Input.Errors.Get(id);
				var el = Innect.$("Errors_" + id);
				if(el) {
					if(Errors.Collection != null) el.innerHTML = Errors.Collection.join("<br>");
					else el.parentNode.removeChild(el);
				}
				else Innect.$("_" + id).insertAdjacentHTML("afterEnd", "<div class=\"Errors\" id=\"Errors_" + id + "\">" + Errors.Collection.join("<br>") + "</div>");
			}
		}
	},
	Initialize: function (el) {
		cssQuery("input, select, textarea", el).forEach(function (el, index) {
			if(!el.id) el.id = "Element_" + index;
			var id = el.id;
			switch (el.nodeName) {
				case "INPUT":
					switch (el.type) {
						case "checkbox":
							if(!Input.UseBrowserControls) {
								el.tabIndex = -1;
								EventManager.Add(el, "click", function () {
									Input.Checkbox(id).Render();
								});
								Input.Checkbox(id).Render();
							}
							break;
						case "file":
							if(el.getAttribute("mimetypes")) EventManager.Add(el, "change", Input.ValidateMimeTypes);
							break;
						case "password":
							if(!Input.UseBrowserControls) el = Input.Text(id).Render();
							if(el.getAttribute("minlength")) EventManager.Add(el, "blur", Input.ValidateLength);
							if(el.getAttribute("constraint") == "passwordmatch") EventManager.Add(el, "blur", Input.ValidatePasswords);
							break;
						case "radio":
							if(!Input.UseBrowserControls) {
								el.tabIndex = -1;
								EventManager.Add(el, "click", function () {
									Input.RadiobuttonGroup(el.name).Render();
								});
								Input.Radiobutton(id).Render();
							}
							break;
						case "text":
							if(!Input.UseBrowserControls) el = Input.Text(id).Render();
							switch (el.getAttribute("constraint")) {
								case "filewithoutextension":
								case "identifier":
								case "item":
								case "phone":
								case "string-basic":
								case "string-extended":
									EventManager.Add(el, "keyup", Input.ValidateConstraint);
									break;
								case "currency":
								case "email":
								case "file":
								case "img":
								case "url":
								case "zip":
									EventManager.Add(el, "blur", Input.ValidateConstraint);
									if(el.getAttribute("mimetypes")) EventManager.Add(el, "blur", Input.ValidateMimeTypes);
									break;
								case "folder":
									EventManager.Add(el, "keyup", Input.ValidateExistence);
									EventManager.Add(el, "keyup", Input.ValidateConstraint);
									break;
								case "number":
									EventManager.Add(el, "keyup", Input.ValidateRange);
									break;
							}
							if(el.getAttribute("command")) EventManager.Add(el, "keyup", Input.ValidateUnique);
							break;
					}
					break;
				case "SELECT":
					if(!Input.UseBrowserControls) {
						el.tabIndex = -1;
						Input["Select" + ((el.size > 1)?"List":"")](id).Render();
					}
					break;
				case "TEXTAREA":
					if(!Input.UseBrowserControls) Input.MultilineText(id).Render();
					if(!el.getAttribute("constraint")) el.setAttribute("constraint", "text");
					EventManager.Add(el, "keyup", Input.ValidateConstraint);
					if(el.getAttribute("maxlength")) EventManager.Add(el, "keyup", Input.ValidateLength);
					break;
			}
		});
	},
	MultilineText: function (id) {
		var el = Innect.$(id);
		return {
			Disable: function () {
				el.disabled = true;
				this.Disabled = true;
				if(!Input.UseBrowserControls) this.Render();
			},
			Disabled: (el.disabled),
			Enable: function () {
				el.disabled = false;
				this.Disabled = false;
				if(!Input.UseBrowserControls) this.Render();
			},
			Node: el,
			Render: function () {
				var classes = "MultilineText" + ((el.getAttribute("required"))?" Required":"") + ((el.disabled)?" Disabled":"");
				if(!Innect.$("_" + id)) {
					el.outerHTML = "<div class=\"" + classes + "\" id=\"_" + id + "\">" + el.outerHTML + "</div>";
					el = Innect.$(id);
				}
				else Innect.Class.Set(el.parentNode, classes);
				EventManager.Add(el, "focus", Input.Shared.Focus);
				EventManager.Add(el, "blur", Input.Shared.Blur);
				return el;
			},
			SetValue: function (value) {
				el.value = value;
				this.Value = value;
			},
			Value: el.value
		}
	},
	Radiobutton: function (id) {
		var el = Innect.$(id);
		var DIV = Innect.$("_" + el.id);
		return {
			Disable: function () {
				el.disabled = true;
				this.Disabled = true;
				if(!Input.UseBrowserControls) this.Render();
			},
			Disabled: (el.disabled),
			Enable: function () {
				el.disabled = false;
				this.Disabled = false;
				if(!Input.UseBrowserControls) this.Render();
			},
			Node: el,
			Render: function () {
				var classes = "Radiobutton" + ((el.checked)?" Checked":"") + ((el.disabled)?" Disabled":"");
				if(!DIV) {
					el.insertAdjacentHTML("beforeBegin", "<div class=\"" + classes + "\" id=\"_" + el.id + "\"></div>");
					DIV = el.previousSibling;
					EventManager.Add(DIV, "click", function () {
						EventManager.Fire(this.nextSibling, "click");
					});
					EventManager.Add(DIV, "keydown", function (e) {
						e = e || window.event;
						if(e.keyCode == 32) EventManager.Fire(this.nextSibling, "click");
					});
					if(window.IE7) IE7.FixFocus(DIV);
				}
				else {
					Innect.Class.Set(DIV, classes);
					DIV.tabIndex = (el.disabled)?-1:0;
				}
			},
			Value: el.value
		}
	},
	RadiobuttonGroup: function (name) {
		var els = Innect.$$(name);
		return {
			Check: function (value) {
				Array.forEach(els, function (el) {
					el.checked = (el.value == value);
				});
				this.Checked = value;
				if(!Input.UseBrowserControls) this.Render();
			},
			Checked: Input.Shared.Checked(els).toString(),
			Disable: function () {
				Array.forEach(els, function (el) {
					el.disabled = true;
				});
				if(!Input.UseBrowserControls) this.Render();
			},
			Enable: function () {
				Array.forEach(els, function (el) {
					el.disabled = false;
				});
				if(!Input.UseBrowserControls) this.Render();
			},
			Nodes: els,
			Render: function () {
				Array.forEach(els, function (el) {
					Input.Radiobutton(el.id).Render();
				});
			}
		}
	},
	RegularExpression: function (regexp) {
		switch (regexp) {
			case "creditcard": return new RegExp("^(\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4})$"); break;
			case "currency": return new RegExp("^\\$?([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)$");
			case "date": return new RegExp("^(?:(?:(?:0?[13578]|1[02])(\\/|-|\\.)31)\\1|(?:(?:0?[1,3-9]|1[0-2])(\\/|-|\\.)(?:29|30)\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:0?2(\\/|-|\\.)29\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\\/|-|\\.)(?:0?[1-9]|1\\d|2[0-8])\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$"); break;
			case "email": return new RegExp("^[0-9a-zA-Z\\.\\-\\_]+\\@[0-9a-zA-Z\\.\\-]+$"); break;
			case "file": return new RegExp("^[^/\\?\\*\\\"\\>\\<\\:\\|]+\\.\\w{2,6}$"); break;
			case "filewithoutextension": new RegExp("^[^\\\\\/\\?\\*\\\"\\>\\<\\:\\|]*$"); break;
			case "folder": return new RegExp("^[^\\\\\/\\?\\*\\\"\\>\\<\\:\\|]*$"); break;
			case "identifier": return new RegExp("^[a-zA-Z0-9_]*$"); break;
			case "img": return new RegExp("^(http|https|ftp)\\://[a-zA-Z0-9\\-\\.]+(:[a-zA-Z0-9]*)?(\\/(?!\\/))(([a-zA-Z0-9\\-_\\/]*)?)([a-zA-Z0-9-_ ])+\\.((jpg|jpeg|gif|png)(?!(\\w|\\W)))$"); break;
			case "item": return new RegExp("^[A-Za-z0-9_&#()<>-\\?\\/' .+]*$"); break;
			case "phone": return new RegExp("^[0-9a-zA-Z]*$"); break;
			case "ssn": return new RegExp("^\\d{3}-\\d{2}-\\d{4}$"); break;
			case "string-basic": return new RegExp("^[-a-zA-Z\u00c6\u00e6\u00d8\u00f8\u00c5\u00e5 ]*$"); break;
			case "string-extended": return new RegExp("^[-a-zA-Z\u00c6\u00e6\u00d8\u00f8\u00c5\u00e50-9_,\\*\\(\\)\+\\$\\./ \\?&'#!:\"]*$"); break;
			case "text": return new RegExp("^[-a-zA-Z0-9_,\\*\\(\\)\+\\$\\./ \\?&'#!:;\"<>@%=\\[\\]{}|\\n\\r\\\\]*$"); break;
			case "url": return new RegExp("^(http|https|ftp)\\://[a-zA-Z0-9\\-\\.]+\\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\\-\\._\\?\\,\\'/\\\\+&%\\$#\\=~])*[^\\.\\,\\)\(]$"); break;
			case "zip": return new RegExp("^\\d{5}$"); break;
		}
	},
	Render: function (el) {
		switch (el.nodeName) {
			case "SELECT": Input[el.size > 1?"SelectList":"Select"](el.id).Render(); break;
			case "INPUT":
				switch (el.type) {
					case "checkbox": Input.Checkbox(el.id).Render(); break;
					case "radio": Input.Radiobutton(el.id).Render(); break;
					case "text":
					case "password": Input.Text(el.id).Render(); break;
				}
				break;
			case "TEXTAREA": Input.MultilineText(el.id).Render(); break;
		}
	},
	Reset: function (id) {
		var el = Innect.$(id);
		switch (el.nodeName) {
			case "SELECT": Array.forEach(el.options, function (option) {
				option.selected = option.defaultSelected;
			}); break;
			case "INPUT":
				switch (el.type) {
					case "checkbox":
					case "radio": if(el.defaultChecked) el.checked = true; break;
					case "text": el.value = el.defaultValue; break;
				}
		}
		if(!Input.UseBrowserControls) Input.Render(el);
	},
	Select: function (id) {
		var el = Innect.$(id);
		var DIV = Innect.$("_" + id);
		var Obj = {
			Disable: function () {
				el.disabled = true;
				this.Disabled = true;
				if(!Input.UseBrowserControls) this.Render();
			},
			Disabled: (el.disabled),
			Enable: function () {
				el.disabled = false;
				this.Disabled = false;
				if(!Input.UseBrowserControls) this.Render();
			},
			Node: el,
			Options: {
				Count: el.options.length,
				Option: function (index) {
					var option = el.options[index];
					return {
						Text: option.text,
						Value: option.value
					}
				},
				Options: function (what) {
					var col = Array.map(el.options, function (option, index) {
						if(what == "Index") return index + 1;
						return ((what == "Text")?option.text:option.value);
					});
					return (col.length > 0)?col:-1;
				},
				Populate: function (options, returnHTML, defaultOptions) {
					if(defaultOptions) options.unshift(defaultOptions);
					if(returnHTML) return options.map(function (option) {
						return "<option value=\"" + option[0] + "\">" + ((typeof option[1] != "undefined")?option[1]:option[0]) + "</option>";
					}).join("");
					el.options.length = 0;
					options.forEach(function (option, index) {
						el[index] = new Option(option[0], (typeof option[1] != "undefined")?option[1]:option[0]);
					});
					this.Count = el.options.length;
					if(!Input.UseBrowserControls) this.parent.Render();
				},
				PopulateWithStates: function (returnHTML, defaultOptions) {
					var states = [["Alabama", "AL"], ["Alaska", "AK"], ["Arizona", "AZ"], ["Arkansas", "AR"], ["California", "CA"], ["Colorado", "CO"], ["Connecticut", "CT"], ["Delaware", "DE"], ["Florida", "FL"], ["Georgia", "GA"], ["Hawaii", "HI"], ["Idaho", "ID"], ["Illinois", "IL"], ["Indiana", "IN"], ["Iowa", "IA"], ["Kansas", "KS"], ["Kentucky", "KY"], ["Louisiana", "LA"], ["Maine", "ME"], ["Maryland", "MD"], ["Massachusetts", "MA"], ["Michigan", "MI"], ["Minnesota", "MN"], ["Mississippi", "MS"], ["Missouri", "MO"], ["Montana", "MT"], ["Nebraska", "NE"], ["Nevada", "NV"], ["New Hampshire", "NH"], ["New Jersey", "NJ"], ["New Mexico", "NM"], ["New York", "NY"], ["Newfoundland", "NF"], ["North Carolina", "NC"], ["North Dakota", "ND"], ["Ohio", "OH"], ["Oklahoma", "OK"], ["Oregon", "OR"], ["Pennsylvania", "PA"], ["Rhode Island", "RI"], ["South Carolina", "SC"], ["South Dakota", "SD"], ["Tennessee", "TN"], ["Texas", "TX"], ["Utah", "UT"], ["Vermont", "VT"], ["Virginia", "VA"], ["Washington", "WA"], ["West Virginia", "WV"], ["Wisconsin", "WI"], ["Wyoming", "WY"]];
					this.Populate(states, returnHTML, defaultOptions);
				},
				PopulateWithTime: function (returnHTML, defaultOptions) {
					var times = [];
					var zones = (Languages.MilitaryTime)?["", ""]:["AM", "PM"];
					var hours = (Languages.MilitaryTime)?[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]:[12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
					var quarters = ["00", "15", "30", "45"];
					zones.forEach(function (zone, index) {
						hours.forEach(function (hour) {
							quarters.forEach(function (quarter) {
								times.push(((Languages.MilitaryTime)?((index == 1)?hour + 12:hour).toString().setLeadingZeros(2) + ":" + quarter:hour + ":" + quarter + " " + zone));
							});
						});
					});
					this.Populate(times, returnHTML, defaultOptions);
				},
				PopulateWithYears: function (returnHTML, defaultOptions) {
					var years = [];
					var year = 1900;
					while(year < 2079) {
						years.push([year]);
						year++;
					}
					this.Populate(years, returnHTML, defaultOptions);
				},
				Raw: function (joinChars) {
					if(!joinChars) joinChars = ["|", "~"];
					return Array.map(el.options, function (option) {
						return option.text + joinChars[0] + option.value;
					}).join(joinChars[1]);
				},
				Select: function (value, what) {
					what = what || "Value";
					var index = el.selectedIndex;
					switch (what) {
						case "Index": el.selectedIndex = value; break;
						case "First": el.selectedIndex = 0; break;
						case "Last": el.selectedIndex = this.Options.Count - 1; break;
						case "Previous": if(index > 0) el.selectedIndex = index - 1; break;
						case "Next": if(index != this.Options.Count - 1) el.selectedIndex = index + 1; break;
						case "Text":
						default:
							Array.forEach(el.options, function (option) {
								if(((what == "Text")?option.text:option.value) == value) option.selected = true;
							});
							break;
					}
					if(!Input.UseBrowserControls) this.parent.Render();
					return el.selectedIndex;
				},
				Selected: function (what) {
					if(el.selectedIndex == -1) return -1;
					else if(what == "Index") return el.selectedIndex;
					else return ((what == "Text")?el[el.selectedIndex].text:el[el.selectedIndex].value);
				}
			},
			Render: function () {
				var size = el.size;
				var classes = Innect.Class.Get(el);
				classes = "Select" + ((classes != "")?" " + classes:"") + ((el.disabled)?" Disabled":"");
				if(!DIV) {
					var str = "<div class=\"" + classes + "\" id=\"_" + id + "\" tabindex=\"0\"><span class=\"Selected\"></span><div class=\"Glyph\"></div><div class=\"Options\"></div></div>";
					el.insertAdjacentHTML("beforeBegin", str);
					DIV = el.previousSibling;
					var LABEL = DIV.previousSibling;
					if(LABEL && LABEL.nodeName == "LABEL") {
						LABEL.removeAttribute("for");
						EventManager.Add(LABEL, "click", function () {
							this.nextSibling.focus();
						});
					}
					EventManager.Add(DIV, "keydown", Input.Shared.HandleEvents);
					EventManager.Add(DIV, "mousedown", Input.Shared.HandleEvents);
					if(window.IE7) {
						IE7.FixFocus(DIV);
						EventManager.Add(DIV, "focusout", function () {
							Input.Shared.Hide(this.lastChild);
						});
					}
					else {
						EventManager.Add(DIV, "focus", function () {
							Innect.Class.Add(this, "Focus");
						});
						EventManager.Add(DIV, "blur", function () {
							Innect.Class.Remove(this, "Focus");
							Input.Shared.Hide(this.lastChild);
						});
					}
				}
				else Innect.Class.Set(DIV, classes);
				var SPAN = DIV.firstChild;
				var options = DIV.lastChild;
				options.innerHTML = " " + Array.map(el.options, function (option, index) {
					return "<span optionindex=\"" + index + "\">" + Innect.HTMLEncode(option.text) + "</span>";
				}).join("");
				SPAN.innerHTML = Innect.HTMLEncode((el.selectedIndex != -1)?el.options[el.selectedIndex].text:"");
				var optionsPadding = parseInt(Innect.Style.Get(options, "paddingLeft")) + parseInt(Innect.Style.Get(options, "paddingRight"));
				var spanPadding = parseInt(Innect.Style.Get(SPAN, "paddingLeft")) + parseInt(Innect.Style.Get(SPAN, "paddingRight"));
				switch (true) {
					case (Innect.Class.Exist(el, "")):
						var textSizeTeller = Innect.$("TextSizeTeller");
						if(!textSizeTeller) {
							textSizeTeller = document.createElement("span");
							textSizeTeller.id = "TextSizeTeller";
							document.body.insertAdjacentElement("afterBegin", textSizeTeller);
						}
						textSizeTeller.innerHTML = Array.map(el.options, function (option) {
							return "<span>" + Innect.HTMLEncode(option.text) + "</span><br>";
						}).join("");
						var width = textSizeTeller.offsetWidth + 1;
						textSizeTeller.innerHTML = "";
						Innect.Style.Set(SPAN, "width", Math.max(0, width) + "px");
						Innect.Style.Set(options, "width", (width + spanPadding) - optionsPadding + "px");
						break;
					case (Innect.Class.Exist(el, "Full")):
						var width = select.offsetWidth;
						Innect.Style.Set(SPAN, "width", width - inputPadding + "px");
						Innect.Style.Set(options, "width", width - optionsPadding + "px");
						break;
				}
				Innect.Style.Set(DIV, "visibility", "visible");
			}
		}
		Obj.Options.parent = Obj;
		return Obj;
	},
	SelectGroup: function (name) {
		var els = Innect.$$(name);
		return {
			Nodes: els
		}
	},
	SelectList: function (id) {
		var el = Innect.$(id);
		var DIV = Innect.$("_" + id);
		var Obj = {
			Disable: function () {
				el.disabled = true;
				this.Disabled = true;
				if(!Input.UseBrowserControls) this.Render();
			},
			Disabled: (el.disabled),
			Enable: function () {
				el.disabled = false;
				this.Disabled = false;
				if(!Input.UseBrowserControls) this.Render();
			},
			Max: el.getAttribute("max"),
			Node: el,
			Options: {
				Add: function (options) {
					options.forEach(function (option) {
						el[el.length] = new Option(option[0], option[1] || option[0]);
					});
					if(!Input.UseBrowserControls) this.parent.Render();
				},
				Change: function (label, value, index) {
					index = index || el.selectedIndex;
					el[index].text = label;
					el[index].value = value;
					if(!Input.UseBrowserControls) this.parent.Render();
				},
				CopyTo: function (destinationId) {
					var destinationEl = Innect.$(destinationId);
					destinationEl.options.length = 0;
					Array.forEach(el.options, function (option) {
						destinationEl[destinationEl.options.length] = new Option(option.text, option.value);
					});
				},
				Count: el.options.length,
				Move: function (upOrDown) {
					var index = el.selectedIndex;
					var value = el[index].value;
					var text = el[index].text;
					var range = true;
					var newIndex;
					if(upOrDown == "Up") newIndex = index - 1;
					else if(upOrDown == "Down") newIndex = index + 1;
					else {
						newIndex = index;
						range = false;
					}
					if(newIndex == this.Count || newIndex < 0) range = false;
					if(range) {
						var newValue = el[newIndex].value;
						var newText = el[newIndex].text;
						el[index].value = newValue;
						el[index].text = newText;
						el[newIndex].value = value;
						el[newIndex].text = text;
						el[newIndex].selected = true;
						if(!Input.UseBrowserControls) this.parent.Render();
					}
					return newIndex;
				},
				MoveTo: function (destinationId) {
					function optionSort(a, b) {
						if(a.text.toLowerCase() < b.text.toLowerCase()) return -1;
						else if(a.text.toLowerCase() > b.text.toLowerCase()) return 1;
						return 0;
					}
			
					var destinationEl = Innect.$(destinationId);
					var max = destinationEl.getAttribute("max");
					Array.forEach(el.options, function (option) {
						if(option.selected && (max == -1 || destinationEl.options.length < max || !max)) destinationEl[destinationEl.options.length] = new Option(option.text, option.value);
					});
					var index = destinationEl.selectedIndex;
					var col = Array.map(destinationEl.options, function (option) {
						return option;
					}).sort(optionSort);
					destinationEl.options.length = 0;
					col.forEach(function (option, index) {
						destinationEl.options[index] = new Option(option.text, option.value);
					});
					destinationEl.selectedIndex = index;
					this.Synchronize(destinationId);
				},
				Option: function (index) {
					var option = el.options[index];
					return {
						Text: option.text,
						Value: option.value
					}
				},
				Options: function (what) {
					var col = Array.map(el.options, function (option, index) {
						if(what == "Index") return index + 1;
						return ((what == "Text")?option.text:option.value);
					});
					return (col.length > 0)?col:-1;
				},
				Populate: function (options, returnHTML) {
					if(returnHTML) return options.map(function (option) {
						return "<option value=\"" + option[0] + "\">" + ((typeof option[1] != "undefined")?option[1]:option[0]) + "</option>";
					}).join("");
					el.options.length = 0;
					options.forEach(function (option, index) {
						el[index] = new Option(option[0], (typeof option[1] != "undefined")?option[1]:option[0]);
					});
					this.Count = el.options.length;
					if(!Input.UseBrowserControls) this.parent.Render();
				},
				Raw: function (joinChars) {
					if(!joinChars) joinChars = ["|", "~"];
					return Array.map(el.options, function (option) {
						return option.text + joinChars[0] + option.value;
					}).join(joinChars[1]);
				},
				Remove: function () {
					for(var i = this.Options.Count - 1; i >= 0; i--) if(el[i].selected) el[i] = null;
					this.Count = el.options.length;
					if(!Input.UseBrowserControls) this.parent.Render();
				},
				Select: function (values, what) {
					var index = el.selectedIndex;
					switch (what) {
						case "First": el.selectedIndex = 0; break;
						case "Last": el.selectedIndex = this.Options.Count - 1; break;
						case "Previous": if(index > 0) el.selectedIndex = index - 1; break;
						case "Next": if(index != this.Options.Count - 1) el.selectedIndex = index + 1; break;
						case "Index":
						case "Text":
						default:
							Array.forEach(el.options, function (option, index) {
								values.forEach(function (value) {
									if(what == "Index") if(index == parseInt(value)) option.selected = true;
									else if(((what == "Text")?option.text:option.value) == value) option.selected = true;
								});
							});
							break;
					}
					if(!Input.UseBrowserControls) this.parent.Render();
					return el.selectedIndex;
				},
				Selected: function (what) {
					var col = [];
					Array.forEach(el.options, function (option, index) {
						if(option.selected) {
							if(what == "Index") col.push(index);
							else col.push(((what == "Text")?option.text:option.value));
						}
					});
					return (col.length > 0)?col:-1;
				},
				Synchronize: function (syncId) {
					var col = this.Options();
					var syncEl = Innect.$(syncId);
					var count = 0;
					Array.forEach(syncEl.options, function (option) {
						var index = col.indexOf(option.value);
						if(index != -1) {
							el[index - count] = null;
							count++;
						}
					});
					if(!Input.UseBrowserControls) {
						this.parent.Render();
						Input.SelectList(syncId).Render();
					}
				}
			},
			Render: function () {
				var size = el.size;
				var classes = Innect.Class.Get(el);
				classes = "SelectList" + ((el.getAttribute("required"))?" Required":"") + ((classes != "")?" " + classes:"") + ((el.disabled)?" Disabled":"");
				if(!DIV) {
					var textSizeTeller = Innect.$("TextSizeTeller");
					if(!textSizeTeller) {
						textSizeTeller = document.createElement("span");
						textSizeTeller.id = "TextSizeTeller";
						document.body.insertAdjacentElement("afterBegin", textSizeTeller);
					}
					var str = "<div class=\"" + classes + "\" id=\"_" + id + "\"><div class=\"Options\"></div></div>";
					el.insertAdjacentHTML("beforeBegin", str);
					DIV = el.previousSibling;
					var col = [];
					var i = 0;
					while(i < size) {
						col.push("<span>&nbsp;</span><br>");
						i++;
					}
					textSizeTeller.innerHTML = col.join("");
					Innect.Style.Set(DIV.lastChild, "height", textSizeTeller.offsetHeight + "px");
					textSizeTeller.innerHTML = "";
					EventManager.Add(DIV, "keydown", Input.Shared.HandleEvents);
					EventManager.Add(DIV, "mousedown", Input.Shared.HandleEvents);
					if(window.IE7) {
						IE7.FixFocus(DIV);
						EventManager.Add(DIV, "selectstart", EventManager.Stop);
					}
					else {
						EventManager.Add(DIV, "focus", function () {
							Innect.Class.Add(this, "Focus");
						});
						EventManager.Add(DIV, "blur", function () {
							Innect.Class.Remove(this, "Focus");
						});
					}
					EventManager.Add(DIV, "dblclick", function () {
						EventManager.Fire(el, "dblclick");
					});
				}
				else Innect.Class.Set(DIV, classes);
				DIV.lastChild.innerHTML = " " + Array.map(el.options, function (option, index) {
					return "<span optionindex=\"" + index + "\" tabindex=\"" + ((index == 0)?"0":"-1") + "\">" + Innect.HTMLEncode(option.text) + "</span>";
				}).join("");
				var SPANs = cssQuery("span", DIV.lastChild);
				SPANs.forEach(function (SPAN) {
					Innect.Class.Remove(SPAN, "Selected");
				});
				var options = Input.SelectList(id).Options.Selected("Index");
				if(options != -1) {
					options.forEach(function (option) {
						SPANs.forEach(function (SPAN, index) {
							if(option == index) Innect.Class.Add(SPAN, "Selected");
						});
					});
				}
				if(window.IE7) IE7.FixFocus();
			}
		}
		Obj.Options.parent = Obj;
		return Obj;
	},
	Shared: {
		Blur: function () {
			Innect.Class.Remove(this.parentNode, "Focus");
		},
		Checked: function (els) {
			return Array.filter(els, function (el) {
				return (el.checked);
			}).map(function (el) {
				return el.value;
			});
		},
		Focus: function () {
			Innect.Class.Add(this.parentNode, "Focus");
		},
		HandleEvents: function (e) {
			e = e || window.event;
			if(Innect.Class.Exist(this, "Disabled")) return false;
			var el = this.nextSibling;
			switch (el.nodeName) {
				case "SELECT":
					function indexSort(a, b) {
						if(a > b) return 1;
						if(a < b) return -1;
						return 0;
					}
					
					var upKey = (e.keyCode == 38);
					var downKey = (e.keyCode == 40);
					var selEl = e.target || e.srcElement;
					var selIndex = selEl.getAttribute("optionindex");
					var options = this.lastChild;
					if(el.size > 1) {
						var tabKey = (e.keyCode == 9);
						var enterKey = (e.keyCode == 13);
						var shiftKey = e.shiftKey;
						var ctrlKey = e.ctrlKey;
						switch (e.type) {
							case "keydown":
								if(!downKey && !upKey && !enterKey) return;
								var selSpans = cssQuery("span.Selected", options);
								if(downKey || upKey) {
									selEl = selEl[((downKey)?"next":"previous") + "Sibling"];
									if(!selEl || selEl.nodeType == 3) {
										EventManager.Stop(e);
										return;
									}
									selIndex = selEl.getAttribute("optionindex");
									selEl.focus();
								}
								if(el.multiple) {
									if(ctrlKey) {
										EventManager.Stop(e);
										return;
									}
									var focalPointEl = cssQuery("span[focalpoint]", options)[0];
									if(shiftKey) {
										if(focalPointEl) {			
											var focalPointIndex = focalPointEl.getAttribute("optionindex");
											var indexOrder = [selIndex, focalPointIndex].sort(indexSort);
											cssQuery("span", options).forEach(function (SPAN, index) {
												if(index > indexOrder[0] && index < indexOrder[1]) Innect.Class.Add(SPAN, "Selected");
												else Innect.Class.Remove(SPAN, "Selected");
											});
											Innect.Class.Add(focalPointEl, "Selected");
										}
										else selEl.setAttribute("focalpoint", "yes");
										Innect.Class.Add(selEl, "Selected");
									}
									else {
										if(focalPointEl) focalPointEl.removeAttribute("focalpoint");
										selEl.setAttribute("focalpoint", "yes");
										if(enterKey) {							
											if(!Innect.Class.Exist(selEl, "Selected")) Innect.Class.Add(selEl, "Selected");
											else Innect.Class.Remove(selEl, "Selected");
										}
										else {
											selSpans.forEach(function (SPAN) {
												Innect.Class.Remove(SPAN, "Selected");
											});
											Innect.Class.Add(selEl, "Selected");
										}
									}
								}
								else {
									selSpans.forEach(function (SPAN) {
										Innect.Class.Remove(SPAN, "Selected");
									});
									Innect.Class.Add(selEl, "Selected");
									selEl.setAttribute("focalpoint", "yes");
								}
								cssQuery("span", options).forEach(function (SPAN) {
									SPAN.tabIndex = -1;
								});
								selEl.tabIndex = 0;
								el.selectedIndex = -1;
								selSpans = cssQuery("span.Selected", options);
								selSpans.forEach(function (SPAN) {
									el.options[SPAN.getAttribute("optionindex")].selected = true;
								});
								if(el.onchange) el.onchange();
								break;
							case "mousedown":
								if(selEl.nodeName != "SPAN") {
									EventManager.Stop(e);
									return;
								}
								selEl.focus();
								var selSpans = cssQuery("span.Selected", options);
								if(el.multiple) {
									var focalPointEl = cssQuery("span[focalpoint]", options)[0];
									if(shiftKey) {
										if(focalPointEl) {				
											var focalPointIndex = focalPointEl.getAttribute("optionindex");
											var indexOrder = new Array(selIndex, focalPointIndex).sort(indexSort);
											cssQuery("span", options).forEach(function (SPAN, index) {
												if(index > indexOrder[0] && index < indexOrder[1]) Innect.Class.Add(SPAN, "Selected");
												else Innect.Class.Remove(SPAN, "Selected");
											});
											Innect.Class.Add(focalPointEl, "Selected");
										}
										else selEl.setAttribute("focalpoint", "yes");
										Innect.Class.Add(selEl, "Selected");
									}
									else {
										if(focalPointEl) focalPointEl.removeAttribute("focalpoint");
										selEl.setAttribute("focalpoint", "yes");
										if(ctrlKey) {
											if(!Innect.Class.Exist(selEl, "Selected")) Innect.Class.Add(selEl, "Selected");
											else Innect.Class.Remove(selEl, "Selected");
										}
										else {
											selSpans.forEach(function (SPAN) {
												Innect.Class.Remove(SPAN, "Selected");
											});
											Innect.Class.Add(selEl, "Selected");
										}
									}
								}
								else {
									selSpans.forEach(function (SPAN) {
										Innect.Class.Remove(SPAN, "Selected");
									});
									Innect.Class.Add(selEl, "Selected");
								}
								cssQuery("span", options).forEach(function (SPAN) {
									SPAN.tabIndex = -1;
								});
								selEl.tabIndex = 0;
								el.selectedIndex = -1;
								selSpans = cssQuery("span.Selected", options);
								selSpans.forEach(function (SPAN) {
									el.options[SPAN.getAttribute("optionindex")].selected = true;
								});
								if(el.onchange) el.onchange();
								break;
						}
						if(window.IE7) this.firstChild.scrollLeft = 0;
						EventManager.Stop(e);
					}
					else {
						var SPAN = this.firstChild;
						switch (e.type) {
							case "keydown":
								if(!downKey && !upKey) return;
								selEl = options.firstChild;
								if(selEl.nodeType == 3) selEl = selEl.nextSibling;
								if(upKey || downKey) {
									selIndex = el.selectedIndex;
									if(upKey) selIndex--
									else selIndex++;
									selEl = cssQuery("span", options)[selIndex];
									if(!selEl) {
										EventManager.Stop(e);
										return;
									}
								}
								el.selectedIndex = selIndex;
								SPAN.innerHTML = Innect.HTMLEncode(selEl.innerText);
								Input.Shared.Hide(options);
								if(el.onchange) el.onchange();
								EventManager.Stop(e);
								break;
							case "mousedown":
								if(selEl != options && selEl != SPAN) {
									if(selEl == SPAN.nextSibling) Input.Shared.Show(options);
									else {
										el.selectedIndex = selIndex;
										SPAN.innerHTML = Innect.HTMLEncode(selEl.innerText);
										Input.Shared.Hide(options);
										if(el.onchange) el.onchange();
									}
								}
								break;
						}
					}
					break;
			}
		},
		Hide: function (el) {
			Innect.Style.Set(el, "display", "none");
			if(window.IE7) Innect.Style.Set(el, "zIndex", "0");
		},
		Show: function (el) {
			var display = Innect.Style.Get(el, "display");
			Innect.Style.Set(el, "display", (display == "none")?"block":"none");
			if(window.IE7) Innect.Style.Set(el.parentNode, "zIndex", (display == "none")?"10000":"0");
		}
	},
	Text: function (id) {
		var el = Innect.$(id);
		return {
			DefaultValue: el.defaultValue,
			Disable: function () {
				el.disabled = true;
				this.Disabled = true;
				if(!Input.UseBrowserControls) this.Render();
			},
			Disabled: (el.disabled),
			Enable: function () {
				el.disabled = false;
				this.Disabled = false;
				if(!Input.UseBrowserControls) this.Render();
			},
			Node: el,
			Render: function () {
				var classes = "Text" + ((el.getAttribute("required"))?" Required":"") + ((el.disabled)?" Disabled":"");
				if(!Innect.$("_" + id)) {
					el.outerHTML = "<div class=\"" + classes + "\" id=\"_" + id + "\">" + el.outerHTML + "</div>";
					el = Innect.$(id);
				}
				else Innect.Class.Set(el.parentNode, classes);
				EventManager.Add(el, "focus", Input.Shared.Focus);
				EventManager.Add(el, "blur", Input.Shared.Blur);
				return el;
			},
			SetDefaultValue: function (value) {
				el.defaultValue = value;
				this.DefaultValue = value;
			},
			SetValue: function (value) {
				el.value = value;
				this.Value = value;
			},
			Value: el.value
		}
	},
	UseBrowserControls: false,
	Validate: function (el, func, e) {
		cssQuery("*[required]:enabled", el).forEach(function (el) {
			if(!el.value) {
				Input.Errors.Add($TXT_ERR_MISSING, el.id);
				EventManager.Add(el, "keyup", function () {
					if(this.value) Input.Errors.Remove($TXT_ERR_MISSING, this.id);
				});
			}
		});
		if(Input.Errors.Collection.length > 0) {
			if(Input.OnError) Input.OnError();
		}
		else func();
		if(e) EventManager.Stop(e);
		return false;
	},
	ValidateConstraint: function () {
		var constraint = this.getAttribute("constraint");
		if(this.value && !this.value.match(Input.RegularExpression(constraint))) {
			Input.Errors.Add($TXT_ERR_INVALID, this.id);
			if(constraint.match(/currency|email|file|img|url|zip/)) EventManager.Add(this, "keyup", Input.ValidateConstraint);
		}
		else {
			Input.Errors.Remove($TXT_ERR_INVALID, this.id);
			if(constraint.match(/currency|email|file|img|url|zip/)) EventManager.Remove(this, "keyup", Input.ValidateConstraint);
		}
	},
	ValidateExistence: function () {
		if(this.value) {
			var id = this.id;
			var input = Input.Text(id).Value;
			var directory = Innect.$(id).getAttribute("directory");
			var directorySuffix = (directory)?"\\" + input:"";
			directory = (directory)?directory:input;
			if(input.length > 0) Ajax.AsyncRequest("POST", "cmd/validateexistence.asp", Ajax.ToQuery("Directory", directory, "DirectorySuffix", directorySuffix), {
				Scope: this,
				Success: function (Obj) {
					var exists = Number(Obj.Response);
					if(this.hasAttribute("existencerequired")) {
						if(exists == 0) Input.Errors.Add($TXT_ERR_NOT_EXIST, this.id);
						else Input.Errors.Remove($TXT_ERR_NOT_EXIST, this.id);						
					}
					else {
						if(exists == 1) Input.Errors.Add($TXT_ERR_EXISTS, this.id);
						else Input.Errors.Remove($TXT_ERR_EXISTS, this.id);
					}
				}
			}, true);
		}
	},
	ValidateLength: function () {
		var minOrMax = (this.getAttribute("minlength"))?"Min":"Max";
		switch (minOrMax) {
			case "Min":
				var min = this.getAttribute("minlength");
				var error = $TXT_ERR_MIN_LENGTH(min);
				if(this.value && this.value.length < min) {
					Input.Errors.Add(error, this.id);
					EventManager.Remove(this, "blur", Input.ValidateLength);
					EventManager.Add(this, "keyup", Input.ValidateLength);
				}
				else Input.Errors.Remove(error, this.id);
				break;
			case "Max":
				var max = this.getAttribute("maxlength");
				var error = $TXT_ERR_MAX_LENGTH(max);
				if(this.value && this.value.length > max) Input.Errors.Add(error, this.id);
				else Input.Errors.Remove(error, this.id);
				break;
		}
	},
	ValidateMimeTypes: function () {
		var ext = this.value.substr(this.value.lastIndexOf(".") + 1).toLowerCase();
		var mimeTypes = this.getAttribute("mimetypes").split(";");
		var supportedMimeTypes = mimeTypes.map(function (el) {
			return el.toUpperCase() + " (." + el + ")";
		});
		var error = $TXT_ERR_INVALID_MIME_TYPE + " " + supportedMimeTypes.join(", ") + ".";
		if(mimeTypes.indexOf(ext) != -1 || !this.value) {
			Input.Errors.Remove(error, this.id);
			EventManager.Remove(this, "keyup", Input.ValidateMimeTypes);
		}
		else if(this.value) {
			Input.Errors.Add(error, this.id);
			EventManager.Add(this, "keyup", Input.ValidateMimeTypes);
		}
		Input.Validate(this.id);
	},
	ValidatePasswords: function () {
		var prefix = this.id.slice(0, this.id.indexOf("_"));
		var password = Input.Text(prefix + "_Password").Value;
		var confirmPassword = Input.Text(prefix + "_ConfirmPassword").Value;
		if(password != "" && confirmPassword != "" && password != confirmPassword) {
			Input.Errors.Add($TXT_ERR_PASSWORD_MISMATCH, this.id);
			EventManager.Remove(this, "blur", Input.ValidatePasswords);
			EventManager.Add(this, "keyup", Input.ValidatePasswords);
		}
		else Input.Errors.Remove($TXT_ERR_PASSWORD_MISMATCH, this.id);
	},
	ValidateRange: function () {
		var min = parseFloat(this.getAttribute("minnum"));
		var max = parseFloat(this.getAttribute("maxnum"));
		var error = $TXT_ERR_OUT_OF_RANGE(min, max);
		if(parseFloat(this.value) < min || parseFloat(this.value) > max || isNaN(this.value)) Input.Errors.Add(error, this.id);
		else Input.Errors.Remove(error, this.id);
	},
	ValidateUnique: function () {
		if(this.value && this.value != this.defaultValue) Ajax.AsyncRequest("POST", this.getAttribute("command"), Ajax.ToQuery(this.id.slice(this.id.indexOf("_") + 1), this.value), {
			Scope: this,
			Success: function (Obj) {
				if(Obj.Response.toBoolean()) Input.Errors.Add($TXT_ERR_NOT_UNIQUE, this.id);
				else Input.Errors.Remove($TXT_ERR_NOT_UNIQUE, this.id);
			}
		});
		else Input.Errors.Remove($TXT_ERR_NOT_UNIQUE, this.id);
	}
}