var defaultEmptyOK = false;

//set up basic character groups
var digits = "0123456789";
var lowercaseLetters = "abcdefghijklmnopqrstuvwxyz";
var uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var whitespace = " \t\n\r";
var nameDelimiters = "-. ";
var decimalPointDelimiter = ".";
var daysInMonth = makeArrayFromString(0,31,29,31,30,31,30,31,31,30,31,30,31);

//set up allowed characters for specific data types

//phone numbers
var phoneNumberDelimiters = "()- ";
var digitsInUSPhoneNumber = 10;
var validUSPhoneChars = digits + phoneNumberDelimiters;
var validWorldPhoneChars = digits + phoneNumberDelimiters + "+";

//electronic addresses
var validDomainNameChars = digits + uppercaseLetters + lowercaseLetters + "-_.";

//snail mail addresses
var addressDelimiters = ".,/-" + whitespace;
var validAddressCharacters = addressDelimiters + digits + uppercaseLetters + lowercaseLetters;

//US mail address parameters
var digitsInZIPCode1 = 5;
var digitsInZIPCode2 = 9;
var ZIPCodeDelimiters = "-";
var ZIPCodeDelimeter = "-";
var validZIPCodeChars = digits + ZIPCodeDelimiters;
var USStateCodes = "AL|AK|AS|AZ|AR|CA|CO|CT|DE|DC|FM|FL|GA|GU|HI|ID|IL|IN|IA|KS|KY|LA|ME|MH|MD|MA|MI|MN|MS|MO|MT|NE|NV|NH|NJ|NM|NY|NC|ND|MP|OH|OK|OR|PW|PA|PR|RI|SC|SD|TN|TX|UT|VT|VI|VA|WA|WV|WI|WY|AE|AA|AE|AE|AP";
var USStateCodeDelimiter = "|";

//Canadian mail address parameters
var cdnProvCodes = "BC|AB|SK|MB|ON|QC|NF|PE|NS|NB|NT|YT|NU";
var postalCodeDelimiter = " ";
var validPostalCodeChars = digits + lowercaseLetters + uppercaseLetters + postalCodeDelimiter;
var charsInPostalCode = 6;
var cdnProvCodeDelimiter = "|";

//credit card parameters
var creditCardDelimiters = " ";

function makeArray(n) {
   for (var i = 1; i <= n; i++) {
      this[i] = 0;
   } 
   this[length] = n;
   return this;
}

function makeArrayFromString() {
   for (var i = 1; i <= makeArrayFromString.arguments.length; i++){
      this[i] = makeArrayFromString.arguments[i];
   }
   this[length] = makeArrayFromString.arguments.length;
   return this;
}

function isEmpty(s) {
    return ((s == null) || (s.length == 0))
}

function isWhitespace(s) {
    var i;

    if (isEmpty(s)) return true;
    for (i = 0; i < s.length; i++)
    {   
        var c = s.charAt(i);
        if (whitespace.indexOf(c) == -1) return false; // not whitespace
    }
    return true;
}

function stripCharsInBag (s, bag){
    var i;
    var 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;
}

function stripCharsNotInBag (s, bag){
    var i;
    var returnString = "";
    for (i = 0; i < s.length; i++)
    {   
        var c = s.charAt(i);
        if (bag.indexOf(c) != -1) returnString += c;
    }
    return returnString;
}

function stripWhitespace (s){
   return stripCharsInBag (s, whitespace)
}

function charInString (c, s){
    for (i = 0; i < s.length; i++){
       if (s.charAt(i) == c) return true;
    }
    return false
}

function stripInitialWhitespace (s){
    var i = 0;
    while ((i < s.length) && charInString (s.charAt(i), whitespace))
       i++;
    return s.substring (i, s.length);
}

function stripEndingWhitespace (s){
    var i = s.length - 1;
    while ((i >= 0) && charInString (s.charAt(i), whitespace))
       i--;
    return s.substring (0,i+1);
}

function bTrimWhitespace (s){
    s = stripInitialWhitespace (s);
    s = stripEndingWhitespace (s);

    return s;
}

function isLetter (c){
   return ( ((c >= "a") && (c <= "z")) || ((c >= "A") && (c <= "Z")) )
}

