//**************************************************
// Client-Side Form Validation
// Written by Sandy Small 7/1/2001
// Modified by Diana Ryan 8/17/01
//
// This script contains two basic types of form validation functions. 
//
// 1. The function which checks required fields (checkInput) is specific to the generic email form handler 
// "genericMailtoFormProc.asp". This function assumes that the form contains a hidden field indicating 
// which fields are required, and another hidden field for storing the order of form fields, to be passed to 
// the email program. The function is called when the form is submitted, and does not submit the form if it 
// finds required fields that are blank. It also will not allow the form to be submitted more than once.
//
// 2. There are several additional functions for checking specific types of string data, to ensure they are 
// formatted correctly. These functions may call reformatting functions, if the data is determined to be valid 
// but is not in the preferred format. These string checking/formatting functions are meant to be called via 
// onChange event handlers.
//
//**************************************************

//**************************************************
// GLOBAL VARIABLES
//**************************************************

// Form submission flag, user cannot submit more than once.
var formSubmitted = false;

// Characters to strip from input strings before form submission.
var badChars = " '";

var digits = "0123456789";

// Used by stripInitialWhitespace and stripTrailingWhitespace
var whitespace = " \t\n\r";

//**************************************************
// Global Variable:  defaultEmptyOK 
//
// Defines default return value 
// for many functions when they are passed the empty string. 
// By default, they will return defaultEmptyOK.
//
// defaultEmptyOK is false, which means that by default, 
// these functions will do "strict" validation.  Function
// isInteger, for example, will only return true if it is
// passed a string containing an integer; if it is passed
// the empty string, it will return false.
//
// You can change this default behavior globally (for all 
// functions which use defaultEmptyOK) by changing the value
// of defaultEmptyOK.
//
// Most of these functions have an optional argument emptyOK
// which allows you to override the default behavior for 
// the duration of a function call.
//
// This functionality is useful because it is possible to
// say "if the user puts anything in this field, it must
// be an integer (or a phone number, or a string, etc.), 
// but it's OK to leave the field empty too."
// This is the case for fields which are optional but which
// must have a certain kind of content if filled in.
//**************************************************

var defaultEmptyOK = false;

//**************************************************
// HELPER FUNCTIONS
//**************************************************

//**************************************************
// Function: isDigit
// Description: Returns true if character c is a digit (0 .. 9).
//**************************************************

function isDigit (c){   

	return ((c >= "0") && (c <= "9"))
	
}// end isDigit

//**************************************************
// Function: isInteger (STRING s [, BOOLEAN emptyOK])
// 
// Returns true if all characters in string s are numbers.
//
// Accepts non-signed integers only. Does not accept floating 
// point, exponential notation, etc.
//
// We don't use parseInt because that would accept a string
// with trailing non-numeric characters.
//
// By default, returns defaultEmptyOK if s is empty.
// There is an optional second argument called emptyOK.
// emptyOK is used to override for a single function call
//      the default behavior which is specified globally by
//      defaultEmptyOK.
// If emptyOK is false (or any value other than true), 
//      the function will return false if s is empty.
// If emptyOK is true, the function will return true if s is empty.
//
// EXAMPLE FUNCTION CALL:     RESULT:
// isInteger ("5")            true 
// isInteger ("")             defaultEmptyOK
// isInteger ("-5")           false
// isInteger ("", true)       true
// isInteger ("", false)      false
// isInteger ("5", false)     true
//**************************************************

function isInteger (s){   

	var i;

    if (isEmpty(s)) 
		if (isInteger.arguments.length == 1) 
			return defaultEmptyOK;
		else 
			return (isInteger.arguments[1] == true);

    // Search through string's characters one by one
    // until we find a non-numeric character.
    // When we do, return false; if we don't, return true.

    for (i = 0; i < s.length; i++){  
     
		// Check that current character is number.
        var c = s.charAt(i);

        if (!isDigit(c)) 
			return false;
    }

    // All characters are numbers.
    return true;
    
}// end isInteger

//**************************************************
// Function isPositiveInteger
//
// isPositiveInteger (STRING s [, BOOLEAN emptyOK])
// 
// Returns true if string s is an integer > 0.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//**************************************************

function isPositiveInteger (s){   

	var secondArg = defaultEmptyOK;

    if (isPositiveInteger.arguments.length > 1)
		secondArg = isPositiveInteger.arguments[1];

    // The next line is a bit byzantine.  What it means is:
    // a) s must be a signed integer, AND
    // b) one of the following must be true:
    //    i)  s is empty and we are supposed to return true for
    //        empty strings
    //    ii) this is a positive, not negative, number

    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s) > 0) ) );
         
}// end isPositiveInteger

