/*
   Script:                 formValidate.js

   Source:                 http://www.shastrynet.com/

   Author:                 Subramanya Shastry Y V H
                                                   shastry@email.com

   Description:            Generic form validation routine.

   Copyright:              This script can be freely used with or without modifications.

                           The author cannot be held responsible for any possible mistakes
                           in the coding. It is the responsibility of the user to make
                           sure that the code is working fine and is bug-less.

                           This Script cannot be distributed without prior permission from
                           the author.
*/

// isWhitespace (s)                    Check whether string s is empty or whitespace.
// isLetter (c)                        Check whether character c is an English letter
// isDigit (c)                         Check whether character c is a digit
// isLetterOrDigit (c)                 Check whether character c is a letter or digit.
// isInteger (s [,eok])                True if all characters in string s are numbers.
// isSignedInteger (s [,eok])          True if all characters in string s are numbers; leading + or - allowed.
// isPositiveInteger (s [,eok])        True if string s is an integer > 0.
// isNonnegativeInteger (s [,eok])     True if string s is an integer >= 0.
// isNegativeInteger (s [,eok])        True if s is an integer < 0.
// isNonpositiveInteger (s [,eok])     True if s is an integer <= 0.
// isFloat (s [,eok])                  True if string s is an unsigned floating point (real) number. (Integers also OK.)
// isSignedFloat (s [,eok])            True if string s is a floating point number; leading + or - allowed. (Integers also OK.)
// isAlphabetic (s [,eok])             True if string s is English letters
// isAlphanumeric (s [,eok])           True if string s is English letters and numbers only.

// FUNCTIONS TO REFORMAT DATA:
//
// stripCharsInBag (s, bag)            Removes all characters in string bag from string s.
// stripCharsNotInBag (s, bag)         Removes all characters NOT in string bag from string s.
// stripWhitespace (s)                 Removes all whitespace characters from s.
// stripInitialWhitespace (s)          Removes initial (leading) whitespace characters from s.
// reformat (TARGETSTRING, STRING,     Function for inserting formatting characters or
//   INTEGER, STRING, INTEGER ... )       delimiters into TARGETSTRING.
// reformatZIPCode (ZIPString)         If 9 digits, inserts separator hyphen.
// reformatSSN (SSN)                   Reformats as 123-45-6789.
// reformatUSPhone (USPhone)           Reformats as (123) 456-789.


// VARIABLE DECLARATIONS

var digits = "0123456789";
var lowercaseLetters = "abcdefghijklmnopqrstuvwxyz"
var uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
var whitespace = " \t\n\r";

// decimal point character differs by language and culture
var decimalPointDelimiter = "."

// non-digit characters which are allowed in phone numbers
var phoneNumberDelimiters = "()- ";

// characters which are allowed in US phone numbers
var validUSPhoneChars = digits + phoneNumberDelimiters;

// characters which are allowed in international phone numbers
// (a leading + is OK)
var validWorldPhoneChars = digits + phoneNumberDelimiters + "+";

// non-digit characters which are allowed in
// Social Security Numbers
var SSNDelimiters = "- ";

// characters which are allowed in Social Security Numbers
var validSSNChars = digits + SSNDelimiters;

// U.S. Social Security Numbers have 9 digits.
// They are formatted as 123-45-6789.
var digitsInSocialSecurityNumber = 9;

// U.S. phone numbers have 10 digits.
// They are formatted as 123 456 7890 or (123) 456-7890.
var digitsInUSPhoneNumber = 10;

// non-digit characters which are allowed in ZIP Codes
var ZIPCodeDelimiters = "-";

// our preferred delimiter for reformatting ZIP Codes
var ZIPCodeDelimeter = "-"

// characters which are allowed in Social Security Numbers
var validZIPCodeChars = digits + ZIPCodeDelimiters

// U.S. ZIP codes have 5 or 9 digits.
// They are formatted as 12345 or 12345-6789.
var digitsInZIPCode1 = 5
var digitsInZIPCode2 = 9

// non-digit characters which are allowed in credit card numbers
var creditCardDelimiters = " "

// returns true if s only contains characters that are in bag
function isOkBag (s, bag)

{   var i;
    var returnString = "";

    // Search through string's characters one by one.
    // If character is not in bag, return false.
    for (i = 0; i < s.length; i++)
    {
        var c = s.charAt(i);
        if (bag.indexOf(c) == -1) return false;
    }
    return true;
}

// Check whether string s is empty.
function isEmpty(s)
{   return ((s == null) || (s.length == 0))
}

