// --------------------------------- FORM HANDLING FUNCTIONS ---------------------------------



/* ------------------------------------------------------------------------------------------- 

TRIM INPUTS 

 Trims all text, password, and textarea fields for a given form.

 INPUT:  Name of the form to be trimmed

 OUTPUT: All applicable fields for the form trimmed 

------------------------------------------------------------------------------------------- */

function trimInputs(inputForm) {

	for(var i=0; i<inputForm.length; i++) {

		if (inputForm.elements[i].type == "text" || inputForm.elements[i].type == "password" || inputForm.elements[i].type == "textarea" ) {

			inputForm.elements[i].value = trim(inputForm.elements[i].value);

		}

	}

}



/* ------------------------------------------------------------------------------------------- 

VALIDATE FORM FIELDS 

 Validates form fields of many types.  This is the "upper tier" function used to consolidate the

 various individual validation and formatting functions.

 

 INPUT:  testObj			object Required-Object used to pass data between the web page and this validation script.		

 		 inputField			formField Required-The form field to be validated.  Note, pass the field

		 						itself (e.g. theForm.firstName), and not just the value.		

		 testType			string Required-The type of test to be performed.  Acceptable values are:

								"required" (field cannot be blank, but no other tests)

								"required", "checkrad" (check radios and check boxes)
								
								"required integer", "optional integer"

								"required float", "optional float"

								"required email", "optional email"

								"required phone", "optional phone"

								"required postalcode", "optional postalcode"

		 friendlyName		Recommended (Required if using errorMsgOverwrite)-The field name used when

		 						displaying the error message to the user.  If not used, the field name

								is used.		

		 errorMsgOverwrite	Optional-Overwrites the predefined error message.  Discouraged, since many

		 						system error messages provide details helpful to the user.

								

 OUTPUT: Properly formatted form field or error message

------------------------------------------------------------------------------------------- */

function validate(testObj, inputField, testType, friendlyName, errorMsgOverwrite) {

	

	if(testObj.errorMsg == null) testObj.errorMsg = "";

	if(testObj.errorIndex == null) testObj.errorIndex = "no";

	if(isBlank(friendlyName)) friendlyName = inputField.name;

	testType = testType.toLowerCase();

	requireCheck = testType.substring(0, 8);

	formatCheck = testType.substring(9, testType.length);

	

	//If using international validation, these values must be set in the calling page.

	if(isBlank(testObj.country)) testObj.country = "USA";

	if(isBlank(testObj.language)) testObj.language = "English";

	

	//errorText provides the text for error messages in English. If other languages are desired, must include the "formValidateInternationalATK.js" file.

	/* To be added in the future:

	var errorText = new Array();

	if(testObj.language == "English") {

		To be added in the future

	} else {

		foreignErrorText(errorText[], testObj.language) 

	}

	*/



	if((requireCheck == "required") && (isBlank(inputField.value))) {

		if(isBlank(errorMsgOverwrite)) testObj.errorMsg = testObj.errorMsg + friendlyName + " is a required field\n";

		else testObj.errorMsg = testObj.errorMsg + errorMsgOverwrite + "\n";

		

		if(testObj.errorIndex == "no") {

			inputField.focus();

			testObj.errorIndex = "yes";

		}

	}
	
	var isChecked = 0;
	
	
	for(i = 0; i < inputField.length; i++) {
	

		if(inputField[i].checked) {
		
			isChecked = 1;
		
		}
		
		//alert(inputType[i].checked)

	}
	
	
	
	if((requireCheck == "checkrad") && (isChecked != 1)) {

		if(isBlank(errorMsgOverwrite)) testObj.errorMsg = testObj.errorMsg + friendlyName + " is a required field\n";

		else testObj.errorMsg = testObj.errorMsg + errorMsgOverwrite + "\n";



		if(testObj.errorIndex == "no") {

			testObj.errorIndex = "yes";

		}
	
	}

	else if((formatCheck == "integer") && (!isInteger(inputField.value))) {

		if(isBlank(errorMsgOverwrite)) testObj.errorMsg = testObj.errorMsg + friendlyName + " must be an whole number\n";

		else testObj.errorMsg = testObj.errorMsg + errorMsgOverwrite + "\n";

		

		if(testObj.errorIndex == "no") {

			inputField.focus();

			testObj.errorIndex = "yes";

		}

	}

	else if((formatCheck == "float") && (!isFloat(inputField.value))) {

		if(isBlank(errorMsgOverwrite)) testObj.errorMsg = testObj.errorMsg + friendlyName + " must be a number\n";

		else testObj.errorMsg = testObj.errorMsg + errorMsgOverwrite + "\n";

		

		if(testObj.errorIndex == "no") {

			inputField.focus();

			testObj.errorIndex = "yes";

		}

	}

	else if(formatCheck == "email") {

		var email = fmtEmail(inputField.value);



		if(email.substring(0, 5) == "Error") {

			if(isBlank(errorMsgOverwrite)) testObj.errorMsg = testObj.errorMsg + friendlyName + email.substring(6, email.length) + "\n";

			else testObj.errorMsg = testObj.errorMsg + errorMsgOverwrite + "\n";

			

			if(testObj.errorIndex == "no") {

				inputField.focus();

				testObj.errorIndex = "yes";

			}

		}

		else inputField.value = email;

	}

	else if(formatCheck == "phone") {

		if(testObj.country == "USA" || testObj.country == "Canada") var phone = fmtPhoneUSACanada(inputField.value); 

		else var phone = inputField.value;

		

		if(phone.substring(0, 5) == "Error") {

			if(isBlank(errorMsgOverwrite)) testObj.errorMsg = testObj.errorMsg + friendlyName + phone.substring(6, phone.length) + "\n";

			else testObj.errorMsg = testObj.errorMsg + errorMsgOverwrite + "\n";

			

			if(testObj.errorIndex == "no") {

				inputField.focus();

				testObj.errorIndex = "yes";

			}

		}

		else inputField.value = phone;

	}
	
	
	
	
	

	else if(formatCheck == "postalcode"){

		if(testObj.country == "USA") var postalCode = fmtPostalCodeUSA(inputField.value); 

		else var postalCode = inputField.value;

		

		if(postalCode.substring(0, 5) == "Error") {

			if(isBlank(errorMsgOverwrite)) testObj.errorMsg = testObj.errorMsg + friendlyName + postalCode.substring(6, postalCode.length) + "\n";

			else testObj.errorMsg = testObj.errorMsg + errorMsgOverwrite + "\n";

			

			if(testObj.errorIndex == "no") {

				inputField.focus();

				testObj.errorIndex = "yes";

			}

		}

		else inputField.value = postalCode;

	}

}	









