/*
$Header: /cvs/genlib/asp/validate2.js,v 1.28 2008/08/11 14:27:09 jeffrey Exp $
=============================================
When        Who   	What
---------------------------------------------
2004-01-28	jsg		added		
2004-10-20	jtc		Modified radio handling. It was breaking if there was only
                    a single radio button.
2005-02-14	jtc		Added PR and VI to issusstate(). Didn't I do a better version of that at one point?
=============================================

Notes:

	Validation functions.
	The validateForm() function processes a structure
	like the example included here and validates
	the form accordingly. 
*/

function isBlank( str ) {
     var isValid = false;
     if ( isNull(str) || isUndef(str) || (str+"" == "") ) {
          isValid = true;
	}
     return isValid;
}  // end IsBlank

function isZero( str ) {
     var isValid = false;
     if (str == 0) {
          isValid = true;
	}
     return isValid;
}  // end IsZero

function isText(str /*, maxlen*/)
{
	var maxlen = 0;
	with (isText) {
		if (arguments.length >= 2) {
			maxlen = new Number(arguments[1]);
		}
	}

//	alert ("maxlen = " + maxlen);
	
	if (maxlen > 0 && str.length > maxlen) {
		return "Only " + maxlen + " characters allowed.";
	}

	var isValid = "";
    if ( isNull(str) || isUndef(str) || (str+"" == "") ) {
		isValid = "Empty entries are not allowed.";
	}
	return isValid;
}
	
function isAllDigits(s)
{
    //alert("input: " + s);
	
	
	
	var maxlen = 0;
	with (isAllDigits) {
		if (arguments.length >= 2) {
			maxlen = new Number(arguments[1]);
		}
	}

//	alert ("maxlen = " + maxlen);
	
	if (maxlen > 0 && s.length > maxlen) {
		return "Only " + maxlen + " characters allowed.";
	}
	
	
	var str = "" + s;
    for (var k = 0; k < str.length; k++) {
		if (! (str.charAt(k) >= "0" && str.charAt(k) <= "9")) {
            return "Only numbers (0 - 9) are allowed.";
        }
    }
    return "";
}



function isAlpha (str /*, maxlen*/) 
{
     // Return immediately if an invalid value was passed in
    if (str+"" == "undefined" || str+"" == "null" || str+"" == "") {
		return "Empty entries are not allowed.";
	}

	var maxlen = 0;
	with (isAlpha) {
		if (arguments.length >= 2) {
			maxlen = new Number(arguments[1]);
		}
	}

	if (maxlen > 0 && str.length > maxlen) {
		return "Only " + maxlen + " letters allowed.";
	}
	
    var isValid = "";
    str += "";
	// convert to a string for performing string comparisons.

    // Loop through string one character at time,  breaking out of for
    // loop when an non Alpha character is found.
	for (i = 0; i < str.length; i++) {
        // Alpha must be between "A"-"Z", or "a"-"z"
        if ( !( ((str.charAt(i) >= "a") && (str.charAt(i) <= "z")) ||
        		((str.charAt(i) >= "A") && (str.charAt(i) <= "Z")) ) )
		{
        	isValid = "Only letters (A - Z) are allowed.";
            break;
        }
   } // end for loop

   return isValid;
}  // end IsAlpha

function isNull( val ) {
     var isValid = false;

     if (val+"" == "null")
          isValid = true;

     return isValid;
}  // end IsNull

function isUndef( val ) {
     var isValid = false;

     if (val+"" == "undefined")
          isValid = true;

     return isValid;
}  // end IsUndef


function isValidTime(str){
	if (str+"" == "undefined" || str+"" == "null" || str+"" == "")
          return "Empty entries are not allowed.";
		  
	var isValid = "";
	
	str += "";
	
	hstr = str.substring(0, str.indexOf(":"));
	mstr = str.substring(str.indexOf(":")+1, str.length);
	
	
	if ((hstr.length == 0) ||
			(mstr.length <= 1) ||
			(str.charAt(str.length-1) != "m"))
		isValid = "Please enter something like '10:00 pm'";
		
	return isValid;	
}	