// Returns true if string s is empty or
// whitespace characters only.
function isWhiteSpace (s)
{   var i;

    // Is s empty?
    if (isEmpty(s)) return true;

    // Search through string's characters one by one
    // until we find a non-whitespace character.
    // When we do, return false; if we don't, 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;
}

// 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;
}

// Removes all characters which do NOT appear in string bag
// from string s.
function stripCharsNotInBag (s, bag)

{   var i;
    var returnString = "";

    // Search through string's characters one by one.
    // If character is 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;
}

// Removes all whitespace characters from s.
// Global variable whitespace (see above)
// defines which characters are considered whitespace.
function stripWhitespace (s)

{   return stripCharsInBag (s, whitespace)
}

// WORKAROUND FUNCTION FOR NAVIGATOR 2.0.2 COMPATIBILITY.
//
// The below function *should* be unnecessary.  In general,
// avoid using it.  Use the standard method indexOf instead.
//
// However, because of an apparent bug in indexOf on
// Navigator 2.0.2, the below loop does not work as the
// body of stripInitialWhitespace:
//
// while ((i < s.length) && (whitespace.indexOf(s.charAt(i)) != -1))
//   i++;
//
// ... so we provide this workaround function charInString
// instead.
//
// charInString (CHARACTER c, STRING s)
//
// Returns true if single character c (actually a string)
// is contained within string s.

function charInString (c, s)
{   for (i = 0; i < s.length; i++)
    {   if (s.charAt(i) == c) return true;
    }
    return false
}

// Removes initial (leading) whitespace characters from s.
// Global variable whitespace (see above)
// defines which characters are considered whitespace.
function stripInitialWhitespace (s)

{   var i = 0;

    while ((i < s.length) && charInString (s.charAt(i), whitespace))
       i++;

    return s.substring (i, s.length);
}

// Returns true if character c is an English letter (A .. Z, a..z).
//
// NOTE: Need i18n version to support European characters.
// This could be tricky due to different character
// sets and orderings for various languages and platforms.
function isLetter (c)
{   return ( ((c >= "a") && (c <= "z")) || ((c >= "A") && (c <= "Z")) )
}

// Returns true if character c is a digit (0 .. 9).
function isDigit (c)
{   return ((c >= "0") && (c <= "9"))
}

// Returns true if character c is a letter or digit.
function isLetterOrDigit (c)
{   return (isLetter(c) || isDigit(c))
}


// isInteger (STRING s [, BOOLEAN emptyOK])
//
// 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.
//
// By default, returns defaultEmptyOK if s is empty.
// There is an optional second argument called emptyOK.
// emptyOK is used to override for a single function call
//      the default behavior which is specified globally by
//      defaultEmptyOK.
// If emptyOK is false (or any value other than true),
//      the function will return false if s is empty.
// If emptyOK is true, the function will return true if s is empty.
//
// EXAMPLE FUNCTION CALL:     RESULT:
// isInteger ("5")            true
// isInteger ("")             defaultEmptyOK
// isInteger ("-5")           false
// isInteger ("", true)       true
// isInteger ("", false)      false
// isInteger ("5", false)     true

function isInteger (s)

{   var i;

    if (isEmpty(s))
       if (isInteger.arguments.length == 1) return defaultEmptyOK;
       else return (isInteger.arguments[1] == true);

    // Search through string's characters one by one
    // until we find a non-numeric character.
    // When we do, return false; if we don't, return true.

    for (i = 0; i < s.length; i++)
    {
        // Check that current character is number.
        var c = s.charAt(i);

        if (!isDigit(c)) return false;
    }

    // All characters are numbers.
    return true;
}

// isSignedInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if all characters are numbers;
// first character is allowed to be + or - as well.
//
// Does not accept floating point, exponential notation, etc.
//
// We don't use parseInt because that would accept a string
// with trailing non-numeric characters.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//
// EXAMPLE FUNCTION CALL:          RESULT:
// isSignedInteger ("5")           true
// isSignedInteger ("")            defaultEmptyOK
// isSignedInteger ("-5")          true
// isSignedInteger ("+5")          true
// isSignedInteger ("", false)     false
// isSignedInteger ("", true)      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];

        // skip leading + or -
        if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") )
           startPos = 1;
        return (isInteger(s.substring(startPos, s.length), secondArg))
    }
}

// isPositiveInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if string s is an integer > 0.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function isPositiveInteger (s)
{   var secondArg = defaultEmptyOK;

    if (isPositiveInteger.arguments.length > 1)
        secondArg = isPositiveInteger.arguments[1];

    // The next line is a bit byzantine.  What it means is:
    // a) s must be a signed integer, AND
    // b) one of the following must be true:
    //    i)  s is empty and we are supposed to return true for
    //        empty strings
    //    ii) this is a positive, not negative, number

    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s) > 0) ) );
}

// isNonnegativeInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if string s is an integer >= 0.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function isNonnegativeInteger (s)
{   var secondArg = defaultEmptyOK;

    if (isNonnegativeInteger.arguments.length > 1)
        secondArg = isNonnegativeInteger.arguments[1];

    // The next line is a bit byzantine.  What it means is:
    // a) s must be a signed integer, AND
    // b) one of the following must be true:
    //    i)  s is empty and we are supposed to return true for
    //        empty strings
    //    ii) this is a number >= 0

    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s) >= 0) ) );
}


// isNegativeInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if string s is an integer < 0.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function isNegativeInteger (s)
{   var secondArg = defaultEmptyOK;

    if (isNegativeInteger.arguments.length > 1)
        secondArg = isNegativeInteger.arguments[1];

    // The next line is a bit byzantine.  What it means is:
    // a) s must be a signed integer, AND
    // b) one of the following must be true:
    //    i)  s is empty and we are supposed to return true for
    //        empty strings
    //    ii) this is a negative, not positive, number

    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s) < 0) ) );
}


// isNonpositiveInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if string s is an integer <= 0.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

function isNonpositiveInteger (s)
{   var secondArg = defaultEmptyOK;

    if (isNonpositiveInteger.arguments.length > 1)
        secondArg = isNonpositiveInteger.arguments[1];

    // The next line is a bit byzantine.  What it means is:
    // a) s must be a signed integer, AND
    // b) one of the following must be true:
    //    i)  s is empty and we are supposed to return true for
    //        empty strings
    //    ii) this is a number <= 0

    return (isSignedInteger(s, secondArg)
         && ( (isEmpty(s) && secondArg)  || (parseInt (s) <= 0) ) );
}


// isFloat (STRING s [, BOOLEAN emptyOK])
//
// 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.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

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;

    // Search through string's characters one by one
    // until we find a non-numeric character.
    // When we do, return false; if we don't, return true.

    for (i = 0; i < s.length; i++)
    {
        // Check that current character is number.
        var c = s.charAt(i);

        if ((c == decimalPointDelimiter) && !seenDecimalPoint) seenDecimalPoint = true;
        else if (!isDigit(c)) return false;
    }

    // All characters are numbers.
    return true;
}


// isSignedFloat (STRING s [, BOOLEAN emptyOK])
//
// True if string s is a signed or unsigned floating point
// (real) number. First character is allowed to be + or -.
//
// Also returns true for unsigned integers. If you wish
// to distinguish between integers and floating point numbers,
// first call isSignedInteger, then call isSignedFloat.
//
// Does not accept exponential notation.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.

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];

        // skip leading + or -
        if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") )
           startPos = 1;
        return (isFloat(s.substring(startPos, s.length), secondArg))
    }
}




// isAlphabetic (STRING s [, BOOLEAN emptyOK])
//
// Returns true if string s is English letters
// (A .. Z, a..z) only.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//
// NOTE: Need i18n version to support European characters.
// This could be tricky due to different character
// sets and orderings for various languages and platforms.

function isAlphabetic (s)

{   var i;

    if (isEmpty(s))
       if (isAlphabetic.arguments.length == 1) return defaultEmptyOK;
       else return (isAlphabetic.arguments[1] == true);

    // Search through string's characters one by one
    // until we find a non-alphabetic character.
    // When we do, return false; if we don't, return true.

    for (i = 0; i < s.length; i++)
    {
        // Check that current character is letter.
        var c = s.charAt(i);

        if (!isLetter(c))
        return false;
    }

    // All characters are letters.
    return true;
}




// isAlphanumeric (STRING s [, BOOLEAN emptyOK])
//
// Returns true if string s is English letters
// (A .. Z, a..z) and numbers only.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//
// NOTE: Need i18n version to support European characters.
// This could be tricky due to different character
// sets and orderings for various languages and platforms.

function isAlphanumeric (s)

{   var i;

    if (isEmpty(s))
       if (isAlphanumeric.arguments.length == 1) return defaultEmptyOK;
       else return (isAlphanumeric.arguments[1] == true);

    // Search through string's characters one by one
    // until we find a non-alphanumeric character.
    // When we do, return false; if we don't, return true.

    for (i = 0; i < s.length; i++)
    {
        // Check that current character is number or letter.
        var c = s.charAt(i);

        if (! (isLetter(c) || isDigit(c) ) )
        return false;
    }

    // All characters are numbers or letters.
    return true;
}




