/*
NOTES:
Floating point validation has been fudged. The floating point decimal 
delimeter being passed to the isFloat() function is being hard coded 
to a period in the variable declarations in validate(). This needs 
to be changed for inernationialization.

All the number validations don't bother with empty fields. If you 
need an error thrown for an empty field, then set the required attribute.
(see implementation part III below).

Date validation is for US date format for now (mm/dd/yyyy). This can be 
changed quickly for European format.

IMPLEMENTATION:
-----------------------------------------------------------------------------------

I. INCLUDING THE SOURCE
The source needs to be included in the document that contains the form to be 
validated using the tags below:

<script src="<<path to source directory>>/validate.js"></script>
-----------------------------------------------------------------------------------

II. CALLING THE SCRIPT
Calling validate() will begin form validation.

(Ex:)
A graphic 'icon_save' calls its own function save().
The save() function calls the validate() function, passing it the form to be 
validated, with an onClick event. If all is good, validate returns true, and 
the regular action(s) occur (in this case, the form is submitted).


<script language="JavaScript">
<!--
function save(){
	if (validate(<<form name>>)){
		document.<<formname>>.submit();
	}
}
//-->
</script>

<a href = "javascript:save();" onMouseover="window.status='Save';return true;" onMouseout="window.status='';return true;">
<img src="images/icon_save.gif" name="save" alt="Save" border="0"></a>
-----------------------------------------------------------------------------------

III. SETTING UP THE FORM ELEMENTS
The available forms of validation and the form element attributes and values required to 
use them are as follows:

Required element      : required="true"
Maximum value allowed : maximimum="<<number>>"
Minimum aalue allowed : minimimum="<<number>>"
Integer check         : integer="true"
Floating point check  : floatingpoint="true"
Date check            : date="true"


PLEASE NOTE that the all scripts are case sensitive to the attribute names.


(EXAMPLE1)
The following example sets the necessary attributes using javascript.
The script needs to be placed BELOW THE FORM ELEMENTS IT IS MODIFYING (NS issue).
It sets the field as required, sets it to be validated for floating point, 
sets the maximum allowed value to 32,000.
Only one form being present in the document is being assumed, otherwise, 'document.forms[0]'
should be replaced with the form name.


<input type="text" name="input1">

<!--- The script below will be referring to the textfield 'input1' --->
<script language = "javascript">
	var d = document.forms[0]; // less typing
	d.input1.required="true";
	d.input1.floatingpoint="true";
	d.input1.maximum="32000";
</script>


(EXAMPLE2)
PLEASE NOTE: This example works only in XHTML compliant browsers - IE5+, Netscape6+!!!
The following example declares the validation attributes in the HTML tag.
It sets the field as required, sets it to be validated for floating point, 
and sets the maximum allowed value to 32,000.

<input type="text" name="input1" required="true" floatingpoint="true" maximum="32000">
-----------------------------------------------------------------------------------
*/




//***********************************************************************************
//***********************************************************************************
// This function takes the error message string from validate(), creates a window,
// and writes the string to it with all the necesary tags.
// Required: (string) error message to be displayed.
//***********************************************************************************

function errorWindow(message){

	var winwidth = 400;
	var winheight = 400;
	var leftalign = (screen.width - winwidth) / 2;
	var topalign = (screen.height - winheight) / 2;
	erWin= open("", "displayWindow", "width="+winwidth+",height="+winheight+",top="+topalign+",left="+leftalign+",status=no,toolbar=no,menubar=no,resizable,scrollbars");

	var messageHeader =  "<hr>"
	messageHeader += "<center><b>Il form non &#232; stato inoltrato a causa dei seguenti errori. "
	messageHeader += "Correggi questi errori e inoltra nuovamente il form.</b></center>"
	messageHeader += "<hr><br>"

	var messageOutput = messageHeader + message;

	// open document for further output
	erWin.document.open();
  
	// create document
	erWin.document.write("<html><head><title>Errori");
	erWin.document.write('</title></head><body bgcolor="white">');
	erWin.document.write('<table align="center" valign="top" width="98%" height="100%" border="0" cellpadding="0" bgcolor="white"><tr><td>');
	erWin.document.write('<font face="arial,verdana,sans-serif" size="2">');
	erWin.document.write(messageOutput);
	erWin.document.write('</font><div align="center"><form>');
	erWin.document.write('<input type="button" onClick="window.close();" value="Chiudi">');
	erWin.document.write('</form></div>');
	erWin.document.write('</table></td></tr>');
	erWin.document.write("</body></html>");
  	
	// align window for Netscape
	erWin.screenX = leftalign;
	erWin.screenY = topalign;
	
	erWin.focus();

}
//***********************************************************************************