function isDigit (c){
   return ((c >= "0") && (c <= "9"))
}

function isLetterOrDigit (c){
   return (isLetter(c) || isDigit(c))
}

function isInteger (s){
    var i;
    if (isEmpty(s)) 
       if (isInteger.arguments.length == 1) return defaultEmptyOK;
       else return (isInteger.arguments[1] == true);
    for (i = 0; i < s.length; i++)
    {   
        var c = s.charAt(i);
        if (!isDigit(c)) return false;
    }
    return 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];
        if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") )
           startPos = 1;    
        return (isInteger(s.substring(startPos, s.length), secondArg))
    }
}

function isPositiveInteger (s){
    var secondArg = defaultEmptyOK;
    if (isPositiveInteger.arguments.length > 1)
        secondArg = isPositiveInteger.arguments[1];
    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s) > 0) ) );
}

function isNonnegativeInteger (s){
    var secondArg = defaultEmptyOK;
    var s1 = s - 0;
    if (isNonnegativeInteger.arguments.length > 1)
        secondArg = isNonnegativeInteger.arguments[1];
    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (s1 >= 0) ) );
}

function isNegativeInteger (s){
    var secondArg = defaultEmptyOK;
    if (isNegativeInteger.arguments.length > 1)
        secondArg = isNegativeInteger.arguments[1];
    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s) < 0) ) );
}

function isNonpositiveInteger (s){
    var secondArg = defaultEmptyOK;
    if (isNonpositiveInteger.arguments.length > 1)
        secondArg = isNonpositiveInteger.arguments[1];
    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s) <= 0) ) );
}

function isFloat (s){
    var i;
    var seenDecimalPoint = false;
    if (isEmpty(s)) 
       if (isFloat.arguments.length == 1) return defaultEmptyOK;
       else return (isFloat.arguments[1] == true);
    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;
}

function isSignedFloat (s){
    if (isEmpty(s)) 
       if (isSignedFloat.arguments.length == 1) return defaultEmptyOK;
       else return (isSignedFloat.arguments[1] == true);
    else {
        var startPos = 0;
        var secondArg = defaultEmptyOK;
        if (isSignedFloat.arguments.length > 1)
            secondArg = isSignedFloat.arguments[1];
        if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") )
           startPos = 1;    
        return (isFloat(s.substring(startPos, s.length), secondArg))
    }
}

function isAlphabetic (s){
    var i;
    if (isEmpty(s)) 
       if (isAlphabetic.arguments.length == 1) return defaultEmptyOK;
       else return (isAlphabetic.arguments[1] == true);
    for (i = 0; i < s.length; i++)
    {   
        var c = s.charAt(i);
        if (!isLetter(c))
        return false;
    }
    return true;
}

function isAlphanumeric (s){
    var i;
    if (isEmpty(s)) 
       if (isAlphanumeric.arguments.length == 1) return defaultEmptyOK;
       else return (isAlphanumeric.arguments[1] == true);
    for (i = 0; i < s.length; i++)
    {   
        var c = s.charAt(i);
        if (! (isLetter(c) || isDigit(c) ) )
        return false;
    }
    return true;
}

function isEmail (s){
    atloc = 0;
    if (isEmpty(s)) {
       if (isEmail.arguments.length == 1) return defaultEmptyOK;
       else return (isEmail.arguments[1] == true); }
    if (isWhitespace(s)){ warn("Address blank"); return false; }
    var i = 1;
    var sLength = s.length;
    while ((i < sLength) && (s.charAt(i) != "@"))
    { i++ }
    if ((i >= sLength) || (s.charAt(i) != "@")){ warn("no @ sign"); return false; }
    else atloc = i;
    j = i+1;
    i += 1;
    while ((j < sLength) && (validDomainNameChars.indexOf(s.charAt(j)) != -1))
    { j++ }
    if (j < sLength){ warn("invalid character in domain name: "+s.charAt(j)); return false; }
    while ((i < sLength) && (s.charAt(i) != "."))
    { i++ }
    if (i == sLength){ warn("no . in domain name"); return false; }
    if (i == (atloc +1)){ warn("not enough space between @ and ."); return false; }
    k = atloc+1;
    while (k < sLength){
      if ((s.charAt(k) == ".") && (s.charAt(k+1) == ".")){ warn("too many .'s"); return false; }
      k++
    }
    l = sLength;
    while ((i < sLength -2) && (l != i) && (s.charAt(l) != "."))
    { l = l-1 }
    if ((i >= sLength - 2) || (s.charAt(i) != ".") || (l >= sLength - 2)) { warn("not enough characters after ."); return false; }
    else return true;
}