// reformat (TARGETSTRING, STRING, INTEGER, STRING, INTEGER ... )
//
// Handy function for arbitrarily inserting formatting characters
// or delimiters of various kinds within TARGETSTRING.
//
// reformat takes one named argument, a string s, and any number
// of other arguments.  The other arguments must be integers or
// strings.  These other arguments specify how string s is to be
// reformatted and how and where other strings are to be inserted
// into it.
//
// reformat processes the other arguments in order one by one.
// * If the argument is an integer, reformat appends that number
//   of sequential characters from s to the resultString.
// * If the argument is a string, reformat appends the string
//   to the resultString.
//
// 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.
//
// It is the caller's responsibility to make sure that we do not
// try to copy more characters from s than s.length.
//
// 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;
}

// takes ZIPString, a string of 5 or 9 digits;
// if 9 digits, inserts separator hyphen
function reformatZIPCode (ZIPString)
{   if (ZIPString.length == 5) return ZIPString;
    else return (reformat (ZIPString, "", 5, "-", 4));
}

// takes USPhone, a string of 10 digits
// and reformats as (123) 456-789
function reformatUSPhone (USPhone)
{   return (reformat (USPhone, "(", 3, ") ", 3, "-", 4))
}

// takes SSN, a string of 9 digits
// and reformats as 123-45-6789
function reformatSSN (SSN)
{   return (reformat (SSN, "", 3, "-", 2, "-", 4))
}

//------------------------------------------------------------------------------------
// function: isLeapYear
//           Function to tell, whether the given year is leap year or not
//------------------------------------------------------------------------------------
function isLeapYear(argYear) {
        return ((argYear % 4 == 0) && (argYear % 100 != 0)) || (argYear % 400 == 0)
}

//------------------------------------------------------------------------------------
// function: daysInMonth
//           Function to return the maximum number of days in a given month of a
//           given year
//------------------------------------------------------------------------------------
function daysInMonth(argMonth, argYear) {
        switch (Number(argMonth)) {
                case 1:         // Jan
                case 3:         // Mar
                case 5:         // May
                case 7:         // Jul
                case 8:         // Aug
                case 10:                // Oct
                case 12:                // Dec
                        return 31;
                        break;

                case 4:         // Apr
                case 6:         // Jun
                case 9:         // Sep
                case 11:                // Nov
                        return 30;
                        break;

                case 2:         // Feb
                        if (isLeapYear(argYear))
                                return 29
                        else
                                return 28
                        break;

                default:
                        return 0;
        }
}

//------------------------------------------------------------------------------------
// function: getDateSeparator
//           Function to return the date separator
//           This function expects date in the format of mm/dd/yyyy or mm/dd/yy
//           or mm-dd-yyyy or mm-dd-yy
//------------------------------------------------------------------------------------
function getDateSeparator(argDate) {
        // Are there invalid separators?
        if ((argDate.indexOf('-') > 0) && (argDate.indexOf('/') > 0))
                return ' '

        if (argDate.indexOf('-') > 0)
                return '-'
        else
                if (argDate.indexOf('/') > 0)
                        return '/'
                else
                        return ' '
}

//------------------------------------------------------------------------------------
// function: getYear
//           Function to return the year part of the given date.
//           This function expects date in the format of mm/dd/yyyy or mm/dd/yy
//           or mm-dd-yyyy or mm-dd-yy
//------------------------------------------------------------------------------------
function getYear(argDate) {
        var dateSep = getDateSeparator(argDate)

        if (dateSep == ' ')
                return 0

        if(argDate.split(dateSep).length == 3)
                return argDate.split(dateSep)[2]
        else
                return 0
}

//------------------------------------------------------------------------------------
// function: getMonth
//           Function to return the month part of the given date.
//           This function expects date in the format of mm/dd/yyyy or mm/dd/yy
//           or mm-dd-yyyy or mm-dd-yy
//------------------------------------------------------------------------------------
function getMonth(argDate) {
        var dateSep = getDateSeparator(argDate)

        if (dateSep == ' ')
                return 0

        if(argDate.split(dateSep).length == 3)
                return argDate.split(dateSep)[0]
        else
                return 0
}

//------------------------------------------------------------------------------------
// function: getDay
//           Function to return the day part of the given date.
//           This function expects date in the format of mm/dd/yyyy or mm/dd/yy
//           or mm-dd-yyyy or mm-dd-yy
//------------------------------------------------------------------------------------
function getDay(argDate) {
        var dateSep = getDateSeparator(argDate)

        if (dateSep == ' ')
                return 0

        if(argDate.split(dateSep).length == 3)
                return argDate.split(dateSep)[1]
        else
                return 0
}

