(function() {
  'use strict';

  /**
   *
   * Modal Utility
   *
   * Attribute: uw-modal
   *
   * Params:
   *  data-modal-trigger: string
   *    Selector for the element that toggles the modal.
   *    If trigger element has "href" attribute the modal will be dynamically loaded from the referenced page
   *  data-modal-closeable: boolean property
   *    If the param is present the modal will have a close-icon and can also be closed by clicking anywhere on the overlay
   *
   * Example usage:
   * <div uw-modal data-modal-trigger='#trigger' data-modal-closeable>This is the modal content
   * <div id='trigger'>Click me to open the modal
   */

  var MODAL_UTIL_NAME = 'modal';
  var MODAL_UTIL_SELECTOR = '[uw-modal]';

  var MODAL_HEADERS = {
    'Is-Modal': 'True',
  };

  var MODAL_INITIALIZED_CLASS = 'modal--initialized';
  var MODAL_CLASS = 'modal';
  var MODAL_OPEN_CLASS = 'modal--open';
  var MODAL_TRIGGER_CLASS = 'modal__trigger';
  var MODAL_CONTENT_CLASS = 'modal__content';
  var MODAL_OVERLAY_CLASS = 'modal__overlay';
  var MODAL_OVERLAY_OPEN_CLASS = 'modal__overlay--open';
  var MODAL_CLOSER_CLASS = 'modal__closer';

  var MAIN_CONTENT_CLASS = 'main__content-body'

  // one singleton wrapper to keep all the modals to avoid CSS bug
  // with blurry text due to `transform: translate(-50%, -50%)`
  // will be created (and reused) for the first modal that gets initialized
  var MODALS_WRAPPER_CLASS = 'modals-wrapper';
  var MODALS_WRAPPER_SELECTOR = '.' + MODALS_WRAPPER_CLASS;
  var MODALS_WRAPPER_OPEN_CLASS = 'modals-wrapper--open';

  var modalUtil = function(element) {

    var modalsWrapper;
    var modalOverlay;
    var modalUrl;

    function _init() {
      if (!element) {
        throw new Error('Modal utility cannot be setup without an element!');
      }

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

      ensureModalWrapper();

      // param modalTrigger
      if (!element.dataset.modalTrigger) {
        throw new Error('Modal utility cannot be setup without a trigger element!');
      } else {
        setupTrigger();
      }

      // param modalCloseable
      if (element.dataset.modalCloseable !== undefined) {
        setupCloser();
      }

      // mark as initialized and add modal class for styling
      element.classList.add(MODAL_INITIALIZED_CLASS, MODAL_CLASS);

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

    function ensureModalWrapper() {
      modalsWrapper = document.querySelector(MODALS_WRAPPER_SELECTOR);
      if (!modalsWrapper) {
        // create modal wrapper
        modalsWrapper = document.createElement('div');
        modalsWrapper.classList.add(MODALS_WRAPPER_CLASS);
        document.body.appendChild(modalsWrapper);
      }

      modalOverlay = modalsWrapper.querySelector('.' + MODAL_OVERLAY_CLASS);
      if (!modalOverlay) {
        // create modal overlay
        modalOverlay = document.createElement('div');
        modalOverlay.classList.add(MODAL_OVERLAY_CLASS);
        modalsWrapper.appendChild(modalOverlay);
      }
    }

    function setupTrigger() {
      var triggerSelector = element.dataset.modalTrigger;
      if (!triggerSelector.startsWith('#')) {
        triggerSelector = '#' + triggerSelector;
      }
      var triggerElement = document.querySelector(triggerSelector);

      if (!triggerElement) {
        throw new Error('Trigger element for Modal not found: "' + triggerSelector + '"');
      }

      triggerElement.classList.add(MODAL_TRIGGER_CLASS);
      triggerElement.addEventListener('click', onTriggerClicked, false);
      modalUrl = triggerElement.getAttribute('href');
    }

    function setupCloser() {
      var closerElement = document.createElement('div');
      element.insertBefore(closerElement, null);
      closerElement.classList.add(MODAL_CLOSER_CLASS);
      closerElement.addEventListener('click', onCloseClicked, false);
      modalOverlay.addEventListener('click', onCloseClicked, false);
    }

    function onTriggerClicked(event) {
      event.preventDefault();
      open();
    }

    function onCloseClicked(event) {
      event.preventDefault();
      close();
    }

    function onKeyUp(event) {
      if (event.key === 'Escape') {
        close();
      }
    }

    function open() {
      element.classList.add(MODAL_OPEN_CLASS);
      modalOverlay.classList.add(MODAL_OVERLAY_OPEN_CLASS);
      modalsWrapper.classList.add(MODALS_WRAPPER_OPEN_CLASS);
      modalsWrapper.appendChild(element);

      if (modalUrl) {
        fillModal(modalUrl);
      }

      document.addEventListener('keyup', onKeyUp);
    }

    function close() {
      modalOverlay.classList.remove(MODAL_OVERLAY_OPEN_CLASS);
      element.classList.remove(MODAL_OPEN_CLASS);
      modalsWrapper.classList.remove(MODALS_WRAPPER_OPEN_CLASS);

      document.removeEventListener('keyup', onKeyUp);
    };

    function fillModal(url) {
      if (!HttpClient) {
        throw new Error('HttpClient not found! Can\'t fetch modal content from ' + url);
      }

      HttpClient.get(url, MODAL_HEADERS)
        .then(function(response) {
          response.text().then(processResponse);
        });
    }

    function processResponse(responseBody) {
      var responseElement = document.createElement('div');
      responseElement.innerHTML = responseBody;

      var modalContent = document.createElement('div');
      modalContent.classList.add(MODAL_CONTENT_CLASS);

      var contentBody = responseElement.querySelector('.' + MAIN_CONTENT_CLASS);

      if (contentBody) {
        modalContent.innerHTML = contentBody.innerHTML;
      }

      var previousModalContent = element.querySelector('.' + MODAL_CONTENT_CLASS);
      if (previousModalContent) {
        previousModalContent.remove();
      }

      modalContent = withPrefixedInputIDs(modalContent);
      element.insertBefore(modalContent, null);

      // setup any newly arrived utils
      UtilRegistry.setupAll(element);
    }

    function withPrefixedInputIDs(modalContent) {
      var idAttrs = ['id', 'for', 'data-conditional-input'];
      idAttrs.forEach(function(attr) {
        Array.from(modalContent.querySelectorAll('[' + attr + ']')).forEach(function(input) {
          var value = element.id + '__' + input.getAttribute(attr);
          input.setAttribute(attr, value);
        });
      });
      return modalContent;
    }

    return _init();
  };

  if (UtilRegistry) {
    UtilRegistry.register({
      name: MODAL_UTIL_NAME,
      selector: MODAL_UTIL_SELECTOR,
      setup: modalUtil
    });
  }
})();
