var INVALID_FORM = "Поля, отмеченные красным цветом, заполены неверно. Пожалуйста, подведите курсор мыши к полю, чтобы получить описание ошибки.";
var REMEMBER_WARNING = "ВНИМАНИЕ!\nДанные в форме будут сохранены на вашем компьютере. Пользователи компьютера могут получить доступ к запомненым данным. Вы уверены, что хотите сохранить поля формы?";

/*pseudo class*/ Form = function (formName, reloadable) {
	_this = document.forms[formName];
	//assert(_this, "Form\n  No form '" + formName + "' found");
	//(_this.name, "Form\n  Form has no name attribute");

	_this.onsubmit =_this.onSubmit = Form_onSubmit;
	_this.onreset =_this.onReset = Form_onReset;
	_this.callScript = Form_callScript;

	_this.validate = Form_validate;

	_this._setInvalid = Form_setInvalid;
	_this._setValid = Form_setValid;
	_this._addValidator = Form_addValidator;
	_this._getLabel = Form_getLabel;
	_this.getServerErrorElement = Form_getServerErrorElement;
	_this.rebuild = Form_rebuild;
	_this.rebuild();

	if (!reloadable) {
		_this.sendTo = Form_sendTo;
		_this.destroy = Form_destroy;

		if (!_this.target) _this.target = _this.id + "Exchanger";

		_this._exchanger = new Exchanger(_this.target);
		_this._exchanger.form = _this._exchanger.owner = _this;

		_this.onServerErrors = function (data) {
			//trace(data);
			this.validate(data.errors);
		}
	}

	if (_this.elements.Remember) {
		_this.elements.Remember.onclick = function () {
			if (this.checked) this.checked = confirm(REMEMBER_WARNING);
		}

		_this.cookie = new StorageCookie(_this.name, ["id", "value"]);

		if (_this.cookie.getLength()) {
			_this.elements.Remember.checked = true;
			var records = _this.cookie.select();
			for (key in records) {
				var record = records[key];
				if (_this.elements[record.id].length) {
					if (_this.elements[record.id][0].setValue)
						_this.elements[record.id][0].setValue(record.value);
				} else
					_this.elements[record.id].value = record.value;
			}
		}
	}
	return _this;
}

function getGroupValue() {
	var elements = this.form.elements;
	for (var i = 0; i < elements.length; i++)
		if (elements[i].checked) return elements[i].value;
}

function setGroupValue(value/*:String*/)/*:Void*/ {
	var elements = this.form.elements;
	for (var i = 0; i < elements.length; i++)
		if (elements[i].value == value)
			elements[i].checked = true;
}

var __func;

function Form_callScript(data) {
	__func = eval(data.scriptName);
	delete data.scriptName;
	__func(data.data);
}

function Form_rebuild() {
	for (var i = 0; i < this.elements.length; i++) {
		switch (this.elements[i].nodeName) {
			case "INPUT":
				switch (this.elements[i].type) {
					 case "radio":
					 	this.elements[i].getValue = getGroupValue;
					 	this.elements[i].setValue = setGroupValue;
					 case "checkbox": case "file": case "password": case "text":
					 	this._addValidator(this.elements[i]); break;
				}
				break;
			case "FIELDSET": break;
			case "TEXTAREA": case "SELECT":
				this._addValidator(this.elements[i]); break;
			default:
				//assert(false, "Form\nUnknown element " + this.elements[i].nodeName);
		}
	}
}

