if( 'undefined'==typeof(labels)) {
	labels= new Array();
	labels['fieldValidation']= 'Field ';
	labels['genericErrorValidation']= 'Generic error ';
	labels['missingFileValidation']= 'Specify a file for field ';
	labels['numberFormatValidation']= ' must be a number ';
	labels['dateFormatValidation']= ' must be a date ';
	labels['emailFormatValidation']= ' must be an email address';
	labels['badLengthValidation']= ' is too long ';
	labels['formatErrorValidation']= 'Bad format, the right one is ';
	labels['mistmatchValidation']= 'Mismatch (the two values you wrote are not the same) for field ';
	labels['mandatoryValidation']= 'is mandatory ';
}
 function isFormValid(fieldsSpecifications) {
 	var errorMessages= new Array();
 	fieldsSpecifications.each(
 		function(n) {
 			var msg= checkField(n);
 			if(msg && msg.size()>0) {
 				errorMessages.push(msg);
 			}
		}
	);
	
	if(errorMessages.size()>0) {
		var m= "";
		errorMessages.flatten().each(
	 		function(n) {
	 			m+= n+'\n';
	 		}
		);
		alert(m);		
 		return false;
	}
 	return true;
 }



 function checkField(f) {
 	var errorMessages= [];
	if(f && f.fieldName) { 
	 	var val= $F(f.fieldName);
	 	var validations= $A(f.validations);
	 	var label= f.fieldLabel && !f.fieldLabel.blank()? f.fieldLabel: f.fieldName;
	 	$A(validations).each(
	 		function(n) {
	 			var msg= validateField(n, val, label, f.fieldName);
	 			if(msg && !msg.blank()) {
	 				errorMessages.push(msg);
	 			}
	 		}
	 	);
	}
 	return errorMessages; 
 }

 function normalizeFormFields(fieldsSpecifications) {
 	fieldsSpecifications.each(
 		function(n) {
 			normalizeField(n);
		}
	);
 }

 function normalizeField(f) {
	if(f && f.fieldName) { 
	 	var val= $F(f.fieldName);
		if(f.normalizations) {
		 	$A(f.normalizations).each(
		 		function(n) {
		 			var newVal= normalizeValue(n, val);
		 			if(newVal && newVal!==null) {
		 				$(f.fieldName).value= newVal;
		 			}
		 		}
		 	);
		}
	}
 }

var emailRexp= /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;

var dateRexp= /^([0-9]?[0-9])[.\-\\\/ ]([0-1]?[0-9])[.\-\\\/ ](([0-9][0-9])?[0-9][0-9])$/;
var maxlenRexp= /^maxlen\(([0-9]+)\)$/;
var areEqualsRexp= /^areEquals\(([^,]+),([^)]+)\)$/;
var formatNumberRexp= /^format\(([^)]+)\)$/;


function validateField(validationType, val, label, fieldName) {
	var isOk= false;
	
	var msg= labels['genericErrorValidation'] + label;
	var isBlank= (''+val).blank();
	
	if('mandatory'==validationType) {
		isOk= !(''+val).blank();
		msg=labels['fieldValidation'] + label + labels['mandatoryValidation'];
	} else if('mandatoryupload'==validationType) {
		isOk= !(''+val).blank();
		if(!isOk) {
			var loaded= $(fieldName+'_alreadyuploaded');
			if(loaded) {
				isOk= !(''+loaded.value).blank();
			}
		}
		msg= labels['missingFileValidation'] + label;
	} else if('numeric'==validationType) {
		msg=labels['fieldValidation'] + label + labels['numberFormatValidation'];
		try {
			var x= parseFloat(val.strip());
			isOk=  isBlank || !isNaN(x);
		} catch (ignored) {
		}
	} else if('date'==validationType) {
		msg=labels['fieldValidation'] + label + labels['dateFormatValidation'];
		try {
			if(isBlank) {
				isOk= true;
			} else if(dateRexp.test(val)) {
				var n= normalizeDate(val);
				isOk= (n && n!==null);
			}
		} catch (ignored) {
		}
	} else if('email'==validationType) {
		isOk=  isBlank || emailRexp.test(val);
		msg=labels['fieldValidation'] + label + labels['emailFormatValidation'];
	} else 	if(validationType.startsWith('maxlen(')) {
		var l= eval(validationType);
		isOk= isBlank || ((""+val).length<l);
		msg= labels['fieldValidation'] + label + labels['badLengthValidation'];
	} else 	if(validationType.startsWith('format(')) {
		var r= validationType.replace(formatNumberRexp, "$1"); 
		var rxp= compileNumberFormatRegexp(r);
		isOk=  isBlank || rxp.test(val);
		msg= labels['formatErrorValidation'] + r + "\n"+compileNumberHelp(r); 
	} else 	if(validationType.startsWith('areEquals(')) {
		var f1= validationType.replace(areEqualsRexp, "$1"); 
		var f2= validationType.replace(areEqualsRexp, "$2");
		isOk= ($F(f1) == $F(f2) );
		msg= labels['mistmatchValidation'] + label;
	} 
	return isOk? '': msg;
}