//------------------------------------------------------------------------------------
// function: isProperDay
//           Function to tell whether the given day of the given month is valid
//------------------------------------------------------------------------------------
function isProperDay(argDay, argMonth, argYear) {
        if ((isWhiteSpace(argDay)) || (argDay == 0))
                return false

        if ((argDay > 0) && (argDay < daysInMonth(argMonth, argYear) + 1))
                return true
        else
                return false
}

//------------------------------------------------------------------------------------
// function: isProperMonth
//           Function to tell whether the given month is a valid one
//------------------------------------------------------------------------------------
function isProperMonth(argMonth) {
        if ((isWhiteSpace(argMonth)) || (argMonth == 0))
                return false

        if ((argMonth > 0) && (argMonth < 13))
                return true
        else
                return false
}

//------------------------------------------------------------------------------------
// function: isProperYear
//           Function to tell whether the given Year is a valid one
//------------------------------------------------------------------------------------
function isProperYear(argYear) {
        if ((isWhiteSpace(argYear)) || (argYear.toString().length > 4) || (argYear.toString().length == 3))
                return false

        switch (argYear.toString().length) {
                case 1:
                        if (argYear >=0 && argYear < 10)
                                return true
                        else
                                return false

                case 2:
                        if (argYear >=0 && argYear < 100)
                                return true
                        else
                                return false

                case 4:
                        if (((argYear >=1900) || (argYear >=2000)) && ((argYear < 3000) || (argYear < 2000)))
                                return true
                        else
                                return false

                default:
                        return false
        }
}

//------------------------------------------------------------------------------------
// function: isProperDate
//           Function to tell whether the given date is valid or not
//           This function expects date in the format of mm/dd/yyyy or mm/dd/yy
//           or mm-dd-yyyy or mm-dd-yy
//------------------------------------------------------------------------------------
function isProperDate(argDate) {
        var tmpDay = getDay(argDate)
        var tmpMon = getMonth(argDate)
        var tmpYear = getYear(argDate)

        return isProperDay(tmpDay, tmpMon, tmpYear) && isProperMonth(tmpMon) && isProperYear(tmpYear)
}

//------------------------------------------------------------------------------------
// function: charOccurences
//           Function to return the number of times a given character is occuring in
//           the given string
//------------------------------------------------------------------------------------
function charOccurences(argString, argChar) {
        var intCt = 0

        for(var intI=0; intI < argString.length; intI++)
                if (argString.charAt(intI) == argChar)
                        intCt++

        return intCt
}

