// 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.
// isNonnegativeInteger (s [,eok])     True if string s is an integer >= 0.
// 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.
// isEmail (s [,eok])                  True if string s is a valid email address.

// 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)
// checkEmail (theField, s [,eok])        Check that theField.value is a valid Email.

// 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+))$/

// BOI, followed by one or more characters, followed by @,
// followed by one or more characters, followed by ., 
// followed by one or more characters, followed by EOI.
var reEmail = /^.+\@.+\..+$/


// VARIABLE DECLARATIONS
var defaultEmptyOK = false

// CONSTANT STRING DECLARATIONS

// s is an abbreviation for "string"
var sEmail = "Email"

// 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 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"
var iEmail = "This field must be a valid email address (like hello@world.com). Please reenter it now."

// 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."

// p is an abbreviation for "prompt"
var pEmail = "valid email address (like hello@world.com)."


//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)
}


// 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));  
    
   
}

// 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)
    }
}


// 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);
	//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 price.\nPlease re-enter it now');
	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);

	//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 [, 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 == 2) emptyOK = defaultEmptyOK;

    //if ((emptyOK == true) && (isEmpty(theField.value))) return true;
		if (isEmpty(theField.value)) {
			if (emptyOK == true) return true;
			else return warnInvalid(theField, mPrefix + s + mSuffix);
		}

    else if (!isEmail(theField.value, false)) 
       //return warnInvalid (theField, iEmail);
       return warnInvalid(theField, s + ' -- This field must be a valid email address (like hello@world.com). \nPlease re-enter it now');
    else return true;
}
