/***********************************************************************
 * Misc functions for validating input forms
 *
 * Created: 4/29/02 John Tacke
 *
 *
 ***********************************************************************/
 
 /*
 
 	SETUP INSTRUCTIONS:
 		The easiest way to implement the validation is to use this code in the html form:
 		
 			<form onsubmit="return validate()"> ... </form>
 		
 		Then, in the document's head, create the validation function:
 		
	 		<script language="javascript">
				function validate() {
					...
				}
			</script>
		
		The USAGE notes are written as the script would appear within the validate() function.
		(Remember that javascript IS case sensitive)
 	
 */
 
 var defaultEmptyOK = true;
 var reWhitespace = /^\s+$/
 
 function isPhone(sTest,phonePart)
 {
 var reAreaCode=/^\d{3}$/;
 var rePrefix=/^\d{3}$/;
 var rePhone=/^\d{4}$/;
 var reExt=/^\d+$/;
 var reFullPhone=/^\(?\d{3}\)?\s|-\d{3}-\d{4}$/;
 
    if (isEmpty(sTest)) 
       if (isPhone.arguments.length <= 2) return defaultEmptyOK;
       else return (isPhone.arguments[2] == true);

	switch (phonePart)
	{
		case 1: //area code
			return reAreaCode.test(sTest)
			
		case 2: 
			return rePrefix.test(sTest)
			
		case 3:
			return rePhone.test(sTest)
			
		case 4://extension
			return reExt.test(sTest)
			
		case 5://full phone number
			return reFullPhone.test(sTest)
			
	}
	
	return false;
 
}
 
 function isInteger(sTest)
 {
 var reInteger=/^\d+$/


    if (isEmpty(sTest)) 
       if (isInteger.arguments.length == 1) return defaultEmptyOK;
       else return (isInteger.arguments[1] == true);

    return reInteger.test(sTest)
 }
 
 function isPercent(sTest) {
	// 5 = places to the left of the decimal
	// 3 = places to the right of the decimal
	var reDecimal = /^-?\d{1,5}\.?\d{0,3}$/
	
	if ( isEmpty(sTest) )
		if ( isPercent.arguments.length == 1 ) return defaultEmptyOK;
	else return ( isPercent.arguments[1] == true );
	
	return reDecimal.test(sTest);
 }


// Time validation
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
	
	USAGE:
	
	if ( !isValidTime(document.form1.text1, false) ) {
		document.form1.text1.focus();
		return false;
	}

*/
function isValidTime(objTime) {
// Checks if time is in HH:MM:SS AM/PM format.
// if it is in military time, or if no AM/PM is specified
// convert to standard and add the AM/PM
var hour = "";
var minute = "";
var second = "";
var ampm = "";
var timeStr = objTime.value;
var timePat = /^(\d{1,2}):(\d{2})(:(\d{2}))?(\s?(AM|am|PM|pm))?$/;
var pos = 0;
var strTmp = "";

if (isEmpty(timeStr)) {
	if (isValidTime.arguments.length == 1) {
		return defaultEmptyOK;
	}
	else {
		return (isValidTime.arguments[1] == true);
	}
}

var matchArray = timeStr.match(timePat);

if (matchArray == null) 
{
	if ( timeStr.length == 4 ) {
		hour = timeStr.substring(0,2);
		minute = timeStr.substring(2,timeStr.length+1);
		second = "";
		ampm = "";
	}
	else {
//		alert("Be sure to enter a valid time (hh:mm (AM|PM) or hhmm).");
		return false;
	}
}
else {
	hour = matchArray[1];
	minute = matchArray[2];
	second = matchArray[4];
	ampm = matchArray[6];
}

// convert the time to standard
if ( hour > 12 ) {
	if ( hour > 23 ) {
//		alert("Be sure to enter a valid time (hh:mm (AM|PM) or hhmm).");
		return false;
	}
	else {
		hour = (hour-12);
		ampm = "PM";
	}
}
else {
	if ( ampm == undefined || ampm == "" ) {
		if ( hour < 12 ) {
			ampm = "AM";
		}
		else {
			ampm = "PM";
		}
	}
}

if ( second == undefined ) {
	second = "";
}

if (hour < 0  || hour > 23) {
	return false;
}
if (hour <= 12 && ampm == "") {
	if (confirm("Please indicate which time format you are using.  OK = Standard Time, CANCEL = Military Time")) {
//		alert("You must specify AM or PM.");
		return false;
   }
}
if  (hour > 12 && ampm != "") {
//	alert("You can't specify AM or PM for military time.");
	return false;
}
if (minute<0 || minute > 59) {
//	alert ("Minute must be between 0 and 59.");
	return false;
}
if (second != "" && (second < 0 || second > 59)) {
//	alert ("Second must be between 0 and 59.");
	return false;
}

objTime.value = hour + ":" + minute
if ( second.length > 0 ) {
	objTime.value += ":" + second;
}
if ( ampm.length > 0 ) {
	objTime.value += " " + ampm;	
}

return true;
}

 