//**************************************************
// Function isSignedInteger
// 
// isSignedInteger (STRING s [, BOOLEAN emptyOK])
// 
// Returns true if all characters are numbers; 
// first character is allowed to be + or - as well.
//
// Does not accept floating point, exponential notation, etc.
//
// We don't use parseInt because that would accept a string
// with trailing non-numeric characters.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//
// EXAMPLE FUNCTION CALL:          RESULT:
// isSignedInteger ("5")           true 
// isSignedInteger ("")            defaultEmptyOK
// isSignedInteger ("-5")          true
// isSignedInteger ("+5")          true
// isSignedInteger ("", false)     false
// isSignedInteger ("", true)      true
//**************************************************

function isSignedInteger (s){   

	if (isEmpty(s)) 
		if (isSignedInteger.arguments.length == 1) 
			return defaultEmptyOK;
		else 
			return (isSignedInteger.arguments[1] == true);

    else {
        var startPos = 0;
        var secondArg = defaultEmptyOK;

        if (isSignedInteger.arguments.length > 1)
            secondArg = isSignedInteger.arguments[1];

        // skip leading + or -
        if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") )
           startPos = 1;   
            
        return (isInteger(s.substring(startPos, s.length), secondArg))
    }
    
}// end isSignedInteger

//**************************************************
// Function: isEmpty
// Description: Check whether string s is empty.
// Helps: checkInput
//**************************************************

function isEmpty(s){   
	
	return ((s == null) || (s.length == 0))

}// end isEmpty

//**************************************************
// Function: split
// Description: split a string s with the delimiter 'del'
// Dependencies:  ProperCase is dependent on this function
//**************************************************
//
function split(s,del){
	arrS= new Array();
	var i=0;
	var j=0;
	var k=0;
	var delim=new String(del);

	//Is the delimeter in the string
	if(s.indexOf(delim)!=-1){
		for (i=0; i<s.length;i++){
			if(s.charAt(i)==delim){
				if(k==0){
					arrS[j]=s.substring(k,i);
				}else{
					arrS[j]=s.substring(k+1,i);
				}
				k=i;
				j++;
			}
		}
		arrS[j]=s.substring(k+1,s.length);
	}else{
		arrS[0]=s;
	}
	return arrS;
}


//**************************************************
// Function: properCase
// Description: Converts a string to a Title Case (Proper case) string.
// Dependencies:  Dependent on the split function above.
//**************************************************
//Converts string to ProperCase with spaces and hyphens
function properCase(s){
	var i;
	var returnString = "";
	var tmpS=s.toLowerCase();
	var arrS= new Array();
	var arrS2 = new Array();
	
	//search each word in array arrS
	arrS=split(tmpS," ");
	
	for (i = 0; i < arrS.length; i++){   
		var thisWord=arrS[i];
		//Check to see if word contains a hyphen
		if(thisWord.indexOf("-")!=-1){
			arrS2 = split(thisWord,"-");
			for(var j=0; j < arrS2.length; j++){
				var thisWord2=arrS2[j];
				returnString = returnString + thisWord2.charAt(0).toUpperCase() + thisWord2.substring(1,thisWord2.length)+"-";
				
			}
			returnString = returnString.substring(0,returnString.length-1)+" ";
		} else {
			returnString = returnString + thisWord.charAt(0).toUpperCase() + thisWord.substring(1,thisWord.length)+" ";
		}
	}
	returnString = returnString.substring(0,returnString.length-1);
	
	return returnString;
}


//**************************************************
// Function: isWhitespace
// Description: Check whether string s is empty or whitespace.
// Helps: checkInput
//**************************************************

function isWhitespace (s){   

	var i;

    // Is s empty?
    if (isEmpty(s)) return true;

    // Search through string's characters one by one
    // until we find a non-whitespace character.
    // When we do, return false; if we don't, return true.

    for (i = 0; i < s.length; i++){   
    
        // Check that current character isn't whitespace.
        var c = s.charAt(i);

        if (whitespace.indexOf(c) == -1) 
			return false;
    }

    // All characters are whitespace.
    return true;
    
}// end isWhitespace

//**************************************************
// Function: isUSPhoneNumber (STRING s [, BOOLEAN emptyOK])
// 
// isUSPhoneNumber returns true if string s is a valid U.S. Phone
// Number.  Must be 10 digits.
//
// NOTE: Strip out any delimiters (spaces, hyphens, parentheses, etc.)
// from string s before calling this function.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//**************************************************

function isUSPhoneNumber (s){   

	var digitsInUSPhoneNumber = 10;

	if (isEmpty(s)) {
		if (isUSPhoneNumber.arguments.length == 1) {
			return defaultEmptyOK;
		} else {
			return (isUSPhoneNumber.arguments[1] == true);
		}
	}
	// Check to see if there is an extension on the US number 
	if (s.indexOf("x") > -1) {
    return (true);
 //   return (isInternationalPhoneNumber (s));
	}
	
   return (isInteger(s) && s.length == digitsInUSPhoneNumber);
}// end isUSPhoneNumber

