//====================================================================
//function that checks field validity and displays alert message
// Parameters:
// fld - field to check,
// ft  - field type,
// ln  - allowed length of the field,
// maxv- maximum value for that field.
// op  - flag if this value is optional (true - optional, false - not optional)
function cfwa (desc, fld, ft, ln, maxv, op ) {

// if there is no field return false
  if (desc == null) {
    alert("There is no field description name to check!");
    return false;
  }
  if (fld == null) {
    alert("There is no field to check!");
    return false;
  }

// initialize one variable as String object to store field value
  var str = new String(fld.value);

  if (op != null)
  {
    if (!op && str == "")
    {
	  alert("Field " + desc + " appears to be empty !");
	  fld.focus();
	  return false;
    }
  }

  if (ln != null) {
    // now we can check length
	if  (str.length > ln) {
	  alert("The maximum length (" + ln + " characters) for the field " + desc + " exceeded!");
	  fld.focus();
	  return false;
	}
  }
//counter, length of the 'str', character
  var i, l, ch; 
  
//if there is no field type then we don't know what to check, so ...
  if (ft == null) {
  	alert("Field type has not been specified!");
    return false;
  }
//now test the field value

  ft = new String(ft);

  switch (ft.toLowerCase()) {
  
    //in case that we checking numeric value
    case "num":
	  l = str.length;
	  //if we have length of the field specified
	  if (ln != null) {
	    if (l > ln) { 
		  alert("Field " + desc + " is larger then allowed!");
		  fld.focus();
		  return false;
		}
	  }

	  if (!isInteger(str))
	  {
	    alert("Field " + desc + " is not an integer value!");
		fld.focus();
	    return false;
	  }

	  // now we can check the 'max value' (if there is one)
	  if (maxv != null) {
	    if (str > maxv) {
		  alert("Field " + desc + " is larger then allowed!");
		  fld.focus();
		  return false;
		}
	  }
	  break;
	case "text":
	  // in case that we checking text field
	  if (ln != null) {
	    // for now we can only check text length
	    if  ( str.length > ln ) {
		  alert("Field " + desc + " is larger then allowed!");
		  fld.focus();
		  return false;
		}
      }
	  break;
	case "email":
	  // in case that we checking e-mail address
	  if (op == null)
	  {
	    op = true;
	  }
	  if ((op && str != "") || !op)
	  {	    
	    if  ( str.indexOf("@") == -1 || str.indexOf(".") == -1 ) {    
	      alert("Field " + desc + " appears to be bad e-mail address!");
		  fld.focus();
          return false;
        }		
	  }
	  break;
	case "date":
	  //delete str;

	  str = new String(maxv);
	  // an exception is that string months ("Jan," etc.) are not accepted		
	  // this function does not handle BC dates or dates past 12/31/9999
				
	  // determine the delimiter character (must be "/" "-" or space)
	  var delimiterCharacter;
	  if ( str.indexOf('/') > 0 )
		delimiterCharacter = '/';
	  else if ( str.indexOf('-') > 0 )
		delimiterCharacter = '-';
	  else if ( str.indexOf(' ') > 0 )
		delimiterCharacter = ' ';
	  else {
	    alert("Field " + desc + " is not date value!");
		fld.focus();
		return false;
	  }
					
	  // split the string into an array of tokens
	  var theTokens = str.split(delimiterCharacter);
		
	  // there must be either two or three tokens (month, 
	  if ( theTokens.length < 2 || theTokens.length > 3 ) {
	    alert("Field " + desc + " is not date value!");
		fld.focus();
	    return false;
	  }
		
	  // convert the tokens to String objects, which will be needed later,
	  // stripping a single leading 0
	  var tokenIndex;
	  for ( tokenIndex = 0; tokenIndex < theTokens.length; tokenIndex++ ) {
		theTokens[tokenIndex] = new String(theTokens[tokenIndex]);
		
	    if ( (theTokens[tokenIndex].charAt(0) == '0') ) {
		   if ( (theTokens[tokenIndex].length == 2))
		   {
		     theTokens[tokenIndex] = theTokens[tokenIndex].substring(1, theTokens[tokenIndex].length);
		   } else {
		     alert("Field " + desc + " is not date value!");
			fld.focus();
		     return false;
		   }		    
		}
      }
	  // all of the tokens must be positive integers
	  for ( tokenIndex = 0; tokenIndex < theTokens.length; tokenIndex++ ) {
		 if ( ! isNonnegativeInteger(theTokens[tokenIndex]) ) {
		   alert("Field " + desc + " is not date value!");
		  fld.focus();
		   return false;
		 }
	  }
		
		// we need to identify the year, month, and day tokens
		var numericValue;
		var yearTokenIndex = -1;
		var monthTokenIndex = -1;
		var dayTokenIndex = -1;
		for ( tokenIndex = 0; tokenIndex < theTokens.length; tokenIndex++ ) {
		  // convert the value
		  numericValue = parseInt(theTokens[tokenIndex], 10);
					
		  // could this token be a month?
		  if ( numericValue <= 12 ) {					
			// yes; do we already have a month?
			if ( monthTokenIndex == -1 ) {
						
			// no; assign this token to the month and continue
			  monthTokenIndex = tokenIndex;
			  continue;
			} else {
							
			  // we already have a month; this token could
			  // also be the day; do we already have a day?
			  if ( dayTokenIndex == -1 ) {
						
			    // no; assign this token to the day and continue
				dayTokenIndex = tokenIndex;
				continue;
			  } else {
							
				// we already have a day; this token could
				// also be the year; do we alreay have a year?
				if ( yearTokenIndex == -1 ) {
						
				  // no; assign this token to the year and continue
				  dayTokenIndex = tokenIndex;
				  continue;
				}
			  }
			}
		  } else {
						
			// the value is too large for a month;
			// could this token be a day?
			if ( numericValue <= 31 ) {
						
			  // yes; do we already have a day?
			  if ( dayTokenIndex == -1 ) {
						
			  // no; assign this token to the day and continue
			  dayTokenIndex = tokenIndex;
			  continue;
			} else {
							
			  // we already have a day; this token could
			  // also be the year; do we alreay have a year?
			  if ( yearTokenIndex == -1 ) {
						
			  	// no; assign this token to the year and continue
			    dayTokenIndex = tokenIndex;
				continue;
			  }
			}
		  } else {
						
			// the value is too large for a day;
			// could this token be a year?
			if ( numericValue <= 9999 ) {
					
			  // yes; do we already have a year?
			  if ( yearTokenIndex == -1 ) {
						
			  	// no; assign this token to the year
			    yearTokenIndex = tokenIndex;
			  }
			}
		  }
		}
	  }	// end of for loop
		
	  // evaluate, based on the number of tokens
	  if ( theTokens.length == 2 ) {
			
		// two tokens can be either a month/year combination or a month/day
		// combination with the current year assumed; either way, we must have
		// a month
		if ( monthTokenIndex == -1 ) {
		  alert("Field " + desc + " is not date value!\nMonth has not been specified!");
		  // no month
		  fld.focus();
		  return false;
		}
				
		// do we have a year?
		if ( ! (yearTokenIndex == -1) ) {
			
		  // yes; month/year combination; must be okay
		  return true;
		} else if ( ! (dayTokenIndex == -1) ) {
		  // no year; do we have a day?	
		  // yes; month/day combination; get the current year
		  var today = new Date();
		  var currentYear = today.getYear();

		  // make sure it's a valid date (we were testing days using
		  // 31, and that might be too many for the month)
		  if (isDate(currentYear, theTokens[monthTokenIndex], theTokens[dayTokenIndex]))
		  {
		    return true;
		  } else {
		    alert("Field " + desc + " is not date value!");
			fld.focus();
			return false;
		  }		  
		} else {
          alert("Field " + desc + " is not date value!\nNo year and no day has been specified!");
		fld.focus();
		  return false;
		}
		// we have neither a year nor a day
	  } else {
		// three tokens; we should have found tokens for year, month, and day
		if ( yearTokenIndex == -1 || monthTokenIndex == -1 || dayTokenIndex == -1 ) {		   		
		  // missing one or more
		  alert("Field " + desc + " is not date value!");
		  fld.focus();
		  return false;
		}
		else
				
		// found all; however, VBScript can only handle the following sequences
		if ( monthTokenIndex == 0 ) {
				
		  // must be m/d/y
		  if ( dayTokenIndex != 1 || yearTokenIndex != 2) {
		    alert("Field " + fld.name + " is not date value!\nMust be m/d/y!"); 
		    return false;
		  }
		} else if ( dayTokenIndex == 0 ) {
				
		    // must be d/m/y
			if ( monthTokenIndex != 1 || yearTokenIndex != 2) {
			  alert("Field " + fld.name + " is not date value!\nMust be d/m/y!");
			  return false;
			}
		} else if ( yearTokenIndex == 0 ) {
			  // must be y/m/d
			  if ( monthTokenIndex != 1 || dayTokenIndex != 2) {
			    alert("Field " + fld.name + " is not date value!\nMust be y/m/d!");
				return false;
			  }
		} else {
			// something is wrong
			alert("Field " + fld.name + " is not date value!");
			return false;
		}		
		  // make sure it's a valid date (we were testing days using a value
		  // of 31, and that might be too many for the actual month)		  
		  if (isDate(theTokens[yearTokenIndex], theTokens[monthTokenIndex], theTokens[dayTokenIndex]))
		  {
		    return true;  
		  } else {
		    alert("Field " + desc + " is not date value!");
		  fld.focus();
		    return false;  
		  }		  
	  }
	  break;	
    case "time":
        if (!isTimeString(str))
        {
		  alert("Field " + desc + " is not time value!");
		fld.focus();
		  return false;
        }
		break;
	default:
  }

    return true;
}


