var HOWF = window.HOWF || {};

/**********************************************************
* Class: HOWF.SubmissionForm
**********************************************************/

/**
 * Create an on-the-fly form based on a JSON object.
 *
 * @param json The structure of the form.
 * @param string The form submission URL.
 */
HOWF.SubmissionForm = function(json_form,url) {

  this.form_structure = json_form;
  this.submission_url = url;

  this.form_root = document.createElement("form");
  this.form_root.setAttribute("action",this.submission_url);
  this.form_root.setAttribute("method","post");

  // just in case, make sure we're not visible here
  this.form_root.style.display = "none";

}

/**
 * Build the form.
 */
HOWF.SubmissionForm.prototype.build = function() {

  for (var x in this.form_structure) {

    // skip fields with no type
    if (typeof this.form_structure[x].type == "undefined") {
      continue;
    }

    var new_element = document.createElement("input");

    new_element.setAttribute("type",this.form_structure[x].type);
    new_element.setAttribute("name",(typeof this.form_structure[x].name != "undefined" ? this.form_structure[x].name : x));
    new_element.setAttribute("value",(typeof this.form_structure[x].value != "undefined" ? this.form_structure[x].value : ""));

    this.form_root.appendChild(new_element);

  }

}

/**
 * Attach the form to an existing element.
 */
HOWF.SubmissionForm.prototype.attach = function(tag) {

  var js_root = document.getElementById(tag);

  js_root.appendChild(this.form_root);

}

/**
 * Submit the form.
 */
HOWF.SubmissionForm.prototype.submit = function() {

  this.form_root.submit();

}

/**********************************************************
* Class: HOWF.FormValidator
**********************************************************/

/**
 * Validate form input based on a JSON structure.
 *
 * @param json The structure of the form.
 */
HOWF.FormValidator = function(json_form,prefix) {

  this.form_structure = json_form;

  if (prefix) {
    this.form_id_prefix = prefix;
  } else {
    this.form_id_prefix = "";
  }

}

/**
 * Check to see if an email address is valid.
 *
 * @param string An email address to validate.
 */
HOWF.FormValidator.prototype.validate_email = function(address) {

  var result = false;
  var ndxAt = ndxDot =  0;

  var ndxAt = address.indexOf("@");
  var ndxDot = address.indexOf(".");
  var ndxDot2 = address.lastIndexOf(".");

  if ((ndxDot < 0) || (ndxAt < 0)) {

    return "Your email address lacks a '.' or '@'. The valid format is 'you@domain.suffix.'\n";

  } else if ( (ndxDot2 - 3) <= ndxAt) {

    return "You may be missing your domain name.\n\nThe format is 'you@dom.suf'\n";

  }

  return "";

}

/**
 * Check the form input fields.
 */