// just a little trick for validateField()
function maxlen(x) {
	return toIntWithDefault(x,0);
}


function toIntWithDefault(s,defVal) {
	if("number" == typeof s) {
		return Math.round(s);
	} 
	s= ""+s;
	var x= parseInt(s.strip(),10);
	if(isNaN(x)) {
		return defVal;
	}
	return x;
}

function toFloatWithDefault(s,defVal) {
	if("number" == typeof s) {
		return s;
	} 
	s= ""+s;
	var x= parseFloat(s.strip().replace(/,/g,"."));
	if(isNaN(x)) {
		return defVal;
	}
	return x;
}


function normalizeDate(s) {
	var d= toIntWithDefault(s.replace(dateRexp, "$1"),0);
	var m= toIntWithDefault(s.replace(dateRexp, "$2"),0);
	var y= toIntWithDefault(s.replace(dateRexp, "$3"),0);
	
	if(y<2000) {
		y+=2000;
	}
	
	var x= new Date(y,(m-1),d);
	if(x.getDate()==d && (x.getMonth()+1)==m && x.getFullYear()==y) {
		return dateToNormalString(x);
	}
	return null;
}

function dateToNormalString(d) {
		return (d.getDate()).toPaddedString(2)
				+'-'
				+((d.getMonth()+1)).toPaddedString(2)
				+'-'
				+(d.getFullYear()).toPaddedString(4)
				;
	
}

var functionDeclarationRegexp= /^([a-zA-Z]\w*)(([(])([^)]*)([)]))?$/;

function normalizeValue(normalizationType, val) {
	
	var newVal= null;
	
	var normalizationName= normalizationType.replace(functionDeclarationRegexp,"$1"); 
	var normalizationParams= normalizationType.replace(functionDeclarationRegexp,"$4").split(","); 
	
	if('date'==normalizationName) {
		try {
			newVal= normalizeDate(val);
		} catch (ignored) {
		}
	}

	if('number'==normalizationName) {
		
		try {
			var intDigits= normalizationParams[0];
			var decimalDigits= normalizationParams[1];
			newVal= normalizeNumber(val, intDigits, decimalDigits);
		} catch (ignored) {
		}
	}

	return newVal;
}

function normalizeNumber(val, intDigits, decimalDigits) {
	
	intDigits= toIntWithDefault(intDigits,1)
	decimalDigits= toIntWithDefault(decimalDigits,0)
	
	
	var newVal= '';
	var x= toFloatWithDefault(val, 0.0);
	var i= Math.floor(x);
	
	if(decimalDigits>0) {
		var d= x-i;
		var factor= Math.pow(10, decimalDigits);
		
		d= Math.round(d*factor)/factor;
		
		var y= (""+d).replace(/([0-9]*.)([0-9*])/,"$2");
		if(y.length<decimalDigits) {
			y+= "0".times(decimalDigits-y.length); 
		}
		newVal= (i).toPaddedString(intDigits)+"."+y;
	} else {
		newVal= (i).toPaddedString(intDigits);
	}
	
	return newVal;	
}