function isEmailAdd (s){
    atloc = 0;
    if (isEmpty(s)) {
       if (isEmailAdd.arguments.length == 1) return defaultEmptyOK;
       else return (isEmailAdd.arguments[1] == true); }
    if (isWhitespace(s)) return ("Address blank");
    var i = 1;
    var sLength = s.length;
    while ((i < sLength) && (s.charAt(i) != "@"))
    { i++ }
    if ((i >= sLength) || (s.charAt(i) != "@")) return("no @ sign");
    else atloc = i;
    j = i+1;
    i += 1;
    while ((j < sLength) && (validDomainNameChars.indexOf(s.charAt(j)) != -1))
    { j++ }
    if (j < sLength) return("invalid character in domain name: "+s.charAt(j));
    while ((i < sLength) && (s.charAt(i) != "."))
    { i++ }
    if (i == sLength) return("no . in domain name");
    if (i == (atloc +1)) return("not enough space between @ and .");
    k = atloc+1;
    while (k < sLength){
      if ((s.charAt(k) == ".") && (s.charAt(k+1) == ".")) return("too many .'s");
      k++
    }
    l = sLength;
    while ((i < sLength -2) && (l != i) && (s.charAt(l) != "."))
    { l = l-1 }
    if ((i >= sLength - 2) || (s.charAt(i) != ".") || (l >= sLength - 2))  return("not enough characters after .");
    else return true;
}


function isYear (s){
    if (isEmpty(s)) 
       if (isYear.arguments.length == 1) return defaultEmptyOK;
       else return (isYear.arguments[1] == true);
    if (!isNonnegativeInteger(s)) return false;
    else return ((s.length == 4) || (s.length == 2));
}

function isIntegerInRange (s, a, b){
    if (isEmpty(s)) 
       if (isIntegerInRange.arguments.length == 1) return defaultEmptyOK;
       else return (isIntegerInRange.arguments[1] == true);
    if (!isInteger(s, false)) return false;
    var num = s - 0;
    return ((num >= a) && (num <= b));
}

function isMonth (s){
    if (isEmpty(s)) 
       if (isMonth.arguments.length == 1) return defaultEmptyOK;
       else return (isMonth.arguments[1] == true);
    return isIntegerInRange (s, 1, 12);
}

function isDay (s){
    if (isEmpty(s)) 
       if (isDay.arguments.length == 1) return defaultEmptyOK;
       else return (isDay.arguments[1] == true);   
    return isIntegerInRange (s, 1, 31);
}

function daysInFebruary (year){
    return (  ((year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0) ) ) ? 29 : 28 );
}

function isDate (year, month, day){ 
    if (! (isYear(year, false) && isMonth(month, false) && isDay(day, false))) return false;
    var intYear = year - 0;
    var intMonth = month - 0;
    var intDay = day - 0;
    if (intDay > daysInMonth[intMonth]) return false; 
    if ((intMonth == 2) && (intDay > daysInFebruary(intYear))) return false;
    return true;
}

function prompts (s){
    window.status = s
}

function warnInvalid (theField,s){
//    theField.focus()
    theField.select()
    alert(s)
    return false
}

function warn (s){
    alert(s)
    return false
}

function checkString (theField, s, emptyOK){
    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;
}