//------------------------------------------------------------------------------------
// function: isProperEmail
//           Function to tell whether the given email is valid or not
//------------------------------------------------------------------------------------
function isProperEmail(argEmail) {
        if (charOccurences(argEmail, '@') + charOccurences(argEmail, '.') < 2)
                return false

        var atPos = argEmail.indexOf('@')
        var dotPos = argEmail.indexOf('.')

        if((atPos == 0) || (atPos == (argEmail.length - 1)))
                return false

        if((dotPos == 0) || (dotPos == (argEmail.length - 1)))
                return false

        if((atPos > dotPos) || (atPos == (dotPos - 1)))
          if (charOccurences(argEmail, '.') == 1)
              return false

        /* The following variable tells the rest of the function whether or not
        to verify that the address ends in a two-letter country or well-known
        TLD.  1 means check it, 0 means don't. */

        var checkTLD=1;

        /* The following is the list of known TLDs that an e-mail address must end with. */

        var knownDomsPat=/^(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum)$/;

        /* The following pattern is used to check if the entered e-mail address
        fits the user@domain format.  It also is used to separate the username
        from the domain. */

        var emailPat=/^(.+)@(.+)$/;

        /* The following string represents the pattern for matching all special
        characters.  We don't want to allow special characters in the address.
        These characters include ( ) < > @ , ; : \ " . [ ] */

        var specialChars="\\(\\)><@,;:\\\\\\\"\\.\\[\\]";

        /* The following string represents the range of characters allowed in a
        username or domainname.  It really states which chars aren't allowed.*/

        var validChars="\[^\\s" + specialChars + "\]";

        /* The following pattern applies if the "user" is a quoted string (in
        which case, there are no rules about which characters are allowed
        and which aren't; anything goes).  E.g. "jiminy cricket"@disney.com
        is a legal e-mail address. */

        var quotedUser="(\"[^\"]*\")";

        /* The following pattern applies for domains that are IP addresses,
        rather than symbolic names.  E.g. joe@[123.124.233.4] is a legal
        e-mail address. NOTE: The square brackets are required. */

        var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;

        /* The following string represents an atom (basically a series of non-special characters.) */

        var atom=validChars + '+';

        /* The following string represents one word in the typical username.
        For example, in john.doe@somewhere.com, john and doe are words.
        Basically, a word is either an atom or quoted string. */

        var word="(" + atom + "|" + quotedUser + ")";

        // The following pattern describes the structure of the user

        var userPat=new RegExp("^" + word + "(\\." + word + ")*$");

        /* The following pattern describes the structure of a normal symbolic
        domain, as opposed to ipDomainPat, shown above. */

        var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");

        /* Finally, let's start trying to figure out if the supplied address is valid. */

        /* Begin with the coarse pattern to simply break up user@domain into
        different pieces that are easy to analyze. */

        var matchArray=argEmail.match(emailPat);

        if (matchArray==null)
                {

                /* Too many/few @'s or something; basically, this address doesn't
                even fit the general mould of a valid e-mail address. */

                return false;
                }
        var user=matchArray[1];
        var domain=matchArray[2];

        // Start by checking that only basic ASCII characters are in the strings (0-127).

        for (i=0; i<user.length; i++)
                {
                if (user.charCodeAt(i)>127)
                        {
                        return false;
                        }
                }
        for (i=0; i<domain.length; i++)
                {
                if (domain.charCodeAt(i)>127)
                        {
                        return false;
                        }
                }

        // See if "user" is valid

        if (user.match(userPat)==null)
                {
                // user is not valid
                return false;
        }

        /* if the e-mail address is at an IP address (as opposed to a symbolic
        host name) make sure the IP address is valid. */

        var IPArray=domain.match(ipDomainPat);
        if (IPArray!=null)
                {
                // this is an IP address
                for (var i=1;i<=4;i++)
                        {
                        if (IPArray[i]>255)
                                {
                                return false;
                                }
                        }
                return true;
                }

        // Domain is symbolic name.  Check if it's valid.

        var atomPat=new RegExp("^" + atom + "$");
        var domArr=domain.split(".");
        var len=domArr.length;
        for (i=0;i<len;i++)
                {
                if (domArr[i].search(atomPat)==-1)
                        {
                        return false;
                        }
                }

        /* domain name seems valid, but now make sure that it ends in a
        known top-level domain (like com, edu, gov) or a two-letter word,
        representing country (uk, nl), and that there's a hostname preceding
        the domain or country. */

        if (checkTLD && domArr[domArr.length-1].length!=2 && domArr[domArr.length-1].search(knownDomsPat)==-1)
                {
                return false;
                }

        // Make sure there's a host name preceding the domain.
        if (len<2)
                {
                return false;
                }

        // If we've gotten this far, everything's valid!
        return true;
}

//------------------------------------------------------------------------------------
// function: isProperNumber
//           Function to tell whether the given string is a proper number
//------------------------------------------------------------------------------------
function isProperNumber(argNumber) {
        var numberValue = Number(argNumber)

        if (isNaN(numberValue))
                return false
        else
                return !isWhiteSpace(argNumber)
}

//------------------------------------------------------------------------------------
// function: isProperAlphabetic
//           Function to tell whether the given string is a proper alphabetic string
//------------------------------------------------------------------------------------
function isProperAlphabetic(argString) {
        var alphabets = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ"

        for(var intI=0; intI<argString.length; intI++)
                if (alphabets.indexOf(argString.charAt(intI)) == -1)
                        return false

        return true
}

//------------------------------------------------------------------------------------
// function: objectValue
//           Function to return the value of the form element
//------------------------------------------------------------------------------------
function objectValue(argFrm, argElem) {
        var intI
        var objElem = null

        for (intI=0; intI<argFrm.length; intI++)
                if (argFrm[intI].name == argElem)
                        objElem = argFrm[intI]

        switch (objElem.type) {
                case 'text':
                case 'hidden':
                case 'password':
                        return objElem.value
                        break;

                case 'select-one':
                        if (objElem.length == 0)
                                return ''
                        else
                                return objElem.options[objElem.selectedIndex].value
                        break;

                case 'radio':
                        for (intI=0; intI<argFrm.length; intI++)
                                if (argFrm[intI].name == argElem)
                                        if (argFrm[intI].checked)
                                                return argFrm[intI].value

                        return ''
                        break;
        }
}

//------------------------------------------------------------------------------------
// function: objectFocus
//           Function to set the focus to the form element
//------------------------------------------------------------------------------------
function objectFocus(argFrm, argElem) {
        var intI
        var objElem = null
        for (intI=0; intI<argFrm.length; intI++)
                if (argFrm[intI].name == argElem)
                        objElem = argFrm[intI]
        objElem.focus();
}