function isUSZip (sTest)
{
	if (sTest != "" ) { sTest = sTest.replace("-","") }
	
   if (isEmpty(sTest)) 
       if (isUSZip.arguments.length == 1) return defaultEmptyOK;
       else return (isUSZip.arguments[1] == true);
    
    else {
	   return (isInteger(sTest) && 
            ((sTest.length == 5) ||
             (sTest.length == 9)))

    }
}
 

// Email validation
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
	
	USAGE:
	
	if ( !isEmail(document.form1.text1.value) ) {
		alert("MESSAGE");
		document.form1.text1.focus();
		return false;
	}

*/
function isEmail (sTest)
{
var reEmail = /^.+\@.+\..+$/

   if (isEmpty(sTest)) 
       if (isEmail.arguments.length == 1) return defaultEmptyOK;
       else return (isEmail.arguments[1] == true);
    
    else {
       return reEmail.test(sTest)
    }
}


// Check whether string s is empty.
function isEmpty(s)
{   
	return ((s == null) || (s.length == 0))
}

// Date validation
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
	
	USAGE:
	
	.NET CLIENT VALIDATION EXAMPLE:
	function validDate(objSource, objArgs) {
		if ( objSource.value != "" && !isDate(objArgs.Value) ) {
			objArgs.IsValid = false;
			return false;
		}
		
		objArgs.IsValid = true;
		return true;
	}
	
	STANDARD JAVASCRIPT EXAMPLE:
	function validDate(objIN) {
		if ( objIN.value != "" && !isDate(objIN.value) ) {
			objIN.focus();
			return false;
		}
		
		return true;
	}
	
	CAN ALSO BE USED TO FORMAT DATE STRINGS:
	function formatDate(objIN) {
		if ( isDate(objIN.value) && objIN.value != "" ) objIN.value = isDate(objIN.value);
	}

*/
function isInteger(s){
	var i;
    for (i = 0; i < s.length; i++){   
        // Check that current character is number.
        var c = s.charAt(i);
        if (((c < "0") || (c > "9"))) return false;
    }
    // All characters are numbers.
    return true;
}

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++){   
        var c = s.charAt(i);
        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 i = 1; i <= n; i++) {
		this[i] = 31;
		if (i==4 || i==6 || i==9 || i==11) {this[i] = 30};
		if (i==2) {this[i] = 29};
   } 
   return this;
}

