var SUBMIT_TIMEOUT = 1000 * 60; // 60 seconds

var disabledHandler = function (e) {
  return false;
};

jQuery(document).ready(function(event) {

  //
  // implemented a optimization for the clientside framework:
  //  - load the formState object aynsychronous
  //  - cache the formState serverside
  //  - add an extra call for the filled in values
  //  - init the bindings
  //

  $('.nn_form').each(function() {
    initCSFW($(this));
  });

  $('.nn_form').live("IAFFormLoaded", function() {
    initCSFW($(this));
  });

  function parseCSFWData(formState, data) {
    $.each(data.steps, function(j,step){
      var stepId = step.identifier;
      $.each(step.fragments, function(i,item) {
        if (typeof item.name != 'undefined') {
          var fragmentObj = FormsUtil.getObject(formState[stepId], item.name);
          if (fragmentObj != null) {
            if (item.value != undefined && (typeof(item.value) != 'string' || item.value.indexOf("<wm-") == -1)) {
              fragmentObj.value = item.value;
              fragmentObj.originalvalue = item.value;
            }
            if (item.visible != undefined) {
              fragmentObj.visible = item.visible;
              fragmentObj.condition = item.visible;
            }
          }
        }
      });
    });
  }

  function initCSFW(formObj) {
    var url = $(formObj).find('.csfw').val();
    var versionId = $(formObj).find('.csfw_versionId').val();
    var stepId = $(formObj).find('.csfw_stepId').val();
    var formId = $(formObj).attr("id");

    //disable submit buttons untill csfw is loaded
    formObj.find(':submit:not(.disabledButton)').each(function () {
      if ($.browser.msie && parseInt ($.browser.version, 10) <= 8) {
        $ (this).closest(".field:not(.back)").addClass ('disabled-button');
      } else {
        $ (this).addClass ('disabled');
      }
      $ (this).click (disabledHandler);
      //$ (this).attr('disabled', 'disabled');

    });

    log('csfw url: ' + url);

    if (typeof url != 'undefined') {
    var $loadPartsInput = $("input[name='load_parts']");

    if ($loadPartsInput.length > 0) {
      var iafloadparts = $loadPartsInput.val();

      if (iafloadparts != '') {
      if (url.indexOf('?') != -1) {
        url = url + '&load=' + iafloadparts;
      } else {
        url = url + '/load=' + iafloadparts;
      }
      log('Added iafloadparts value to url: '+url);
      }
    }

      $.ajax({
        url: url,
        async: true,
        success: function(data) {

          eval(data);
          var formState = WebmanagerFormStateRegistry[formId];

          // we don't get the form values from the user when we don't have a wmstepid in the form
          if (stepId != '') {

            $.ajax({
              url: contextPath + '/wcbservlet/nl.gx.forms.wmpformelement.servlet?formVersionId=' +  versionId,
              async: true,
              success: function(data) {
                parseCSFWData(formState,data);
                init(formObj);
              },
              error: function(xhr) {
                var response = null;
                try {
                  response = xhr.responseText;
                } catch (e) {}
                if (response != null && response != '') {
                  response = response.replace(/\\([^"])/g, "$1");
                  response = response.replace(/,\s*}/g, "}");
                  response = response.replace(/,\s*\n*\s*]/g, "]");

                  // Fixed in the servlet in 2.1.0
                  response = response.replace(/,\s*\n*\s*,/g, ",");

                  var jsonResponse = jQuery.parseJSON(response);
                  parseCSFWData(formState,jsonResponse);
                }
                init(formObj);
              }
            });
          } else {
            init(formObj);
          }
        }
      });
    } else {
      // do the old behavior
      init(formObj);
    }
  }

  function checkButtons (formObj) {
    if (formObj.hasClass("nosubmitwitherrors")) {
      var step = WebmanagerFormStateRegistry[$(formObj).attr("id")].currentStep();
      hasErrors = FormValidation.validateForm($(formObj), step, true);

      if (hasErrors) {
        //disable submit buttons untill csfw is loaded
        formObj.find(':submit:not(.disabledButton):not(.back-button)').each(function () {
          if ($.browser.msie && parseInt ($.browser.version, 10) <= 8) {
            $ (this).closest(".field:not(.back)").addClass ('disabled-button');
          } else {
            $ (this).addClass ('disabled');
          }
          $ (this).click (disabledHandler);      
        });
      } else {      
        formObj.find(':submit:not(.disabledButton):not(.back-button)').each (function () {  
          if ($.browser.msie && parseInt ($.browser.version, 10) <= 8) {
            $ (this).parents(".field").removeClass ('disabled-button');
          } else {
            $ (this).removeClass ('disabled');
          }
          $(this).removeAttr("disabled");
          $ (this).unbind("click", disabledHandler);
        });
      }
    }
  }
  
  //
  // The init is called after the form values from the use are set in the client side framework:
  // Now we can add the events.
  //
  function init(formObj) {

    log("[init] formId = "+$(formObj).attr("id"));

    //enable submit buttons
    if (! formObj.hasClass("nosubmitwitherrors")) {
      formObj.find(':submit:not(.disabledButton)').each (function () {  
        if ($.browser.msie && parseInt ($.browser.version, 10) <= 8) {
          $ (this).parents(".field").removeClass ('disabled-button');
        } else {
          $ (this).removeClass ('disabled');
        }
        $(this).removeAttr("disabled");
        $ (this).unbind("click", disabledHandler);
      });
    }
    //enable back-buttons
    formObj.find(':submit.back-button:not(.disabledButton)').each (function () {  
      if ($.browser.msie && parseInt ($.browser.version, 10) <= 8) {
        $ (this).parents(".field").removeClass ('disabled-button');
      } else {
        $ (this).removeClass ('disabled');
      }
      $(this).removeAttr("disabled");
      $ (this).unbind("click", disabledHandler);
    });
      

    //
    // (1) Set a change event on all inputs: we can determine clientside if other fields needs to be shown
    // This is not done by looping over the inputs, because this doesn't work for repeats
    //
    formObj.find(':input').change(function() {
      FormValidation.changeFragment($(this), true, false);
      checkButtons(formObj);
    });

    formObj.find(':input').blur(function() {
      FormValidation.changeFragment($(this), true, false);
      checkButtons(formObj);
    });

    // (3) validate all inputs when the form is submitted
    formObj.submit(function(event) {
      var formId = $(this).attr("id");
      var step = WebmanagerFormStateRegistry[formId].currentStep();

      log("[submit] formId = "+formId);

      var useAjax = $("input[name='clientsideRouting']", this).val();
      if (useAjax == 'true') {
        event.preventDefault();
      }

      var backValue = $("#wmback" + $(this).attr("id"), this).val();
      if (backValue != 'back') {
        var noValidation = $("input[name='noValidation']", this).val();
        var hasErrors = false;
        if (noValidation != 'true') {
          hasErrors = FormValidation.validateForm($(this), step);
        } else {
          log('No validation executed because the \'noValidation\' input has value \'true\'.');
        }

        if (!hasErrors && $(this).data('preventSubmit') != true) {
          log("[submit] Triggered [IAFBeforeSubmit]");
          $(this).trigger("IAFBeforeSubmit");

          // now we can submit the form
          FormValidation.submitForm($(this), step);
        } else {
          event.preventDefault();
          $(this).trigger("SubmitCanceled");
        }
      } else {
        log('No validation executed for the backbutton');
        $(this).trigger("IAFBeforeSubmit");

        // now we can submit the form
        FormValidation.submitForm($(this), step);
      }
    });

    // Binding for the back button
    $("#btnback"+$(formObj).attr("id"), formObj).bind("click.iaf", function(event) {
      log('Backbutton clicked');
      event.preventDefault();
      $("#wmback" + $(formObj).attr("id")).val("back");
      var useAjax = $("input[name='clientsideRouting']", formObj).val();
      if (useAjax == 'true') {
        log('Backbutton clicked: IAFBack triggered');
        $(formObj).trigger("IAFBack");
      } else {
        log('Backbutton clicked: trigger form submit');
        $(formObj).trigger("submit");
      }
    });

    //
    // Set a click event on all radio inputs and pipe it to the onChange
    // this to avoid problems in IE6/IE7/IE8 that have a different event model
    //
    formObj.find(':input:radio').click(function() {
      if (FormsUtil.isIE) {
        $(this).change();
      }
    });


    //
    // (5) Set the initial value and visibility
    //
    var inputs = new Array();
    // This is for the radio and checkboxes: we only need to set them once
    var done = new Array();

    formObj.find(':input').each(function() {
      var formId = formObj.attr("id");
      var step = WebmanagerFormStateRegistry[formId].currentStep();

      var inputName = $(this).attr("name");
      var inputType = $(this).attr("type");
      if (inputName != '' && !FormsUtil.contains(done, inputName)) {
        if (inputType != 'hidden') {
          done.push(inputName);
        }

        var fragmentObj = FormsUtil.getObject(step, $(this).attr("name"));

        if (fragmentObj != null && inputType != 'hidden') {
          var isVisible = true;
          // When form is hidden the :visible inherits the invisibility of the form.
          // We therefore check for the specific displayNone class in that case
          if (!$(formObj).is(":visible")) {
            $(this).parents(".field").each(function() {
              if ($(this).hasClass("displayNone")) {
                isVisible = false;
              }
            });
          } else {
            isVisible = $(this).is(":visible");
          }
          fragmentObj.visible = isVisible;
          fragmentObj.condition = isVisible;

          inputs.push($(this));
        }
      }
    });

    // Turn clientSideRouting on for ajax forms
    $("input[name='clientsideRouting']", formObj).val(formObj.hasClass("ajax"));

    // Submit form to new window when it has the class newwindow
    if (formObj.hasClass("newwindow") && formObj.attr('target') == '') {
        formObj.attr('target', '_blank');
    }

    formObj.data('iaForm', {
      isDirty : false,
      isBusy : false
    });

    if (formObj.hasClass("nosubmitwitherrors")) {
      checkButtons(formObj);
    }
    //bind expandable-component behaviour to hide and show events
    $(".field.expandable-component", formObj).each(function(){
      this.expandable = new nn.classes.ExpandableComponent ($(this));
    });

    // Trigger the change event after the value and visibility is set
    for (var i = 0; i < inputs.length; ++i) {
      FormValidation.changeFragment(inputs[i], false, false);
    }
    formObj.trigger('IAF_ClientsideFrameworkLoaded');
  }

  // Called on submit of form when there are no clientside errors.
  jQuery("form.nn_form").live("IAF_SubmitForm", function(event) {
      var useAjax = $("input[name='clientsideRouting']", this).val();
      log("[IAF_SubmitForm] useAjax = "+useAjax);
      iaForm = $(this);
      if (useAjax == 'true') {
          $(this).ajaxSubmit({
              dataType:'json',
              timeout: SUBMIT_TIMEOUT,
              error: function(xhr) {
                  var response = null;
                  try {
                    response = xhr.responseText;
                  } catch (e) {}
                  if (response != null && response.toLowerCase().indexOf("<pre>") == 0) {
                    // When the form contains an upload, the json response is wrapped in (firefox) or
                    // prefixed by (IE 8)a <pre> tag. As a result the default conversion to json fails
                    var data = response.substring(5, response.lastIndexOf("}") + 1);
                    log("[IAF_SubmitForm] (error) Triggered [IAFAfterSubmit] with data " + data);
                    iaForm.trigger("IAFAfterSubmit", $.parseJSON(data));
                  } else {
                    log("[IAF_SubmitForm] (error) Triggered [IAFAfterSubmit]");
                    iaForm.trigger("IAFAfterSubmit");
                  }
              },
              success: function(data) {
                  log("[IAF_SubmitForm] (success) Triggered [IAFAfterSubmit]");
                  iaForm.trigger("IAFAfterSubmit", data);
              },
              semantic: false
          });
      } else {
          log("[IAF_SubmitForm] Normal submit");
      }
  });

  jQuery("form.nn_form :input:[type != 'hidden']:not(button),form.nn_form :input.forcevalidation").live("IAF_ShowError", function(event, errordivid, arr) {
     if (!jQuery(this).hasClass('error')) {
         jQuery(this).addClass('error');
     }

     var formObj = $(this).closest("form");
     var inputName = jQuery(this).attr("name");
     var errorHolder = jQuery('#'+errordivid, formObj);


     if (errorHolder.length > 0) {
         var errorString = '';
         for (var item in arr) {
             if (errorString != '') {
                errorString += '<br />';
             }
             errorString += arr[item];
         }

         errorHolder.html(errorString);
         if (!errorHolder.hasClass('error-message')) {
             errorHolder.addClass('error-message');
         }
         if (errorHolder.hasClass('displayNone')) {
             errorHolder.removeClass('displayNone');
         }
     }
  });

  jQuery("form.nn_form :input:[type != 'hidden']:not(button),form.nn_form :input.forcevalidation").live("IAF_HideError", function(event, arr) {
     if (jQuery(this).hasClass('error')) {
         jQuery(this).removeClass('error');
     }

     var formObj = $(this).closest("form");
     var inputName = jQuery(this).attr("name");
     var errorHolder = jQuery('#error_' + inputName.replace(/[.]/g,'_'), formObj);

     if (errorHolder.length > 0) {
         errorHolder.html('');
         if (errorHolder.hasClass('error-message')) {
             errorHolder.removeClass('error-message');
         }
         if (!errorHolder.hasClass('displayNone')) {
             errorHolder.addClass('displayNone');
         }
     }
  });

  jQuery("form.nn_form").live("IAFAfterSubmit", function(event, data) {
     if (typeof data == "undefined" || (typeof data.routingResult != "undefined" &&
         typeof data.routingResult.httpError != "undefined"))
     {
         // There was no response or the response is a routing result with http error
         if (!jQuery("#generalerrormessage").hasClass('error-message')) {
             jQuery("#generalerrormessage").addClass('error-message');
         }
         if (jQuery("#generalerrormessage").hasClass('displayNone')) {
             jQuery("#generalerrormessage").removeClass('displayNone');
         }
     } else if (typeof data.routingResult != "undefined") {
       if (data.routingResult.type == '0') {
         document.location.href = data.routingResult.url;
       } else {
         $(this).trigger("NNShowFormStep", data.routingResult.step);
       }
     } else if (typeof data.result != "undefined") {
         var formStep = jQuery(":input[name='wmstepid']:first", jQuery(this)).val();
         $(this).trigger("NNShowFormStep", formStep);
     }

  });

  jQuery("div.field").live("IAF_ShowFormFragment", function(event) {
    var div = jQuery(this);
    var classes = div.attr("class");

    if (classes && classes.indexOf("displayNone") != -1) {
      log("IAF_ShowFormFragment: has been called with classes: " + classes, " id = " + $(this).attr("id"));
      if (classes && classes.indexOf("expandable-component") != -1) {
        this.expandable.open();
      }

      // Manually remove the displayNone class, by removing it, removing the double spaces and trimming. jQuery's removeClass does not always work
      var classes = div.attr("class");
      classes = classes.replace(/displayNone/g, "");
      classes = classes.replace(/\s+/g, " ");
      classes = classes.replace(/^\s\s*/, "").replace(/\s\s*$/, "");
      div.attr("class", classes);
      nn.handlers.invalidateParent(0);

      $(this).trigger('IAF_ShowFormFragment_updated');
    }
  });

  jQuery("div.field").live("IAF_HideFormFragment", function(event) {
    if(event.target != this){ return true; } // prevent propagation bubbling.
    var div = jQuery(this);
    var classes = div.attr("class");

    if (!classes || classes.indexOf("displayNone") == -1) {
      log("IAF_HideFormFragment: has been called with classes: " + classes, " id = " + $(this).attr("id"));
      if (classes && classes.indexOf("expandable-component") != -1) {
        this.expandable.close();
      }

      // Manually add the displayNone class. jQuery's addClass does not always work
      classes += " " + "displayNone";
      div.attr("class", classes);
      nn.handlers.invalidateParent(0);

      $(this).trigger('IAF_HideFormFragment_updated');
    }
  });

  jQuery("form.nn_form").live("IAFBeforeSubmit", function(event) {
     if (jQuery("#generalerrormessage").hasClass('error-message')) {
         jQuery("#generalerrormessage").removeClass('error-message');
     }
     if (!jQuery("#generalerrormessage").hasClass('displayNone')) {
         jQuery("#generalerrormessage").addClass('displayNone');
     }
  });

  jQuery("form.nn_form").live("IAFBack", function(event) {
     $(this).submit();
  });

  jQuery("form.nn_form").live("SubmitCanceled", function(event) {
     // Set the focus to the first input with an error message
     jQuery(":input.error:not(:input.displayNone):first", jQuery(this)).focus();
  });

  jQuery("form.nn_form").live("NNShowFormStep", function(event, formStep) {
     var baseUrl = jQuery(this).data("formBaseUrl");
     var nextUrl = baseUrl;
     if (typeof formStep != 'undefined' && formStep != '') {
         if (nextUrl.indexOf('?') != -1) {
             nextUrl = nextUrl + '&wmstepid=' + formStep;
         } else {
             nextUrl = nextUrl + '/wmstepid=' + formStep;
         }
     }

     log('nextUrl:' + nextUrl);

     jQuery(this).parents(".jq_formholder").load(nextUrl, function() {
         nn.handlers.initializeObjects(this);

         jQuery(this).find("form.nn_form").trigger("NNAfterShowFormStep", formStep);

         jQuery(this).find("form.nn_form").trigger("IAFFormLoaded");
     });
  });

  jQuery("form.nn_form").live("IAFautoSubmit", function(event, formStep) {
    log("IAFAutoSubmit");
    var isDirty = false;
    var isBusy = false;
    try {
      isDirty = $(this).data('iaForm').isDirty;
      isBusy = $(this).data('iaForm').isBusy;
    } catch (e) {}
    if (isDirty && !isBusy) {
      $(this).data('iaForm').isDirty = false;
      $(this).data('iaForm').isBusy = true;

      var formId = $(this).attr("id");
      var step = WebmanagerFormStateRegistry[formId].currentStep();

      var hasErrors = FormValidation.validateForm($(this), step);
      if (hasErrors || $(this).data('preventSubmit')) {
        log('Could not autosubmit form because of validation errors');
        $(this).data('iaForm').isBusy = false;
        $(this).data('preventSubmit', false);
        return;
      }

      $(this).trigger("IAFBeforeAutoSubmit");

      var iaForm = $(this);
      $(this).ajaxSubmit({
        dataType:'json',
        timeout: SUBMIT_TIMEOUT,
        error: function() {
          log("[IAFautoSubmit] (error) Triggered [IAFAfterSubmit]");
          iaForm.trigger("IAFAfterSubmit");
          iaForm.data('iaForm').isBusy = false;
        },
        success: function(data) {
          iaForm.trigger("IAFAfterAutoSubmit", data);
          iaForm.data('iaForm').isBusy = false;
        }
      });

    }
  });

}); // end

// Helper function for console logging
function log() {
    if (window.console && window.console.log) {
        window.console.log('[jquery.iaf] ' + Array.prototype.join.call(arguments,''));
    }
};