//------------------------------------------------------------------------------------
// function: isProperZip
//           Function to validate a Zip code
//------------------------------------------------------------------------------------
function isProperZip(argZip) {
        if ((argZip.length == 5) || (argZip.length == 9))
                return isProperNumber(argZip)

        if (argZip.length == 10)
                return (isProperNumber(argZip.substr(0, 5)) && isProperNumber(argZip.substr(6, 4)) & (argZip.charAt(5) == '-'))
}

//------------------------------------------------------------------------------------
// returns true if string s is a valid U.S. Phone Number.  Must be 10 digits.
//------------------------------------------------------------------------------------
function isProperUSPhone (argPhone)
{
        var argPhone2 = stripCharsNotInBag(argPhone,"0123456789")
    return (isOkBag(argPhone,"01234567890 -().") && isInteger(argPhone2) && argPhone2.length==digitsInUSPhoneNumber)
}

//------------------------------------------------------------------------------------
// function: isProperUSSSN
//------------------------------------------------------------------------------------
function isProperUSSSN(argSSN) {
        var argSSN2 = stripCharsNotInBag(argSSN,"0123456789")
    return (isOkBag(argSSN,"01234567890-") && isInteger(argSSN2) && argSSN2.length==11)
}

//------------------------------------------------------------------------------------
// function: actionFields
//           Function to parse the action arguments
//------------------------------------------------------------------------------------
function actionFields(argActions) {
        this.email                      = (argActions.indexOf('[email]') > -1)
        this.required           = (argActions.indexOf('[req]') > -1)
        this.checkDate          = (argActions.indexOf('[date]') > -1)
        this.checkZip           = (argActions.indexOf('[zip]') > -1)
        this.checkNumber        = (argActions.indexOf('[number]') > -1)
        this.checkAlphabetic= (argActions.indexOf('[alpha]') > -1)
        this.checkUSPhone       = (argActions.indexOf('[usphone]') > -1)
        this.checkUSSSN         = (argActions.indexOf('[usssn]') > -1)

        if (argActions.indexOf('[len=') > -1) {
                this.checkLength = true

                var lenToCheck = ''
                var bolCont = true

                for (var intI=(argActions.indexOf('[len=') +  5);((intI < argActions.length) && bolCont); intI++)
                        if (argActions.charAt(intI) != ']')
                                lenToCheck += argActions.charAt(intI)
                        else
                                bolCont = false
                this.lengthToCheck = lenToCheck
        }
        else
                this.checkLength = false

        if (argActions.indexOf('[blankalert=') > -1) {
                this.blankAlert = true

                var alertString = ''
                var bolCont = true

                for (var intI=(argActions.indexOf('[blankalert=') +  12);((intI < argActions.length) && bolCont); intI++)
                        if (argActions.charAt(intI) != ']')
                                alertString += argActions.charAt(intI)
                        else
                                bolCont = false
                this.blankAlertMessage = alertString
        }
        else
                this.blankAlert = false

        if (argActions.indexOf('[invalidalert=') > -1) {
                this.invalidAlert = true

                var alertString = ''
                var bolCont = true

                for (var intI=(argActions.indexOf('[invalidalert=') +  14);((intI < argActions.length) && bolCont); intI++)
                        if (argActions.charAt(intI) != ']')
                                alertString += argActions.charAt(intI)
                        else
                                bolCont = false
                this.invalidAlertMessage = alertString
        }
        else
                this.invalidAlert = false

        if (argActions.indexOf('[equals=') > -1) {
                this.shouldEqual = true

                var equalsString = ''
                var bolCont = true

                for (var intI=(argActions.indexOf('[equals=') +  8);((intI < argActions.length) && bolCont); intI++)
                        if (argActions.charAt(intI) != ']')
                                equalsString += argActions.charAt(intI)
                        else
                                bolCont = false
                this.shouldEqualString = equalsString
        }
        else
                this.shouldEqual = false

}


