/*
Instructions: This file must be included in the page of the form you want to validate.  For this
	validation to work, the following requirements must be met:
	- Only one form can exists per page.  If there is more than one form then the validation will
	  only check the first form (forms[formIndex]).
	- All fields that need validation must contain the following:
		- ID - The ID tag identifies the field as needing validation. Possible ID values:
			- reqnumber - will check to make sure the input field only contains numbers
			- checknumber - field is not required but if data is entered then wil validate that field only contains numbers
			- reqemail - will check that data passes basic email address requirements
			- checkemail - field is not required but if data is entered will check email validation
			- reqdate - will check that the date is valid (date must be in mm/dd/yyyy format)
			- checkdate - field is not required but if data is entered will check for valid date (mm/dd/yyyy format)
			- reqtext - will check to make suer the field length is greater than zero
			- reqselect - will check to make sure the selectedIndex is greater than zero on a select box
			- min field length - to identify a minimum field length for a text field then follow the
			  id name by an underscore and a number representing the minimum field length
		- Title - The title is the message that will be displayed in the alert box 
		          if validation fails for that field.  All fields that fail validation will be listed
		          in one alert box at the end of validation.

	- Examples:
		<input type="text" name="FirstName" ID="reqtext" Title="First Name">
			- Will check that the length of the First Name field is greater than zero.  
			  If length is zero then the title "First Name" will be displayed in alert box.
		<input type="text" name="HomePhone" ID="reqnumber_10" Title="Home Phone">
			- Will check that the length of the Home Phone field is not less than 10.  
			  If length is less than 10 then the title "Home Phone (must be 10 digits long)" 
			  will be displayed followed by in alert box.			  
*/

var strInputColor = "white";  //default background color for form fields
var strInputErrorColor = "yellow";  //background color to identify fields with errors
var strErrorMsg; //string to hold error message displayed in alert box
var intFocusElement; //element to set focus to

// Declaring valid date character, minimum year and maximum year
var dtCh= "/";
var minYear=1900;
var maxYear=2100;
var formIndex;
function validateForm(formIndexToValidate) {

	formIndex = formIndexToValidate;
	strErrorMsg = ""; //set error message to nothing
	intFocusElement = -1; //set focus field to nothing
	
	//loop through all elements in form
    for (var i = 0; i<document.forms[formIndex].elements.length; i++) {
		var fieldName = document.forms[formIndex].elements[i].name;
        var strValue = Trim(document.forms[formIndex].elements[i].value); //get field value
		var idName = document.forms[formIndex].elements[i].id.toUpperCase(); //get field name
		var type = document.forms[formIndex].elements[i].type.toUpperCase(); //get type of field
		var strTitle = document.forms[formIndex].elements[i].title; //get field title message
		
		if (idName.indexOf('_') >0) {
			var minFieldLen = idName.substring(idName.indexOf('_')+1,idName.length);
		}
		else {
			var minFieldLen = 0;
		}
		//alert(type);
		if (idName.length > 0){
	        if ((type == 'TEXT') || (type == 'TEXTAREA') || (type == 'PASSWORD')) {
				document.forms[formIndex].elements[i].style.backgroundColor = strInputColor;
				//set trimmed value
				document.forms[formIndex].elements[i].value = strValue;
	        
				if (idName.substring(0,9) == 'REQNUMBER'){
		            validateNumeric(i,strValue,strTitle,minFieldLen,fieldName);
		        }
	            else if ((idName.substring(0,11) == 'CHECKNUMBER') && (strValue.length > 0)){
		            validateNumeric(i,strValue,strTitle,minFieldLen,fieldName);
		        }		        
		        else if (idName.substring(0,7) == 'REQTEXT'){
					validateText(i,strValue,strTitle,minFieldLen,fieldName);
		        }
		        else if (idName.substring(0,8) == 'REQEMAIL'){
					emailCheck(i,strValue,strTitle,fieldName);
		        }
		        else if ((idName.substring(0,10) == 'CHECKEMAIL') && (strValue.length > 0)){
					emailCheck(i,strValue,strTitle,fieldName);
		        }		        
		        else if (idName.substring(0,7) == 'REQDATE'){
					isDate(i,strValue,strTitle);
		        }
		        else if ((idName.substring(0,9) == 'CHECKDATE') && (strValue.length > 0)){
					isDate(i,strValue,strTitle);
		        }		        
	        }
	        else if (type == 'SELECT-ONE') {
				if (idName == 'REQSELECT'){
					document.forms[formIndex].elements[i].style.backgroundColor = strInputColor;
					validateSelectOne(i,strTitle);
				}
	        }
	        else if (type == 'SELECT-MULTIPLE') {
				if (idName == 'REQSELECT'){
					document.forms[formIndex].elements[i].style.backgroundColor = strInputColor;
					validateSelectMultiple(i,strTitle);
				}
	        }	
	        else if (type == 'RADIO') {
				if (idName == 'REQCHECK'){
					document.forms[formIndex].elements[i].style.backgroundColor = strInputColor;
					validateRadioCheckbox(i,fieldName,strTitle)
				}
	        }	
	        else if (type == 'CHECKBOX') {
				if (idName == 'REQCHECK'){
					document.forms[formIndex].elements[i].style.backgroundColor = strInputColor;
					validateRadioCheckbox(i,fieldName,strTitle)
				}
	        }		        	                
	    }        
    }
    
    //if length of message is greater than zero then display alert message with errors
    if (strErrorMsg.length > 0){
		alert('Please complete the following fields before submitting:\n' + strErrorMsg);
		if (intFocusElement >= 0){
			document.forms[formIndex].elements[intFocusElement].focus();
		}
		return false;
    }
    else {
		// no errors found
		return true;
	}
}