function isValidMilitaryTime(str){
	if (str+"" == "undefined" || str+"" == "null" || str+"" == "")
          return "Empty entries are not allowed.";
		  
	str += "";
	var errstr = "Please enter time in military format, like '23:30' or '2330'";
	var colonindex = str.indexOf(":");
	
	/* Allows for quick entry, like 1545 or 300 or 1215 */
	if (colonindex == -1){
		if (str.length < 3)	return errstr; //wasn't long enough to be a time
		var tmpnum = str*1;
		if (tmpnum > 2459 || tmpnum < 0) return errstr; // was out of range
		for (i=0; i<str.length; i++) {
			if ((str.charAt(i) < "0") || (str.charAt(i) > "9")) return errstr; //wasn't all digits
	    }
	}
	else{
		hstr = str.substring(0, colonindex);
		mstr = str.substring(colonindex + 1, str.length);
		hnum = hstr * 1;
		mnum = mstr * 1;
		if (hnum > 24 || hnum < 0 || mnum > 59 || mnum < 0) return errstr;
	}
	
	return "";	
}	


function isValidDate(str)
{
	
	var splitters = new Array("-", " ", "/");
	var fourdigityear = false;
	
	//for (key in splitters){
	for (var key=0; key<splitters.length; key++) {
		//Split on " " or "-" or "/"
		arr = str.split(splitters[key]);
		//Still good if array has 3 elements
		
		if (arr.length == 3){
			//alert("So it is split on |" + splitters[key] + "|.");
			//for (key2 in arr) {
			for (var key2=0; key2<arr.length; key2++) {
				//alert("arr[" + key2 + "] = |" + arr[key2] + "|");
				fourdigityear = (fourdigityear || arr[key2].length == 4);
				//Still good if one of the elements is 4 digits long
				if (fourdigityear){
					//Finally, make sure each of the three elements is all digits
					//for (key3 in arr) {
					for (var key3=0; key3<arr.length; key3++) {
						//alert("arr[" + key3 + "] = |" + arr[key3] + "|");
						return isAllDigits(arr[key3]);
					}
				}
			}
		}
		else{
			//alert("So it is NOT split on |" + splitters[key] + "|.");
		}
	}
	return "A 4-digit year is required. Enter date like '2/30/2001' or '2001-02-30' or even '2001 2 30'."
}		

// Specific validation for date in this format: "mm/dd/yyyy"
function isValidDate2(str) {
	
	var arr = str.split("/");
	var errstr = "Please enter date in the following format: MM/DD/YYYY.  Ex: '2/30/2001'";
	var gooddate = true;

	//Still good if array has 3 elements
	if (arr.length == 3) {
		//for (key in arr) {
		for (var key=0; key<arr.length; key++) {
			// month
			if (key == 0) {
				if (arr[key] < 1 || arr[key] > 12) return(errstr);
				if (isAllDigits(arr[key]) != "") return(errstr);
			}
			// day
			else if (key == 1) {
				if (arr[key] < 1 || arr[key] > 31) return(errstr);
				if (isAllDigits(arr[key]) != "") return(errstr);
			}
			// year
			else if (key == 2) {
				if (arr[key].length != 4) return(errstr);
				if (isAllDigits(arr[key]) != "") return(errstr);
			}
		}
	}

	// bad array
	else {
		return(errstr);
	}

// looks good...
return("");
}
	