//**************************************************
// Function isInternationalPhoneNumber (STRING s [, BOOLEAN emptyOK])
// 
// isInternationalPhoneNumber returns true if string s is a valid 
// international phone number.  Must be digits only; any length OK.
// May be prefixed by + character.
//
// NOTE: A phone number of all zeros would not be accepted.
// I don't think that is a valid phone number anyway.
//
// NOTE: Strip out any delimiters (spaces, hyphens, parentheses, etc.)
// from string s before calling this function.  You may leave in 
// leading + character if you wish.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//**************************************************

function isInternationalPhoneNumber (s){
   
	if (isEmpty(s)) 
		if (isInternationalPhoneNumber.arguments.length == 1) 
			return defaultEmptyOK;
		else 
			return (isInternationalPhoneNumber.arguments[1] == true);
       
    return (isPositiveInteger(s))
}

//**************************************************
// isSSN (STRING s [, BOOLEAN emptyOK])
// 
// isSSN returns true if string s is a valid U.S. Social
// Security Number.  Must be 9 digits.
//
// NOTE: Strip out any delimiters (spaces, hyphens, etc.)
// from string s before calling this function.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//**************************************************

function isSSN (s){   

	var digitsInSocialSecurityNumber = 9;

	if (isEmpty(s)) 
		if (isSSN.arguments.length == 1) return defaultEmptyOK;
			else return (isSSN.arguments[1] == true);
			
    return (isInteger(s) && s.length == digitsInSocialSecurityNumber)
}

//**************************************************
// Function: isZIPCode (STRING s [, BOOLEAN emptyOK])
// 
// Description: isZIPCode returns true if string s is a valid 
// U.S. ZIP code.  Must be 5 or 9 digits only.
//
// NOTE: Strip out any delimiters (spaces, hyphens, etc.)
// from string s before calling this function.  
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//
// Helps: checkZipCode
//
//**************************************************

function isZIPCode (s){  

var digitsInZIPCode1 = 5
var digitsInZIPCode2 = 9

	if (isEmpty(s)) 
		if (isZIPCode.arguments.length == 1) 
			return defaultEmptyOK;
		else 
			return (isZIPCode.arguments[1] == true);
		
	return (isInteger(s) && 
           ((s.length == digitsInZIPCode1) ||
           (s.length == digitsInZIPCode2)))
}// end isZIPCode

//**************************************************
// Function: isCreditCard(st)
// 
// Description: Returns true if the credit card number
// passes the Luhn Mod-10 test. Otherwise returns false.
//
// Helps: checkCC
//**************************************************

function isCreditCard(st) {

	// Encoding only works on cards with less than 19 digits
	if (st.length > 19)
		return (false);

	sum = 0; mul = 1; l = st.length;
	
	for (i = 0; i < l; i++) {
		digit = st.substring(l-i-1,l-i);
		tproduct = parseInt(digit ,10)*mul;
		
		if (tproduct >= 10)
			sum += (tproduct % 10) + 1;
		else
			sum += tproduct;
			
		if (mul == 1)
			mul++;
		else
			mul--;
	}
  
// Uncomment the following line to help create credit card numbers
// 1. Create a dummy number with a 0 as the last digit
// 2. Examine the sum written out
// 3. Replace the last digit with the difference between the sum and
//    the next multiple of 10.

//  document.writeln("<BR>Sum      = ",sum,"<BR>");
//  alert("Sum      = " + sum);

	if ((sum % 10) == 0)
		return (true);
	else
		return (false);

} //end isCreditCard()

//**************************************************
// Function: stripCharsInBag
// Description: Removes all characters which appear in string bag from string s.
// Used by checkPhone
//**************************************************

function stripCharsInBag (s, bag){   

	var i;
    var returnString = "";

    // Search through string's characters one by one.
    // If character is not in bag, append to returnString.

    for (i = 0; i < s.length; i++){   
        
        // Check that current character isn't whitespace.
        var c = s.charAt(i);
        if (bag.indexOf(c) == -1) returnString += c;
    }

    return returnString;
    
}// end stripCharsInBag

//**************************************************
// Function: stripInitialWhitespace
// Description: Removes initial (leading) whitespace characters from s.
// Global variable whitespace (see above) defines which characters are considered whitespace.
//**************************************************

function stripInitialWhitespace (s){   

	var x = 0;

    while ((x < s.length) && charInString (s.charAt(x), whitespace))
		x++;
    
    return s.substring (x, s.length);
    
}//end stripInitialWhitespace

//**************************************************
// Function: stripTrailingWhitespace
// Description: Removes trailing whitespace characters from s.
// Global variable whitespace defines which characters are considered whitespace.
//**************************************************

function stripTrailingWhitespace (s){   

	var y = s.length-1;

    while ((y > 0) && charInString (s.charAt(y), whitespace)){
		y--;
    }
    
    return s.substring (0, y+1);
    
}//end stripTrailingWhitespace

//**************************************************
// Function: stripSingleQuotes
// Description: Removes single quotes from s.
//**************************************************