//=====================================================================
function isTimeString(stringValue) {

		// create a String object
		var theString = new String(stringValue);
		
		// the string must have either two (hours and minutes) or three
		// (hours, minutes and seconds) tokens, delimited by ":";
		// split the string into an array of tokens
		var theTokens = theString.split(':');
		if ( theTokens.length < 2 || theTokens.length > 3 )
			return false;
		
		// convert the tokens to String objects, which will be needed later,
		// stripping whitespace
		var firstToken = new String(theTokens[0])
		firstToken = trim(firstToken);
		var middleToken;
		if ( theTokens.length == 3 ) {
			middleToken = new String(theTokens[1])
			middleToken = trim(middleToken);
		}
		var lastToken = new String(theTokens[theTokens.length - 1])
		lastToken = trim(lastToken);

		// the first token (hours) must be an integer between 0 and 23
		if ( ! isInteger(firstToken) )
			return false;
		if ( ! isIntegerInRange(firstToken, 0, 23) )
			return false;
		
		// are there three tokens?
		if ( theTokens.length == 3 ){
		
			// the middle token (minutes) must be an integer between 0 and 59
			if ( ! isInteger(middleToken) )
				return false;
			if ( ! isIntegerInRange(middleToken, 0, 59) )
				return false;
		}
			
		// the first one or two characters of the last token (either minutes
		// and optional am/pm indicator or seconds and am/pm indicator) must
		// be digits
		if ( ! isDigit(lastToken.charAt(0)) )
			return false;
		
		// the first character is a digit; split the last token into the minutes
		// or seconds value and the indicator; depending on the second character
		var lastValue;
		var ampmIndicator;
		if ( isDigit(lastToken.charAt(1)) ) {
			lastValue = new String(lastToken.substring(0, 2));
			if ( lastToken.length >= 3 )
				ampmIndicator = new String(trim(lastToken.substring(2, lastToken.length)));
			else
				ampmIndicator = new String();
		}
		else {
			lastValue = new String(lastToken.substring(0, 1));
			if ( lastToken.length >= 2 )
				ampmIndicator = new String(trim(lastToken.substring(1, lastToken.length)));
			else
				ampmIndicator = new String();
		}
		ampmIndicator = ampmIndicator.toUpperCase();
		
		// the last value must be between 0 and 59
		if ( ! isIntegerInRange(lastValue, 0, 59) )
			return false;
		
		// check the am/pm indicator, if there is one
		if ( ampmIndicator.length > 0 )
			if ( ! ( ampmIndicator == "AM" || ampmIndicator == "PM" ) )
				return false;
				
		// valid time
		return true;
	}

	// most of the following was derived from Netscape's FormChek.js
	// library, which should be reviewed for documentation and comments

	var daysInMonth = makeArray(12);
	daysInMonth[1] = 31;
	daysInMonth[2] = 29;
	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;

	var whitespace = " \t\n\r";

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

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