// New function that validates the email in the form
function isValidEmail (str /*, maxlen */) {
     // Return immediately if an invalid value was passed in
    if (str+"" == "undefined" || str+"" == "null" || str+"" == "") {
          return "Empty entries are not allowed.";
	}

     var isValid = "";
     str += "";

     namestr = str.substring(0, str.indexOf("@"));
	 // everything before the '@'
     domainstr = str.substring(str.indexOf("@")+1, str.length);
	 // everything after the '@'

	 // Rules: namestr cannot be empty, or that would indicate no
	 // characters before the '@',
     // domainstr must contain a period that is not the first character
	 // (i.e. right after
     // the '@').  The last character must be an alpha.
     if ((namestr.length == 0) ||
               (domainstr.indexOf(".") <= 0) ||
               (domainstr.indexOf("@") != -1))
               //isAlpha(str.charAt(str.length-1)) != "")
	{
//		alert(isAlpha(str.charAt(str.length-1)));
    	isValid = "Please enter a valid email address like 'user@domain.org'.";
	}
	
	var reg1 = /(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/; // not valid
  	var reg2 = /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/; // valid
  	if (reg1.test(str) || !reg2.test(str)) { // if syntax is invalid
    	isValid = "Please enter a valid email address like 'user@domain.org'.";
  	}
  	

     return isValid;
} // end IsValidEmail

function isUSState(str) 
{
	str = str.toUpperCase();
	
  	if ( (str == "AA") || (str == "AE") || (str == "AK") || (str == "AL") || (str == "AR") || (str == "AP") || (str == "AZ") || (str == "CA") || (str == "CO") || (str == "CT") || (str == "DC") || (str == "DE") || (str == "FL") || (str == "GA") || (str == "HI") || (str == "IA") || (str == "ID") || (str == "IL") || (str == "IN") || (str == "KS") || (str == "KY") || (str == "LA") || (str == "MA") || (str == "MD") || (str == "ME") || (str == "MI") || (str == "MN") || (str == "MO") || (str == "MS") || (str == "MT") || (str == "NE") || (str == "NC") || (str == "ND") || (str == "NH") || (str == "NJ") || (str == "NM") || (str == "NV") || (str == "NY") || (str == "OH") || (str == "OK") || (str == "OR") || (str == "PA") || (str == "RI") || (str == "SC") || (str == "SD") || (str == "TN") || (str == "TX") || (str == "UT") || (str == "VA") || (str == "VT") || (str == "WA") || (str == "WI") || (str == "WV") || (str == "WY") || (str == "PR") || (str == "VI") )
	{
		return "";
	}
	else {
		return "Please enter a valid 2-letter US state code.";
	}
}

// Functions that validates the phone number in the form
function isPhoneNum(str) 
{
	var errstr = "Please enter a phone number in the format 800-555-1212";

  	if (str.length != 12) { 
  		return errstr;
	}
  	for (i=0; i<str.length; i++) {
    	if ((i == 3) || (i == 7)) {
	      	if (str.charAt(i) != "-") { 
				return errstr;
			}
    	} 
		else {
    	  	if ((str.charAt(i) < "0") || (str.charAt(i) > "9")) { 
				return errstr;
			}
	    }
	}
  	return "";
}

// Functions that validates the phone number in the form in this format: (###) ###-####
function isPhoneNum2(str) {

	var errstr = "Please enter a phone number in the format (800) 555-1212";

  	if (str.length != 14) { 
  		return errstr;
	}
  	for (i=0; i<str.length; i++) {
    	if (i == 0) {
	      	if (str.charAt(i) != "(") { 
				return errstr;
			}
    	} 
    	else if (i == 4) {
	      	if (str.charAt(i) != ")") { 
				return errstr;
			}
    	} 
    	else if (i == 5) {
	      	if (str.charAt(i) != " ") { 
				return errstr;
			}
    	} 
    	else if (i == 9) {
	      	if (str.charAt(i) != "-") { 
				return errstr;
			}
    	} 
		else {
    	  	if ((str.charAt(i) < "0") || (str.charAt(i) > "9")) { 
				return errstr;
			}
	    }
	}
  	return "";
}

function isValidZIPCode(zip)
{
    if (zip.length == 5) {
        return (isAllDigits(zip));
	}
    else if (zip.length == 10)
    {
        return (isAllDigits(zip.substring(0,5)) && (zip.substring(5,6) == "-") && (isAllDigits(zip.substring(6,10))));
    }
	return "Please enter a ZIP code in the format '12345' or '12345-6789'.";
}

function isValidMonth(str)
{
	var errstr;
	if ((errstr = isAllDigits(str)) != "") {
		return errstr;
	}
	var num = new Number(str);
	if (num < 1 || num > 12) {
		return "Please enter a number between 1 and 12.";
	}
	return "";
}

function isValidDay(str)
{
	var errstr;
	if ((errstr = isAllDigits(str)) != "") {
		return errstr;
	}

	var num = new Number(str);
	if (num < 1 || num > 12) {
		return "Please enter a number between 1 and 31.";
	}
	return "";
}

// Verify mod10 status of number.  Last character is modulus character.
function isMod10(instr) {
	var isValid = "";
	var digitstr = new String(instr);
	digitstr = digitstr.replace(/\D/g, '');  // strip all things non-numeric
	var modchar = parseInt(digitstr.substring(digitstr.length-1, digitstr.length)); // get the mod character
	digitstr = digitstr.substring(0, digitstr.length-1); // and the data string without mod character
	var strlen = digitstr.length;
	var currnum = 0;
	var sum = 0;

	dbg("digitstr", digitstr);
	dbg("modchar", modchar);

	for (i = 0; i < strlen; i++) {
		currnum = parseInt(digitstr.charAt(i));
		if (!(i & 1)) {				// double the even ones starting with 0, but i don't quite know why
			currnum += currnum;		// double it 
			if (currnum > 9) {		// check for any carry 
				currnum -= 9;
			}
		}
		sum += currnum;
	}
	sum %= 10;						// mod 10 it
	if (sum > 0) {
		sum = 10 - sum;
	}
	sum = parseInt(sum);			// make sure its an integer
	if (sum != modchar) {
		isValid = "Invalid Order Number";
	}

	return(isValid);
}

/*	Check to see if a radio set is blank. */
function radio_isBlank(radio)
{
	var	isBlank = true;

	/* 	2004-10-20 - jtc - really, really weird: if there is only one radio button,
		the radio group doesn't have a length property. */
	if ('undefined' == '' + radio.length) {
		isBlank = radio.checked ? false : true;
		//		alert("isBlank=" + isBlank);
		return isBlank;
	}


	//	alert("length=" + radio.length);
	for (index = 0; index < radio.length; index++) {
		//		alert ("Checking radio #" + index + "...");
		if (radio[index].checked == true) {
			isBlank = false;
			break;
		}
	}
	//	alert("isBlank=" + isBlank);
	return isBlank;
}

//tweaked isAllDigits for this one
function isValidHeight(h)
{
    var str = "" + h;
    for (var k = 0; k < str.length; k++) {
		if (! ((str.charAt(k) >= "0" && str.charAt(k) <= "9") || (str.charAt(k) == "-" && str.charAt(k) == "-"))  ) {
            return "Please enter a value like 5-10";
        }
    }
    return "";
}

/*	This prototype defines a validation "object". We make an array of these objects that is 
	specific for a particular form being validated. */
function valobj(fieldname,fieldcapt,inptype,blankfunc,validfunc,maxlen)
{ this.fieldname = fieldname; this.fieldcapt = fieldcapt; this.inptype = inptype; this.blankfunc = blankfunc;  this.validfunc = validfunc; 
this.maxlen = (("undefined" == "" + maxlen || maxlen == null) ? 0 : 0 + maxlen);
//alert("this.maxlen = " + this.maxlen);
}

/*	This code below should go near the form being validated or in a page-specific script file. */
/*	Example:
var valfields = new Array();
var cnt = 0;

valfields[cnt++] = new valobj("Lname", "Last Name", "text", isBlank, isText);
valfields[cnt++] = new valobj("State", "State", "text", isBlank, isUSState);
valfields[cnt++] = new valobj("Zip", "Zip", "text", isBlank, isValidZIPCode);
valfields[cnt++] = new valobj("Telephone", "Telephone", "text", isBlank, isPhoneNum);
valfields[cnt++] = new valobj("Email", "Email", "text", isBlank, isValidEmail);
valfields[cnt++] = new valobj("C1Fname", "First Child First Name", "text", isBlank, isText);
valfields[cnt++] = new valobj("C1Lname", "First Child Last Name", "text", null, isText);
valfields[cnt++] = new valobj("C1Sex", "First Child Sex", "radio", radio_isBlank, null);
valfields[cnt++] = new valobj("C1month", "First Child Birthday Month", "text", isBlank, isValidMonth);
valfields[cnt++] = new valobj("C1day", "First Child Birthday Day", "text", isBlank, isValidDay);
valfields[cnt++] = new valobj("C1year", "First Child Birthday Year", "text", isBlank, isAllDigits);
valfields[cnt++] = new valobj("C2Fname", "Second Child First Name", "text", null, isText);
*/



/*	Here's the granddaddy function that does it all. */
function validateForm(form) 
{
	//alert("In validateForm()... Form name = " + form.name);
	var fieldarray;
	var	local = false;
	
	
	/*	Allow an alternate field array to be passed in as a second parameter. */
	if (validateForm.arguments.length == 2) {
		fieldarray = validateForm.arguments[1];
		local = true;
		//alert('overriding with alternate field array');
	}
	else {
		/*	Use default, global fieldarray. */
		fieldarray = valfields;
		//alert('going with the default fields');
	}
	
	//alert("fieldarray.length = " + fieldarray.length);
	
	//var logstr = "";
	//var fieldno = 0;
	//for (fieldno in fieldarray)
	//2009-07-09 JNN The 'for' syntax above was breaking in IE. Worked in Firefox. But not IE. At least not not studentform.asp.
	for (var fieldno = 0; fieldno < fieldarray.length; fieldno++)
	{
		//alert("fieldno = " + fieldno);
		var fieldname = fieldarray[fieldno].fieldname;
		var fieldcapt = fieldarray[fieldno].fieldcapt;
		fieldcapt = fieldcapt.replace(/<br>/gi, ' ');
		var blankfunc = fieldarray[fieldno].blankfunc;
		var validfunc = fieldarray[fieldno].validfunc;
		var inptype = fieldarray[fieldno].inptype;
		var maxlen = fieldarray[fieldno].maxlen;
//		alert("fieldarray[].maxlen = " + maxlen);
		var blank = false;
		
		//logstr += fieldname + "; "
		//alert(fieldname + " - " + fieldcapt);
		
		if (typeof (form[fieldname]) != "object") {
			//alert("Form inputs processed so far: " + logstr);
			alert("Program error: '" + fieldname + "' is not a form input.");
			continue;
		}
		
		/*	First check the blankness of the input. The polarity is such that if the
			function returns true we're blank. If no function is specified then it's ok
			for this input to be blank. But if there's a validfunc we'll still check its
			validity if there's something in it. */
		if (typeof (blankfunc) == "function") {
			if (inptype == "radio") {

				//				alert("Testing radio set...");

				/*	Pass the actual input object */
				blank = blankfunc(form[fieldname]);

				//				alert("blank=" + blank);

				if (blank) {
					alert("Please select an option for '" + fieldcapt + "'.");
					/*	Focus on the first radio in the group. */
					if ('undefined' == '' + form[fieldname].length) {
						form[fieldname].focus();
					}
					else {
						form[fieldname][0].focus();
					}
				}
			}
			else {
				//alert(fieldname + " = |" + form[fieldname].value + "|");
				blank = blankfunc(form[fieldname].value);
				if (blank) {
					alert("Please enter a value in the '" + fieldcapt + "' box.");
					form[fieldname].focus();
				}
			}
			if (blank) return (false);
		}
		else {
			/*	This might look funny, but if we passed the blank function but
				if we get here we either don't have a blankfunc or we passed it. But
				do a check to make sure the input isn't blank; if it is it will probably
				fail its validation routine, so continue to the next input. */
			if (inptype == "text" && isBlank(form[fieldname].value)) continue;
		}
		
		/*	Now check the validness of the input. Polarity is true == good value. */
		/*	Figure that radio buttons will not need a validate func. */
		var errstr;
		if ((typeof (validfunc) == "function") && ((errstr = validfunc(form[fieldname].value,maxlen)) != "")) {
			alert("'" + form[fieldname].value + "' is not a valid value for '" + fieldcapt + "'.\r\n" + errstr);
//			form[fieldname].select();
			form[fieldname].focus();
			return (false);
		}
	}
	
	if (!local) {
		if (typeof(local_validateForm) == "function") {
			return local_validateForm(form);
		}
	}
	
	return true;
}

/*    New function to validate Expiration Dates for credit cards (format: MM/YY)  */
function isValidExpDate(str) {
	var splitter = "/";
	var str_error = "Expiration dates must be in the MM/YY format (ex: 08/07)";
	
	//Split on "/"
	arr = str.split(splitter);
	
	//Still good if array has 2 elements
	if (arr.length == 2){
	        //for (key in arr) {
			for (var key=0; key<arr.length; key++) {
	                if (arr[key].length != 2 || isNaN(arr[key])) {
	                        return str_error;
	                }
	        }
	}
	// Otherwise its an error
	else {
	        return str_error;
	}
	return "";
}

function isValidExpDate2(str) {
	var splitter = "/";
	var str_error = "Expiration dates must be in the MM/YYYY format (ex: 08/2007)";
	
	//Split on "/"
	arr = str.split(splitter);
	
	//Still good if array has 2 elements
	if (arr.length == 2){
		// MM
		if (arr[0].length != 2 || isNaN(arr[0])) {
		        return str_error;
		}

		// YY or YYYY
		if (arr[1].length != 4 || isNaN(arr[0])) {
		        return str_error;
		}
	}
	// Otherwise its an error
	else {
	        return str_error;
	}
	return "";
}

/*	Format and validate a credit card number in a strict format. */
function format_credit_card(inval, splitchar)
{
	if (format_credit_card.arguments.length < 2) splitchar = '-';
	var intval = strip_to_digits(inval); 

	if (intval.length < 15 || intval.length > 16) return "1|Credit card number must be 15 or 16 digits";
	
	var cardtype = intval.substr(0, 1);
	var cardcodes = "3456";
	if (cardcodes.indexOf(cardtype) == -1) return "2|Credit card must start with 3 (AMEX), 4 (Visa), 5 (MasterCard), or 6 (Discover)";
	
	if (cardtype == "3") {
		if (intval.length != 15) return "3|AMEX Credit Card number must start with 3 and have 15 digits";
	} else if (intval.length != 16) return "4|Visa/MasterCard/Discover card number must have 16 digits";
//	if (isAllDigits(intval) != '') return null;
		
	var outval = intval.substr(0, 4) + '-' + intval.substr(4, 4) + '-' + intval.substr(8, 4) + '-' + intval.substr(12, 4)
	
	return "0|" + outval;
}