function stripSingleQuotes (s){   

	var a = s.split("'");
    var b = a.join("`"); // try &acute;
    
    return b;
    
}//stripSingleQuotes

//**************************************************
// Function: charInString
// Description:
// WORKAROUND FUNCTION FOR NAVIGATOR 2.0.2 COMPATIBILITY.
//
// The below function *should* be unnecessary.  In general,
// avoid using it.  Use the standard method indexOf instead.
//
// However, because of an apparent bug in indexOf on 
// Navigator 2.0.2, the below loop does not work as the
// body of stripInitialWhitespace:
//
// while ((i < s.length) && (whitespace.indexOf(s.charAt(i)) != -1))
//   i++;
//
// ... so we provide this workaround function charInString
// instead.
//
// charInString (CHARACTER c, STRING s)
//
// Returns true if single character c (actually a string)
// is contained within string s.
//**************************************************

function charInString (c, s){   

	for (i = 0; i < s.length; i++){   
		if (s.charAt(i) == c) 
			return true;
    }
    
    return false
    
}// end charInString

//**************************************************
// Function: reformat
//
// reformat (TARGETSTRING, STRING, INTEGER, STRING, INTEGER ... )       
//
// Handy function for arbitrarily inserting formatting characters
// or delimiters of various kinds within TARGETSTRING.
//
// reformat takes one named argument, a string s, and any number
// of other arguments.  The other arguments must be integers or
// strings.  These other arguments specify how string s is to be
// reformatted and how and where other strings are to be inserted
// into it.
//
// reformat processes the other arguments in order one by one.
// * If the argument is an integer, reformat appends that number 
//   of sequential characters from s to the resultString.
// * If the argument is a string, reformat appends the string
//   to the resultString.
//
// NOTE: The first argument after TARGETSTRING must be a string.
// (It can be empty.)  The second argument must be an integer.
// Thereafter, integers and strings must alternate.  This is to
// provide backward compatibility to Navigator 2.0.2 JavaScript
// by avoiding use of the typeof operator.
//
// It is the caller's responsibility to make sure that we do not
// try to copy more characters from s than s.length.
//
// EXAMPLES:
//
// * To reformat a 10-digit U.S. phone number from "1234567890"
//   to "(123) 456-7890" make this function call:
//   reformat("1234567890", "(", 3, ") ", 3, "-", 4)
//
// * To reformat a 9-digit U.S. Social Security number from
//   "123456789" to "123-45-6789" make this function call:
//   reformat("123456789", "", 3, "-", 2, "-", 4)
//
// HINT:
//
// If you have a string which is already delimited in one way
// (example: a phone number delimited with spaces as "123 456 7890")
// and you want to delimit it in another way using function reformat,
// call function stripCharsNotInBag to remove the unwanted 
// characters, THEN call function reformat to delimit as desired.
//
// EXAMPLE:
//
// reformat (stripCharsNotInBag ("123 456 7890", digits),
//           "(", 3, ") ", 3, "-", 4)
//**************************************************

function reformat (s, blank, area, dash1, lead, dash2, end){   

	var arg;
    var sPos = 0;
    var resultString = "";

    for (var i = 1; i < reformat.arguments.length; i++) {
		arg = reformat.arguments[i];
       
		if (i % 2 == 1) 
			resultString += arg;
		else {
			resultString += s.substring(sPos, sPos + arg);
			sPos += arg;
		}
    }
    
    return resultString;
}

//**************************************************
// Function reformatUSPhone
// takes USPhone, a string of 10 digits
// and reformats as (123) 456-789
//**************************************************

function reformatUSPhone (USPhone){   

	return (reformat(USPhone, "", 3, "-", 3, "-", 4));
}

//**************************************************
// Function: reformatZIPCode
//
// Description: Takes ZIPString, a string of 5 or 9 digits;
// if 9 digits, inserts separator hyphen
//**************************************************

function reformatZIPCode (ZIPString){   

	if (ZIPString.length == 5) 
		return ZIPString;
		
    else 
		return (reformat (ZIPString, "", 5, "-", 4));
		
}// end reformatZIPCode

//**************************************************
// takes SSN, a string of 9 digits
// and reformats as 123-45-6789
//**************************************************

function reformatSSN (SSN){   

	return (reformat (SSN, "", 3, "-", 2, "-", 4))
}

//**************************************************
// Function: cleanString
// Description: Remove leading/trailing 
// spaces, before onChange validation. (email)
//**************************************************

function cleanString (fieldVal){   

	var tempString = fieldVal;
	
	tempString = stripInitialWhitespace(tempString);
	tempString = stripTrailingWhitespace(tempString);
	
	return tempString;
    
}//end cleanString

//**************************************************
// STRING FORMATTING FUNCTIONS (onChange)
//**************************************************