/*private*/ function Form_onSubmit()/*:Void*/ {
	if (!this.validate()) return false;

	if (this.cookie) {
		var element;
		this.cookie.remove();

		if (this.elements.Remember.checked)
			for (var i = 0; i < this.elements.length; i++) {
				element = this.elements[i];
				switch (element.nodeName) {
					case "INPUT":
						switch (element.type) {
							case "radio":
							 	this.cookie.insert({id: element.name, value: element.getValue()});
							break;
	////						 case "checkbox":
							case "password": case "text":
								this.cookie.insert({id: element.name, value: element.value});
						}
						break;
	//				case "textarea":
	//					this.cookie.insert({this.elements[i].name, this.elements[i].innerHTML});
	//				case "selected"
	//					this.cookie.insert({this.elements[i].name, this.elements[i].index});
				}
			}
		this.cookie.set(null, 100 * 24 * 3600);
	}
	return true;
}

function Form_sendTo(url, data)/*:Void*/ {
	this._exchanger.sendTo(url, data);
}

function Form_destroy()/*:Void*/ {
	this._exchanger.destroy();
	this.parentNode.removeChild(this);
}

/*private*/ function Form_onReset()/*:Void*/ {
	for (var i = 0; i < this.elements.length; i++)
		if (this.elements[i].validate)
			this._setValid(this.elements[i]);
}

/*private*/ function Form_addValidator(element)/*:Void*/ {
	element.validate = Element_validate;
	element.validateFake = Element_validateFake;
	//warning(!element.onchange, "Form.addValidator\nOnChange event handler already exists\n" + element.onchange);
	if (!element.onchange) element.onchange = element.validateFake;
}

function Element_validateFake() {
	this.validate();
	return true;
}

function Form_getServerErrorElement(name/*:String*/)/*:Object*/ {
	if (this[name]) return this[name];

	var name2 = name.replace(/\[\d*\]$/, "[]");
	var index = getServerErrorIndex(name);

	if (this[name2] && this[name2][index]) return this[name2][index];

	for (var i = 0; i < this.elements.length; i++) { // IE feature
		if (this.elements[i].name == name) return this.elements[i];
		if (this.elements[i].name == name2) return this.elements[i][index];
	}

	//assert(false, "Form.getServerErrorElement\n Field " + name + " not found");
}

function Form_validate(serverErrors/*:Array*/)/*:Boolean*/ {
	var result = true, name, error, index, element;

	for (var i = 0; i < this.elements.length; i++)
		if (this.elements[i].validate)
			result = this.elements[i].validate() && result;

	if (serverErrors) {
		for (var i = 0; i < this.elements.length; i++)
			if (this.elements[i].validate)
				this._setValid(this.elements[i]);

		for (var i = 0; i < serverErrors.length; i++)
			this._setInvalid(this.getServerErrorElement(serverErrors[i].name), serverErrors[i].error);
		result = false;
	}

	if (!result) alert(INVALID_FORM);

	return result;
}

/*private*/ function Form_setInvalid(sender, message)/*:Void*/ {
	sender.style.color = "Red";
	sender.title = message;

	var htmlLabel = this._getLabel(sender);
	if (htmlLabel) {
		htmlLabel.style.color = "Red"
		htmlLabel.title = message;
	}
}

/*private*/ function Form_setValid(sender)/*:Void*/  {
	sender.style.color = "";
	sender.title = "";

	var htmlLabel = this._getLabel(sender);
	if (htmlLabel) {
		htmlLabel.style.color = "";
		htmlLabel.title= "";
	}
}