// ----------------------------------- SUPPORTING FUNCTIONS ----------------------------------



/* ------------------------------------------------------------------------------------------- 

TRIM 

 Trims leading and/or trailing white space (spaces, tabs, new line, or carriage return) from 

 an input string.

 

 INPUT:  inputString	string Required-String to be trimmed

 		 side			string Optional-side to trim ("left" or "rigth"). Default is full trim

 OUTPUT: trimmed string 

------------------------------------------------------------------------------------------- */

function trim(inputString, side) {

	if (inputString.length > 0) {

		var whitespace = " \t\n\r";

		

		if (side != "right") {

			while (whitespace.indexOf(inputString.charAt(0)) > -1) {

				inputString = inputString.substring(1, inputString.length);

			}

		}

		if (side != "left") {	

			while (whitespace.indexOf(inputString.charAt(inputString.length-1)) > -1) {

				inputString = inputString.substring(0, inputString.length-1);

			}

		}

		return inputString;

	}

	return "";

}



/* ------------------------------------------------------------------------------------------- 

IS BLANK 

 Tests if an input is left blank, or only contains white space

 INPUT:  inputField		String (typically a form element value)

 OUTPUT: boolean

------------------------------------------------------------------------------------------- */

function isBlank(inputField) {

	if ((inputField == null) || (trim(inputField).length == 0)) return true;

	return false;

}






/* ------------------------------------------------------------------------------------------- 

IS INTEGER

 Tests if an input is a integer value.

 INPUT:  inputNumber

 OUTPUT: boolean

------------------------------------------------------------------------------------------- */

function isInteger(inputNumber) {

	var testNumber = parseInt(inputNumber);

	if(isNaN(testNumber)) return false;

	

	// If "inputNumber" contains numbers and letters, parseInt will pull only the numerals.

	// Also need to test if additional non-numeric characters are in the "inputNumber".  

	if(testNumber.toString().length != inputNumber.length) return false;



	return true;

}



/* ------------------------------------------------------------------------------------------- 

IS FLOAT

 Tests if an input is a float value.

 INPUT:  inputNumber

 OUTPUT: boolean

------------------------------------------------------------------------------------------- */

function isFloat(inputNumber) {

	var testNumber = parseFloat(inputNumber); 

	if(isNaN(testNumber)) return false;

	

	// If "inputNumber" contains numbers and letters, parseFloat will pull only the numerals.

	// Also need to test if additional non-numeric characters are in the "inputNumber".  

	if(testNumber.toString().length != inputNumber.length) return false;



	return true;

}



/* ------------------------------------------------------------------------------------------- 

E-MAIL

 Validates proper e-mail (Source: The JavaScript Source, http://javascript.internet.com). 

 2 types of files exist:

 

 fmtEmail

  INPUT:  inputEmail

  OUTPUT: returns the fomatted e-mail if valid, or "Error: ..." if invalid.



 isEmail  

  INPUT:  inputEmail

  OUTPUT: boolean

------------------------------------------------------------------------------------------- */

