var Validation = {};
Validation.init = function(valData, form, errorClass) {
  var valSpec, fld;
  for ( valSpec in valData ) {
    fld = form.elements[valSpec];
    if ( typeof fld == "undefined" ) continue;
    // for radio buttons, attach to each
    //   selects also have a length, radio groups have no tagName
    if (( typeof fld == "object" ) && ( fld.length ) && ( ! fld.tagName )) {
      for ( var i = 0; i < fld.length; i++ ) {
        fld[i].validation = valData[valSpec];
        $(fld[i]).bind("click", function() {
           Validation.validateField(this); 
        });        
      }
    } else {
      fld.validation = valData[valSpec];
      $(fld).bind("change", function() {
         Validation.validateField(this); 
      });
    }
  }
  $(form).bind("submit", Validation.validateForm);
  Validation.errorClass = errorClass
}

Validation.DontValidate = function(form) {
  $(form).unbind("submit", Validation.validateForm);
}

Validation.validateField = function(fld) {
  var aTest, type, params, val, errors = [];
  fld.isValid = true;
  if ( fld.validation ) {
    if ( Validation.checkDependencies(fld) ) {  // dependencies satisfied
      for ( var i = 0; i < fld.validation.length; i++ ) {
        aTest = fld.validation[i].test.split(":");
        type = aTest.shift();
        params = aTest.join(":");
        if ( ! Validation.check(fld, type, params) ) {
          fld.isValid = false;
          errors.push(fld.validation[i].msg);
        }
      }
    }
    this.showErrors(fld, errors);
  }
  return fld.isValid;
}

Validation.validateForm = function() {
  var valid = true;
  for ( var i = 0; i < this.elements.length; i++ ) {
    if ( ! Validation.validateField(this.elements[i]) ) valid = false;
  }
  return valid;
}

Validation.showErrors = function(fld, errors) {
  var jQFld = $(fld);
  if ( errors.length > 0 ) {
    tError = "<p class=\"Error\">";
    tError += errors.join(".  ");
    tError += ".</p>";
    jQFld.parent().find(".Error").remove();
    jQFld.addClass(Validation.errorClass).parent().append(tError);
    jQFld.parent().find(".Error").hide().show("slow");
  } else {
    if ( fld.type == "radio" ) {
      $("input[@name='"+fld.name+"']", fld.form).removeClass(Validation.errorClass);
    } 
    jQFld.removeClass(Validation.errorClass).parent().find(".Error").hide("slow", function() {
        $(this).remove();
      });
  }
  
}

Validation.GetValue = function(fld) {
  // radio group
  if (( typeof fld == "object" ) && ( fld.length ) && ( ! fld.tagName )) {
    var name = fld[0].name;
    return $("input[@name='" + name + "']:checked").val();
  }
  if ( fld.type == "radio" ) { // got 1 element of a radio group
    var name = fld.name;
    return $("input[@name='" + name + "']:checked").val();
  }
  if ( fld.tagName.toLowerCase() == "select" ) {
    return fld.options[fld.selectedIndex].value;
  } else {
    if (( fld.type == "checkbox" ) && ( ! fld.checked )) return "";
    return fld.value;
  }
}

Validation.checkDependencies = function(fld) {
  var doValidation = true;
  var aChecks, type, params;
  for ( var i = 0; i < fld.validation.length; i++ ) {
    var aTest = fld.validation[i].test.split(":");
    if ( aTest.shift() == "ValidateIf") {
      var relField = fld.form.elements[aTest.shift()];
      if ( relField ) {
        var checks = aTest.join(":").split("\n");
        for ( var j = 0; j < checks.length; j++ ) {
          aChecks = checks[j].split(":");
          type = aChecks.shift();
          params = aChecks.join(":");
          if ( ! Validation.check(relField, type, params) ) {
            doValidation = false;
          }
        }
      }
    }
  }
  return doValidation;
}

Validation.check = function(fld, type, params) {
  var aParams, val, max, min;
  aParams = params.split(",");
  val = Validation.GetValue(fld);  
  switch ( type ) {
    case "ValidateIf": return true; // used in checkDependencies
    case "Required": return Validation.checkRequired(val);
    case "Email": return Validation.checkEmail(val);
    case "Range":
      max = 32767;
      min = aParams[0];
      if ( aParams.length > 1 ) max = aParams[1];
      return Validation.checkNumberRange(val, min, max);
    case "Length": 
      max = 32767;
      min = aParams[0];
      if ( aParams.length > 1 ) max = aParams[1];
      return Validation.checkStringLength(val, min, max);
    case "Regex": return Validation.checkString(val, params);
    case "Match": return Validation.checkString(val, params);
    case "Function": return Validation.checkFunction(fld, params);
    default: return false;
  }
}

Validation.checkRequired = function(val) {
  if ( val > "" ) return true;
  else return false;
}

Validation.checkEmail = function(val) {
	//var regExp = "^[A-Za-z0-9\._-]+@{1}([A-Za-z0-9]{1}[A-Za-z0-9-]*[A-Za-z0-9]{1}\.{1})+([A-Za-z]+\.){0,1}([A-Za-z]+){1}$";
	//var regExp = "^[\w\.\-]+\@[\w\.\-]+\.(com|edu|org|net|gov|mil|info){1}(\.(\w{2}))?$";
	//return Validation.checkString(val, regExp);

	var nameExp = "^[a-zA-Z0-9\._-]*$";
	var domainExp = "^([a-zA-Z0-9]{1}[a-zA-Z0-9-]*[a-zA-Z0-9]{1})+[\.]{1}([A-Za-z]+\.){0,1}([A-Za-z]+){1}$";

	var pieces = val.split("@");
	
	if(pieces.length != 2)
		return false;

	if((Validation.checkString(pieces[0], nameExp)) && (Validation.checkString(pieces[1], domainExp)))
		return true;
	else
		return false;
}

Validation.checkNumberRange = function(val, min, max) {
  // strip comma and dollar sign
  val = val.replace(/\$|\,/g, "");
  val = parseInt(val, 10);
  min = parseInt(min, 10);
  max = parseInt(max, 10);
  if (( val >= min ) && ( val <= max )) return true;
  else return false;
}

Validation.checkStringLength = function(val, min, max) {
  min = parseInt(min, 10);
  max = parseInt(max, 10);
  if (( val.length >= min ) && ( val.length <= max )) return true;
  else return false;        
}

Validation.checkString = function(val, regex) {
  if ( regex.charAt(0) == "/" ) regex = regex.substring(1, regex.length - 1);
  var re = new RegExp(regex);
  return re.test(val);
}

Validation.checkFunction = function(fld, params) {
  var aParams = params.split(",");
  var func = aParams.shift();
  params = aParams.join(",");
  
  // if it exists and is attached to the field
  if ( typeof fld[func] == "function" ) return fld[func](fld, params);
  // if it exists ans is attached to the form
  if ( typeof fld.form[func] == "function" ) return fld.form[func](fld, params);
  // if it exists ans is attached to the validator
  if ( typeof Validation[func] == "function" ) return Validation[func](fld, params);
  // if it exists and is a standalone (it gets auto-attached to the window obj)
  if ( typeof window[func] == "function" ) return window[func](fld, params);
  return false;
}
