// VARIABLE DECLARATIONS
var whitespace = " \t\n\r"; // whitespace characters
var decimalPointDelimiter = "." // decimal point character differs by language and culture
var digitsInUSPhoneNumber = 10; // U.S. phone numbers have 10 digits. They are formatted as 123 456 7890 or (123) 456-7890.
var phoneNumberDelimiters = "()- "; // non-digit characters which are allowed in phone numbers
var ZIPCodeDelimiters = "-"; // non-digit characters which are allowed in ZIP Codes
// U.S. ZIP codes have 5 or 9 digits. They are formatted as 12345 or 12345-6789.
var digitsInZIPCode1 = 5
var digitsInZIPCode2 = 9

var defaultEmptyOK = false

// m is an abbreviation for "missing"
var mPrefix = "You did not enter a value into the "
var mSuffix = " field. This is a required field. Please enter it now."

// i is an abbreviation for "invalid"
var iEmail = "This field must be a valid email address. Please reenter it now."
var iZIPCode = "This field must be a 5 or 9 digit U.S. ZIP Code (like 94043). Please reenter it now."
var iUSPhone = "This field must be a 10 digit U.S. phone number (like 415 555 1212). Please reenter it now."

// BASIC DATA VALIDATION FUNCTIONS:

// Check whether string s is empty.
function isEmpty(s) { return ((s == null) || (s.length == 0)) }

// Returns true if character c is a digit 
function isDigit (c) { return ((c >= "0") && (c <= "9")) }

// Returns true if string s is empty or  whitespace characters only.
function isWhitespace (s)
{   
    var i;
    if (isEmpty(s)) 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;
}

// isInteger (STRING s)
// 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.
function isInteger (s)
{
    var i;
    if (isEmpty(s)) return false;
	var c;
    for (i = 0; i < s.length; i++)
    {   
        c = s.charAt(i);
        if (!isDigit(c)) return false;
    }
    return true;
}

// isFloat (STRING s)
// True if string s is an unsigned floating point (real) number. 
// Also returns true for unsigned integers. If you wish
// to distinguish between integers and floating point numbers,
// first call isInteger, then call isFloat.
// Does not accept exponential notation.
function isFloat (s)
{
	var i;
    var seenDecimalPoint = false;
    if (isEmpty(s)) return false;
    if (s == decimalPointDelimiter) return false;
    for (i = 0; i < s.length; i++)
    {   
        var c = s.charAt(i);
        if ((c == decimalPointDelimiter) && !seenDecimalPoint) seenDecimalPoint = true;
        else if (!isDigit(c)) return false;
    }
    return true;
}

// Notify user that required field theField is empty.
// String s describes expected contents of theField.value.
// Put focus in theField and return false.
function warnEmpty (theField, s)
{
    theField.focus()
    alert(mPrefix + s + mSuffix)
    return false
}

function warnInvalid (s, theField)
{
	if (warnInvalid.arguments.length == 2) {
	    theField.focus();
    	theField.select();
	}
    alert(s);
    return false
}

// checkString (TEXTFIELD theField, STRING s, [, BOOLEAN emptyOK==false])
// Check that string theField.value is not all whitespace.
function checkString (theField, s, emptyOK)
{
   // Next line is needed on NN3 to avoid "undefined is not a number" error
    // in equality comparison below.
    if (checkString.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (isWhitespace(theField.value)) return warnEmpty (theField, s);
    else return true;
}

// Check to see if an option has been selected in a drop down
function isSelected (obj) {
	if (obj.selectedIndex == 0) return false;
	return true;
}

function checkDropDown(theField,s) {
	if (!isSelected(theField)) { return warnInvalid("Please select a valid " + s); }
	return true;
}

// Removes all characters which appear in string bag from string s.
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;
}

// reformat (TARGETSTRING, STRING, INTEGER, STRING, INTEGER ... )       
//
// 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.
//
// 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)

{   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;
}

// PHONE NUMBER VALIDATION FUNCTIONS 

// 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.
function isUSPhoneNumber (s)
{   if (isEmpty(s)) 
       if (isUSPhoneNumber.arguments.length == 1) return defaultEmptyOK;
       else return (isUSPhoneNumber.arguments[1] == true);
    return (isInteger(s) && s.length == digitsInUSPhoneNumber)
}

// takes USPhone, a string of 10 digits and reformats as (123) 456-789
function reformatUSPhone (USPhone) { return (reformat (USPhone, "(", 3, ") ", 3, "-", 4)) }

// checkUSPhone (TEXTFIELD theField [, BOOLEAN emptyOK==false])
// Check that string theField.value is a valid US Phone.
function checkUSPhone (theField, emptyOK)
{   if (checkUSPhone.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    else
    {  var normalizedPhone = stripCharsInBag(theField.value, phoneNumberDelimiters)
       if (!isUSPhoneNumber(normalizedPhone, false)) return warnInvalid (iUSPhone,theField);
       else 
       {  
			    theField.value = reformatUSPhone(normalizedPhone);
          return true;
       }
    }
}

// EMAIL VALIDATION FUNCTIONS
// isEmail (STRING s [, BOOLEAN emptyOK])
// 
// Email address must be of form a@b.c -- in other words:
// * there must be at least one character before the @
// * there must be at least one character before and after the .
// * the characters @ and . are both required
function isEmail (s)
{   if (isEmpty(s)) 
       if (isEmail.arguments.length == 1) return defaultEmptyOK;
       else return (isEmail.arguments[1] == true);
   
    // is s whitespace?
    if (isWhitespace(s)) return false;
    
    // there must be >= 1 character before @, so we
    // start looking at character position 1 
    // (i.e. second character)
    var i = 1;
    var sLength = s.length;

    // look for @
    while ((i < sLength) && (s.charAt(i) != "@"))
    { i++
    }

    if ((i >= sLength) || (s.charAt(i) != "@")) return false;
    else i += 2;

    // look for .
    while ((i < sLength) && (s.charAt(i) != "."))
    { i++
    }

    // there must be at least one character after the .
    if ((i >= sLength - 1) || (s.charAt(i) != ".")) return false;
    else return true;
}

// checkEmail (TEXTFIELD theField [, BOOLEAN emptyOK==false])
// Check that string theField.value is a valid Email.
function checkEmail (theField, emptyOK)
{
   if (checkEmail.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    else if (!isEmail(theField.value, false)) 
       return warnInvalid (iEmail, theField);
    else return true;
}


// ZIP CODE VALIDATION FUNCTIONS

// isZIPCode (STRING s [, BOOLEAN emptyOK])
// 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.  
function isZIPCode (s)
{  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)))
}

// takes ZIPString, a string of 5 or 9 digits; if 9 digits, inserts separator hyphen
function reformatZIPCode (ZIPString)
{
	if (ZIPString.length == 5) return ZIPString;
    return (reformat (ZIPString, "", 5, "-", 4));
}


// checkZIPCode (TEXTFIELD theField [, BOOLEAN emptyOK==false])
// Check that string theField.value is a valid ZIP code.
function checkZIPCode (theField, emptyOK)
{
    if (checkZIPCode.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    else
    { var normalizedZIP = stripCharsInBag(theField.value, ZIPCodeDelimiters)
      if (!isZIPCode(normalizedZIP, false)) 
         return warnInvalid (iZIPCode,theField);
      else 
      {  // if you don't want to insert a hyphen, comment next line out
         theField.value = reformatZIPCode(normalizedZIP)
         return true;
      }
    }
}

//******* END OF VALIDATION FUNCTIONS ********