//***********************************************************************************
//***********************************************************************************
// This function checks to see if a form element value contains only white space
// Required: (string) form element value
// Returns: true if string contains only whitespace or is empty
//***********************************************************************************
function isBlank(s){
	
	if ((s == '') || (s == null)){
		return true; //return true if empty
	} 
	
	for(var x = 0; x<s.length; x++){
		var c = s.charAt(x);
		if ((c != ' ') || (c != '<br>') || (c != '\t')){
			return false;
		}
		return true; //return true if contains only whitespace
	}
}
//***********************************************************************************


//***********************************************************************************
// This returns the appropriate text description for a given form element 
// Required: (object) form element, (int) form element index
// Optional: (string) string to add after form element description
// Returns: (string) desc
//***********************************************************************************
function findDesc(e, x){
	var desc;
	if (e.label){desc = e.label;}
	else if (e.name){desc = e.name;}
	else {desc = "Form element " + (x + 1);}
	return desc;
}
//***********************************************************************************

//***********************************************************************************
// This returns the appropriate text description for a given form element 
// Required: (object) form element, (int) form element index
// Optional: (string) string to add after form element description
// Returns: (string) desc
//***********************************************************************************
function formatDesc(e, x, s){
	var desc = findDesc(e,x);
	desc = "&nbsp;&nbsp;&nbsp;&nbsp;&raquo;&nbsp;&nbsp;" + desc;
	if (s) desc += " " + s;
	desc += "<br>";
	return desc;
}
//***********************************************************************************



//***********************************************************************************
// This is a utility function used by isDate()
// Required: (string) year to check
// Returns: true if year is a leap year
//***********************************************************************************
function LeapYear(intYear) {
	if (intYear % 100 == 0) {
		if (intYear % 400 == 0) { return true; }
	}
	else {
		if ((intYear % 4) == 0) { return true; }
	}	
	return false;
}
//***********************************************************************************


//***********************************************************************************
//***********************************************************************************
// This function checks all form elements for the 'required' attribute.
// If a required element is not filled out, it will be added to the string 'empty_fields'
// Required: (object) [document.<<formname>>] to be validated
// Returns: (string) 'empty_fields'
//***********************************************************************************
function required(f){
	var empty_fields = '';
	var req;
	for (var x=0; x<f.length; x++){ //start looping through elements		
		
		e = f.elements[x];
		v = e.value;
		req = "";
		if(e.required){
			req = e.required.toLowerCase();
		}
		
		if (req == "true"){
			// start test text and textarea
			if ((e.type == "text") || (e.type == "textarea") || (e.type == "password")){
				if (isBlank(v)){
					empty_fields += formatDesc(e,x); 
				}
			}
			// end test text and textarea	
			
			//start test checkbox and radio button
			else if ((e.type == "checkbox") || (e.type == "radio")){
				if (e.checked == false){
					empty_fields += formatDesc(e,x); 
				}
			}
			//end test checkbox and radio button
			
			//start test select box
			else if ((e.type == "select-one") || (e.type == "select-multiple")){
				opt = "";
				for (var i = 0; i < e.length; i++){
					if(e.options[i].selected == true){
					 opt = e.options[i];
					}
				}
				if (isBlank(opt.value)){
					empty_fields += formatDesc(e,x); 
				}
			}
			//end test select box
			
		}//end 'if req == "true"'
		
	}//end loop through elements
	return empty_fields;			
}
//***********************************************************************************