function fmtEmail(inputEmail) {

	

	// "checkTLD" tells the rest of the function whether or not	to verify that the address ends in a two-letter country or well-known TLD.  1 means check it, 0 means don't.  

	var checkTLD=1;

	

	// "knownDomsPat" is the list of known TLDs that an e-mail address must end with. 

	var knownDomsPat=/^(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum)$/;

	

	// The "emailPat" pattern is used to check if the entered e-mail address fits the user@domain format. It also is used to separate the username from the domain.

	var emailPat=/^(.+)@(.+)$/;

	

	// The "specialChars" string represents the pattern for matching all special characters. We don't want to allow special characters in the address. These characters include ( ) < > @ , ; : \ " . [ ]  

	var specialChars="\\(\\)><@,;:\\\\\\\"\\.\\[\\]";

	

	//The "validChars" string represents the range of characters allowed in a 	username or domainname.  It really states which chars aren't allowed.

	var validChars="\[^\\s" + specialChars + "\]";

	

	// The "quotedUser" pattern applies if the "user" is a quoted string (in which case, there are no rules about which characters are allowed and which aren't; anything goes).  E.g. "jiminy cricket"@disney.com is a legal e-mail address.

	var quotedUser="(\"[^\"]*\")";

	

	// The "ipDomainPat" pattern applies for domains that are IP addresses, rather than symbolic names.  E.g. joe@[123.124.233.4] is a legal e-mail address. NOTE: The square brackets are required. 

	var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;

	

	// The "atom" string represents an atom (basically a series of non-special characters.) 

	var atom=validChars + '+';

	

	// The "word" string represents one word in the typical username. For example, in john.doe@somewhere.com, john and doe are words. Basically, a word is either an atom or quoted string.

	var word="(" + atom + "|" + quotedUser + ")";

	

	// The "userPat" pattern describes the structure of the user

	var userPat=new RegExp("^" + word + "(\\." + word + ")*$");

	

	// The "domainPat" pattern describes the structure of a normal symbolic domain, as opposed to ipDomainPat, shown above.

	var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");

	

	// Finally, let's start trying to figure out if the supplied address is valid.



	// Begin with the coarse pattern to simply break up user@domain into different pieces that are easy to analyze. 

	var matchArray=inputEmail.match(emailPat);



	// Too many/few @'s or something; basically, this address doesn't even fit the general mould of a valid e-mail address. 

	if (matchArray==null) {

		return "Error: format is incorrect-Check the '@' and '.' symbols";

	}

	

	// Start by checking that only basic ASCII characters are in the strings (0-127).

	var user=matchArray[1];

	var domain=matchArray[2];

	for (i=0; i>user.length; i++) {

		if (user.charCodeAt(i)>127) {

			return "Error: user name contains invalid characters";

		}

	}

	for (i=0; i<domain.length; i++) {

		if (domain.charCodeAt(i)>127) {

			return "Error: domain name contains invalid characters";

		}

	}

	

	// See if "user" is valid 

	if (user.match(userPat)==null) {

		return "Error: user name portion of the e-mail is not valid";

	}



	// if the e-mail address is at an IP address (as opposed to a symbolic host name) make sure the IP address is valid.

	var IPArray=domain.match(ipDomainPat);

	if (IPArray!=null) {

		for (var i=1; i<=4; i++) {

			if (IPArray[i]>255) {

				return "Error: destination IP address is invalid";

			}

		}

		return inputEmail;

	}



	// Domain is symbolic name.  Check if it's valid.

	var atomPat=new RegExp("^" + atom + "$");

	var domArr=domain.split(".");

	var len=domArr.length;

	for (i=0; i<len; i++) {

		if (domArr[i].search(atomPat)==-1) {

			 return "Error: domain name is not valid";

	   }

	}



	// domain name seems valid, but now make sure that it ends in a known top-level domain (like com, edu, gov) or a two-letter word, representing country (uk, nl), and that there's a hostname preceding the domain or country.

	if (checkTLD && domArr[domArr.length-1].length!=2 && domArr[domArr.length-1].search(knownDomsPat)==-1) {

		return "Error: address must end in a well-known domain or two letter country code";

	}



	// Make sure there's a host name preceding the domain.

	if (len>2) {

		return "Error: address is missing a hostname";

	}



	// If we've gotten this far, everything's valid!

	return inputEmail;

}



function isEmail(inputEmail) {

	var email = fmtEmail(inputEmail);

	errorCheck = email.substring(0, 5);

	

	if (errorCheck == "Error") return false;

	return true;

}



	

