(function() {
  'use strict';

  window.utils = window.utils || {};

  var JS_INITIALIZED_CLASS = 'js-inputs-initialized';

  window.utils.inputs = function(wrapper, options) {
    options = options || {};
    var utilInstances = [];

    if (wrapper.classList.contains(JS_INITIALIZED_CLASS) && !options.force) {
      return false;
    }

    // checkboxes
    var checkboxes = Array.from(wrapper.querySelectorAll('input[type="checkbox"]'));
    checkboxes.forEach(function(checkbox) {
      utilInstances.push(window.utils.setup('checkbox', checkbox));
    });

    // radios
    var radios = Array.from(wrapper.querySelectorAll('input[type="radio"]'));
    radios.forEach(function(radio) {
      utilInstances.push(window.utils.setup('radio', radio));
    });

    // file-uploads
    var fileUploads = Array.from(wrapper.querySelectorAll('input[type="file"]'));
    fileUploads.forEach(function(input) {
      utilInstances.push(window.utils.setup('fileUpload', input, options));
    });

    // file-checkboxes
    var fileCheckboxes = Array.from(wrapper.querySelectorAll('.file-checkbox'));
    fileCheckboxes.forEach(function(input) {
      utilInstances.push(window.utils.setup('fileCheckbox', input, options));
    });

    function destroyUtils() {
      utilInstances.filter(function(utilInstance) {
        return !!utilInstance;
      }).forEach(function(utilInstance) {
        utilInstance.destroy();
      });
    }

    wrapper.classList.add(JS_INITIALIZED_CLASS);

    return {
      scope: wrapper,
      destroy: destroyUtils,
    };
  };

  // (multiple) dynamic file uploads
  // expects i18n object with following strings:
  // »filesSelected«: label of multi-upload button after selection
  //    example: "Dateien ausgewählt" (will be prepended by number of selected files)
  // »selectFile«: label of single-upload button before selection
  //    example: "Datei auswählen"
  // »selectFiles«: label of multi-upload button before selection
  //    example: "Datei(en) auswählen"

  var FILE_UPLOAD_INPUT_LIST_CLASS = 'file-input__list';
  var FILE_UPLOAD_INPUT_UNPACK_CHECKBOX_CLASS = 'file-input__unpack';
  var FILE_UPLOAD_INPUT_LABEL_CLASS = 'file-input__label';
  var FILE_UPLOAD_INPUT_HIDDEN_CLASS = 'file-input__input--hidden';

  window.utils.fileUpload = function(input, options) {
    var isMulti = input.hasAttribute('multiple');
    var fileList = isMulti ? addFileList() : null;
    var label = addFileLabel();
    var i18n = options.i18n;

    if (!i18n) {
      throw new Error('window.utils.fileUpload(input, options) needs to be passed i18n object via options');
    }

    function renderFileList(files) {
      fileList.innerHTML = '';
      Array.from(files).forEach(function(file, index) {
        var fileDisplayEl = document.createElement('li');
        fileDisplayEl.innerHTML = file.name;
        fileList.appendChild(fileDisplayEl);
      });
    }

    function updateLabel(files) {
      if (files.length) {
        if (isMulti) {
          label.innerText = files.length + ' ' + i18n.filesSelected;
        } else {
          label.innerHTML = files[0].name;
        }
      } else {
        resetFileLabel();
      }
    }

    function addFileList() {
      var list = document.createElement('ol');
      list.classList.add(FILE_UPLOAD_INPUT_LIST_CLASS);
      var unpackEl = input.parentElement.querySelector('.' + FILE_UPLOAD_INPUT_UNPACK_CHECKBOX_CLASS);
      if (unpackEl) {
        input.parentElement.insertBefore(list, unpackEl);
      } else {
        input.parentElement.appendChild(list);
      }
      return list;
    }

    function addFileLabel() {
      var label = document.createElement('label');
      label.classList.add(FILE_UPLOAD_INPUT_LABEL_CLASS);
      label.setAttribute('for', input.id);
      input.parentElement.insertBefore(label, input);
      return label;
    }

    function resetFileLabel() {
      if (isMulti) {
        label.innerText = i18n.selectFiles;
      } else {
        label.innerText = i18n.selectFile;
      }
    }

    // initial setup
    resetFileLabel();
    input.classList.add(FILE_UPLOAD_INPUT_HIDDEN_CLASS);
    input.addEventListener('change', function() {
      input.dispatchEvent(new Event('input'));
      if (isMulti) {
        renderFileList(input.files);
      }

      updateLabel(input.files);
    });

    return {
      scope: input,
      destroy: function() {},
    };
  }

  // to remove previously uploaded files

  var FILE_UPLOAD_CONTAINER_CLASS = 'file-container';
  var FILE_UPLOAD_CONTAINER_CHECKED_CLASS = 'file-container--checked';

  window.utils.fileCheckbox = function(input) {
    // adds eventlistener(s)
    function addListener(container) {
      input.addEventListener('change', function(event) {
        container.classList.toggle(FILE_UPLOAD_CONTAINER_CHECKED_CLASS, this.checked);
      });
    }

    // initial setup
    function setup() {
      var cont = input.parentNode;
      while (cont !== document.body) {
        if (cont.matches('.' + FILE_UPLOAD_CONTAINER_CLASS)) {
          break;
        }
        cont = cont.parentNode;
      }
      addListener(cont);
    }

    setup();

    return {
      scope: input,
      destroy: function() {},
    };
  }

  // turns native checkboxes into custom ones
  window.utils.checkbox = function(input) {

    if (!input.parentElement.classList.contains('checkbox')) {
      var parentEl = input.parentElement;
      var siblingEl = input.nextElementSibling;
      var wrapperEl = document.createElement('div');
      var labelEl = document.createElement('label');
      wrapperEl.classList.add('checkbox');
      labelEl.setAttribute('for', input.id);
      wrapperEl.appendChild(input);
      wrapperEl.appendChild(labelEl);

      if (siblingEl) {
        parentEl.insertBefore(wrapperEl, siblingEl);
      } else {
        parentEl.appendChild(wrapperEl);
      }
    }

    return {
      scope: input,
      destroy: function() {},
    };
  }

  // turns native radio buttons into custom ones
  window.utils.radio = function(input) {

    if (!input.parentElement.classList.contains('radio')) {
      var parentEl = input.parentElement;
      var siblingEl = input.nextElementSibling;
      var wrapperEl = document.createElement('div');
      wrapperEl.classList.add('radio');
      wrapperEl.appendChild(input);

      if (siblingEl && siblingEl.matches('label')) {
        wrapperEl.appendChild(siblingEl);
      }

      parentEl.appendChild(wrapperEl);
    }

    return {
      scope: input,
      destroy: function() {},
    };
  }

  // Override implicit submit (pressing enter) behaviour to trigger a specified submit button instead of the default
  window.utils.implicitSubmit = function(input, options) {
    var submit = options.submit;

    if (!submit) {
      throw new Error('window.utils.implicitSubmit(input, options) needs to be passed a submit element via options');
    }

    var doSubmit = function(event) {
      if (event.keyCode == 13) {
        event.preventDefault();
        submit.click();
      }
    };

    input.addEventListener('keypress', doSubmit);

    return {
      scope: input,
      destroy: function() {
        input.removeEventListener('keypress', doSubmit);
      },
    };
  }
})();