//***********************************************************************************
//***********************************************************************************
// This function validates checks all form fields for the 'integer' attribute
// If an 'integer' form element is not an int, it will be added to the string 'integer_fields'.
// Required: (object) [document.<<formname>>] to be validated
// Returns: (string) 'integer_fields'
//***********************************************************************************
function isInteger(f){
	var integer_fields = '';
	var integer;
	var ok;
	
	for (var x=0; x<f.length; x++){ //start looping through elements
		e = f.elements[x];
		v = e.value;
		ok = "yes";
		integer = "";
		if(e.integer) integer = e.integer.toLowerCase();
		
		if (integer == "true"){
			// do the actual check. We're rounding the value and checking it to the original
			// if they're equal, then it's an int
			if (v.length > 0){
				rounded = Math.round(e.value);
				if (e.value != rounded) ok = "no";
				if (ok == "no") integer_fields += formatDesc(e,x);
			}
		}//end 'if integer == "true"'
	}//end loop through elements
	return integer_fields;
}
//***********************************************************************************



//***********************************************************************************
//***********************************************************************************
// This function validates checks all form fields for the 'minimum' attribute.
// If the form element value exceeds that of the value specified by the 'minimum'
// attribute, it is added to the string minimum_fields.
// Required:  (object) [document.<<formname>>] to be validated
// Returns: (string) 'minimum_fields'
//***********************************************************************************
function minimumNumber(f){
	var minimum_fields = '';
	var minimum;
	var checkMin;
	
	for (var x=0; x<f.length; x++){ //start looping through elements
		e = f.elements[x];
		v = e.value;
		checkMin = '';
		minimum = 0;
		
		if(e.minimum){			
			minimum = e.minimum;
			checkMin = "true";
		}
		
		// was having trouble with direct less than comparison, so 
		// divided the value by the minimum and compared it to one.
		if (checkMin == "true"){
			if (v.length > 0){ 
				if (v/minimum < 1){ 
					minimum_fields += formatDesc(e,x,"< minimum of " + minimum);
				}
			}
		}
	}//end loop through elements
	return minimum_fields;			
}
//***********************************************************************************


//***********************************************************************************
//***********************************************************************************
// This function validates checks all form fields for the 'maximum' attribute.
// If the form element value exceeds that of the value specified by the 'maximum'
// attribute, it is added to the string maximum_fields.
// Required:  (object) [document.<<formname>>] to be validated
// Returns: (string) 'maximum_fields'
//***********************************************************************************
function maximumNumber(f){
	var maximum_fields = '';
	var maximum;
	var checkMax;
	
	for (var x=0; x<f.length; x++){ //start looping through elements
		e = f.elements[x];
		v = e.value;
		checkMax = '';
		maximum = 0;
		// see if maximum element attribute exists
		if(e.maximum){
			maximum = e.maximum;
			checkMax = "true";
		}
		
		// was having trouble with direct greater than comparison, so 
		// divided the value by the minimum and compared it to one.
		if (checkMax == "true"){
			if (v.length > 0){
				if (v/maximum > 1){maximum_fields += formatDesc(e,x,"> maximum of " + maximum);}
			}
		}
	}//end loop through elements
	return maximum_fields;			
}
//***********************************************************************************



//***********************************************************************************
//***********************************************************************************
// This function checks all form fields for the 'floatingPoint' attribute
// If a 'floating' form element is not in floating point format, 
// it will be added to the string 'floating_fields'.
// Required: (object) [document.<<formname>>] to be validated, (char) decimalPointDelimeter
// Returns: (string) 'floating_fields'
//***********************************************************************************
function isFloat(f, delimeter){
	var floating_fields = '';
	var floating;
	var ok;
	var seenDecimalPoint;
	var dpd = delimeter.toString(); // set the decimal point delimeter
	
	for (var x=0; x<f.length; x++){ //start looping through elements
		e = f.elements[x];
		v = e.value;
		ok = "yes";
		floating = "";
		if(e.floatingpoint) floating = e.floatingpoint.toLowerCase();
		seenDecimalPoint = false;
		
		if (floating == "true"){
			if (v.length > 0){
				seenDecimalPoint = false;
				if (v == dpd) ok = "no"; // bad element value.
				// Search through element value string. If we find a non-numeric character
				// other than the decimalPointDelimeter, set ok to 'no'.
				// decimalPointDelimeter is allowed to show up only once.
				for (var i = 0; i < v.length; i++){   
        			// Check that current character is number.
        			var c = v.charAt(i);
					if ((c == dpd) && !seenDecimalPoint) seenDecimalPoint = true;
        			else if (!((c >= "0") && (c <= "9"))) ok = "no"; // bad element value.
    			}
			}
			if (ok == "no") floating_fields += formatDesc(e,x);
		}//end 'if floating == "true"'
	}//end loop through elements
	return floating_fields;			
}
//***********************************************************************************