function validateText(i,strValue,strTitle,intMinLen,fieldName){
	
	if (strValue.length == 0){
    	strErrorMsg = strErrorMsg + '- ' + strTitle + '\n';
		failedValidation(i);
	}
	else if ((intMinLen > 0) && (strValue.length < intMinLen)){
    	strErrorMsg = strErrorMsg + '- ' + strTitle + ' (must be at least '+intMinLen+' characters long)\n';
		failedValidation(i);
	}
}

function validateNumeric(i,strValue,strTitle,intMinLen,fieldName) {
    if (!strValue){
    	strErrorMsg = strErrorMsg + '- ' + strTitle + ' (must be numeric)\n';
    	failedValidation(i);
    	return false;
    }
	else if ((intMinLen > 0) && (strValue.length < intMinLen)){
		strErrorMsg = strErrorMsg + '- ' + strTitle + ' (must be numeric and at least '+intMinLen+ ' digits long)\n';
		failedValidation(i);
		return false;
	}    
    
    var Chars = "0123456789";

    for (var x = 0; x < strValue.length; x++) {
       if (Chars.indexOf(strValue.charAt(x)) == -1){
           	strErrorMsg = strErrorMsg + '- ' + strTitle + ' (must be numeric)\n';
           	failedValidation(i);
           	return false;
       }
    }
} 

function validateSelectOne(i,strTitle){
	if (document.forms[formIndex].elements[i].selectedIndex == 0){
		failedValidation(i);
		strErrorMsg = strErrorMsg + '- ' + strTitle + '\n';
	}
}

function validateSelectMultiple(i,strTitle){
	if (document.forms[formIndex].elements[i].selectedIndex < 0){
		failedValidation(i);
		strErrorMsg = strErrorMsg + '- ' + strTitle + '\n';
	}
}

function validateRadioCheckbox(i,fieldName,strTitle){
	var strOption = "";
	
    for (var z=0;z<document.forms[formIndex].elements[fieldName].length;z++) {
        if (document.forms[formIndex].elements[fieldName][z].checked){
            strOption = z;
        }
    }
    
    if (strOption.length == 0){
		strErrorMsg = strErrorMsg + '- ' + strTitle + '\n';
		failedValidation(i);
	}
}


