 /*
	Used names are
	$formname
	name
	must
	mustnot
	error
	value
	def
*/

RegExp.Multiline=true;
function FormException(desc)
{
	this.description=desc;
}

//----------------------------------------------------------------------------------------
function Form()
{
	var argv=Form.arguments;
	this.$fields=new Array();
	this.$validators = new Array();
	var rx=/(\$\w+)\s*=\s*(.*)/;
	for (var i=0;i<argv.length;i++)
	{
		if (rx.test(argv[i]))
			this[RegExp.$1]=RegExp.$2;
		else
			this.addField(argv[i]);
	}
	this.$form=document.forms[this.$formname];
}
//---------------------------------------------------------------------------------------
function __Form_Add_Validator__(func,params,error){
	this.$validators[this.$validators.length]={'func':func,'params':params,'error':error};
}
//---------------------------------------------------------------------------------------
//####################   This function parses definition #################################
function __Form_Add_Field__(str)
{
	var arr = String(str).split("&");
	var eqrx = new RegExp().compile("([^=]+)\\s*=\\s*((.|\\n)*)");
	var obj = new Object();
	var name,val;
	for (var i=0;i<arr.length;i++)
	{
		eqrx.exec(arr[i]);
		name=RegExp.$1;
		val=RegExp.$2;
		if (!name) 
			continue;
		obj[name]=String(val).replace(/##__ampersand__##/g,"&");
	}
	if (obj.must)
		obj.must=new  RegExp(obj.must,"");
	if (obj.mustnot)
		obj.mustnot=new  RegExp(obj.mustnot,"");
	this.$fields[this.$fields.length]=obj;
}
//---------------------------------------------------------------------------------------
//####################   This function reads values from form fields #####################
function __Form_Read_Fields__()
{
	var form=this.$form;
	var val,obj;
	for (var i=0;i<this.$fields.length;i++)
	{
		obj=this.$fields[i];
		this.$objname=obj.name;
		switch (form[obj.name].type)
		{
			case "textarea":
			case "text":
			case "hidden":
			case "password":
				val=form[obj.name].value;
				break;
			case "select-one":
			case "select-multiple":
			case "select":
				val=GetSelectValue(form[obj.name]);
				break;
			case "undefined":
				break;
			default:
				val=GetCheckValue(form[obj.name])
		}
		obj.value=val || obj.undef || "";
		if (obj.value == "undefined" || obj.value == null) 
				obj.value="";
		this[obj.name]=obj.value;
	}
}
//---------------------------------------------------------------------------------------
//####################   This function checks if values are right #########################
function __Form_Check_Fields__(){
	try{
		this.readFields();
	}
	catch(e){
		alert("Exception caught: " + e.description + "\n" + this.$objname);
	}
	var status,obj;
	for (var i=0;i<this.$fields.length;i++) {
		obj=this.$fields[i];
//		alert(obj.name + " | " + obj.def + " | " + obj.value + " | " + obj.mustnot)
//		if (obj.mustnot)
//			alert(obj.mustnot.test(obj.vlue));
		if (obj.must && !obj.must.test(obj.value))
			return this.error(obj);
		if (obj.mustnot && obj.mustnot.test(obj.value))
			return this.error(obj);
	}
	var o,v;
	if (this.$validators.length){
		for(var i = 0;i< this.$validators.length; i++){
			v=this.$validators[i];
			eval("o = " + v.func + "(this.$form," + v.params + " );");
			if (o && o.error){
				o.error = v.error;
				return this.error(o);
			}
		}
	}
	return true;
}
//----------------------------------------------------------------------------------------
function __Form_Reset_Fields__()
{
	var form=this.$form;
	var val,obj;
	for (var i=0;i<this.$fields.length;i++)
	{
		obj=this.$fields[i];
		if (obj.def == null)
			continue;
		if (!form[obj.name])
		{
			alert("unknown:" + obj.name);
			continue;
		}
		switch (form[obj.name].type)
		{
			case "textarea":
			case "text":
			case "password":
			case "hidden":
				form[obj.name].value=obj.def;
				break;
			case "select-multiple":
			case "select-one":
			case "select":
				SetSelectValue(form[obj.name],obj.def);
				break;
			case "checkbox":
			case "radio":
				if (obj.def == form[obj.name].value)
					form[obj.name].checked=1;
				break;
			case "undefined":
			default:
				if (this.$propagate){
					SetCheckValuesPropagate(form[obj.name],obj.def,this);
				}
				else
					SetCheckValues(form[obj.name],obj.def);
				break;
		}
	}
	return false;
}
//------------------------------------------------------------------------
function __Form_Error__(obj)
{
	alert("Error: " + obj.error + "!");
	switch (this.$form[obj.name].type)
	{
		case "hidden":
			break;
		case "radio":
		case "textarea":
		case "text":
		case "select-one":
		case "select-multiple":
		case "select":
		case "password":
		case "checkbox":
			this.$form[obj.name].focus();
			break;
	}
	return false;
}
//------------------------------------------------------------------------
new Form();
Form.prototype.addValidator= __Form_Add_Validator__;
Form.prototype.addField=__Form_Add_Field__;
Form.prototype.checkFields=__Form_Check_Fields__;
Form.prototype.resetFields=__Form_Reset_Fields__;
Form.prototype.readFields=__Form_Read_Fields__;
Form.prototype.error=__Form_Error__;
//-------------------------------------------------------------------------
function SetCheckValuesPropagate(check,value,fm){
	var o=typeof(value) == "string" ? map1(value.split(/\s*,\s*/)): value;
	if (typeof(check) !="object" || !check.length)
		return ;
	var result = 0;
	for (var i=0;i<check.length;i++){
		if (o[check[i].value]){
			check[i].checked=1;
			result=1;
		}
		else
			check[i].checked=0;
		if(fm.$form[check[i].value] && SetCheckValuesPropagate(fm.$form[check[i].value],o,fm)) {
			check[i].checked=1;
			result = 1;
		}
	}
	return result;
}
//-------------------------------------------------------------------------
function GetCheckValuesPropagate(check,fm){
	if (typeof(check) !="object" )
		return "";

	if(!check.length){
		if (check.checked) 
			return check.value
		return "";
	}
	var result = 0;
	var vals = [],val;
	for (var i=0;i<check.length;i++){
		if (!check[i].checked)
			continue;
		val = check[i].value;
		if (!/^\d+$/.test(val))
			val =  GetCheckValuesPropagate(fm[val],fm);
		if (val)
			vals[vals.length] = val;
	}
	return vals.join(",");
}
//-------------------------------------------------------------------------