//***********************************************************************************
//***********************************************************************************
// This function validates checks all form fields for the 'date' attribute
// If a 'date' form element is not in mm/dd/yyyy, 
// it will be added to the string 'date_fields'.
// Required: (object) [document.<<formname>>] to be validated, (char) decimalPointDelimeter
// Returns: (string) 'date_fields'
//***********************************************************************************
function isDate(f){
	var date_fields = '';
	var strDatestyle = "US"; //United States date style
	//var strDatestyle = "EU";  //European date style
	var strDate;
	var strDateArray;
	var strDay;
	var strMonth;
	var strYear;
	var intday;
	var intMonth;
	var intYear;
	var strSeparatorArray = new Array("-"," ","/",".");
	var count;
	

	
	for (var x=0; x<f.length; x++){ //start looping through elements
		e = f.elements[x];
		v = e.value;
		date = "";
		ok = "yes"
		if(e.date) date = e.date.toLowerCase();

		// begin checking date if attribute found
		if (date == "true"){
			if (v.length > 0){

				//convert date string to array
				strDate = v;
				for (count = 0; count < strSeparatorArray.length; count++) {
					if (strDate.indexOf(strSeparatorArray[count]) != -1) {
						strDateArray = strDate.split(strSeparatorArray[count]);
						if (strDateArray.length != 3) {
							ok = "no";
						}
						else {
							if (strDatestyle == "US") {
								strMonth = strDateArray[0];
								strDay = strDateArray[1];
								strYear = strDateArray[2];
							}
							else if (strDatestyle == "EU") {
								strDay = strDateArray[0];
								strMonth = strDateArray[1];
								strYear = strDateArray[2];
							}
						}
   					}
				}


				// check if strings are valid integers
				intday = parseInt(strDay, 10);
				intMonth = parseInt(strMonth, 10);
				intYear = parseInt(strYear, 10);			
				if (isNaN(intday) || isNaN(intMonth) || isNaN(intYear)) {
					ok = "no";
				}

				// check if values are zero
				if ((intday < 1) || (strMonth < 1) || (strYear < 1)) {
					ok = "no";
				}

				// check for valid month values
				if (intMonth>12 || intMonth<1) {
					ok = "no";
				}
	
				// insure year is four digit
				if (!isBlank(strYear)){ 
					if (strYear.length != 4) {
					ok = "no";
					}
				}
	

				// check for valid day values in relation to month
				if ((intMonth == 1 || intMonth == 3 || intMonth == 5 || intMonth == 7 || intMonth == 8 || intMonth == 10 || intMonth == 12) && (intday > 31)) {
					ok = "no";
				}

				if ((intMonth == 4 || intMonth == 6 || intMonth == 9 || intMonth == 11) && (intday > 30)) {
					ok = "no";
				}

				if (intMonth == 2) {
					if (LeapYear(intYear) == true) {
						if (intday > 29) {
							ok = "no";
						}
					}
					else {
						if (intday > 28) {
							ok = "no";
						}
					}
				}			
			
			}// end 'if v.length > 0'
			if (ok == "no") date_fields += formatDesc(e,x);
		}//end 'if date == "true"'
	}//end loop through elements
	return date_fields;			
}

//***********************************************************************************



