// BASIC DATA VALIDATION FUNCTIONS:
// isEmpty (s)												 Check whether string s is empty 
// isWhitespace (s)										 Check whether string s is empty or whitespace.
// isCorrectDate(s)
// 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.
// isAlphanumeric (s [,eok])           True if string s is English letters and numbers only.
// isNonnegativeInteger (s [,eok])     True if string s is an integer >= 0.
// isSignedFloat (s [,eok])            True if string s is a floating point number; leading + or - allowed. (Integers also OK.)
// isIntegerInRange (s, a, b [,eok])   True if string s is an integer between a and b, inclusive.
// isYear (s [,eok])                   True if string s is a valid Year number.
// isMonth (s [,eok])                  True if string s is a valid month between 1 and 12.
// isDay (s [,eok])                    True if string s is a valid day between 1 and 31.
// daysInFebruary (year)               Returns number of days in February of that year.
// isDate (year, month, day)           True if string arguments form a valid date.

// FUNCTIONS TO PROMPT USER:
// warnEmpty (theField, s)             Notify user that required field theField is empty.
// warnInvalid (theField, s)           Notify user that contents of field theField are invalid.

// FUNCTIONS TO INTERACTIVELY CHECK FIELD CONTENTS:
// checkString (theField, s [,eok])    Check that theField.value is not empty or all whitespace.
// checkYear (theField [,eok])         Check that theField.value is a valid Year.
// checkMonth (theField [,eok])        Check that theField.value is a valid Month.
// checkDay (theField [,eok])          Check that theField.value is a valid Day.
// checkDate (yearField, monthField, dayField, labelString, OKtoOmitDay)

// REGULAR EXPRESSION DECLARATIONS

// BOI, followed by one or more whitespace characters, followed by EOI.
var reWhitespace	= /^\s+$/

//var reDate				= /(\d{1,2})\s*[-\/]\s*(\d{1,2})\s*[-\/]\s*(\d{2,4})/
var reDate				= /^(\d{1,2})\s*[-\/]\s*(\d{1,2})\s*[-\/]\s*(\d{4})/  
// Removed hyphens to not allow negative numbers to be entered for the month.
// Also made the year a 4 digit year.
 
var reDateSep			= /\s*[-\/]\s*/


// Removed hyphens to not allow negative numbers entered for the month.



// BOI, followed by one or more digits, followed by EOI.
var reInteger = /^\d+$/

// BOI, followed by an optional + or -, followed by one or more digits, followed by EOI.
var reSignedInteger = /^(\+|-)?\d+$/

// BOI, followed by one of these two patterns:
// (a) one or more digits, followed by ., followed by zero or more digits
// (b) zero or more digits, followed by ., followed by one or more digits
// ... followed by EOI.
var reFloat = /^((\d+(\.\d*)?)|((\d*\.)?\d+))$/

var reSignedFloat = /^(\-)?\d*(\.\d+)?$/
// |(\d*\.)?\d+$/

// BOI, followed by one or more lower or uppercase English letters
// or digits, followed by EOI.
var reAlphanumeric = /^[a-zA-Z0-9]+$/

var reEmail = /^.+\@.+\..+$/

// VARIABLE DECLARATIONS
var defaultEmptyOK = false

// CONSTANT STRING DECLARATIONS

// i is an abbreviation for "invalid"
var iDay = "The day must be a day number between 1 and 31.  Please reenter it now."
var iMonth = "The month must be a month number between 1 and 12.  Please reenter it now."
var iYear = "The year must be a 4 digit year number.  Please reenter it now."
var iValidYear = "The year must be greater than 1752.  Please reenter it now."
var iDate = "This is an invalid date. Please enter the date in the format MM/DD/YYYY." /* or MM/DD/YY" */
var iDatePrefix = "The Day, Month, and Year for \n   "
var iDateSuffix = " \ndo not form a valid date.  \n\nPlease reenter them now in the format \nMM/DD/YYYY." /* or MM/DD/YY." */
var iMoney = "This is not a valid price"

// m is an abbreviation for "missing"
var mPrefix = "You did not enter a value into the \n   "
var mSuffix = " \nfield. This is a required field. \n\nPlease enter it now."


//MakeArray
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;

// BASIC DATA VALIDATION FUNCTIONS:

// 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)
{	// Is s empty?
	return (isEmpty(s) || reWhitespace.test(s));
}

//isCorrectDate; returns true if string is a correct date string
function isCorrectDate(s)
{
	return (reDate.test(s));
}

// 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);
	return reInteger.test(s)
}


// 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.
// 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 {
       return reSignedInteger.test(s)
    }
}

// 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,10) >= 0) ) );
}

// isIntegerInRange (STRING s, INTEGER a, INTEGER b [, BOOLEAN emptyOK])
// isIntegerInRange returns true if string s is an integer 
// within the range of integer arguments a and b, inclusive.
function isIntegerInRange (s, a, b)
{   if (isEmpty(s))
      if (isIntegerInRange.arguments.length == 1) return defaultEmptyOK;
       else return (isIntegerInRange.arguments[1] == true);

    // Catch non-integer strings to avoid creating a NaN below,
    // which isn't available on JavaScript 1.0 for Windows.
    if (!isInteger(s, false)) return false;

    // Now, explicitly change the type to integer via parseInt
    // so that the comparison code below will work both on 
    // JavaScript 1.2 (which typechecks in equality comparisons)
    // and JavaScript 1.1 and before (which doesn't).
    var num = parseInt (s,10);
     
    //alert (s+', '+num);
    return ((num >= a) && (num <= b));
    
}


// 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)

{   if (isEmpty(s)) 
       if (isFloat.arguments.length == 1) return defaultEmptyOK;
       else return (isFloat.arguments[1] == true);

    return reFloat.test(s)
}


function isSignedFloat (s)

{   if (isEmpty(s)) 
       if (isSignedFloat.arguments.length == 1) return defaultEmptyOK;
       else return (isSignedFloat.arguments[1] == true);

    return reSignedFloat.test(s)
}


// isAlphanumeric (STRING s)
// Returns true if string s is English letters 
// (A .. Z, a..z) and numbers only.
function isAlphanumeric (s)
{   
  return reAlphanumeric.test(s)
}


// isYear (STRING s [, BOOLEAN emptyOK])
// isYear returns true if string s is a valid Year number.  Must be 2 or 4 digits only.
// For Year 2000 compliance, you are advised to use 4-digit year numbers everywhere.
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 == 2) || (s.length == 4));  
}

function isValidYear (s)
{  
	if (s.length == 4 && s < 1753)
    return false;
  else
    return true;  
}

// isMonth (STRING s [, BOOLEAN emptyOK])
// isMonth returns true if string s is a valid 
// month number between 1 and 12.
function isMonth (s)
{
	//alert(s);
   if (isEmpty(s)) 
       if (isMonth.arguments.length == 1) return defaultEmptyOK;
       else return (isMonth.arguments[1] == true);
   return isIntegerInRange (s, 1, 12);
}


// isDay (STRING s [, BOOLEAN emptyOK])
// isDay returns true if string s is a valid 
// day number between 1 and 31.
function isDay (s)
{   if (isEmpty(s))
      if (isDay.arguments.length == 1) return defaultEmptyOK;
       else return (isDay.arguments[1] == true);   
    return isIntegerInRange (s, 1, 31);
}


// daysInFebruary (INTEGER year)
// Given integer argument year,
// returns number of days in February of that year.
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 );
}


// isDate (STRING year, STRING month, STRING day)
// isDate returns true if string arguments year, month, and day 
// form a valid date.
function isDate (year, month, day)
{   // catch invalid years (not 2- or 4-digit) and invalid months and days.
    if (! (isYear(year, false) && isMonth(month, false) && isDay(day, false))) return false;
   
    // Explicitly change type to integer to make code work in both
    // JavaScript 1.1 and JavaScript 1.2.
    var intYear = parseInt(year,10);
    var intMonth = parseInt(month,10);
    var intDay = parseInt(day,10);
    

    // catch invalid days, except for February
    if (intDay > daysInMonth[intMonth]) return false; 

    if ((intMonth == 2) && (intDay > daysInFebruary(intYear))) return false;

    return true;
}


// 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
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
function isEmail (s)
{   if (isEmpty(s)) 
       if (isEmail.arguments.length == 1) return defaultEmptyOK;
       else return (isEmail.arguments[1] == true);
    
    else {
       return reEmail.test(s)
    }
}


