
	if (!FORM_JS) {
		var FORM_JS = true;
		
		var Form = function (sId, aErrors) {
			this.sId = sId;
			this.rows = [];
			this.input = [];
			this.errors = aErrors;
			this.state = {};
			
			on_window_load(createMethodReference(this, this.initialize));
		};
		
		Form.prototype.initialize = function () {
			this.oForm = $(this.sId);
			
			var row = getElementsByClass('form_row', this.oForm, 'div');
			for (var k = 0; k < row.length; k ++) {
				var r = {
					"input": {}
				};
				
				var input = getElementsByClass('form_input', row[k]);
				var is_error = false;
				
				for (var j = 0; j < input.length; j ++) {
					var st = is_subclass_of(input[j], 'checkform-groupstatus') ? getElementsByClass('form_status', input[j].parentNode.parentNode) : getElementsByClass('form_status', input[j]);

					var i = {
						"status": st.length ? st[0] : null,
						"row": row[k],
						"input": input[j],
						"form": this,
						"controlChecking": false,
						"controlCheckingTimeout": null
					};
					
					var control = i['control'] = this.getControl(input[j]);

					if (!control) {
						if (this.errors[name])
							alert(this.errors[name]);

						continue;
					}
						
					var name = i['name'] = control.getAttribute('name').replace('[]', '');

					var ctrl = Form.getControls(input[j]);
					for (var l = 0; l < ctrl.length; l ++) {
						attachEvent(ctrl[l], 'blur', createMethodReference(i, this.controlChange));
						attachEvent(ctrl[l], 'change', createMethodReference(i, this.controlChangeDelay));
						attachEvent(ctrl[l], 'keyup', createMethodReference(i, this.controlChangeDelay));
					}
					
					r.input[name] = i;
					this.input[name] = i;

					this.state[name] = 1;
					
					if (this.errors[name]) {
						is_error = true;
						if (i.status) {
							i.status.innerHTML = '<img src="' + JS_HOST + 'view/images/icon_error.png" class="mid" /> ' + this.errors[name];
							i.status.className += ' form_error_status';
							i.status.style.display = '';
						} else if ($(this.sId + 'err')) {
							var d = n('div');
							d.className = 'error';
							d.innerHTML = this.errors[name];
							$(this.sId + 'err').appendChild(d);
						} else {
							this.state[name] = 0;
						}

						input[j].parentNode.className += ' form_error';
					} else if (i.status) {
						i.status.style.display = 'none';
					}
				}
				
				if (is_error) {
					//row[k].className += ' form_error';
				}
			}

			for (k in this.errors) {
				if (!this.state[k]) {
					alert(this.errors[k]);
				}
			}
		};

		Form.prototype.getControl = function (node) {
			var input = node.getElementsByTagName('input');
			if (input.length > 0 && !is_subclass_of(input[0], 'skip-autoform'))
				return input[0];

			input = node.getElementsByTagName('textarea');
			if (input.length > 0 && !is_subclass_of(input[0], 'skip-autoform'))
				return input[0];

			input = node.getElementsByTagName('select');
			if (input.length > 0 && !is_subclass_of(input[0], 'skip-autoform'))
				return input[0];

			return null;
		};
		
		Form.getControls = function (node, named) {
			var res = named ? {"item": {}, "length": 0} : [];
			
			var input = node.getElementsByTagName('input');
			for (var i = 0; i < input.length; i ++) {
				if (named) {
					res.item[input[i].name] = input[i];
					res.length ++;
				} else
					res.push(input[i]);
			}
				
			input = node.getElementsByTagName('textarea');
			for (i = 0; i < input.length; i ++) {
				if (named) {
					res.item[input[i].name] = input[i];
					res.length ++;
				} else
					res.push(input[i]);
			}
				
			input = node.getElementsByTagName('select');
			for (i = 0; i < input.length; i ++) {
				if (named) {
					res.item[input[i].name] = input[i];
					res.length ++;
				} else
					res.push(input[i]);
			}

			return res;
		};
		
		Form.prototype.controlChangeDelay = function () {
			clearInterval(this.controlCheckingTimeout);
			this.controlCheckingTimeout = setTimeout(createMethodReference(this, this.form.controlChange), 1000);
		};
		
		Form.prototype.controlChange = function () {
			if (!this.controlChecking) {
				clearInterval(this.controlCheckingTimeout);
				
				this.controlChecking = true;
				
				try {
					var sUrl = this.form.oForm.getAttribute('action');
					sUrl = sUrl.replace(/\/[^\/]+\/(\?(.*))?$/, '/checkfield/?$2');
					sUrl += '&field=' + this.name;
					
					var conn = new TConnection;
					conn.sUrl = sUrl;
					conn.sMethod = 'POST';
					
					conn.onData = createMethodReference(this, function (c) {
						try {
							try {
								eval('var data = ' + c.responseText + ';');
								
								if (data) {
									if (data.is_null) {
										this.input.parentNode.className += ' form_error';
										this.status.innerHTML = '<img src="' + JS_HOST + 'view/images/icon_error.png" class="mid" /> ' +  data.errstr;
										this.status.style.display = '';
										this.status.className += ' form_error_status';
									} else {
										this.input.parentNode.className = this.input.parentNode.className.replace(/ form_error/g, '');
										this.status.className = this.input.parentNode.className.replace(/ form_error_status/g, '');
										
										this.status.innerHTML = '<img src="' + JS_HOST + 'view/images/icon_ok.png" class="mid" /> ' + (this.status.nodeName.toLowerCase() == 'div' ? 'OK' : '');
										//this.status.style.display = 'none';
									}
								}
							} catch (e) {
								debug(e);
							}
						} finally {
							this.controlChecking = false;
						}
					});
					
					setFormDataToConnection(this.form.oForm, conn);
					
					conn.open();
				} catch (e) {
					debug(e);
					this.controlChecking = false;
				}
			}
		};
	}