//=====================================================================
function isDate(year, month, day) {

  if ( ! ( isYear(year) && isMonth(month) && isDay(day) ) ) return false;

  var intYear = parseInt(year);
  var intMonth = parseInt(month);
  var intDay = parseInt(day);

  if ( intDay > daysInMonth[intMonth] ) return false; 
  if ( ( intMonth == 2 ) && ( intDay > daysInFebruary(intYear) ) ) return false;
  return true;
}

//=====================================================================
function isDay(s) {
  return isIntegerInRange(s, 1, 31);
}

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

//=====================================================================
function isInteger(s) {
var i;
  for ( i = 0; i < s.length; i++ )
  {   
    var c = s.charAt(i);
	if ( ! isDigit(c) ) return false;
  }
  return true;
}

//=====================================================================
function isIntegerInRange(s, a, b) {
	    if ( ! isInteger(s) ) return false;
	    var num = parseInt (s);
	    return ( ( num >= a ) && ( num <= b ) );
}

//=====================================================================
function isMonth(s) {
  return isIntegerInRange (s, 1, 12);
}

//=====================================================================
function isNonnegativeInteger(s) {
  return ( isSignedInteger(s) && ( parseInt(s) >= 0 ) );
}

//=====================================================================
function isSignedInteger(s) {
var startPos = 0;

  if ( ( s.charAt(0) == "-" ) || ( s.charAt(0) == "+" ) )
	startPos = 1;    
	return ( isInteger(s.substring(startPos, s.length)) )
  }

//=====================================================================
function isYear(s) {

  if ( ! isNonnegativeInteger(s) ) return false;
  return ( (s.length == 2) || (s.length == 4) );
}

//=====================================================================
function lTrim(s) {
var i = 0;

  while ( (i < s.length) && charInString(s.charAt(i), whitespace) )
    i++;
	return s.substring(i, s.length);
  }

//=====================================================================
function makeArray(n) {

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

//=====================================================================
function rTrim(s) {
var i = 0;

  while ( (i < s.length) && charInString(s.charAt(i), whitespace) )
    i++;
  return s.substring(i, s.length);
}

//=====================================================================
function trim(s) {
  return lTrim(rTrim(s));
}
//=====================================================================
// Check against special characters
function check_spec_char(desc, fld) {
	var str = new String(fld.value);

	if ( str.indexOf("<") != -1 || str.indexOf(">") != -1 || str.indexOf("{") != -1 || str.indexOf("}") != -1 || str.indexOf('"') != -1 || str.indexOf("'") != -1) 
	{
		window.alert("Please don't use special characters like: <, >, {, }, \", ' for "+desc);
		return false;
	}
	return true;
}