(function collonadeClosure() {
  'use strict';

  /**
   *
   * Async Form Utility
   *  prevents form submissions from reloading the page but instead firing an AJAX request
   *
   * Attribute: uw-async-form
   *   (works only on <form> elements)
   *
   * Example usage:
   *   <form uw-async-form method='POST' action='...'>
   *     ...
   *
   * Internationalization:
   *  This utility expects the following translations to be available:
   *    asyncFormFailure: text that gets shown if an async form request fails
   *      example: "Oops. Something went wrong."
   */

  var ASYNC_FORM_UTIL_NAME = 'asyncForm';
  var ASYNC_FORM_UTIL_SELECTOR = 'form[uw-async-form]';

  var ASYNC_FORM_INITIALIZED_CLASS = 'check-all--initialized';
  var ASYNC_FORM_RESPONSE_CLASS = 'async-form__response';
  var ASYNC_FORM_LOADING_CLASS = 'async-form--loading';
  var ASYNC_FORM_MIN_DELAY = 600;

  var MODAL_SELECTOR = '.modal';
  var MODAL_HEADER_KEY = 'Is-Modal';
  var MODAL_HEADER_VALUE = 'True';

  var asyncFormUtil = function(element) {

    var lastRequestTimestamp = 0;

    function init() {
      if (!element) {
        throw new Error('Async Form Utility cannot be setup without an element!');
      }

      if (element.classList.contains(ASYNC_FORM_INITIALIZED_CLASS)) {
        return false;
      }

      element.addEventListener('submit', submitHandler);

      element.classList.add(ASYNC_FORM_INITIALIZED_CLASS);

      return {
        name: ASYNC_FORM_UTIL_NAME,
        element: element,
        destroy: function() {},
      };
    }

    function processResponse(response) {
      var responseElement = makeResponseElement(response.content, response.status);
      var parentElement = element.parentElement;

      // make sure there is a delay between click and response
      var delay = Math.max(0, ASYNC_FORM_MIN_DELAY + lastRequestTimestamp - Date.now());

      setTimeout(function() {
        parentElement.insertBefore(responseElement, element);
        element.remove();
      }, delay);
    }

    function makeResponseElement(content, status) {
      var responseElement = document.createElement('div');
      status = status || 'info';
      responseElement.classList.add(ASYNC_FORM_RESPONSE_CLASS);
      responseElement.classList.add(ASYNC_FORM_RESPONSE_CLASS + '--' + status);
      responseElement.innerHTML = content;
      return responseElement;
    }

    function submitHandler(event) {
      event.preventDefault();

      if (!HttpClient) {
        throw new Error('HttpClient not found! Can\'t fetch submit form asynchronously!');
      }

      element.classList.add(ASYNC_FORM_LOADING_CLASS)
      lastRequestTimestamp = Date.now();

      var url = element.getAttribute('action');
      var headers = { };
      var body = new FormData(element);

      var isModal = element.closest(MODAL_SELECTOR);
      if (!!isModal) {
        headers[MODAL_HEADER_KEY] = MODAL_HEADER_VALUE;
      }

      HttpClient.post(url, headers, body)
        .then(function(response) {
          if (response.headers.get("content-type").indexOf("application/json") !== -1) {// checking response header
            return response.json();
          } else {
            throw new TypeError('Unexpected Content-Type. Expected Content-Type: "application/json". Requested URL:' + url + '"');
          }
        }).then(function(response) {
          processResponse(response[0]);
        }).catch(function(error) {
          var failureMessage = I18n.get('asyncFormFailure');
          processResponse({ content: failureMessage });

          element.classList.remove(ASYNC_FORM_LOADING_CLASS);
        });
    }

    return init();
  };

  if (UtilRegistry) {
    UtilRegistry.register({
      name: ASYNC_FORM_UTIL_NAME,
      selector: ASYNC_FORM_UTIL_SELECTOR,
      setup: asyncFormUtil
    });
  }
})();