//function checkZipCode
function checkZipCode (theField, s, OKtoOmit)
{
	if (checkZipCode.arguments.length == 2) OKtoOmit = false;
	if (isEmpty(theField.value)) {
		if (OKtoOmit == true) return true;
		else return warnInvalid(theField, mPrefix + s + mSuffix);
	}
	else
		return true;
}


// FUNCTIONS TO PROMPT USER:

// 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
}

// Notify user that contents of field theField are invalid.
// String s describes expected contents of theField.value.
// select theField, put focus in it, and return false.
function warnInvalid (theField, s)
{   
	//theField.focus()
	//theField.select()
	alert(s)
	return false
}


// FUNCTIONS TO INTERACTIVELY CHECK FIELD CONTENTS:


//function checkNonnegativeInteger
function checkNonnegativeInteger (theField, s, OKtoOmit)
{
	if (checkNonnegativeInteger.arguments.length == 2) OKtoOmit = false;
	if (isEmpty(theField.value)) {
		if (OKtoOmit == true) return true;
		else return warnInvalid(theField, mPrefix + s + mSuffix);
	}

	if (isNonnegativeInteger(theField.value)) 
		return true; 
	else return warnInvalid (theField, s + ' is not a valid number. \nPlease re-enter it now');
}

//function checkInteger
function checkInteger (theField, s, OKtoOmit)
{
	if (checkInteger.arguments.length == 2) OKtoOmit = false;
	if (isEmpty(theField.value)) {
		if (OKtoOmit == true) return true;
		else return warnInvalid(theField, mPrefix + s + mSuffix);
	}

	if (isSignedInteger(theField.value)) 
		return true; 
	else return warnInvalid (theField, s  + ' is not a valid number. \nPlease re-enter it now');
}


// Check that string theField.value is not all whitespace.
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 formChekCleanNumber(strNum)
{
	if (!strNum) return strNum;
	strNum = formChekReplace(strNum, '$', '', 0);
	strNum = formChekReplace(strNum, ',', '', 0);
	strNum = formChekReplace(strNum, '%', '', 0);
	
	//( and ) added by Hande 3/9/2001; As per Bug 00-165;
	//strNum = formChekReplace(strNum, '(', '', 0);
	//strNum = formChekReplace(strNum, ')', '', 0);
	
	//strNum = formChekReplace(strNum, '+', '', 0);
	//strNum = formChekReplace(strNum, '-', '', 0);

	return strNum;
}


function formChekReplace(szBuf, szFind, szReplace, lStart)
{
	szBuf = '' + szBuf; // Make sure it's a string
	var lFind = 0;
	if (!lStart) lStart = 0;
	
	while (lFind != -1) {
		lFind = szBuf.indexOf(szFind, lStart);
		if (lFind != -1) {
			szBuf = szBuf.substring(0,lFind) + szReplace + szBuf.substring(lFind + szFind.length);
			lStart = lFind + szReplace.length;
		}
	}
	return szBuf;
}

function checkFloat( theField, s, emptyOK)
{
	/*
	if (checkFloat.arguments.length == 2) emptyOK = false;
	if ((isWhitespace(theField.value)) || (isEmpty(theField.value)))
	   return warnEmpty (theField, s);
	*/

	if (checkFloat.arguments.length == 2) emptyOK = false;
	if (isEmpty(theField.value)) {
		if (emptyOK == true) return true;
		else return warnInvalid(theField, mPrefix + s + mSuffix);
	}

	//Hande changed this on 2/21/2000; Added formChekCleanNumber
	//if (!isFloat(theField.value)) //iMoney
	if (!isFloat( formChekCleanNumber(theField.value) ) ) //iMoney
		return warnInvalid (theField, s + ' is not a valid value.\nPlease re-enter it now');
	else return true;
}


function checkSignedFloat( theField, s, emptyOK)
{

	if (checkSignedFloat.arguments.length == 2) emptyOK = false;
	if (isEmpty(theField.value)) {
		if (emptyOK == true) return true;
		else return warnInvalid(theField, mPrefix + s + mSuffix);
	}

	if (!isSignedFloat( formChekCleanNumber(theField.value) ) ) 
		return warnInvalid (theField, s + ' is not a valid value.\nPlease re-enter it now');
	else return true;
}

