// BROWSER SNIFFER (Sniff out the good and bad browsers)

function Is() {
  var agent = navigator.userAgent.toLowerCase();
  this.major = parseInt(navigator.appVersion);
  this.minor = parseFloat(navigator.appVersion);
  this.ns  = ((agent.indexOf('mozilla')!=-1) && ((agent.indexOf('spoofer')==-1) && (agent.indexOf('compatible') == -1)));
  this.ns2 = (this.ns && (this.major == 2));
  this.ns3 = (this.ns && (this.major == 3));
  this.ns4b = (this.ns && (this.minor < 4.04));
  this.ns4 = (this.ns && (this.major >= 4));
  this.ie   = (agent.indexOf("msie") != -1);
  this.ie3  = (this.ie && (this.major == 2));
  this.ie4  = (this.ie && (this.major >= 4));
  this.op3 = (agent.indexOf("opera") != -1);
  this.win   = (agent.indexOf("win")!=-1);
  this.mac   = (agent.indexOf("mac")!=-1);
  this.unix  = (agent.indexOf("x11")!=-1);
}
var is = new Is();

// VARIABLE DECLARATIONS

var digits = "0123456789";
var lowercaseLetters = "abcdefghijklmnopqrstuvwxyz";
var uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var whitespace = " \t\n\r";
var decimalPointDelimiter = ".";
var validZIPCodeChars = digits;
var digitsInZIPCode1 = 5;
var digitsInZIPCode2 = 9;
var phoneNumberDelimiters = "()- ";
var validUSPhoneChars = digits + phoneNumberDelimiters;
var digitsInUSPhoneNumber = 10;

// i is an abbreviation for "invalid"

var iDay =          "This field must contain a day number between 1 and 31.";
var iMonth =        "This field must contain a month number between 1 and 12.";
var iYear =         "This field must contain a 4 digit year number.";
var iDayMonth =     "The day is too large for the month.";
var iRequired =     "This is a required field.";
var iNumeric =      "This field must contain a valid number.";
var iAreaCode =     "The Area Code must be between 200 and 999.";
var iExchange =     "The Phone Exchange must be between 200 and 999.";
var iPNumber =      "The Phone Number must be between 0001 and 9999.";
var iPhone =        "The Phone Number has an error.";
var iEmail =        "The Email address has an error.";
var iInvalid =      "The phrase or sentence contains an unacceptable character.";
var iDayMonth =     "The month does not have that many days.";
var iHyperlink =    "The URL has an error.";
var iLength =       "The entry is not the correct length.";
var iLength4 =      "The entry must be at least 4 characters.";
var iLength6 =      "The entry must be at least 6 characters.";
var iAlphaNumeric = "The entry may only contain letters and numbers.";

var defaultEmptyOK = true;

function makeArray(n)
{  for (var i = 1; i <= n; i++) {
      this[i] = 0
   } 
   return this
}

var daysInMonth = makeArray(12);
daysInMonth[1] = 31;
daysInMonth[2] = 29;   // must programmatically check this
daysInMonth[3] = 31;
daysInMonth[4] = 30;
daysInMonth[5] = 31;
daysInMonth[6] = 30;
daysInMonth[7] = 31;
daysInMonth[8] = 31;
daysInMonth[9] = 30;
daysInMonth[10] = 31;
daysInMonth[11] = 30;
daysInMonth[12] = 31;

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;
    }
    return true;
}

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 isAccountPunctuation (c)
{   return (( c == " ") || ( c == "-"))
}

function isWordPunctuation (c)
{   return (( c == "'") || ( c == " ") || ( c == "-") || ( c == "."))
}

