var FormValidation = function() {

  function changeFragment(obj, validate) {
    var formId = obj.parents('form:first').attr("id");
    var step = WebmanagerFormStateRegistry[formId].currentStep();

    var inputName = obj.attr("name");
    var fragmentObj = FormsUtil.getObject(step, inputName);

    // set the value in the scope
    var newValue = getValue(obj);
    if (fragmentObj != null && fragmentObj.value != newValue) {
      
      // only trigger actions when the value is changed
      fragmentObj.value = newValue;
      fragmentObj.validated = false;

      // Revalidate the fragment
      if (validate) {
        validateFormFragment(obj, fragmentObj);
      }

      // (2) we only check for conditions for radio, chechboxes and select boxes: this is the most likely use case and we don't want to create extra overhead
      // Added hidden, because you can have a hidden counter (eg for the repeater) which needs to trigger the checkConditions
      var inputType = obj.attr("type");

      var changes = FormsUtil.checkConditions(step, '', formId);
      for (var i=0; i < changes.length;i++) {
        if (changes[i].value == 'show') {
          // throw high level event, so custom code can react on that
          $('#' + FormsUtil.normalize(changes[i].identifier)).trigger('IAF_ShowFormFragment');
        } else {
          // throw high level event, so custom code can react on that
          $('#' + FormsUtil.normalize(changes[i].identifier)).trigger('IAF_HideFormFragment');
        }
      }
    }

  }

  //
  // Function to validate a form fragment
  //
  function validateFormFragment(inputObj, fragmentObj) {
    var inputName = inputObj.attr("name");

    var hasError = false;
    if (fragmentObj != null && !fragmentObj.validated) {

      // validate the input: only when visible
      if (FormValidation.isVisible(inputObj)) {
        var validationResult = fragmentObj.validate();

        // gather the errors
        var errors = FormsUtil.join(validationResult,',');
        hasError = (errors != '');

        var errorDivId = "error_" + FormsUtil.normalize(inputName);
        var errorObj = $("#" + errorDivId);
        if (errorObj.length > 0) {
          if (errors != '') {
            errorObj.trigger('IAF_ShowError',[errorDivId,validationResult]);
          } else {
            errorObj.trigger('IAF_HideError', errorDivId);
          }
        }
      }
    }
    return hasError;
  }


  //
  // Function for validating the form: the inputs are validated and the form is not submitted, when there are errors
  //
  function validateForm(event, formObj, step) {
    // loop over the inputs
    var hasError = false;
    $(':input', formObj).each(function() {
      var inputName = $(this).attr("name");
      var inputType = $(this).attr("type");
      if (inputName != '' && inputType != 'hidden' && inputType != 'button' && inputType != 'submit') {

        // sanity check
        var fragmentObj = FormsUtil.getObject(step, inputName);
        var fragmentError = validateFormFragment($(this), fragmentObj);
        if (fragmentError) {
          hasError = true;
        }

      }
    });

    // don't submit the form when there is an error
    event.preventDefault();
    if (!hasError) {
      // (4) make the value empty to prevent to be routed to the same step
      // issue: http://jira.gxdeveloperweb.com/jira/browse/GXWMF-626

      // This is done the prevent recursion: we don't want to do the validations anymore
      // formObj.addClass("IAF_ignoreValidation");

      formObj.unbind('submit');

      $(':input', formObj).each(function() {
        // skip the hidden inputs
        var inputName = $(this).attr("name");

        var fragmentObj = FormsUtil.getObject(step, inputName);
        if (fragmentObj != null && !fragmentObj.visible) {
          // clear the value
          switch(this.type) {
            case 'password':
            case 'select-multiple':
            case 'select-one':
            case 'text':
            case 'textarea':
              $(this).val('');
              break;
            case 'checkbox':
            case 'radio':
              $(this).removeAttr("checked");
              // add an empty input type="hidden": this because the browser doesn't send an empty radio
              formObj.append('<input type="hidden" name="' + inputName + '" value="" />');
          }
        }
      });
      formObj.trigger('IAF_SubmitForm');
    }
  };


  //
  // Utility functions with jQuery syntax, and thus not in the formutil.js
  //


  // Get the value(s) for an object. This implementation differs per input type
  function getValue(obj) {
    value = obj.val();

    if (obj.attr("type") == 'radio') {
      value = $('input[name=' + obj.attr("name") + ']:checked').val();
    }
    // for checkboxes we pass the array of values
    if (obj.attr("type") == 'checkbox') {
      values = $('input:checkbox[name=' + obj.attr("name") + ']:checked') || [];
      value = new Array();

      i=0;
      values.each(function() {
        value.push($(this).val());
        i++;
      });
    }
    return value;
  }

  // checks if the object is visible
  function isVisible(obj) {
    var visible = true;
    obj.parents().each(function() {
      if ($(this).css("display") == 'none') {
        visible = false;
        return false;      
      }
    });
    return visible;
  }

  // Public methods and variables.
  return {
    changeFragment:changeFragment,
    validateForm:validateForm,
    validateFormFragment:validateFormFragment,
    getValue:getValue,
    isVisible:isVisible
  }

}();