/*private*/ function Form_getLabel (element/*:DomElement*/)/*:DomElement*/ {
	if (!this._labels) this._labels = getElementsByTagName(this, "LABEL");

	// Атрибут for тега label равен атрибуту id элемента
	if (element.id) {
		for (var i = 0; i < this._labels.length; i++)
			if (this._labels[i].getAttribute("htmlFor") == element.id) return this._labels[i];
	}

	// Атрибут for тега label равен атрибуту name элемента без []
	if (element.name) {
		var name = element.name.match(/^([^\[]*)(?:\[(\d*)\])?/)[1];
		for (var i = 0; i < this._labels.length; i++)
			if (this._labels[i].getAttribute("htmlFor") == name) return this._labels[i];
	}

	// Элемент находится внутри тега label и не radio
	if (element.parentNode.nodeName == "LABEL" && element.getAttribute("type") != "radio")
		return element.parentNode;

	// Элемент находится внутри тега fieldset
	if (elements = getFirstAncestor(element, "fieldset"))
		return elements.firstChild;

	//warning(false, "Form.getLabel\n  No label exists for " + element.tagName + " " +  element.name);
}

function getValidateFunctionName(elementName/*:String*/)/*:String*/ {
	return "validate" + elementName.replace(/\[(\d*)\]$/, "").replace(/\[/g, "_").replace(/\]/g, "_");
}

/**
 * Получает индекс массива атрибута name, например, name="birthdate[5]" возвратит 5.
 * TODO name="birthdate[]" - ?
 */
function getValidateFunctionIndex(elementName/*:String*/)/*:String*/ {
	//debugger
	var index = elementName.match(/\[(\d*)\]$/);
	if (index && typeof index == "object" && index.length > 1) {
		return index[1];
}	else
		return '';
}

function getServerErrorIndex(name/*:String*/)/*:Object*/ {
	try {
		return name.match(/\[(\d*)\]$/)[1];
	} catch (e) {

	}
}

function Element_validate()/*:Boolean*/ {
	//warning(this.name, "Form.addValidator\n  Element " + this.nodeName + " has no name attribute" );
	if (!this.name) return true;

	try {
		this.validateFunction = eval(getValidateFunctionName(this.name));
		this.index= getValidateFunctionIndex(this.name);
	} catch (e) {
//		warning(false,
//			"Element_validate\nValidate function <strong>" +
//			getValidateFunctionName(this.name) +
//			"</strong> is not defined</br><strong>function </strong>" +
//			getValidateFunctionName(this.name) + "() {</br></br>}"
//		);
		return true;
	}

	if (typeof this.validateFunction != "function") {
		return true;
	}

	var error;

	if (error = this.validateFunction()) {
		this.form._setInvalid(this, error);
		return false;
	} else {
		this.form._setValid(this);
		return true;
	}
}

function validateRemember() {

}


///*DomElement*/ function getErrorCaption(/*DomElement*/ element) {
//	return element.childNodes[1];
//}

///*void*/ function _setInvalid(/*DomElement*/ field, /*:String*/ text) {
//	var fieldLabel = Form_getLabel(field);
//	var div = getErrorCaption(fieldLabel);
//	if (!div) {
//		div = document.createElement("sup");
//		fieldLabel.appendChild(div);
//		div.className = "ErrorDesc";
//	}
//	div.innerHTML = text;
//}

///*void*/ function _setValid(/*DomElement*/ field) {
//	var fieldLabel = Form_getLabel(field);
//	if (getErrorCaption(fieldLabel)) removeNode(getErrorCaption(fieldLabel));
//}


//	for (var i = 0; i < this.elements.length; i++) {
//		if (this.elements[i].nodeName == "INPUT" &&
//			this.elements[i].type == "text"	&&
//			this.elements[i].id != this.elements[i].name) {
//			s +=
//			this.elements[i].nodeName +
//			", name=" + this.elements[i].name +
//			", id=" + this.elements[i].id + "\n";
//		}
//
////		if (this.elements[i].id != this.elements[i].name && this.elements[i].nodeName != "FIELDSET") {
////			s +=
////			this.elements[i].nodeName +
////			", name=" + this.elements[i].name +
////			", id=" + this.elements[i].id + "\n";
////		}
//		//if (this.elements[i] && (error = this.elements[i].Element_validate())) this.errorString += error;
//}
//alert (s);
//	//alert("Извините, но Вы неверно заполнили форму.\n" + this.errorString);
//	//this.errorString = "";
//	return false;
//}

//var FORMS_JS = COMMON_JS && VALIDATE_JS && STRING_JS && EXCHANGER_JS && COOKIES_JS;
