if (typeof Form.Label == 'undefined') {
	Form.Label = function (id) {
		var labels = document.getElementsByTagName('label'), label;
		for (var i = 0, n = labels.length; i < n; i++) {
			if (labels[i].htmlFor == id) {
				label = labels[i];
				break;
			}
		}
		if (! label) {
			return null;
		}
		
		label.error = '';
		Engine.attachDestructor(label, 'error');
		
		Engine.attachWatcher(label, 'error', function (property, oldValue, newValue) {
			if (newValue) {
				HTML.addStyleClass(this, 'error');
				HTML.addFloatingMessage(this);
			} else {
				HTML.removeStyleClass(this, 'error');
				HTML.removeFloatingMessage(this);
			}
			return newValue;
		});
		
		label.changed = false;
		Engine.attachDestructor(label, 'changed');
		
		Engine.attachWatcher(label, 'changed', function (property, oldValue, newValue) {
			if (newValue) {
				HTML.addStyleClass(this, 'changed');
			} else {
				HTML.removeStyleClass(this, 'changed');
			}
			return newValue;
		});
		
		return label;
	}
}
if (typeof Form.Item == 'undefined') {
	Form.Item = function (id) {
		var item = document.getElementById(id);
		if (! item) {
			return null;
		}
		
		var name = item.name;
		
		item.label = Form.Label(id);
		Engine.attachDestructor(item, 'label');
		
		item.error = '';
		Engine.attachDestructor(item, 'error');
	
		item.changed = false;
		Engine.attachDestructor(item, 'changed');
	
		item.clear = function () {
			if (this.value !== '') {
				this.value = '';
			}
			this.error = false;
		}
		Engine.attachDestructor(item, 'clear');
	
		item.reset = function () {
			if (this.value !== this.defaultValue) {
				this.value = this.defaultValue;
			}
			this.error = false;
		}
		Engine.attachDestructor(item, 'reset');
		
		item.enable = function () {
			this.disabled = false;
			this.error = false;
		}
		Engine.attachDestructor(item, 'enable');
		
		item.disable = function () {
			this.error = false;
			this.disabled = true;
		}
		Engine.attachDestructor(item, 'enable');
		
		item.attachEvent('onkeydown', function (e) {
			if (! e) e = event;
			e.srcElement.isKeyDown = true;
		});
		
		item.attachEvent('onkeyup', function (e) {
			if (! e) e = event;
			e.srcElement.isKeyDown = null;
		});
		
		Engine.attachWatcher(item, 'value', function (property, oldValue, newValue) {
			if (! this.isKeyDown) {
				this.fireEvent('onchange');
			}
			return newValue;
		});
		
		Engine.attachWatcher(item, 'error', function (property, oldValue, newValue) {
			if (this.label) {
				this.label.error = newValue;
			}
			if (newValue) {
				HTML.addStyleClass(this, 'error');
				HTML.addFloatingMessage(this);
			} else {
				HTML.removeStyleClass(this, 'error');
				HTML.removeFloatingMessage(this);
			}
			return newValue;
		});
		
		Engine.attachWatcher(item, 'changed', function (property, oldValue, newValue) {
			if (this.label) {
				this.label.changed = newValue;
			}
			if (newValue) {
				HTML.addStyleClass(this, 'changed');
			} else {
				HTML.removeStyleClass(this, 'changed');
			}
			return newValue;
		});
		
		item.attachEvent('onreset', function (e) {
			if (! e) e = event;
			var item = e.srcElement;
			item.reset();
		});
		
		item.attachEvent('onchange', function (e) {
			if (! e) e = event;
			var item = e.srcElement;
			item.changed = Boolean(item.value != item.defaultValue);
			item.error = '';
		});
		
		item.validators = [];
		Engine.attachDestructor(item, 'validators');
		
		item.isValid = function () {
			for (var i = 0, n = this.validators.length, v; i < n; i++) {
				v = this.validators[i];
				if (! v.isValid(this, v.message)) {
					this.error = v.message;
					return false;
				}
			}
			this.error = '';
			return true;
		}
		Engine.attachDestructor(item, 'isValid');
	
		return item;
	}
}