HOWF.FormValidator.prototype.validate_form = function() {

  var errorMsg = "";
  var returnValue = true;

  HOWF.Debug.log("Entering HOWF.FormValidator; form structure is:");
  HOWF.Debug.log(HOWF.Utils.dumpObject(this.form_structure,false,true));

  for (var x in this.form_structure) {

    var thisElement = document.getElementById(this.form_id_prefix + x);

    //alert("checking: " + this.form_id_prefix + x + " which is: " + thisElement);

    if (!thisElement) {
      HOWF.Debug.log("FormValidator: Could not locate element: " + x);
      continue;
    }

    // skip password fields that are not required
    if (this.form_structure[x].type == "password" && !this.form_structure[x].required && thisElement.value == "") {
      continue;
    }

    // check to see if we have a confirm field
    if (this.form_structure[x].confirm) {

      var thisElementConfirm = document.getElementById("confirm_" + x);

      if (thisElement.value != thisElementConfirm.value) {

        HOWF.Debug.log("FormValidator: Mismatch on confirm for field: " + x);

        errorMsg = errorMsg + "The values entered for " + this.form_structure[x].description + " do not match.\n";

        returnValue = false;

        continue;

      }

    }

    if (this.form_structure[x].type != "tri_date") {

      // create copy and strip whitespace
      var stripped = HOWF.Utils.trim(thisElement.value);

      // if it's text, check to make sure it's not empty
      if (typeof(this.form_structure[x].required) != 'undefined' && this.form_structure[x].required === true && stripped == "") {

        HOWF.Debug.log("FormValidator: Missing value for field: " + x);

        errorMsg = errorMsg + "You must enter a value for " + this.form_structure[x].description + ".\n";

        returnValue = false;

        continue;

      }

      // check for required patterns
      if (typeof(this.form_structure[x].regexp) != 'undefined') {

        var testRE = new RegExp(this.form_structure[x].regexp);

        if (!testRE.test(thisElement.value)) {

          HOWF.Debug.log("FormValidator: Pattern mismatch for field: " + x);

          errorMsg = errorMsg + "You must enter a value for " + this.form_structure[x].description + " in the form of " + this.form_structure[x].regexp_description + "\n";

          returnValue = false;

          continue;

        }

      }

      // check min/max length
      if (typeof(this.form_structure[x].minlength) != 'undefined' && stripped != "") {

        var minLength = parseInt(this.form_structure[x].minlength);

        if (thisElement.value.length < minLength) {

          HOWF.Debug.log("FormValidator: Below minimum length for field: " + x);

          errorMsg = errorMsg + "You must enter at least " + minLength + " characters for " + this.form_structure[x].description + "\n";

          returnValue = false;

          continue;

        }

      }

      if (typeof(this.form_structure[x].maxlength) != 'undefined' && stripped != "") {

        var maxLength = parseInt(this.form_structure[x].maxlength);

        if (thisElement.value.length > maxLength) {

          HOWF.Debug.log("FormValidator: Above maximum length for field: " + x);

          errorMsg = errorMsg + "You must enter " + maxLength + " or fewer characters for " + this.form_structure[x].description + "\n";

          returnValue = false;

          continue;

        }

      }

      var validCharacterRE = /^[a-zA-Z0-9\. _\-\'\"]+$/;
      var validAlphaRE = /[a-zA-Z_]+/;

      // make sure we are taking only alphanumeric characters if required
      if (this.form_structure[x].alphanumeric && !validCharacterRE.test(thisElement.value)) {

        HOWF.Debug.log("FormValidator: Non-alphanumeric characters found in field: " + x);

        errorMsg = errorMsg + "Please enter only alphanumeric characters for " + this.form_structure[x].description + ".\n";

        returnValue = false;

        continue;

      }

      // make sure we have at least one alphabetical character if required
      if (this.form_structure[x].alpharequired && !validAlphaRE.test(thisElement.value)) {

        HOWF.Debug.log("FormValidator: Lack of at least one letter in field: " + x);

        errorMsg = errorMsg + "You must enter at least one letter in " + this.form_structure[x].description + ".\n";

        returnValue = false;

        continue;

      }

    }

    // do any special processing
    switch (this.form_structure[x].type) {

      case "email":

        var msg = this.validate_email(thisElement.value);

        if (msg != "") {

          errorMsg = errorMsg + msg;

          returnValue = false;

        }

        break;

      case "checkbox":

        if (this.form_structure[x].mandatory && !thisElement.checked) {

          if (this.form_structure[x].subtype && this.form_structure[x].subtype == 'agreement') {

            errorMsg = errorMsg + "You must agree to the " + this.form_structure[x].description + ".\n";

          } else {

            errorMsg = errorMsg + "You must check the " + this.form_structure[x].description + " field.\n";

          }

          HOWF.Debug.log("FormValidator: Missing required checkbox for field: " + x);

          returnValue = false;

        }

        break;

      case "select":

        if (this.form_structure[x].required && thisElement.selectedIndex == 0) {

          HOWF.Debug.log("FormValidator: Empty select for field: " + x);

          errorMsg = errorMsg + "You must select a value for " + this.form_structure[x].description + ".\n";

          returnValue = false;

        }

        break;

      case "tri_date":

        var js_day = document.getElementById(x + "_day");
        var js_month = document.getElementById(x + "_month");
        var js_year = document.getElementById(x + "_year");

        // make sure all fields are selected or filled
        if (!( (js_day.selectedIndex > 0 && js_month.selectedIndex > 0 && js_year.selectedIndex > 0) || (!this.form_structure[x].required && js_day.selectedIndex == 0 && js_month.selectedIndex == 0 && js_year.selectedIndex == 0) )) {

          HOWF.Debug.log("FormValidator: Missing complete date for field: " + x);

          errorMsg = errorMsg + "You must enter a complete date for " + this.form_structure[x].description + ".\n";

          returnValue = false;

          break;

        }

        var day_options = js_day.getElementsByTagName("option");
        var day_value = parseInt(day_options[js_day.selectedIndex].value);

        var month_options = js_month.getElementsByTagName("option");
        var month_value = parseInt(month_options[js_month.selectedIndex].value) - 1;

        var year_options = js_year.getElementsByTagName("option");
        var year_value = parseInt(year_options[js_year.selectedIndex].value);

        // check for valid date in general
        var real_date = new Date(year_value,month_value,day_value);

        if (real_date.getMonth() != month_value || real_date.getDate() != day_value) {

          HOWF.Debug.log("FormValidator: Missing valid date for field: " + x);

          errorMsg += errorMsg + "You must enter a valid date for " + this.form_structure[x].description + ".\n";

          returnValue = false;

        }

        var input_date = new Date((year_value + parseInt(this.form_structure[x].min_age)),month_value,day_value);
        var today_date = new Date;

        if ((today_date.getTime() - input_date.getTime()) < 0) {

          HOWF.Debug.log("FormValidator: Below minimum age for field: " + x);

          errorMsg = errorMsg + "You must be at least " + this.form_structure[x].min_age + " years old to access this site.\n";

          returnValue = false;

        }

        break;

      default:

        break;

    }

  }

  // display any errors that we've accumulated
  if (errorMsg != "") {

    HOWF.Debug.log("FormValidator: Form validation failed.");

    alert(errorMsg);

  }

  return returnValue;

}