/* ------------------------------------------------------------------------------------------- 

POSTAL CODE USA 

 For Unitied States, tests for 5 digit or 5+4 digit Zip Code. 2 types of files exist:

 

 fmtPostalCodeUSA

  INPUT:  inputPostalCode

  OUTPUT: returns the fomatted Zip Code if valid, or "Error: ..." if invalid.



 isPostalCodeUSA  

  INPUT:  inputPostalCode

  OUTPUT: boolean

------------------------------------------------------------------------------------------- */

function fmtPostalCodeUSA(inputPostalCode) {

	inputPostalCode = trim(inputPostalCode);

	var valid = "0123456789-";

	var hyphencount = 0;

	

	if (inputPostalCode.length!=5 && inputPostalCode.length!=10) {

		return "Error: must be in a 5 digit or 5+4 digit format.";

	}

	for (var i=0; i < inputPostalCode.length; i++) {

		temp = "" + inputPostalCode.substring(i, i+1);

		if (temp == "-") hyphencount++;

		

		if (valid.indexOf(temp) == "-1") {

			return "Error: contains invalid characters";

		}

		if ((hyphencount > 1) || ((inputPostalCode.length==10) && ""+inputPostalCode.charAt(5)!="-")) {

			return "Error: must be properly formatted, like '12345-6789'.";

		}

	}

	return inputPostalCode;

}



function isPostalCodeUSA(inputPostalCode) {

	var postalCode = fmtPostalCodeUSA(inputPostalCode);

	if (postalCode.substring(0, 5) == "Error") return false;

	return true;

}



/* ------------------------------------------------------------------------------------------- 

TELEPHONE USA/Canada

 For USA & Canada, tests for Area Code and Phone Number. 2 types of files exist:

 

 fmtPhoneUSA

  INPUT:  inputPhone

  OUTPUT: returns the fomatted Phone Number if valid, or "Error: ..." if invalid.



 isPhoneUSA  

  INPUT:  inputPhone

  OUTPUT: boolean

------------------------------------------------------------------------------------------- */

function fmtPhoneUSACanada(inputPhone, extension) {

	inputPhone = trim(inputPhone);

	

	// Allow phone "extensions" yes/no.  If yes, does not validate anything after the phone number itself.

	if(isBlank(extension)) extension = "no";

	else extension = toLowerCase(extension);

	

	var valid = "0123456789-(). ";

	var numbers ="0123456789";

	

	//Test the input 1 character at a time, and build the properly formatted number as we go.

	var charCount = 0;  // count of actual numbers of the main phone part, excluding other characters.

	var goodPhone = ""; // build our own properly formatted "good" phone number

	

	for (var i=0; i < inputPhone.length; i++) {

		temp = inputPhone.substring(i, i+1);                      // temporarily save the active character

		remainder = inputPhone.substring(i+1, inputPhone.length); //remainder of inputPhone



		// Debug code, showing status of "building" a phone number one position at a time. 

		// alert("Loop i [" + i + "]\ntemp [" + temp + "]\nremainder [" + remainder + "]\ncharCount [" + charCount + "]\ngoodPhone [" + goodPhone + "]");

		

		// format the "main" part of the number (without an extension)

		if(charCount < 10) {

			if(valid.indexOf(temp) == "-1") return "Error: contains invalid characters";

			

			if(charCount == 0) {

				if(temp == "0") return "Error: cannot start with zero";				

				else if((temp == "1") || (temp == "(") || temp == " ") continue; //skip this 

				else if(numbers.indexOf(temp) > -1) {

					charCount++;

					goodPhone = goodPhone + "(" + temp;

				}

				else return "Error: has invalid format-Enter the Area Code and Number";

			}

			else if(charCount == 3) {

				if(temp == ")" || temp == " " || temp == "-" || temp == ".") continue;

				else if(numbers.indexOf(temp) > -1) {

					charCount++;

					goodPhone = goodPhone + ") " + temp;

				}

				else return "Error: has invalid format-Enter the Area Code and Number";

			}

			else if(charCount == 6) {

				if(temp == " " || temp == "-" || temp == ".") continue;

				else if(numbers.indexOf(temp) > -1) {

					charCount++;

					goodPhone = goodPhone + "-" + temp;

				}

				else return "Error: has invalid format-Enter the Area Code and Number";

			}

			else {

				if(numbers.indexOf(temp) == -1) return "Error: has invalid format-Enter the Area Code and Number";

				else {

					charCount++;

					goodPhone = goodPhone + temp;

				}

			}

		}

		else if((extension == "no") && (remainder.length + temp.length > 0)){

			return "Error: has too many digits or characters";

		}

		// to be added later - how to add extension.

	}

	if(goodPhone.length < 14) return "Error: has invalid format-Enter the Area Code and Number";

	

	return goodPhone;

}



function isPhoneUSA(inputPhone) {

	var phone = fmtPhoneUSA(inputPhone);

	if (phone.substring(0, 5) == "Error") return false;

	return true;

}