function checkEmail (theField, emptyOK){
    if (checkEmail.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    else {
      emailStatus = isEmail(theField.value, false)
      if (emailStatus != true) return warnInvalid (theField, "Invalid Email Address");
      else return true;
    }
}

function checkYear (theField, emptyOK){
    if (checkYear.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isYear(theField.value, false)) 
       return warnInvalid (theField, "Invalid Year");
    else {
    if (theField.value.length == 2)
    {
       var tmp1 = theField.value - 0;
       if (tmp1 >= 40 && tmp1 <= 99) theField.value = tmp1 + 1900;
       else theField.value = tmp1 + 2000;
    }

   // theField.value = (parseInt(theField.value)+1900);


    return true;
    }
}

function checkMonth (theField, emptyOK){
    if (checkMonth.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isMonth(theField.value, false)) 
       return warnInvalid (theField, "Invalid Month");
    else return true;
}

function checkDay (theField, emptyOK){
    if (checkDay.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isDay(theField.value, false)) 
       return warnInvalid (theField, "Invalid Day");
    else return true;
}

function checkDate (yearField, monthField, dayField, labelString, OKtoOmitDay){
    if (checkDate.arguments.length == 4) OKtoOmitDay = false;
    if (!isYear(yearField.value)) return warnInvalid (yearField, "Invalid Year");
    else if (yearField.value.length == 2) yearField.value = (parseInt(yearField.value)+1900);
    if (!isMonth(monthField.value)) return warnInvalid (monthField, "Invalid Month");
    if ( (OKtoOmitDay == true) && isEmpty(dayField.value) ) return true;
    else if (!isDay(dayField.value)) 
       return warnInvalid (dayField, "Invalid Day");
    if (isDate (yearField.value, monthField.value, dayField.value))
       return true;
    alert ("The " + labelString + " is invalid" )
    return false
}

function checkMDY(theField, todayDate, emptyOK)
{
  if (checkMDY.arguments.length == 1) {
    emptyOK = defaultEmptyOK;
    todayDate = defaultEmptyOK;
  }

  if (isEmpty(theField.value))
    return emptyOK;
  else
  {
    var dateString = stripCharsInBag(theField.value,"-/ ");
    var dd = dateString.substring(0,2);
    var mm = dateString.substring(2,4);
    var yyyy = dateString.substring(4,theField.value.length);
    if (!isDay(dd)) return warn("Format must be DD/MM/YYYY.");
    if (!isMonth(mm)) return warn("Format must be DD/MM/YYYY."); 
    if (!isYear(yyyy)) return warn("Format must be DD/MM/YYYY."); 
    if (yyyy.length == 2) {
      var year = yyyy - 0;
      year > 10 ? yyyy = 1900 + year : yyyy = 2000 + year;
    }
    if (isDate(yyyy.toString(),mm.toString(),dd.toString()))
    {
      theField.value = dd+"/"+mm+"/"+yyyy;

      var dateString = yyyy.toString() + mm.toString() + dd.toString();

      if (todayDate != false && dateString > todayDate)
      {
         warn("Date must not be in the future.");
         return false;
      }

      return true;
    }
    else
    {
       warn("Format must be DD/MM/YYYY.");
       return false;
    }
  }
}

function checkMDYPP(theField, todayDate, pastDate, emptyOK)
{
  if (checkMDYPP.arguments.length == 1) {
    emptyOK = defaultEmptyOK;
    todayDate = defaultEmptyOK;
  }

  if (isEmpty(theField.value))
    return emptyOK;
  else
  {
    var dateString = stripCharsInBag(theField.value,"-/ ");
    var dd = dateString.substring(0,2);
    var mm = dateString.substring(2,4);
    var yyyy = dateString.substring(4,theField.value.length);
    if (!isDay(dd)) return warn("Format must be DD/MM/YYYY.");
    if (!isMonth(mm)) return warn("Format must be DD/MM/YYYY."); 
    if (!isYear(yyyy)) return warn("Format must be DD/MM/YYYY."); 
    if (yyyy.length == 2) {
      var year = yyyy - 0;
      year > 10 ? yyyy = 1900 + year : yyyy = 2000 + year;
    }
    if (isDate(yyyy.toString(),mm.toString(),dd.toString()))
    {
      theField.value = dd+"/"+mm+"/"+yyyy;

      var dateString = yyyy.toString() + mm.toString() + dd.toString();

      if (todayDate != false && dateString > todayDate)
      {
         warn("Date must not be in the future.");
         return false;
      }

      if (pastDate != false && dateString < pastDate)
      {
         warn("Please re-check your purchase date.  The date entered cannot be before the passport was issued or the purchase date recorded by the previous owner.");
         return false;
      }

      return true;
    }
    else
    {
       warn("Format must be DD/MM/YYYY.");
       return false;
    }
  }
}