//**Note** I have commented out all of the element-select
// functions (which were used in conjunction with the element-focus
// when data was not in valid format) because of browser issues.
// IE5.5 does not do the select (no highlight), and btw focuses on the wrong field
// N6 selects the correct field but focuses on the wrong field - usability problem
// N4.7 actually does both correctly, but that is not a browser we would encourage
// users to use.

//*************************************************************** Begin Check Functions *****************
// Function: checkCC(formObj, fieldname, fieldVal)
//
// Description: Checks to see if the card number entered
// is a valid credit card number. If not, user is prompted
// to try again.
//
//**************************************************

function checkCC(formObj, fieldname, fieldVal){

	var f = formObj;	
	var CCDelimiters = " "	
		
	//card number may contain spaces
	var normalizedCC = stripCharsInBag(fieldVal, CCDelimiters)
	
	if(isCreditCard(normalizedCC))
		return true;
	else{
	
		alert('Please enter a valid credit card number.');
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
		return false;
	}

}// end checkCC

//**************************************************
// Function: checkDate(formObj, fieldname, fieldVal, isUSDate)
//
// Description: Checks to see if the date is a valid date.
// If not, user is prompted to try again.
//
// Checks for the following valid date format: 
// MM/DD/YY or MM/DD/YYYY  
// Also separates date into month, day, and year variables
//
// Checks for foreign date format if isUSDate is passed to 
// the function as false or the country is 'usa'.
//**************************************************

function checkDate(formObj, fieldname, fieldVal) {
  
	var f = formObj;	
  
	/*
	^^^^ Information about this string ^^^^
	Ignore first and last '/' it is code for RegExp
	Anything between () will be matched and remembered for later use
	^ matches first input
	$ matches last input
	\ means that the next char after the '\' has a special meaning
	\2 means same thing as second operation in this case its : (\/|-)
	d means digit, it matches a number from 0 to 9
	{n,m] = matches at least N and at most M occurences. N & M are assumed to be positive
	*/	
	
	// MM/DD/YYYY
	// var datePat = /^(\d{1,2})(\/)(\d{1,2})\2(\d{4})$/;
	// MM/DD/YY or MM/DD/YYYY
	var datePat = /^(\d{1,2})(\/)(\d{1,2})\2(\d{2,4})$/;
	
	// is the format ok?
	var matchArray = fieldVal.match(datePat); 
	
	if (matchArray == null) {	
		alert("The "+fieldname+" is not in a valid format.\nPlease enter it in MM/DD/YY or MM/DD/YYYY format");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
		return false;
	}
  
	// The date format is correct. Now make sure that it is a valid date. Some forms use
	// true in isUSDate to determine the format. The correct method is to check to see if the
	// value of the country field is "USA" which all forms should default as.
	// Parse the date into the appropriate variables based on US or foreign format
//	if((isUSDate.toString().toLowerCase() == "usa") || (isUSDate.toString() == "") || (isUSDate == "") || (isUSDate)) {
		// US date format MM/DD/YY
		month = matchArray[1];	// Month
		day = matchArray[3];	// Day
		year = matchArray[4];	// Year
//	} else {
		// Foreign date format DD/MM/YY
//		day = matchArray[1];	// Day
//		month = matchArray[3];	// Month
//		year = matchArray[4];	// Year
//	}
	
	//  alert("Month="+month+", Day="+day+", Year="+ year);
	
	if (month < 1 || month > 12) {  // check month range  
		alert("The month must be between 1 and 12.");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
		return false;
	}
  
	// check day range for months with 31 days
	if (day < 1 || day > 31) { 
		alert("The day must be between 1 and 31.");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
		return false;
	}
  
	// check day range for months with 30 days
	if ((month==4 || month==6 || month==9 || month==11) && day==31) { 
		alert("The month "+month+" doesn't have 31 days!");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
		return false
	}
  
	// check for February 29th 
	if (month == 2) { 
		var isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
		if (day>29 || (day==29 && !isleap)) {
			alert("February " + year + " doesn't have " + day + " days!");
			f.elements[fieldname].focus();
			//f.elements[fieldname].select();
			return false;
		}
	}
} // end checkDate

//**************************************************
// Function: checkCCDate(formObj, fieldname, fieldVal)
//
// Description: Checks to see if the Credit Card epiration 
// date is a valid date.
// If not, user is prompted to try again.
//
// Checks for the following valid date format: 
// MM/YY or MM/YYYY  
// Also separates date into month, day, and year variables
//
// Checks for foreign date format if isUSDate is passed to 
// the function as false or the country is 'usa'.
//**************************************************