function isDate(dtStr)
{
	//dtStr = objIN.value;
	
	if (isEmpty(dtStr)) { 
		if (isDate.arguments.length == 1) {
			if ( defaultEmptyOK == false ) {
				alert("Please enter a valid date, using the following format (mm/dd/yyyy), (mm/dd/yy), (mmddyyyy) or (mmddyy)");
			}

			return defaultEmptyOK;
		}
		else {
			if ( isDate.arguments[1] == false ) {
				alert("Please enter a valid date, using the following format (mm/dd/yyyy), (mm/dd/yy), (mmddyyyy) or (mmddyy)");
			}
			
			return (isDate.arguments[1] == true);
		}
	}
	 
	//return !isNaN(Date.parse(s))
	
	var dtCh = "/";

	if (dtStr.indexOf(dtCh)==-1) {
		dtCh = "-";
	}
	
	var minYear=1900;
	var maxYear=2100;
	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 i = 1; i <= 3; i++) {
		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){
		// process the date without '/' or '-'
		
		// 010203 or 01022003
		
		if (dtStr.length == 6 || dtStr.length == 8) {
			strMonth=dtStr.substring(0,2);
			strDay=dtStr.substring(2,4);
			strYear=dtStr.substring(4,dtStr.length+1);
		}
		else {
//			alert("Please enter a valid date, using the following format (mm/dd/yyyy), (mm/dd/yy), (mmddyyyy) or (mmddyy)");
			return false;
		}
	}
	if (strMonth.length<1 || strMonth<1 || strMonth>12){
//		alert("Please enter a valid month");
		return false;
	}
	if (strDay.length<1 || day<1 || day>31 || (month==2 && day>daysInFebruary(year)) || day > daysInMonth[month]){
//		alert("Please enter a valid day");
		return false;
	}
	if ( strYear.length == 4 ) {
		if (strYear==0 || strYear<minYear || strYear>maxYear){
//			alert("Please enter a valid 4 digit year between "+minYear+" and "+maxYear);
			return false;
		}
	}
	else {
		if (strYear.length != 2 || strYear<0){
//			alert("Please enter a valid 2 digit year");
			return false;
		}
	}
	if (dtStr.indexOf(dtCh,pos2+1)!=-1 || isInteger(stripCharsInBag(dtStr, dtCh))==false){
//		alert("Please enter a valid date");
		return false;
	}
	
	return strMonth + "/" + strDay + "/" + strYear;;
}
// end date validation
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Returns true if string s is empty or 
// whitespace characters only.

function isWhitespace (s)

{   // Is s empty?
    return (isEmpty(s) || reWhitespace.test(s));
}

/*********************************************
 * cardType:
 *  1 - visa
 *  2 - master card
 *  3 - amex
 *********************************************/
 