function emailCheck (i,emailStr,strTitle,fieldName) {

	/* The following variable 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;

	/* The following 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 following 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 following 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 following 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 following 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 following 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 following string represents an atom (basically a series of non-special characters.) */

	var atom=validChars + '+';

	/* The following 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 following pattern describes the structure of the user

	var userPat=new RegExp("^" + word + "(\\." + word + ")*$");

	/* The following 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=emailStr.match(emailPat);

	if (matchArray==null) {

		/* Too many/few @'s or something; basically, this address doesn't
		even fit the general mould of a valid e-mail address. */

		//alert("Email address seems incorrect (check @ and .'s)");
		strErrorMsg = strErrorMsg + "- " + strTitle + " (check @ and .'s)\n";
		failedValidation(i);
		return false;
	}
	var user=matchArray[1];
	var domain=matchArray[2];

	// Start by checking that only basic ASCII characters are in the strings (0-127).

	for (x=0; x<user.length; x++) {
	if (user.charCodeAt(x)>127) {
		//alert("Ths username contains invalid characters.");
		strErrorMsg = strErrorMsg + '- ' + strTitle + ' (username contains invalid characters)\n';
		failedValidation(i);
		return false;
	   }
	}
	for (x=0; x<domain.length; x++) {
	if (domain.charCodeAt(x)>127) {
		//alert("Ths domain name contains invalid characters.");
		strErrorMsg = strErrorMsg + '- ' + strTitle + ' (domain name contains invalid characters)\n';
		failedValidation(i);	
		return false;
	   }
	}

	// See if "user" is valid 

	if (user.match(userPat)==null) {

	// user is not valid

		//alert("The username doesn't seem to be valid.");
		strErrorMsg = strErrorMsg + '- ' + strTitle + ' (username is invalid)\n';
		failedValidation(i);		
		return false;
	}

	/* 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) {

	// this is an IP address

	for (var x=1;x<=4;x++) {
	if (IPArray[x]>255) {
		//alert("Destination IP address is invalid!");
		strErrorMsg = strErrorMsg + '- ' + strTitle + ' (Destination IP address is invalid)\n';
		failedValidation(i);		
		return false;
	   }
	}
	return true;
}

// Domain is symbolic name.  Check if it's valid.
 
var atomPat=new RegExp("^" + atom + "$");
var domArr=domain.split(".");
var len=domArr.length;
for (x=0;x<len;x++) {
if (domArr[x].search(atomPat)==-1) {
		//alert("The domain name does not seem to be valid.");
		strErrorMsg = strErrorMsg + '- ' + strTitle + ' (domain name does not seem to be valid)\n';
		failedValidation(i);
		return false;
   }
}

/* 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) {
		//alert("The address must end in a well-known domain or two letter " + "country.");
		strErrorMsg = strErrorMsg + '- ' + strTitle + ' (address must end in a well-known domain or two letter " + "country.)\n';
		failedValidation(i);
		return false;
}

// Make sure there's a host name preceding the domain.

if (len<2) {
		//alert("This address is missing a hostname!");
		strErrorMsg = strErrorMsg + '- ' + strTitle + ' (address is missing a hostname)\n';
		failedValidation(i);
		return false;
}

// If we've gotten this far, everything's valid!
	return true;
}

// ============================ validate date functions =====================================
function isInteger(s){
	var x;
    for (x = 0; x < s.length; x++){   
        // Check that current character is number.
        var c = s.charAt(x);
        if (((c < "0") || (c > "9"))) return false;
    }
    // All characters are numbers.
    return true;
}

function stripCharsInBag(s, bag){
	var x;
    var returnString = "";
    // Search through string's characters one by one.
    // If character is not in bag, append to returnString.
    for (x = 0; x < s.length; x++){   
        var c = s.charAt(x);
        if (bag.indexOf(c) == -1) returnString += c;
    }
    return returnString;
}

function daysInFebruary (year){
	// February has 29 days in any year evenly divisible by four,
    // EXCEPT for centurial years which are not also divisible by 400.
    return (((year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0))) ? 29 : 28 );
}
function DaysArray(n) {
	for (var x = 1; x <= n; x++) {
		this[x] = 31
		if (x==4 || x==6 || x==9 || x==11) {this[x] = 30}
		if (x==2) {this[x] = 29}
   } 
   return this
}

function isDate(i,dtStr,strTitle){
	var daysInMonth = DaysArray(12)
	var pos1=dtStr.indexOf(dtCh)
	var pos2=dtStr.indexOf(dtCh,pos1+1)
	var strMonth=dtStr.substring(0,pos1)
	var strDay=dtStr.substring(pos1+1,pos2)
	var strYear=dtStr.substring(pos2+1)
	strYr=strYear
	
	if (strDay.charAt(0)=="0" && strDay.length>1) strDay=strDay.substring(1)
	if (strMonth.charAt(0)=="0" && strMonth.length>1) strMonth=strMonth.substring(1)
	for (var x = 1; x <= 3; x++) {
		if (strYr.charAt(0)=="0" && strYr.length>1) strYr=strYr.substring(1)
	}
	month=parseInt(strMonth)
	day=parseInt(strDay)
	year=parseInt(strYr)
	if (pos1==-1 || pos2==-1){
		strErrorMsg = strErrorMsg + '- ' + strTitle + ' (date must be in "mm/dd/yyyy" format)\n';
		failedValidation(i);		
		return false
	}
	if (strMonth.length<1 || month<1 || month>12){
		strErrorMsg = strErrorMsg + '- ' + strTitle + ' (must be a valid month)\n';
		failedValidation(i);	
		return false
	}
	if (strDay.length<1 || day<1 || day>31 || (month==2 && day>daysInFebruary(year)) || day > daysInMonth[month]){
		strErrorMsg = strErrorMsg + '- ' + strTitle + ' (must be a valid day)\n';
		failedValidation(i);	
		return false
	}
	if (strYear.length != 4 || year==0 || year<minYear || year>maxYear){
		strErrorMsg = strErrorMsg + '- ' + strTitle + ' (Please enter a valid 4 digit year between '+minYear+' and '+maxYear+')\n';
		failedValidation(i);		
		return false
	}
	if (dtStr.indexOf(dtCh,pos2+1)!=-1 || isInteger(stripCharsInBag(dtStr, dtCh))==false){
		strErrorMsg = strErrorMsg + '- ' + strTitle + ' (must be a valid date)\n';
		failedValidation(i);		
		return false
	}
return true
}


// ================================================================================

function failedValidation(i){
	//set background color for field that failed validation
	document.forms[formIndex].elements[i].style.backgroundColor = strInputErrorColor;
	//set focus variable for first error that form validation comes across
	if (intFocusElement == -1){
		intFocusElement = i;
	}
	return true;	
}

// Trim functions
function Trim(strValue) { return LTrim(RTrim(strValue)); } 
function LTrim(strValue){ var LTRIMrgExp = /^\s */; return strValue.replace(LTRIMrgExp, ''); } 
function RTrim(strValue){ var RTRIMrgExp = /\s *$/; return strValue.replace(RTRIMrgExp, ''); }