function checkCCDate(formObj, fieldname, fieldVal) {
  
	var f = formObj;	
  
	/*
	^^^^ Information about this string ^^^^
	Ignore first and last '/' it is code for RegExp
	Anything between () will be matched and remembered for later use
	^ matches first input
	$ matches last input
	\ means that the next char after the '\' has a special meaning
	\2 means same thing as second operation in this case its : (\/|-)
	d means digit, it matches a number from 0 to 9
	{n,m] = matches at least N and at most M occurences. N & M are assumed to be positive
	*/	
	
	// MM/DD/YYYY
	// var datePat = /^(\d{1,2})(\/)(\d{1,2})\2(\d{4})$/;
	// MM/DD/YY or MM/DD/YYYY
	//var datePat = /^(\d{1,2})(\/)(\d{1,2})\2(\d{2,4})$/;
	// MM/YY or MM/YYYY
	var datePat = /^(\d{1,2})(\/)(\d{2,4})$/;
	
	// is the format ok?
	var matchArray = fieldVal.match(datePat); 
	
	if (matchArray == null) {	
		alert("The "+fieldname+" is not in a valid format.\nPlease enter it in MM/YY or MM/YYYY format");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
		return false;
	}
  
	// The date format is correct. Now make sure that it is a valid date.
		// US date format MM/YY or MM/YYYY
		month = matchArray[1];	// Month
		year = matchArray[3];	// Year	
	
	if (month < 1 || month > 12) {  // check month range  
		alert("The month must be between 1 and 12.");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
		return false;
	}
	
	// Set the day to the last day of the entered month
	var day = 31; 
	var isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
	if (month==4 || month==6 || month==9 || month==11) {
		day = 30; 
	} else if (month == 2 && !isleap) {
		day = 28; 
	} else if (month == 2 && isleap) {
		day = 29;
	}
	//alert("Month="+month+", Day="+day+", Year="+ year);
	  
	// Check that the expiration date is in the future, for CC expiration.
	var today = new Date();
	if (year < 2000) { year = parseInt(year) + 2000; }
	var expDate = new Date(month+"/"+day+"/"+year);
	//alert("today="+today +", expDate="+expDate);
		
	if (expDate < today)  {	
		alert("The "+fieldname+" is not valid, as it is expired.\nPlease recheck and enter it in MM/YY or MM/YYYY format");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
		return false;
	} else {
		f.elements[fieldname].value = month+"/"+day+"/"+year;
	}
	
} // end checkCCDate

//**************************************************
// Function: checkTime(formObj, fieldname, fieldVal)
//
// Description: Check to make sure the user has entered a valid time format
// of HH:MM:SS AM/PM format. The seconds and AM/PM are optional. If not 
// valid, the user is prompted to try again.
//
//**************************************************

function checkTime(formObj, fieldname, fieldVal) {
	
	var f = formObj;		

	//var timePat = /^(\d{1,2})(:)(\d{2})(\2(\d{1,2}))?$/;
	// Use this to include seconds. am or pm is not in 6 instead of 4
	// # of seconds in 4
	// s sign (seconds) in 5
	
	var timePat = /^(\d{1,2}):(\d{2})(:(\d{2}))?(\s?(AM|am|PM|pm))?$/;
	var matchArray = fieldVal.match(timePat);
	
	if (matchArray == null) {
		alert("The "+fieldname+" is not in a valid format.\nPlease enter it in HH:MM am (or pm) or HH:MM:SS am (or pm) format.");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
		return false;
	}
	
	hour = matchArray[1];
	minute = matchArray[2];
	second = matchArray[4];

	// If the seconds were not entered, make them 00
	if (second=="") { second = null; }
	
	// Check to make sure the hour is between 0 and 23 (for military time)
	if (hour < 0  || hour > 23) {
		alert("The "+fieldname+" is not in a valid format.\nThe hour value must be between 1 and 23.");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
		return false;
	 }

	// Check to make sure the minutes are between 0 and 59
	if (minute < 0 || minute > 59) {
		alert("The "+fieldname+" is not in a valid format.\nThe minute value must be between 0 and 59.");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
		return false;
	}

	// Check to make sure the seconds are between 0 and 59
	if (second != null && (second < 0 || second > 59)) {
		alert("The "+fieldname+" is not in a valid format.\nThe optional second value must be between 0 and 59.");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
		return false;
	}

	// If the seconds were not entered, make them 00
	if (second==null) { fieldVal += ":00"; }
	
	// The time is valid
	return true;
	
} // end checkTime

//**************************************************
// checkZipCode (formObj, fieldname, fieldVal)
//
// Check that string fieldVal is a valid ZIP code.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//**************************************************

function checkZipCode (formObj, fieldname, fieldVal){   

	var f = formObj;	
	
	var ZIPCodeDelimiters = "- "
	var normalizedZIP = stripCharsInBag(fieldVal, ZIPCodeDelimiters)
	
	if (!isZIPCode(normalizedZIP, false)){
		alert("'"+fieldVal+"' is not a valid Zip Code. Please re-enter.");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
	}
	else{  // if you don't want to insert a hyphen, comment next line out
		f.elements[fieldname].value = reformatZIPCode(normalizedZIP)
		return true;
	}
}// end checkZipCode

//**************************************************
// Function: checkEmail
//
// Description: onChange event handler to check for valid e-mail format
// If not valid, prompts user to try again.
//
//**************************************************