// ---------------------------------------------------------------------
function isCreditCard(CC_Num,CC_Type)
// ---------------------------------------------------------------------
    {
// ---------------------------------------------------------------------
// CCN_digits stores just the digits from the Credit Card Number
// ---------------------------------------------------------------------
    var CCN_digits = ""

// ---------------------------------------------------------------------
// get the digits from the entered Card Number
// Note - the isNaN (Not a Number) function is not used 
// because it is not supported by JavaScript 1.0
// ---------------------------------------------------------------------
    for (var i = 0; i < CC_Num.length; i++)
        {
        if ((CC_Num.charAt(i) == "0") || 
            (CC_Num.charAt(i) == "1") ||
            (CC_Num.charAt(i) == "2") || 
            (CC_Num.charAt(i) == "3") ||  
            (CC_Num.charAt(i) == "4") || 
            (CC_Num.charAt(i) == "5") || 
            (CC_Num.charAt(i) == "6") || 
            (CC_Num.charAt(i) == "7") || 
            (CC_Num.charAt(i) == "8") || 
            (CC_Num.charAt(i) == "9"))
            {
             CCN_digits = CCN_digits + CC_Num.charAt(i);
            }
        }

// ---------------------------------------------------------------------
// validcard is the true/false indicator for a valid card 
//  - it is returned to the calling routine.
// ---------------------------------------------------------------------
    var validcard = false;

// ---------------------------------------------------------------------
// msgind is used to communicate the type of alert to 
// post in case of a problem
//    1=invalid prefix (prefix does not match card type)
//    2=invalid number of digits in card number 
//        for the card type selected
// ---------------------------------------------------------------------
    var msgind = 0;

// ---------------------------------------------------------------------
// Check the card for having a valid prefix and number of  
// digits (length) for the card type.
// Note - the if, else if construct was used here because 
// switch/case is not supported by JavaScript 1.0
// ---------------------------------------------------------------------
// VALID LENGTH AND PREFIX VALUES
// --------------------------------------------------------------------- 
//  AMEX Discover MasterCard Visa 
// LENGTHS 15 16 16 13/16 
// PREFIXES 34 6011 51 4 
//  37  52  
//    53  
//    54  
//    55  
 

    if (CC_Type == "American Express")
        if (CCN_digits.length == 15)
            if ((CCN_digits.substring (0, 2) == "34") || 
                (CCN_digits.substring (0, 2) == "37"))
                validcard = true;
            else
                msgind = 1;
        else    
            msgind = 2;
    else if (CC_Type == "Discover")
        if (CCN_digits.length == 16)
            if (CCN_digits.substring (0, 4) == "6011")
                validcard = true;
            else
                msgind = 1;
        else    
            msgind = 2;
    else if (CC_Type == "MasterCard")
        if (CCN_digits.length == 16)
            if ((CCN_digits.substring (0, 2) >= "51") && 
                (CCN_digits.substring (0, 2) <= "55"))
                validcard = true;
            else
                msgind = 1;
        else    
            msgind = 2;
    else if (CC_Type == "Visa")
        if ((CCN_digits.length == 16) || 
            (CCN_digits.length ==13))
            if (CCN_digits.substring (0, 1) == "4")
                validcard = true;
            else
                msgind = 1;
        else    
            msgind = 2;
    else
// ---------------------------------------------------------------------
// Invalid card type - this should be impossible to reach as 
// long  as all valid card types are in the list above....
// ---------------------------------------------------------------------
        alert ("Sorry, "+ CC_Type + " is not currently being accepted - please contact us by phone or email.");

    if (!validcard)
        {
        if (msgind == 1)
// ---------------------------------------------------------------------
//            Invalid prefix
// ---------------------------------------------------------------------
            alert ("The Card Number ("+CC_Num + ") and the Card Type (" + CC_Type + ") do not match.");

        else if (msgind == 2)
// ---------------------------------------------------------------------
//            Invalid number of digits (length)
// ---------------------------------------------------------------------
            alert ("The Card Number ("+CC_Num + ") is not the right length for the Card Type (" + CC_Type + ").");
        }

    if (!validcard)
        return (validcard);

// ---------------------------------------------------------------------
// Perform the mod10 check sum routine on the 
//  digits in the card number
//    1) Go through the Credit Card Number digits, starting on 
//        the RIGHT.
//            If the position is odd
//                 add the digit to the checksum tally. 
//            If the position is even
//                 multiply the digit by 2
//                 if the result is greater than 9
//                     divide the result by 10 
//                     and add the remainder 
//                         to the checksum tally
//                     add 1 to the checksum tally
//                 if the result is 9 or less
//                     add the result to the checksum tally
//        Repeat for each digit.
//    2) Divide the checksum tally by 10
//    3) If there is a remainder
//                     the Credit Card Number is not valid.
// ---------------------------------------------------------------------
    var CheckSum = 0;
// ---------------------------------------------------------------------
// for loop to look at the Credit Card Number
// ---------------------------------------------------------------------
    for (var x = 1; x <= CCN_digits.length; x++)
        {
// ---------------------------------------------------------------------
// x is subtracted from the length of the CCN 
// to point at the digits from RIGHT to LEFT
// ---------------------------------------------------------------------
        var CurrentDigit = CCN_digits.charAt
                                            (CCN_digits.length - x);
        if (x % 2 == 0)
            {
// ---------------------------------------------------------------------
// even position in credit card number 
// (2nd, 4th, etc. from RIGHT of Credit Card Number)
// ---------------------------------------------------------------------
            var WorkDigit = CurrentDigit * 2;    
            if (WorkDigit > 9)
                { 
                CheckSum = CheckSum + (1 - 0);
                CheckSum = CheckSum + (WorkDigit % 10);
                }
            else
                {
                CheckSum = CheckSum + (WorkDigit - 0);
                }     
            }
        else
            {
// ---------------------------------------------------------------------
// odd position in credit card number 
// (1st, 3rd, etc. from RIGHT of Credit Card Number)
// ---------------------------------------------------------------------
            CheckSum = CheckSum + (CurrentDigit - 0);
            }
        }
// ---------------------------------------------------------------------
// end for loop
// ---------------------------------------------------------------------

    if (CheckSum % 10) 
        { 
// ---------------------------------------------------------------------
// The CheckSum does not divide evenly by 10
// ---------------------------------------------------------------------
        validcard = false; 
        alert ("I'm sorry, the Card Number ("+ CC_Num +") is not correct - perhaps there is a typo or two numbers are reversed?"); 
        } 
    return (validcard); 
    }