function parseNumberFormat(format) {
	var r= '';
	var c;
	var curPos=0;
	var optionalDigit= '?';
	var mandatoryDigit= '#';
	var anyNumberOfDigits= '*';

	var retVal= {
		integerPart: {
			universal:0,
			optional:0,
			mandatory:0
		},
		numDots:0,
		fractionalPart: {
			universal:0,
			mandatory:0,
			optional:0
		}
	};
	
	retVal.integerPart.universal=scanStringFor(format, anyNumberOfDigits, curPos);;  // number of universal quantifiers on the left of dot
	curPos += retVal.integerPart.universal;
	
	retVal.integerPart.optional=scanStringFor(format, optionalDigit, curPos); // number of optional digits on the left of dot
	curPos += retVal.integerPart.optional;

	retVal.integerPart.mandatory=scanStringFor(format, mandatoryDigit, curPos);;  // same as above but for mandatory digits
	curPos += retVal.integerPart.mandatory;
	
	retVal.numDots=scanStringFor(format, ',.', curPos);;  // number of dots or commas
	curPos += retVal.numDots;

	retVal.fractionalPart.universal=scanStringFor(format, anyNumberOfDigits, curPos);;  // number of universal quantifiers on the right of dot
	curPos += retVal.fractionalPart.universal;
	
	retVal.fractionalPart.mandatory=scanStringFor(format, mandatoryDigit, curPos);;  // number of mandatory digits on the right of dot
	curPos += retVal.fractionalPart.mandatory;
	
	retVal.fractionalPart.optional=scanStringFor(format, optionalDigit, curPos);; // same as above but for optional digits
	curPos += retVal.fractionalPart.optional;
	
	return retVal;
}



function compileNumberFormatRegexp(format) {
	var fmt= parseNumberFormat(format);
	
	var tmp= "^\\s*(";

	if(fmt.integerPart.universal>0) {
		tmp+= "\\d*";
	}

	
	if(fmt.integerPart.optional>0) {
		tmp+= getRegexpRepetitions("\\d", 0,fmt.integerPart.optional);
	}
	
	if(fmt.integerPart.mandatory>0) {
		tmp+= getRegexpRepetExactly("\\d",fmt.integerPart.mandatory);
	}

	if(fmt.numDots>0) {
		if(fmt.fractionalPart.universal>0) {
			if(fmt.integerPart.optional>0) {
				tmp+= "[,.]?\\d*";
			}
		} else {
			if(fmt.fractionalPart.mandatory>0) {
				tmp+= getRegexpRepetExactly("[,.]\\d",fmt.fractionalPart.mandatory);
			} else {
				tmp+= "[,.]?";
			}
			if(fmt.fractionalPart.optional>0) {
				tmp+= getRegexpRepetitions("\\d", 0,fmt.fractionalPart.optional);
			}
		}
	}
	
	tmp+= ")?\\s*$"
	return new RegExp(tmp);
}

function pluraOrSingular(n, singularSuffix, pluralSuffix) {
	return ""+n+(n<2? singularSuffix: pluralSuffix);
}

function compileNumberHelp(format) {

	var fmt= parseNumberFormat(format);
	var tmp= "";
	if(fmt.integerPart.optional>0) {
		tmp+= "Fino a " + pluraOrSingular(fmt.integerPart.optional, " cifra opzionale, "," cifre opzionali, ");
	}
	
	if(fmt.integerPart.mandatory>0) {
		tmp+= pluraOrSingular(fmt.integerPart.mandatory, " cifra obbligatoria, "," cifre obbligatorie, ");
	}

	if(fmt.numDots>0) {
	
		tmp+= "punto (o virgola) decimale, ";

		if(fmt.fractionalPart.universal>0) {
			tmp+= "qualunque numero di decimali (anche nessuno)";
		} else {
			if(fmt.fractionalPart.mandatory>0) {
				tmp+= "almeno " + pluraOrSingular(fmt.fractionalPart.mandatory , " cifra, "," cifre, ");
			}
			if(fmt.fractionalPart.optional>0) {
				tmp+= "al massimo altre " + pluraOrSingular(fmt.fractionalPart.optional," cifra opzionale, "," cifre opzionali, ");
			}
		}
	}
	return tmp.substring(0,tmp.length-2);
}

function getRegexpRepetitions(entity,min, max) {
	return entity+"{"+min+","+max+"}";
}

function getRegexpRepetExactly(entity,times) {
	if(times==1) {	
		return entity;
	}
	return getRegexpRepetitions(entity,times,times);
	
}

function scanStringFor(s, chars, startingFrom) {
	var i=startingFrom;
	var count=0;
	var msg="";
	while(i<s.length) {
		var c= s.charAt(i);
		if(chars.indexOf(c)<0)  {
			return count;
		}
		++count;
		++i;
	}
	return count;
}

function toggleImageInputField(fieldName) {
	var deleteIsActive= $F(fieldName+"Delete")? true: false;
	var f= $("field_"+fieldName);
	if(deleteIsActive) {
		f.disable();
		f.value= '';
	} else {
		f.enable();
	}
}
