/* **************************************************************************************

validate_form.js 

SUMMARY 

This is a collection of functions to be used to provide client-side
validation of fields submitted to applications on the B2B Portal 

Parameters:
required - boolean value to indicate if the field must contain a value
fieldLabel - friendly name of the field to be used when building error messages
formField - DOM reference to a field in the form.  ex: myForm.firstName
s - a string
c - a 1 character string

The following functions return a string containing any error messages.  
If the string is blank or consists entirely of whitespace, then the 
field passed validation.  Use the function isblank() to see if the 
returned string contains an error message.

function validEmail (formField, fieldLabel, required)
function validEmailAdmin (formField, formFieldconf, smAdminNumber, fieldLabel,required)
function validName(formField,fieldLabel, required)
function (formField,fieldLabel, required)
function (formField, fieldLabel, required)
function validZip(formField, fieldLabel, required)
function validUserID(formField, fieldLabel, required)
function validPassword(formField, fieldLabel, required)
function validChallengeAnswer(formField, fieldLabel, required)
function validPasswordHint(hintField, passField, hintLabel, passLabel, required)
function validDropDown(formField, fieldLabel, required)
function validPhoneExtension(formField, fieldLabel, required)
function validPhone (areaCodeFormField, prefixFormField, suffixFormField, fieldLabel, required)
	In addition to the parameters described above, this takes additional parameters
	for forms in which the area code, suffix, and prefix are captured in separate fields
	
function validPasswordVerify(passField, passVerifyField, passVerifyFieldLabel)
	checks to see that two password fields match 
	(for confirming password choice)

	passField - DOM reference to the password field (es: myForm.password)
	passVerifyField - DOM reference to the password verification field (ex: myForm.passVerify)
	passVerifyFieldLabel - friendly name of the password verification field
	use for building error messages.
	
function isblank(s)
	Returns true if the string "s" consists only of whitespace or is blank.

Here is an example of how to use the User ID validation function (this code should be
included in the HTML of the page containing the form).

	//verify the user ID
	var newIDError = validUserID(theForm.newID,"ID", true);
	if (! isblank(newIDError))
	{
		alert(newIDError);
		return false;
	}
		
/* *********************************************************************************** */
/*Still + and ,!#$~%=|?{} sign needs to be filtered */
/* ************* GLOBAL VARIABLES ****************
*********************************************** */
var forbiddenCharsList = "()[]<>*&^\";:\\";
var forbiddenCharsUserEmail = "()[]<>*&%^\/:\\!#$%*+=|;,?~{}";
var forbiddenCharsFilter = /[\<\>\(\)\[\]\:\;\"\&\\\*\^]/
var forbiddenCharsPasswordFilter = /[\<\>\(\)\[\]\:\;\"\&\\\*\$\#\|\~\!\/\^]/
var forbiddenUserEmail = /[\<\>\,\!\#\$\~\%\=\|\+\?\{\}\(\)\[\]\:\/\;\"\&\\\*\^]/
var userIDMinLen = 7;
var userIDMaxLen = 64;
var passMinLen = 8;
//var passMaxLen = 16
var passMaxLen = 32


/* ************* HELPER FUNCTIONS ****************
************************************************ */
//returns false if more than half of its characters are repeating
//ex: 'aaaaas', 'als3333', and 'lkjrrrrrl' return false
//while 'Password1', 'StrongPasss', or 'Abc1111z' return true
function checkRepeatChars(pass)
{
	//var maxRepeatChars = Math.round(pass.length/2);
	var maxRepeatChars = 3;
	var passLen = pass.length;
	var currChar;				//current character
	var prevChar;				//last character checked
	var numRepeats;			//num times current character is repeated
	
	for (var counter=0; counter<passLen; counter++)
	{
		currChar = pass.charAt(counter);
		if (currChar == prevChar)
		{
			numRepeats++;
			if (numRepeats > maxRepeatChars)
			{
				return false;
			}

		} else {
			numRepeats = 1;	
		}
		

		prevChar = currChar;

	}
	return true;
}

//portions of the user ID > half of the length of the password cannot 
//appear in the user's password
function checkIDSubstrings(pass, id)
{
	var substrLen = Math.round(pass.length/2);	//maximum allowed substring length
	var passLen = pass.length;				//length of user's password
	var idLen = id.length;					//length of user's ID
	var currSubstr;						//current user id substring
	var numChecks = idLen - substrLen;			//number of substrings to look for
	var lBound = 0;						//start creating substrings from index 0
	var uBound = lBound + substrLen;			//set end point
	
	//if the total len of the ID is less than the maximum allowed substring
	//return true since portions of the ID can never exceed the max allowed substring
	if (substrLen > idLen) return true;
	
	for (var counter=0; counter<=numChecks; counter++)
	{
		currSubstr = id.substring(lBound, uBound);	//grab a substring

		if (pass.indexOf(currSubstr) >= 0)			//see if the substring exists in the password
		{
			//alert('substring matched');
			return false;
		}

		lBound ++;	//increment bounds for next substring
		uBound ++;

	}

	return true;
}


//this function returns true of the string contains only whitespace
function isblank(s)
{
    for(var i = 0; i < s.length; i++) {
        var c = s.charAt(i);
        if ((c != ' ') && (c != '\n') && (c != '\t')) return false;
    }
    return true;
}

//returns true of the character c is found in the string s
function isInString(c, s)
{

	for(var i=0;i<s.length; i++) 
	{
		//alert('evaluating ' + c + ' against ' + s.charAt(i));
	
		if (c==s.charAt(i))
		{
			return true;
		}
	
	}
	
	return false;
}


function isLetter (c) 
{   return ( ((c >= "a") && (c <= "z")) || ((c >= "A") && (c <= "Z")) ) 
} 


// Returns true if character c is a digit 
// (0 .. 9). 
function isDigit (c) 
{   return ((c >= "0") && (c <= "9")) 
} 


// Returns true if character c is a letter or digit. 
function isLetterOrDigit (c) 
{   return (isLetter(c) || isDigit(c)) 
} 


//this function returns true if the string is letters and numbers only
function isAlphanumeric (s) 
{   
	var i; 
    
    // Search through string's characters one by one 
    // until we find a non-alphanumeric 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 or letter. 
        var c = s.charAt(i); 
        if (! (isLetter(c) || isDigit(c) ) ) 
        return false; 
    } 
    // All characters are numbers or letters. 
    return true; 
} 


//this function returns true if the string has atleast one alpha character
function isNotatLeastOneAlpha (s) 
{   
	var i; 
    
    // Search through string's characters one by one 
    // until we find at least one alpha character. 
    // When we do, return false; if we don't, return true. 
    for (i = 0; i < s.length; i++) 
    {   
        // Check that current character is a alpha character. 
        var c = s.charAt(i); 
        if  (isLetter(c)) 
        return false; 
    } 
    // not even one alpha. 
    return true; 
} 

//this function returns true of the string s is an unsigned integer
function isInteger (s) 
{   
	var i; 
 
    // 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; 
} 

//returns true if character c is whitespace
function isWhitespace(c) 
{
	var whitespace = " \t\n\r"; 
	
	if (whitespace.indexOf(c) == -1) return false; 
	
	return true;
}




/* **************FIELD VALIDATION FUNCTIONS *****************
********************************************************** */

//checks proper format (user@subdomain.domain.com or user@domain.com) and
//forbidden characters list

function validEmailAdmin (formField, formFieldconf, smAdminNumber, fieldLabel, required) {

	var error="";
	var strng = formField.value;
	var strngC = formFieldconf.value;
	var strAdminnum = smAdminNumber.value;
	
	
	
	if (strAdminnum.length != 0) {
		
		
		if (strAdminnum != "YES") {
		
		if (isblank(strng) || isblank(strngC)) {					
			if (required) error = error + "Please provide a valid email address.";
			//Please enter a value for the " + fieldLabel + " field.";			
			}		
		else
		{			
			if (strng != strngC){
									
				if (required) error = error + "Please re-type your email address for verification.";
			}
		}										
	}			
	}
	return error;  
}
		
function validEmail (formField, fieldLabel, required) {

	var error="";
	var strng = formField.value;
	//var emailFilter=/^.+@.+\..{2,3}$/;

	//Modified strict Email checking for  R10962
	var emailFilter=/^[a-z0-9]([.'a-z0-9_\-]*)@([.'a-z0-9_\-]*)(\.[a-z]{2,3}(\.[a-z]{2}){0,2})$/i;


//The email field can be blank. this change is done to accomidate the user
//who do not have an email id.

	/*if (isblank(strng)) 
	{
		if (required) error = error + " Please enter a value for the " + fieldLabel + " field.";
	}
	else*/
if (! isblank(strng)) 
{
if (!(emailFilter.test(strng))) error = error + "Enter your Email Address using only letters, numbers, periods, underscores, 1 @ sign, Hyphen, and your internet provider after the @";			
		 else if (strng.match(forbiddenUserEmail)) error = error + "Enter your Email Address using only letters, numbers, periods, underscores, 1 @ sign, Hyphen, and your internet provider after the @";							
		 else						
			for (cnt=0;cnt<strng.length;cnt++)							
				if ((strng.substring(cnt+1,cnt-1) == "..") & (error.length == 0))				
						error = error + "Enter your Email Address using only letters, numbers, periods, underscores, 1 @ sign, Hyphen, and your internet provider after the @"; 			 																	 
				else if ((strng.substring(cnt+1,cnt-1) == ".@") & (error.length == 0))					
						error = error + "Enter your Email Address using only letters, numbers, periods, underscores, 1 @ sign, Hyphen, and your internet provider after the @";
				else if ((strng.substring(cnt+1,cnt-1) == "@.") & (error.length == 0))				
						error = error + "Enter your Email Address using only letters, numbers, periods, underscores, 1 @ sign, Hyphen, and your internet provider after the @";
		}
	return error;   
}

// allows Alpha, hyphen, period, whitespace, apostrophe
function validName(formField,fieldLabel, required)
{
	var error="";
	var filter = /[^a-zA-Z\'\-\.\s]/;
	var strng = formField.value;

	if (isblank(strng))
	{
		if (required) error = error + ' Please enter a value for the ' + fieldLabel +' field.';
	}
	else if (filter.test(strng)) error = error + " The " + fieldLabel + " can only contain letters, hyphens, periods, spaces, and apostrophes.  ";
	
	return error;
}

//Allows Alphanumeric, whitespace, period, number sign, slash, hyphen
function validAddress(addressField1, addressField2, fieldLabel, required)
{
	var address1 = addressField1.value;
	var address2 = addressField2.value;
	var error = "";

	//var filter = /[^\w\s\.\#\/\-]/;
	var filter = /[^\w\s\.\'\#\/\-]/;
	
	if (isblank(address1))
	{
		if (required) error = error + ' Please enter a value for the first line of the "' + fieldLabel +'" field.';
	}
	else if (filter.test(address1)) error = error + " The " + fieldLabel + " can only contain letters, numbers, spaces, periods, hyphens, number signs, or forward slashes.  ";
	else if (filter.test(address2)) error = error + " The " + fieldLabel + " can only contain letters, numbers, spaces, periods, hyphens, number signs, or forward slashes.  ";
	
	return error;
}

function validCity(formField, fieldLabel, required)
{
	var strng = formField.value;
	var error = "";

	//var filter = /[^\w\s\.\#\/\-]/;
	var filter = /[^\w\s\.\'\#\/\-]/;

	if (isblank(strng))
	{
		if (required) error = error + ' Please enter a value for the ' + fieldLabel + ' field.';
	}
	else if (filter.test(strng)) error = error + " The " + fieldLabel + " can only contain letters, numbers, spaces, periods, hyphens, number signs, or forward slashes.  ";

	
	return error;
}


// Check that a US zip code or canadian postal code is valid 
function validZip(formField, fieldLabel, required) 
{ 
	var strng = formField.value; 
	var error = "";
	
	//blank required fields are bad
	if (isblank(strng)) 
	{
		if (required) error = 'Please enter a value for the ' + fieldLabel + ' field.';
	}
	
	//incorrect # of characters for zip or postal code
	if (!(strng.length ==5 || strng.length ==9 || strng.length ==10 || strng.length==6 || strng.length==7) && (! isblank(strng)))
	{
		error = error + ' Please enter a 5 or 9 digit US Zip Code or a 6 digit Canadian Postal Code';

	}

	//us zip codes have to be numerical
	if ((strng.length == 5 || strng.length == 9) && !isInteger(strng)) 
	{
		error = error + 'US Zip codes can only contain numbers.  Canadian postal codes should be 6 characters long.';

	}
	
	//checks for 12345-6789 zip format
	if (strng.length == 10 && strng.search(/^\d{5}-\d{4}$/) == -1)
	{
		error = error + '9 digit US zip codes should contain 5 digits and an optional hyphen followed by 4 more digits.  Ex: 12345-6789 .';

	}

	
	if (strng.length == 6 && strng.search(/^[a-zA-Z]\d[a-zA-Z]\d[a-zA-Z]\d$/) == -1)
	{
		error = error + 'Canadian Postal Codes should be 6 characters long, start with a letter, and alternate between letters and numbers.';

	}
	else if (strng.length == 7 && strng.search(/^[a-zA-Z]\d[a-zA-Z]-\d[a-zA-Z]\d$/) == -1) 
	{
		error = error + 'Canadian Postal Codes should be 6 characters long, start with a letter, and alternate between letters and numbers.';

	}
	
	return error; 
} 


function validPhone (areaCodeFormField, prefixFormField, suffixFormField, fieldLabel, required)
{

	var areaCode = areaCodeFormField.value;
	var prefix = prefixFormField.value;
	var suffix = suffixFormField.value;

	var error = "";

	var acFilter = /\d{3}/
	var prefixFilter = /\d{3}/
	var suffixFilter = /\d{4}/
	
	if (isblank(areaCode) || isblank(prefix) || isblank(suffix))
	{
		if (required) error = error + 'The ' + fieldLabel +' field should be filled out completely.  ';
	}
	else
	{
		
		if (!(acFilter.test(areaCode)))
		{
			error = error + 'The area code should contain a 3 digit number.  ';

		}

		if (!(prefixFilter.test(prefix)))

		{
			error = error + 'The prefix should contain a 3 digit number.  ';

		}

		if (!(suffixFilter.test(suffix)))

		{
			error = error + 'The suffix should contain a 4 digit number.  ';

		}

	
	}

	return error;
}

function validPhoneExtension (formField, fieldLabel, required)
{
	var strng = formField.value;
	var error = "";

	var extFilter = /[^\d]/
	
	if (isblank(strng))
	{
		if (required) error = error + 'The ' + fieldLabel +' field should be filled in completely.  ';
	}
	else
	{
		if (extFilter.test(strng))
		{
			error = error + 'The extension should only contain numbers.  ';

		}
	}

	return error;
}

//alphanumeric, 4-16 characters, cannot start with 00 or 99
function validUserID(formField, fieldLabel, required)
{
	var strng = formField.value;
	var error = "";
	var filter = /\W/;	//matches any non-word characters
		
	if (isblank(strng))
	{
		if (required) error = error + ' The ' + fieldLabel +' field cannot be left blank.';

	} 
	else 	if (isNotatLeastOneAlpha(strng))
	{
		error = error + ' The ' + fieldLabel + ' field should have at least one alpha character. ';
	}
	 else 	if (! (strng.length>=userIDMinLen && strng.length<=userIDMaxLen))
	{
		error = error + ' Please enter a value between ' + userIDMinLen + ' and ' + userIDMaxLen + ' characters for the ' + fieldLabel + ' field.  ';
	}
	//else if (strng.match(forbiddenCharsFilter)) error = error + 'B2B IDs cannot contain the following special characters: ' + forbiddenCharsList + '  ';
	else if (strng.match(forbiddenUserEmail)) error = error + 'B2B IDs cannot contain the following special characters: ' + forbiddenCharsUserEmail + '  ';
	else if (strng.match(/\s/)) error = error + 'B2B IDs cannot contain spaces.  ';

	return error;
}

//alphanumeric, special characters except &, 8-16 characters
//cannot match the value in the altPassField
function validPasswordResetCompare(passField, passFieldLabel, required, altPassField, altPassFieldLabel)
{
	var newPass = passField.value;
	var altPass = altPassField.value;
	var defaultMsg = 'For assistance, please click the Reset Password Help link.  ';
	var error = '';
	

	if (isblank(newPass))
	{
		if (required) error = error + ' Please enter a value for the "' + passFieldLabel +'" field.  ' + defaultMsg;

	} else 	if (! (newPass.length>=passMinLen && newPass.length<=passMaxLen))
	{
		error = error + 'Your password must be between ' + passMinLen + ' and ' + passMaxLen + ' characters long.  ' + defaultMsg;
	}
	//else if (newPass.match(forbiddenCharsFilter)) error = error + 'B2B passwords cannot contain the following special characters: ' + forbiddenCharsList + '  ' + defaultMsg;
	else if (newPass.match(forbiddenCharsPasswordFilter)) error = error + 'B2B passwords cannot contain the following special characters: ' + forbiddenCharsList + '  ' + defaultMsg;
	else if (newPass.match(/\s/)) error = error + 'B2B passwords cannot contain spaces.  ' + defaultMsg;
	else if (newPass == altPass) error = error + 'The ' + passFieldLabel + ' cannot be the same as the ' + altPassFieldLabel + '.  ' + defaultMsg;

	return error;
}

//alphanumeric, special characters except &, 8-16 characters
//cannot match the value in the altPassField
function validPasswordReset(passField, passFieldLabel, required)
{
	var newPass = passField.value;
	var error = "";
	var defaultMsg = 'For assistance, please click the Reset Password Help link.  ';	

	if (isblank(newPass))
	{
		if (required) error = error + ' Please enter a value for the "' + passFieldLabel +'" field.  ' + defaultMsg;

	} else 	if (! (newPass.length>=passMinLen && newPass.length<=passMaxLen))
	{
		error = error + 'Your password must be between ' + passMinLen + ' and ' + passMaxLen + ' characters long.  ' + defaultMsg;
	}
	//else if (newPass.match(forbiddenCharsFilter)) error = error + 'B2B passwords cannot contain the following special characters: ' + forbiddenCharsList + '  ' + defaultMsg;
	else if (newPass.match(forbiddenCharsPasswordFilter)) error = error + 'B2B passwords cannot contain the following special characters: ' + forbiddenCharsList + '  ' + defaultMsg;
	else if (newPass.match(/\s/)) error = error + 'B2B passwords cannot contain spaces.  ' + defaultMsg;
	else if (!(newPass.match(/[a-z]/))) error = error + 'B2B passwords must contain at least one lower case character.  ' + defaultMsg;
	else if (!(newPass.match(/[0-9]/))) error = error + 'B2B passwords must contain at least one number.  ' + defaultMsg;

	return error;
}

function validPassword(passField, passFieldLabel, required, userIDField)
{
	var newPass = passField.value;
	var userID = userIDField.value;
	var error = "";
	var defaultMsg = 'For assistance, please click the Password Help link.  ';	

	if (isblank(newPass))
	{
		if (required) error = error + ' Please enter a value for the ' + passFieldLabel + ' field.  ' + defaultMsg;

	} else 	if (! (newPass.length>=passMinLen && newPass.length<=passMaxLen))
	{
		error = error + 'Your password must be between ' + passMinLen + ' and ' + passMaxLen + ' characters long.  ' + defaultMsg;
	}
	//else if (newPass.match(forbiddenCharsFilter)) error = error + 'B2B passwords cannot contain the following special characters: ' + forbiddenCharsList + '  ' + defaultMsg;
	else if (newPass.match(forbiddenCharsPasswordFilter)) error = error + 'B2B passwords cannot contain the following special characters: ' + forbiddenCharsList + '  ' + defaultMsg;
	else if (newPass.match(/\s/)) error = error + 'B2B passwords cannot contain spaces.  ' + defaultMsg;
	else if (!(newPass.match(/[a-z]/))) error = error + 'B2B passwords must contain at least one lower case character.  ' + defaultMsg;
	else if (!(newPass.match(/[0-9]/))) error = error + 'B2B passwords must contain at least one number.  ' + defaultMsg;
	else if (newPass.indexOf(userID) > 0) error = error + 'B2B passwords must not contain your ID.  ' + defaultMsg;
	else if (!(checkRepeatChars(newPass))) error = error + 'B2B passwords cannot have 4 occurences of the same character.  ' + defaultMsg;
	else if (!(checkIDSubstrings(newPass, userID))) error = error + 'B2B passwords cannot contain long portions of your ID.  ' + defaultMsg;

	return error;
}

//similar to validPassword above but doesn't check password rules - used to validate
//passwords at login for special characters (protects from malicious input but is
//less restrictive for logging in than for establishing a new password)
function validCurrentPassword(passField, passFieldLabel, required)
{
	var password = passField.value;
	var error = "";

	//all input validation on validCurrentPassword is handled server-side (ASP validation or SiteMinder)	

	return error;
}

//checks to see that two password fields match (for confirming password choice)
function validPasswordVerify(passField, passVerifyField, passVerifyFieldLabel)
{
	var error = "";

	if (passField.value != passVerifyField.value)
	{
		if (passVerifyFieldLabel != "Verify Security Answer")
		   error = error + ' Passwords do not match.  Please re-enter your password in the ' + passVerifyFieldLabel + ' field.';
                else
                   error = error + ' Security Question Answers do not match.  Please re-enter your Security Question Answer in the ' + passVerifyFieldLabel + ' field.';
                
	}
	
	return error;
}

//Alphanumeric, no blanks or special characters
function validChallengeAnswer(formField, fieldLabel, required)
{
	var strng = formField.value;
	var error = "";
	
	if (isblank(strng))
	{
		if (required) error = error + ' Please enter a value for the ' + fieldLabel +' field.';
	}
	else if (strng.match(forbiddenCharsFilter)) error = error + ' The ' + fieldLabel + ' cannot contain the following special characters: ' + forbiddenCharsList + '  ';

	
	return error;
}

//Alphanumeric, special characters except < > ( ) [ ] , : ; "
function validPasswordHint(hintField, passField, hintLabel, passLabel, required)
{

	var hint = hintField.value;
	var pass = passField.value;
	var error = "";
	
	if (isblank(hint))
	{
		if (required) error = error + ' Please enter a value for the ' + hintLabel +' field.';
	}
	else if (hint.toUpperCase() == pass.toUpperCase()) error = error + 'The ' + hintLabel + ' cannot be the same as the ' + passLabel + '.';
	//else if (hint.match(forbiddenCharsFilter)) error = error + 'The ' + hintLabel + ' cannot contain the following special characters: ' + forbiddenCharsList + '  ';
	else if (hint.match(forbiddenCharsPasswordFilter)) error = error + 'B2B passwords cannot contain the following special characters: ' + forbiddenCharsList + '  ' + defaultMsg;
	return error;
}

function validDropDown(formField, fieldLabel, required)
{
	var error = "";
	
	if (isblank(formField.value))
	{
		if (required) error = error + ' Please choose an entry for the ' + fieldLabel + ' field.';
	}
	
	return error;
}