// Check that string is A/N if empty is not OK
function checkAlphanumeric (theField, s, emptyOK)
{   
    if (((checkAlphanumeric.arguments.length == 2) || (emptyOK == true)) && (isEmpty(theField.value))) return true;
        
    if (!isAlphanumeric(theField.value)) 
      return warnInvalid (theField, s + ' contains invalid character(s).\nPlease enter only alpha/numeric characters.');
    else return true;

}


// Check that string theField.value is a valid Year.
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, iYear);
    else {
      
      return true;
    }  
}


// Check that string theField.value is a valid Month.
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, iMonth);
    else return true;
}


// Check that string theField.value is a valid Day.
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, iDay);
    else return true;
}



// checkDate (yearField, monthField, dayField, STRING labelString [, OKtoOmitDay==false])
// Check that yearField.value, monthField.value, and dayField.value 
// form a valid date.
// If they don't, labelString (the name of the date, like "Birth Date")
// is displayed to tell the user which date field is invalid.
// If it is OK for the day field to be empty, set optional argument
// OKtoOmitDay to true.  It defaults to false.
function checkDateAux(yearField, monthField, dayField, labelString, OKtoOmitDay)
{	// Next line is needed on NN3 to avoid "undefined is not a number" error
	// in equality comparison below.
	if (checkDateAux.arguments.length == 4) OKtoOmitDay = false;

	if (!isYear(yearField)) return warnInvalid (yearField, iYear);

  if (!isValidYear(yearField)) return warnInvalid (yearField, iValidYear);

	//alert("Before isMonth");
	if (!isMonth(monthField)) return warnInvalid (monthField, iMonth);
	//alert("After isMonth");

	if ( (OKtoOmitDay == true) && isEmpty(dayField) ) return true;
	else if (!isDay(dayField)) 
		return warnInvalid (dayField, iDay);
	if (isDate (yearField, monthField, dayField))
		return true;
	alert (iDatePrefix + labelString + iDateSuffix)
	return false
}


function checkDate(dateField, labelString, OKtoOmitDay)
{
	if (checkDate.arguments.length == 2) OKtoOmitDay = false;
	if (isEmpty(dateField.value)) {
		if (OKtoOmitDay == true) return true;
		else return warnInvalid(dateField, mPrefix + labelString + mSuffix);
	}
	if (isCorrectDate(dateField.value)) {
		myArray = dateField.value.split(reDateSep);
		//alert(myArray);
		return checkDateAux(myArray[2], myArray[0], myArray[1], labelString, OKtoOmitDay);
	}
	return warnInvalid(dateField, iDatePrefix + labelString + iDateSuffix);
/*
Converting a string to a date like this works and returns true from isNaN for both 
IE and Navigator when the date is not valid;however, you can have days bigger than 
31 (or however many days are in the month). It just rolls ahead the number of days over.
var dt = new Date(dateField.value);
if (isNaN(dt)) alert('Not a valid date--NaN');
else alert(dt);
*/
}

function checkDateOrder(dateLowField, dateHighField, labelLow, labelHigh, equalOK)
{
	if (checkDateOrder.arguments.length == 4) equalOK = false;
	var dateLow = new Date(dateLowField.value);
	var dateHigh = new Date(dateHighField.value);
	// if (dateLow == dateHigh) always returned false, so we subtracted and compared to zero.
	if ((dateLow < dateHigh) || ((equalOK == true) && (dateHigh - dateLow == 0))) return true;
	else {
		if (equalOK == true) {
			var str = labelLow + ' should be the same or before ' + labelHigh;
		}
		else {
			var str = labelLow + ' should be before ' + labelHigh;
		}
		str += '.\n\nPlease reenter the dates.'
		return warnInvalid(dateLowField, str);
	}
}


// checkEmail (TEXTFIELD theField, s Field name [, BOOLEAN emptyOK==false])
//
// Check that string theField.value is a valid Email.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
function checkEmail (theField, s, emptyOK)
{   if (checkEmail.arguments.length == 1) emptyOK = defaultEmptyOK;
    if ((emptyOK == true) && (isEmpty(theField.value))) return true;
    else if (!isEmail(theField.value, false)) 
       return warnInvalid (theField, s + ' must be a valid email address (like foo@bar.com). Please reenter it now.');
    else return true;
}