//***********************************************************************************
//***********************************************************************************
//This function calls the individual validation functions and generates the
//message to be output if any errors are encountered.
//Required: (object) [document.<<formname>>] to be validated
//Returns: true if no errors encountered
//***********************************************************************************
function validate(f){

	var message = "";
	var errors = 0;
	var delimeter = "."; // used for isFloat()

	//call to required function
	var empty_fields =  required(f);
	//add errors to message if any
	if (empty_fields.length > 0){
		errors++;
		message += "<b>Tutti i campi contrassegnati con * sono obbligatori. ";
		message += "I seguenti campi non sono stati compilati.</b><br>";
		message += empty_fields + "<br>";
	}
		
	//call to maximum function
	var maximum_fields = maximumNumber(f);
	//add errors to message if any
	if (maximum_fields.length > 0){
		errors++;
		message += "<b>The following fields' values have exceeded their ";
		message += "maximum allowed values.</b><br>";
		message += maximum_fields + "<br>";
	}
	
	//call to minimum function
	var minimum_fields = minimumNumber(f);
	//add errors to message if any
	if (minimum_fields.length > 0){
		errors++;
		message += "<b>The following fields' values are below their ";
		message += "minimum allowed values.</b><br>";
		message += minimum_fields + "<br>";
	}

	//call to integer function
	var integer_fields = isInteger(f);
	//add errors to message if any
	if (integer_fields.length > 0){
		errors++;
		message += "<b>The following fields are required to be valid integers.</b><br>";
		message += integer_fields + "<br>";
	}
	
	//call to floating point function
	var floating_fields = isFloat(f, delimeter);
	//add errors to message if any
	if (floating_fields.length > 0){
		errors++;
		message += "<b>The following fields are required to be ";
		message += "valid floating point numbers.</b><br>";
		message += floating_fields + "<br>";
	}
	
	//call to date function
	var date_fields = isDate(f);
	//add errors to message if any
	if (date_fields.length > 0){
		errors++;
		message += "<b>The following fields should be dates entered ";
		message += "in format mm/dd/yyyy.</b><br>";
		message += date_fields + "<br>";
	}
	
	
	//call to date compare function
	var compareDates_fields = compareDateTo(f);
	//add errors to message if any
	if (compareDates_fields.length > 0){
		errors++;
		message += "<b>The following date fields are required to be as shown.</b><br>";
		message += compareDates_fields + "<br>";
	}
	
	//call to minimum date function
	var minimumDate_fields = minimumDate(f);
	//add errors to message if any
	if (minimumDate_fields.length > 0){
		errors++;
		message += "<b>The following date fields are required to be as shown.</b><br>";
		message += minimumDate_fields + "<br>";
	}
	
	if (errors > 0){
		errorWindow(message);
		//alert(message);
		return false;
	}
	
	return true;
}
//***********************************************************************************



//***********************************************************************************
// This is a utility function used by AmcHTMLDateTimeTag
// Required: (string) hidden field, day dropdown, month dropdwon, year dropdown,
// date format of US or EU
//***********************************************************************************
function dateHandler(hiddenName, dayName, monthName, yearName){
	
	var i;
	var val;
		
	var dayField = MM_findObj(dayName);
	var monthField = MM_findObj(monthName);
	var yearField = MM_findObj(yearName);
	var hiddenField = MM_findObj(hiddenName);
	
	var selectedDay = dayField.options[dayField.selectedIndex].value;
	var selectedMonth = monthField.options[monthField.selectedIndex].value;
	var selectedYear = yearField.options[yearField.selectedIndex].value;
	
	timeA = new Date(selectedYear, selectedMonth,1);
	timeDifference = timeA - 86400000;
	timeB = new Date(timeDifference);
	var daysInMonth = timeB.getDate();
	for (var i = 0; i < dayField.length; i++) {
		dayField.options[0] = null;
	}
	for (var i = 0; i < daysInMonth; i++) {
		newValue = i+1;
		newValue = newValue.toString();
		if (newValue.length <= 1) optStr = "0" + newValue;
		else optStr = newValue;
		dayField.options[i] = new Option(optStr, optStr, false, false);
	}
	
	//make sure day selection is updated
	if (selectedDay <= dayField.length){
		dayField.options[selectedDay - 1].selected = true;
	}
	else{
		dayField.options[0].selected = true;
	}
	selectedDay = dayField.options[dayField.selectedIndex].value;
	
	// set date string to hidden field value
	hiddenField.value = selectedMonth + "/" + selectedDay + "/" + selectedYear;
	

}// end dateHandler function
//***********************************************************************************