function isParagraphPunctuation (c)
{   return (((c >= " ") &&  (c <= "/")) || (c == ":") || (c == ";") || (c == "/") || (c == "?") || (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 isNonnegativeInteger (s)
{   var secondArg = defaultEmptyOK;
    if (isNonnegativeInteger.arguments.length > 1)
        secondArg = isNonnegativeInteger.arguments[1];
    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s) >= 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 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 isParagraph (s)
{   var i;
    if (isEmpty(s)) 
       if (isParagraph.arguments.length == 1) return defaultEmptyOK;
       else return (isParagraph.arguments[1] == true);
    for (i = 0; i < s.length; i++)
    {   
        var c = s.charAt(i);
        if (!isLetterOrDigit(c) && !isParagraphPunctuation(c))
        return false;
    }
    return true;
}

function isAccountID (s)
{   var i;
    if (isEmpty(s)) 
       if (isAccountID.arguments.length == 1) return defaultEmptyOK;
       else return (isAccountID.arguments[1] == true);
    for (i = 0; i < s.length; i++)
    {   
        var c = s.charAt(i);
        if (!isLetterOrDigit(c) && !isAccountPunctuation(c))
        return false;
    }
    return true;
}


function isWords (s)
{   var i;
    if (isEmpty(s)) 
       if (isWords.arguments.length == 1) return defaultEmptyOK;
       else return (isWords.arguments[1] == true);
    for (i = 0; i < s.length; i++)
    {   
        var c = s.charAt(i);
        if (!isLetter(c) && !isWordPunctuation(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 isUSPhoneNumber (s)
{   if (isEmpty(s)) 
       if (isUSPhoneNumber.arguments.length == 1) return defaultEmptyOK;
       else return (isUSPhoneNumber.arguments[1] == true);
    return (isInteger(s) && s.length == digitsInUSPhoneNumber)
}

function isYear (s)
{   if (isEmpty(s)) 
      if (isYear.arguments.length == 1)
        return defaultEmptyOK;
      else
        return (isYear.arguments[1] == true)
      ;
    if (!isNonnegativeInteger(s)) return false;
    return (s.length == 4);
}

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 = parseInt (s);
    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)
{   // 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 );
}

/* FUNCTIONS TO NOTIFY USER OF INPUT REQUIREMENTS OR MISTAKES. */

function warn (s)
{
  alert(s);
  return false;
};

function warnColor (theField, s)
{
  if (is.ie4) theField.style.backgroundColor = "red";
  theField.focus();
  alert(s);
  if (is.ie4) theField.style.backgroundColor = document.bgColor;
  theField.select();
  return false;
};

/* FUNCTIONS TO REFORMAT FIELD VALUES */

function reformatUSPhone (USPhone)
{   return (reformat (USPhone, "(", 3, ") ", 3, "-", 4))
}

function capitolize (theField)
{   var returnString = "";
    var first = true;
    for (i = 0; i < theField.value.length; i++)
    {   var c = theField.value.charAt(i);
        if (first)
        {   returnString += c.toUpperCase();
            first = false;
        }else
        {   returnString += c;
        };
        if (isWordPunctuation(c)) first = true;
    }
    theField.value = returnString;
    return true;
}

function stripCharsInBag (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 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 lTrim(s,c)
{    
    var returnString = "";
	while ((s.charAt(0) == c) && (s.length > 0))
	{
	  s = s.substring(1,s.length);
	}
    return returnString = s;
}


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;
}

/* FUNCTIONS TO CHECK FIELD VALUES */

function checkUserID (theField, emptyOK)
{   if (checkUserID.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (isWhitespace(theField.value)) return warnColor (theField, iRequired);
    if (!isAlphanumeric(theField.value)) return warnColor (theField, iAlphaNumeric);
	if (theField.value.length < 6) return warnColor (theField, iLength6);
    return true;
}

function checkPassword (theField, emptyOK)
{   if (checkPassword.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (isWhitespace(theField.value)) return warnColor (theField, iRequired);
    if (!isAlphanumeric(theField.value)) return warnColor (theField, iAlphaNumeric);
	if (theField.value.length < 4) return warnColor (theField, iLength4);
    return true;
}

function checkUSPhone (theField, emptyOK)
{   if (checkUSPhone.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (isWhitespace(theField.value)) return warnColor (theField, iRequired);
    var normalizedPhone = stripCharsNotInBag(theField.value, digits);
    if (!isUSPhoneNumber(normalizedPhone, false)) 
       return warnColor (theField,iPhone);
    else 
    {//if you don't want to reformat as (123) 456-789, comment next line out
       theField.value = reformatUSPhone(normalizedPhone)
       return true;
    }
}

function checkLetter (theField, s, emptyOK)
{  if (checkLetter.arguments.length == 2) emptyOK = defaultEmptyOK;
   if ((emptyOK == true) && (isEmpty(theField.value))) return true;
   if (!isLetter(theField.value)) return warnColor (theField,s);
   return true;
}

function checkIntegerInRange (theField, a, b, s)
{  if (!isIntegerInRange(theField.value, a, b)) return warnColor (theField,s);
   return true;
}

function checkInteger(theField, s, emptyOK)
{  if (checkInteger.arguments.length == 2) emptyOK = defaultEmptyOK;
   if ((emptyOK == true) && (isEmpty(theField.value))) return true;
   if (!isNonnegativeInteger(theField.value)) return warnColor (theField,s);
   return true;
}

function checkFloat (theField, s, emptyOK)
{  if (checkFloat.arguments.length == 2) emptyOK = defaultEmptyOK;
   if ((emptyOK == true) && (isEmpty(theField.value))) return true;
   if (!isFloat(theField.value)) return warnColor (theField,s);
   return true;
}

function checkEmpty (theField, s) 
{  if (isEmpty(theField.value)) return warnColor (theField,'');
   return true;
}

function checkYear (theField, s, emptyOK)
{   // Next line is needed on NN3 to avoid "undefined is not a number" error
    // in equality comparison below.
    if (checkYear.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isYear(theField.value)) return warnColor (theField, s);
    return true;
}

function checkWord (theField, s, emptyOK)
{   // Next line is needed on NN3 to avoid "undefined is not a number" error
    // in equality comparison below.
    if (checkWord.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (!isAlphabetic(theField.value)) return warnColor (theField, s);
    return true;
}

function checkWords (theField, s, emptyOK)
{   // Next line is needed on NN3 to avoid "undefined is not a number" error
    // in equality comparison below.
    if (checkWords.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (isWhitespace(theField.value)) return warnColor (theField, iRequired);
    if (!isWords(theField.value)) return warnColor (theField, s);
    return true;
}

function checkUSDate (theField, s, emptyOK)
{   // catch invalid days, except for February
    if (checkUSDate.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    var dateArray = theField.value.split("/");
    if (!isMonth(lTrim(dateArray[0],"0"))) return warnColor (theField, "Not a valid Month, " + s);
    if (!isDay(lTrim(dateArray[1],"0"))) return warnColor (theField, "Not a valid Day, " + s);
    if (!isYear(dateArray[2])) return warnColor (theField, "Not a valid Year, " + s);
    if ( dateArray[1] > daysInMonth[dateArray[0]]) return warnColor (theField,iDayMonth); 
    if ((dateArray[0] == 2) && (dateArray[1] > daysInFebruary(dateArray[2]))) return warnColor (theField,iDayMonth);
    return true;
}

function checkMilTime (theField, s, emptyOK)
{   // catch invalid days, except for February
    if (checkMilTime.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    var timeArray = theField.value.split(":");
    if (!isIntegerInRange(timeArray[0], 0, 23)) return warnColor (theField,s);
    if (!isIntegerInRange(timeArray[1], 0, 59)) return warnColor (theField,s);
    return true;
}

function checkDate (dayField, intDay, intMonth, intYear)
{   // catch invalid days, except for February
    if (checkDate.arguments.length != 4) return false;
    if (intDay > daysInMonth[intMonth]) return warnColor (dayField,iDayMonth); 
    if ((intMonth == 2) && (intDay > daysInFebruary(intYear))) return warnColor (dayField,iDayMonth);
    return true;
}

function checkAccountID (theField, s, emptyOK)
{   // Next line is needed on NN3 to avoid "undefined is not a number" error
    // in equality comparison below.
    if (checkAccountID.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (isWhitespace(theField.value)) return warnColor (theField, iRequired);
    if (!isAccountID(theField.value)) return warnColor (theField, s);
    return true;
}

function checkZip5 (theField, emptyOK)
{   if (checkZip5.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (isWhitespace(theField.value)) return warnColor (theField, iRequired);
    if (!isInteger(theField.value)) return warnColor (theField, iNumeric); 
    if (!(theField.value.length == 5)) return warnColor (theField, iLength);
    return true;
 }

function checkZip4 (theField, emptyOK)
{   if (checkZip4.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (isWhitespace(theField.value)) return warnColor (theField, iRequired);
    if (!isInteger(theField.value)) return warnColor (theField, iNumeric);
    if (!(theField.value.length == 4)) return warnColor (theField, iLength);
    return true;
}

function checkParagraph (theField, s, emptyOK)
{   // Next line is needed on NN3 to avoid "undefined is not a number" error
    // in equality comparison below.
    if (checkParagraph.arguments.length == 2) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    if (isWhitespace(theField.value)) return warnColor (theField, iRequired);
    if (!isParagraph(theField.value)) return warnColor (theField, s);
    return true;
}

function checkEmail(theField, emptyOK)
{   // Next line is needed on NN3 to avoid "undefined is not a number" error
    // in equality comparison below.
    if (checkEmail.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    var reg1 = /(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/; // not valid
    var reg2 = /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?)$/; // valid
    if (reg1.test(theField.value) || !reg2.test(theField.value)) return warnColor (theField, iEmail);
    return true;
}