function checkEmail(formObj, fieldname, fieldVal) {

	var f = formObj;
	
	f.elements[fieldname].value = cleanString(fieldVal);
	fieldVal = f.elements[fieldname].value;
	
	// Use the regular expression to determine correct characters
	var goodEmail = fieldVal.match(/\b(^(\S+@).+((\.com)|(\.net)|(\.edu)|(\.mil)|(\.gov)|(\.org)|(\..{2,2}))$)\b/gi);

	if(!goodEmail) {
		alert("'"+fieldVal+"' is not a valid email address. Please re-enter.");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
	} 
	
} // end checkEmail

//**************************************************
// Function: checkPhone
// Description: onChange event handler to check for 
// valid US or International Phone format.
//
// Checks for international format if isUS is passed to 
// the function as false or the country is not 'usa'.
//**************************************************

//function checkPhone (formObj, fieldname, fieldVal) {  
function checkPhone (formObj, fieldname, fieldVal, country) {  

	//var country = "usa";
	var f = formObj;	
	
	var phoneNumberDelimiters = "()- et";
	var normalizedPhone = stripCharsInBag(fieldVal, phoneNumberDelimiters)
  
  //alert("normalizedPhone="+normalizedPhone+", index="+normalizedPhone.indexOf("x"));
	// Check to see if the value of the incoming 'country' parameter is "USA",
	// which all forms should default to. Otherwise if no country parameter is
	// sent, assume US phone format, and parse appropriately.
	if((country.toString().toLowerCase() == "usa") || (country.toString() == "")) {
		// US Phone
		if (!isUSPhoneNumber(normalizedPhone, false)) {
			alert("The "+fieldname+" is not in a valid format.\nPlease enter it in 999-999-9999 or 999-999-999 x99 format.");
			f.elements[fieldname].focus();
			//f.elements[fieldname].select();
			return false;
		} else {  
			if (normalizedPhone.indexOf("x") > -1) {
				f.elements[fieldname].value = reformat(stripCharsInBag(normalizedPhone, "x"), "", 3, "-", 3, "-", 4, " x", 5)
			} else {
				// if you don't want to reformat as 123-456-789, comment next line out
				f.elements[fieldname].value = reformatUSPhone(normalizedPhone)
			}
			return true;
		}
		
	} else {
		// Foreign Phone		
		if (!isInternationalPhoneNumber(normalizedPhone, false)) {
			alert("The "+fieldname+" is not valid.\nPlease enter it in the appropriate format.");
			f.elements[fieldname].focus();
			//f.elements[fieldname].select();
			return false;
		}	
	}
	
} // end checkPhone

//**************************************************
// Function checkIntlPhone
// Check that string fieldVal is a valid International Phone.
//**************************************************

function checkIntlPhone (formObj, fieldname, fieldVal) {  

	var f = formObj;	
	
	var phoneNumberDelimiters = "()- ";
	var normalizedPhone = stripCharsInBag(fieldVal, phoneNumberDelimiters)
	
	if (!isInternationalPhoneNumber(normalizedPhone, false)) {
		alert("The "+fieldname+" is not valid.\nPlease enter it in the appropriate format.");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
		return false;
	} 
  
} // end checkIntlPhone

//**************************************************
// Check that string fieldVal is a valid SSN.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//**************************************************

function checkSSN (formObj, fieldname, fieldVal){   

	var f = formObj;

	var SSNDelimiters = "- ";
    var normalizedSSN = stripCharsInBag(fieldVal, SSNDelimiters)
    
	if (!isSSN(normalizedSSN, false)){ 
		alert("'"+fieldVal+"' is not a valid Social Security Number. Please \nre-enter using 9 digits or in the form NNN-NN-NNNN.");
		f.elements[fieldname].focus();
		//f.elements[fieldname].select();
		return false;
	}
	else {  // if you don't want to reformats as 123-456-7890, comment next line out
		f.elements[fieldname].value = reformatSSN(normalizedSSN)
		return true;
    }
}

//**************************************************
// FORM VALIDATION FUNCTIONS (onSubmit)
//**************************************************

//**************************************************
// Function: checkInput
// Description: Saves field order in pipe(|) delimited string, in hidden field for generic email form handler.
// Checks required fields to ensure they are not empty or null.
//**************************************************