// make sure textarea does not exceed maximum length allowed
// pass function two variables:
// name = name of textarea (this.name)
// max = maximum length allowed
// example: <textarea name="notes" onkeyup="javascript:validateTextAreaLength(this.name,100);"></textarea>
function validateTextAreaLength(formIndexToValidate,name,max){
	if (document.forms[formIndexToValidate].elements[name].value.length > max){
		document.forms[formIndexToValidate].elements[name].value=document.forms[formIndexToValidate].elements[name].value.substring(0,max)
		alert('Please limit text to ' + max + ' characters!');
		document.forms[formIndexToValidate].elements[name].focus();
	}
}

function hasDangerousCharacters(str)
{
	var pattern1 = /[\{\}\(\)\`;=\|&\$%\"\\,\<\>\+]/;
	var pattern2 = /(%7[bB])|(%7[dD])|(%28)|(%29)|(%27)|(%3[bB])|(%3[dD)|(%7[cC])|(%26)|(%24)|(%25)|(%22)|(%2[bB])|(%2[cC])|(%5[cC])|(%3[cC])|(%3[eE])|(%0[dD])|(%0[aA])|(%00)/;
	
	if (str.search(pattern1) == -1)
	{
		if (str.search(pattern2) == -1)
		{
			return false;
		}
		else
		{
			return true;
		}
	}
	else
	{
		return true;
	}
}