//***********************************************************************************
// This a utility function that was provided with Macromedia Dreamweaver 3. 
// Required: (string) The name of the object to find
// Returns: (object) The specified object
//***********************************************************************************
function MM_findObj(n, d) { //v3.0
	var p,i,x;  

	if(!d) d=document;
	
	if((p=n.indexOf("?"))>0&&parent.frames.length) { 
		d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);
	}
  
	if(!(x=d[n])&&d.all) 
		x=d.all[n]; 

	for (i=0;!x&&i<d.forms.length;i++) 
		x=d.forms[i][n];
  
	for(i=0;!x&&d.layers&&i<d.layers.length;i++) 
		x=MM_findObj(n,d.layers[i].document); 

	return x;
}
//***********************************************************************************

					
//***********************************************************************************
//***********************************************************************************
// This function compares two date values. 
// This is used by AmcHTMLDateTimeTag.generateComparisonDateTagstr
// Required: (object) [document.<<formname>>] to be validated
// Returns: compareDates_fields - (String) formatted field names for error message
//***********************************************************************************
function compareDateTo(f){
	var compareDates_fields = "";
	var message = "";
	var secondDateField;
	
	for (var x=0; x<f.length; x++){ //start looping through elements
		e = f.elements[x];
		v = e.value;
		
		// see if maximum element attribute exists
		if(e.compareDateTo)
		{
			var argStr = unescape(e.compareDateTo);
			var args = new Array();
			
			args = argStr.split(",");
			
			secondDateField = MM_findObj(args[0]);
			
			if (secondDateField == null)
			{
			alert("Invalid compareToName: '" + args[0] + "'\n\nPlease ensure that the name is spelled correctly.")
			}
			secondDate = secondDateField.value;
			checkIt = "true";
		}
		else
		{
			checkIt = "false";
		}
		
		if (checkIt == "true")
		{
			if (args[1] == ">") message = " must be greater than ";
			else if (args[1] == ">=") message = " must be greater than or equal to ";
			else if (args[1] == "<") message = " must be less than ";
			else if (args[1] == "<=") message = " must be less than or equal to ";
			else alert("Invalid comparison operator.");

			var arrayFirstDate = new Array(3);
			var arraySecondDate = new Array(3);
			var date1, date2;
			
			arrayFirstDate = v.split("/");
			arraySecondDate = secondDate.split("/");
			
			date1 = arrayFirstDate[2] + arrayFirstDate[0] + arrayFirstDate[1];
			date2 = arraySecondDate[2] + arraySecondDate[0] + arraySecondDate[1];
			
			var strToEval = "date1"  + args[1] +  "date2";
			
			if (!eval(strToEval)){compareDates_fields += formatDesc(e, x, message + findDesc(secondDateField, x)  );}
		}
	}//end loop through elements
	return compareDates_fields;			
}
//***********************************************************************************



//***********************************************************************************
//***********************************************************************************
// This function validates checks all form fields for the 'minimumDate' attribute.
// If the form element value exceeds that of the value specified by the 'minimum'
// attribute, it is added to the string minimumDate_fields.
// Required:  (object) [document.<<formname>>] to be validated
// Returns: (string) 'minimum_fields'
//***********************************************************************************
function minimumDate(f){
	var minimumDate_fields = '';
	var minimumDate;
	var checkMin;
	
	for (var x=0; x<f.length; x++){ //start looping through elements

		e = f.elements[x];
		v = e.value;
		checkMin = '';
		minimumDate = 0;
		
		
		if(e.minimumDate)
		{			

			minimumDate = e.minimumDate;
			checkMin = "true";
			
			var arrayFirstDate = new Array(3);
			var arraySecondDate = new Array(3);
			var date1, date2;
			
			arrayFirstDate = v.split("/");
			arraySecondDate = minimumDate.split("/");
			
			date1 = arrayFirstDate[2] + arrayFirstDate[0] + arrayFirstDate[1];
			date2 = arraySecondDate[2] + arraySecondDate[0] + arraySecondDate[1];
		}


		
		// was having trouble with direct less than comparison, so 
		// divided the value by the minimum and compared it to one.
		if (checkMin == "true"){
			if (v.length > 0){ 
				if (date1 < date2){ 
					minimumDate_fields += formatDesc(e,x," must be greater than or equal " + minimumDate);
				}
			}
		}
	}//end loop through elements
	return minimumDate_fields;			
}
//***********************************************************************************