//------------------------------------------------------------------------------------
// function: validateForm
//           Function to validate a HTML form
//------------------------------------------------------------------------------------
function validateForm(argForm)
        {
        var frmElements = argForm.elements
        var elemName
        var elemObj

        submitonce(argForm);

        for (var intI=0; intI < frmElements.length; intI++) {// *
                elemObj = frmElements[intI]
                elemName = elemObj.name

                if ((elemObj.type == 'hidden') && (elemName.length > 5))
                        if (elemName.substr(elemName.length - 5).toLowerCase() == '_vldt') {// **
                                var objAction = new actionFields(objectValue(frmElements, elemName))
                                var actElem = elemName.substr(0, elemName.length - 5)

                                // Is it a required field?
                                if (objAction.required) {
                                        if (isWhiteSpace(objectValue(frmElements, actElem))) {// ***
                                                alert (objAction.blankAlert?objAction.blankAlertMessage:actElem + ' cannot be left blank')
                                                objectFocus(frmElements, actElem);
                                                submitenabled(argForm);
                                                return false
                                        } // ***
                                }

                                // Check the type validations
                                if ((objectValue(frmElements, actElem) > '') && (!isWhiteSpace(objectValue(frmElements, actElem)))){// ***
                                        // Date
                                        if (objAction.checkDate)
                                                if (!isProperDate(objectValue(frmElements, actElem))) {// ****
                                                        alert (objAction.invalidAlert?objAction.invalidAlertMessage:actElem + ' cannot have an invalid date')
                                                        objectFocus(frmElements, actElem);
                                                        submitenabled(argForm);
                                                        return false
                                                } // ****

                                        // Number
                                        if (objAction.checkNumber)
                                                if (!isProperNumber(objectValue(frmElements, actElem))) {// ****
                                                        alert (objAction.invalidAlert?objAction.invalidAlertMessage:actElem + ' cannot have an invalid number')
                                                        objectFocus(frmElements, actElem);
                                                        submitenabled(argForm);
                                                        return false
                                                } // ****

                                        // Zip
                                        if (objAction.checkZip)
                                                if (!isProperZip(objectValue(frmElements, actElem))) {// ****
                                                        alert (objAction.invalidAlert?objAction.invalidAlertMessage:actElem + ' cannot have an invalid zipcode')
                                                        objectFocus(frmElements, actElem);
                                                        submitenabled(argForm);
                                                        return false
                                                } // ****

                                        // Alphabetic
                                        if (objAction.checkAlphabetic)
                                                if (!isProperAlphabetic(objectValue(frmElements, actElem))) {// ****
                                                        alert (objAction.invalidAlert?objAction.invalidAlertMessage:actElem + ' cannot have invalid characters')
                                                        objectFocus(frmElements, actElem);
                                                        submitenabled(argForm);
                                                        return false
                                                } // ****

                                        // Check US phone
                                        if (objAction.checkUSPhone)
                                                if (!isProperUSPhone(objectValue(frmElements, actElem))) {// ****
                                                        alert (objAction.invalidAlert?objAction.invalidAlertMessage:actElem + ' cannot have invalid characters')
                                                        objectFocus(frmElements, actElem);
                                                        submitenabled(argForm);
                                                        return false
                                                } // ****

                                        // Check US SSN
                                        if (objAction.checkUSSSN)
                                                if (!isProperUSSSN(objectValue(frmElements, actElem))) {// ****
                                                        alert (objAction.invalidAlert?objAction.invalidAlertMessage:actElem + ' cannot have invalid characters')
                                                        objectFocus(frmElements, actElem);
                                                        submitenabled(argForm);
                                                        return false
                                                } // ****

                                        // Check email
                                        //if (objAction.email)
                                        //        if (!isProperEmail(objectValue(frmElements, actElem))) {// ****
                                        //                alert (objAction.invalidAlert?objAction.invalidAlertMessage:actElem + ' cannot have invalid characters')
                                        //                objectFocus(frmElements, actElem);
                                        //                submitenabled(argForm);
                                        //                return false
                                        //        } // ****

                                        // Check for length
                                        if (objAction.checkLength)
                                                if (objectValue(frmElements, actElem).length < objAction.lengthToCheck) {// ****
                                                        alert (objAction.invalidAlert?objAction.invalidAlertMessage:actElem + ' must be at least ' + objAction.lengthToCheck + ' characters long')
                                                        objectFocus(frmElements, actElem);
                                                        submitenabled(argForm);
                                                        return false
                                                } // ****
                                } // ***
                        } // **
        } // *

        return true
}


function submitenabled(theform)
        {
        // if IE 4+ or NS 6+
        if (document.all||document.getElementById)
                {
                //screen thru every element in the form, and hunt down "submit" and "reset"
                for (i=0;i<theform.length;i++)
                        {
                        var tempobj=theform.elements[i];
                        if(tempobj.type.toLowerCase()=="submit" || tempobj.type.toLowerCase()=="reset")
                                //disable em
                                tempobj.disabled=false;
                        }
                }
        }


function submitonce(theform)
        {
        // if IE 4+ or NS 6+
        if (document.all||document.getElementById)
                {
                //screen thru every element in the form, and hunt down "submit" and "reset"
                for (i=0;i<theform.length;i++)
                        {
                        var tempobj=theform.elements[i];
                        if(tempobj.type.toLowerCase()=="submit" || tempobj.type.toLowerCase()=="reset")
                                //disable em
                                tempobj.disabled=true;
                        }
                }
        }