function checkInput(formObj) {

	//formSubmitted is a global variable, initially set to false
	if(formSubmitted == true){
		//alert('Your form has been submitted. Please be patient.');
		return false;
	}
	
	var f = formObj;
	var formOK = true;	
		
	// Gathers the names of all the fields on the submitting form in a pipe (|) delimited string,
	// so that the field names can be displayed in the same order and grouped by sections,
	// the same manner as on the form in the email body which is created by the
	// generic mailto form handler [genericMailtoFormProc.asp]. Duplicate field names
	// are not saved (as in the case of a required group of checkboxes, etc.).
	var strFields = "";
	
	for (i=0; i < f.length; i++) {
	
		//Convert singe quotes in text fields to back-quotes
		if( (f.elements[i].type == "text") || (f.elements[i].type == "textarea") ){
		
			var v = f.elements[i].value;
			var a = v.split("'");
			var b = a.join("`");
			f.elements[i].value = b;
		}
	
		if (((f.elements[i].type != "hidden") || (f.elements[i].name.indexOf("**") > -1))
			&& (strFields.indexOf(f.elements[i].name) == -1)) {
			
			// Add the next field name to the string only if it is not hidden or not a 
			// section header (i.e. contains "**"
			strFields = strFields + f.elements[i].name + "|";
		}
	}
	// Remove the trailing pipe (|) and save the string in a hidden field
	strFields = strFields.substr(0,strFields.length-1);
	f.fieldorder.value = strFields;
	//---------------------------------------------------

	// If there are required fields, convert comma-delimited string of required field names to array.
	if (f.required.value != "") {

		var requiredFields = f.required.value.split(",");
	
		// Check required fields based on input type
		var oneChecked = false;
		for (i=0; i<requiredFields.length; i++){

			//check arrays of radio buttons or checkboxes
			if(  (f.elements[requiredFields[i]]) &&  (f.elements[requiredFields[i]].length > 0)  ){

				var ft = f.elements[requiredFields[i]][0].type;
				
				if(ft == "checkbox"){
				
					oneChecked = false;
				
					for (j=0; j< f.elements[requiredFields[i]].length; j++) {
					
						if (f.elements[requiredFields[i]][j].checked) { oneChecked = true; }
					}
					if (!oneChecked){
					
						alert("Please select at least one of the " + requiredFields[i] + " checkboxes.");
						f.elements[requiredFields[i]][0].focus();
						formOK = false;
						break;
					}
				}
				else if(ft == "radio"){
				
					oneChecked = false;
					
					for (j=0; j< f.elements[requiredFields[i]].length; j++){
					
						if (f.elements[requiredFields[i]][j].checked) { oneChecked = true; }
						
					}
					if (!oneChecked){
					
						alert("Please select one of the " + requiredFields[i] + " radio buttons.");
						f.elements[requiredFields[i]][0].focus();
						formOK = false;
						break;
					}
				}
				else{
				
					//select type is recognized as an array, but the type is not at the array element level
					ft = f.elements[requiredFields[i]].type; 
					
					//the select element is considered empty if the first (0th) element is selected, 
					//or if the value of the selected element is blank.
					if( (ft == "select-one")||(ft == "select-multiple") ){
						var si = f.elements[requiredFields[i]].selectedIndex;
				
						if ( (si == 0) || (f.elements[requiredFields[i]].options[si].value == "") ){
						     
							alert("Please enter a valid value for the " + requiredFields[i] + ".");
							f.elements[requiredFields[i]].focus();
							formOK = false;
							break;
						}
					}
				}
			}
			//check text/textarea fields & ungrouped required checkboxes
			else{
			
				var ft = f.elements[requiredFields[i]].type;
				var fn = f.elements[requiredFields[i]].name;
				var fv = f.elements[requiredFields[i]].value;
	
				if( (ft == "text")||(ft == "textarea") ){
				
					if( (isEmpty(fv)) || (isWhitespace(fv)) ){
					
						alert("Please enter a valid value for the " + requiredFields[i] + ".");
						f.elements[requiredFields[i]].focus();
						formOK = false;
						break;
					}
				}
				else if(ft == "checkbox"){
				
					if (!(f.elements[requiredFields[i]].checked)) {
						alert("The " + requiredFields[i] + " checkbox is required.");
						f.elements[requiredFields[i]].focus();
						formOK = false;
						break;
					}
				}
				
			}//end else	
		}//end for
	}//end if required
	
	// ********** Global code to check resubmit needs to be added
	// All required fields validated, so check to see if the form 
	// has already been submitted, and then submit the form
	
	if(formOK){
		formSubmitted = true;
		return true;
	}
	else
		return false;
	
} // end checkInput

//**************************************************
// Function: checkForAlphas
// Description: Removes all characters which appear in string bag from string s.
// Used by checkPhone
//**************************************************

function checkForAlphas (obj){   
	//rjp added var to reference for form validation.
	var sAlphabet = "abcdefghiklmnopqrstuvwxyzABCDEFGHIKLMNOPQRSTUVWXYZ"
	var i;
	var s = obj.value;

    // Search through string's characters one by one.
    // If one of the characters is an alpha then throw error.

    for (i = 0; i < s.length; i++){   
        
        // Check that current character isn't whitespace.
        var c = s.charAt(i);
        if (sAlphabet.indexOf(c) > -1) {
			alert("The " + obj.name + " can not include alphabetic characters.");
			obj.focus();
			formOK = false;
			break;
        }
    }

}// end checkForAlphas

