var defaultEmptyOK = false

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


function isEmpty(s) {
  return ((s == null) || (s.length == 0));
}

// Determine the return value if the string is empty

function emptyReturn() {
  var argv = emptyReturn.arguments;
  if (argv.length == 1) return defaultEmptyOK;
  else return (argv[0] == true);
}

// Returns true if string s is empty or 
// whitespace characters only.

function isWhitespace (s) {
    // 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 (var 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;
}

function isEmail(s) {
  if (isEmpty(s)) return emptyReturn(isEmail.arguments);
   
  // is s whitespace?
  if (isWhitespace(s)) return false;
    
  // there must be >= 1 character before @, so we
  // start looking at character position 1 
  // (i.e. second character)
  var i = 1;
  var sLength = s.length;

  // look for @
  while ((i < sLength) && (s.charAt(i) != "@")) {
    i++
  }

  if ((i >= sLength) || (s.charAt(i) != "@")) return false;
  else i += 2;

  // look for .
  while ((i < sLength) && (s.charAt(i) != ".")) {
    i++
  }

  // there must be at least one character after the .
  if ((i >= sLength - 1) || (s.charAt(i) != ".")) return false;
  else return true;
}

function isSqlDate(str) {
  var arr = str.split(/\s*[\/-]\s*/);
  return isDate(arr[1]+'/'+arr[2]+'/'+arr[0]);
}

function isDate(str) {
  var st_d = (new Date(Date.parse(str))).toString().toLowerCase();
  return (st_d != 'invalid date' && st_d != 'nan');
}

// Constructor for the FormField object
function FormField(elmt, name, func, mesg) {
  this.elmt = elmt;
  this.name = name;
  this.func = func;
  this.mesg = mesg;
}
// fields is the array of everything.
// Set fields = null to avoid checking the form.
// Can safely handle the case where fields[j] = null
// Each array element contains an object which defines:
//   * Form element (from <element name="...")
//   * Name to present to the user for the form element.
//   * Additional function to check the form element with
//     (Set to null to avoid using an additional function.)
//   * Error message to display if the additional check fails
// This array must be defined in the 'setArrays(form)' function on the
// page itself.
function validateForm(form) {
  var missing = "";
  var error = "";

  if (setArrays(form) == false) return false;

  if (fields == null) return true;

  for (var j = 0; j < fields.length; j++) {
    if (fields[j] == null) continue;
    var elmt = fields[j].elmt;
    var name = fields[j].name;
    var func = fields[j].func;
    var type = "";
    var hasErrors = false;
    if (elmt.length > 0 && elmt.options == null) {
      type = elmt[0].type;
    } else {
      type = elmt.type;
    }
    type = type.toLowerCase()

    if (type == "checkbox" || type == "radio") {
      var isChecked = false;
      var checkElmt = null;
      if (elmt.length > 0) {
	for (var i = 0; i < elmt.length; i++) {
	  if (elmt[i].checked) {
	    isChecked = true;
	    checkElmt = elmt[i];
	    break;
	  }
	}
      } else {
	if (elmt.checked) {
	  isChecked = true;
	  checkElmt = elmt;
	}
      }
      if (!isChecked) {
	if (alwaysShowMsgs) {
	  error += name+":  "+fields[j].mesg+"\n\n";
	} else {
	  missing += name+"\n";
	}
      } else if (func != null && checkElmt != null) {
	if (!func(checkElmt.value)) error += name+":  "+fields[j].mesg+"\n\n";
      }
    } else if (type == "select-one") {
      if (func != null) {
	if (!func(elmt.options[elmt.selectedIndex].value)) {
	  error += name+":  "+fields[j].mesg+"\n\n";
	  hasErrors = true;
	}
	if (errorStyles) {
	  if (hasErrors) {
	    elmt.className = 'error';
	  } else {
	    elmt.className = 'required';
	  }
	}
      }
    } else if (type == "select-multiple") {
      var isChecked = false;
      var checkElmt = null;
      for (var i = 0; i < elmt.length; i++) {
	if (elmt[i].selected) {
	  isChecked = true;
	  checkElmt = elmt[i];
	  break;
	}
      }
      if (!isChecked) {
	if (alwaysShowMsgs) {
	  error += name+":  "+fields[j].mesg+"\n\n";
	} else {
	  missing += name+"\n";
	}
	hasErrors = true;
      } else if (func != null && checkElmt != null) {
	if (!func(checkElmt.value)) {
	  error += name+":  "+fields[j].mesg+"\n\n";
	  hasErrors = true;
	}
      }
      if (errorStyles) {
	if (hasErrors) {
	  elmt.className = 'error';
	} else {
	  elmt.className = 'required';
	}
      }
    } else if (type == "text" || type == "password"
	    || type == "textarea" || type == "file") {
      if (elmt.value.length < 1 || isWhitespace(elmt.value)) {
	if (alwaysShowMsgs) {
	  error += name+":  "+fields[j].mesg+"\n\n";
	} else {
	  missing += name+"\n";
	}
	hasErrors = true;
      } else if (func != null) {
	if (!func(elmt.value)) {
	  error += name+":  "+fields[j].mesg+"\n\n";
	  hasErrors = true;
	}
      }
      if (errorStyles) {
	if (hasErrors) {
	  elmt.className = 'error';
	} else {
	  elmt.className = 'required';
	}
      }
    } else if (type == "hidden") {
      if (func != null) {
	if (!func(elmt.value)) {
	  error += name+":  "+fields[j].mesg+"\n\n";
	  hasErrors = true;
	}
      }
      if (errorStyles) {
	var itm = document.getElementById(elmt.name);
	if (hasErrors) {
	  itm.className = 'error';
	} else {
	  itm.className = 'required';
	}
      }
    } else if (type == "reset") {  // ignore the buttons
    } else if (type == "submit") {
    } else if (type == "button") {
    } else {
      missing += 'Unsupported form element type: '+type+' ('+j+')\n';
    }
  }

  if (missing.length == 0 && error.length == 0) return true;

  // we have missing fields and/or errors
  var alertStr = "";
  if (missing.length != 0 && error.length != 0) {
    alertStr = "The following required fields are missing:\n\n"+missing
	     + "\n\nAdditionally, the following errors occured:\n\n"+error;
  } else if (missing.length == 0 && error.length != 0) {
    alertStr = error;
  } else if (missing.length != 0 && error.length == 0) {
    alertStr = "The following required fields are missing:\n\n"+missing;
  }
  alert(alertStr);
  return false;
}
