/**

* Copyright (c) 2001-present, Vonage.
*
* Modals (requires core)
*/

'use strict';

Volta.modal = function () {

var _class = {
  auto: 'Vlt-modal--auto',
  bodyModalOpen: 'Vlt-body--modal-open',
  cancel: 'Vlt-modal__cancel',
  confirm: 'Vlt-modal__confirm',
  content: 'Vlt-modal__content',
  modal: 'Vlt-modal',
  out: 'Vlt-modal--out',
  panel: 'Vlt-modal__panel',
  trigger: 'Vlt-modal-trigger',
  visible: 'Vlt-modal_visible',
  dismiss: 'Vlt-modal__dismiss',
}

var body,
  dismissModalHandler,
  cancelModalHandler,
  confirmModalHandler,
  escHandler,
  clickHandler,
  escAttached;

function Modal() {}

Modal.prototype = {
  attachButtons: function() {
    var _this = this;
    _this.dismissBtn = _this.modal.querySelector('.' + _class.dismiss);

    if(_this.dismissBtn) {
      dismissModalHandler = dismissModal.bind(_this);
      _this.dismissBtn.addEventListener('click', dismissModalHandler);
    }

    _this.cancelBtn = _this.modal.querySelector('.' + _class.cancel);

    if(_this.cancelBtn) {
      cancelModalHandler = cancelModal.bind(_this);
      _this.cancelBtn.addEventListener('click', cancelModalHandler);
    }

    _this.confirmBtn = _this.modal.querySelector('.' + _class.confirm);

    if(_this.confirmBtn) {
      confirmModalHandler = confirmModal.bind(_this);
      _this.confirmBtn.addEventListener('click', confirmModalHandler);
    }
  },
  html: function(newHtml) {
    this.modal.innerHTML = newHtml;
    return this;
  },
  init: function(elementOrId) {
    if(elementOrId.length) {
      this.modal = document.querySelector('#' + elementOrId);
    } else {
      this.modal = elementOrId;
    }

    this._callback = Volta._getFunction(this.modal.dataset.callback);
  },
  open: function(e) {
    if(e && e.preventDefault) {
      e.preventDefault();
      e.stopPropagation();
    }

    this.modal.classList.remove(_class.out);
    this.modal.classList.add(_class.visible);
    this.attachButtons();

    disableScroll();

    if(!escAttached && !this.modal.dataset.disableEsc || this.modal.dataset.disableEsc === "false") {
      escHandler = closeModalOnEscape.bind(this);
      body.addEventListener('keyup', escHandler, { once: true });
      escAttached = true;
    }

    if(!this.modal.dataset.disableClick || this.modal.dataset.disableClick === "false") {
      clickHandler = closeModalOnClick.bind(this);
      this.modal.addEventListener('click', clickHandler, { once: true });
    }
  },
  dismiss: function(e, confirmed) {
    var _this = this;

    if(e && e.preventDefault) {
      e.preventDefault();
      e.stopPropagation();
    }

    enableScroll();

    if(_this.modal){
      _this.modal.classList.remove(_class.visible);
      _this.modal.classList.add(_class.out);
    }

    if(_this._callback) {
      _this._callback(confirmed);
    }

    removeModal(_this);
  }
}

return {
  create: create,
  init: attachModalHandlers
}

/**
 *    @public
 *
 *    @description Attach a click listener to each modals trigger on the screen, which will open the modal
 */
function attachModalHandlers() {
  if(!body) {
    body = document.querySelector('body');
  }

  var triggers = document.querySelectorAll('.' + _class.trigger);

  if(triggers.length > 0) {
    triggers.forEach(attachTriggerHandler);
  }

  //Not the recommended way to use modals
  var modals = document.querySelectorAll('.' + _class.modal);

  if(modals.length > 0) {
    modals.forEach(attachModalHandler);
  }

  function attachModalHandler(modal) {
    if(Volta._hasClass(modal, _class.auto)) {
      var trigger = document.querySelector('#' + modal.dataset.trigger);
      trigger.addEventListener('click', function() {
        create(modal).open();
      });
    }
  }

  function attachTriggerHandler(trigger) {
    if(trigger.dataset.modal) {
      var modal = document.querySelector('#' + trigger.dataset.modal);

      if(!modal) {
        console.warn('Volta: modal ' + trigger.dataset.modal + ' cannot be found');
      }

      trigger.addEventListener('click', function() {
        create(modal).open();
      });
    }
  }
}

/**
 *    @private
 *
 *    @description Close the modal, triggered by cancel button, passes false to callback function
 *  @param {event} e
 */
function cancelModal(e) {
  return this.dismiss(e, false);
}

/**
 *    @private
 *
 *    @description Close the modal, triggered by confirm button, passes true to callback function
 *  @param {event} e
 */
function confirmModal(e) {
  return this.dismiss(e, true);
}

/**
 *    @private
 *
 *    @description Close the modal, triggered by 'x' button, passes false to callback function
 *  @param {event} e
 */
function dismissModal(e) {
  return this.dismiss(e, false);
}

/**   @private
 *
 *    @description Close the modal, triggered by 'esc' key, passes false to callback function
 *  @param {event} e
 */
function closeModalOnEscape(e){
  if(e && e.keyCode === 27) {
    this.dismiss(e, false);
  } else {
    body.addEventListener('click', escHandler, { once: true });
  }
}

/**   @private
 *
 *    @description Close the modal, triggered by 'body click, passes false to callback function
 *  @param {event} e
 */
function closeModalOnClick(e){
  if(!Volta._hasClass(e.target, _class.trigger)
    && !Volta._closest(e.target, '.' + _class.trigger, '.' + _class.trigger)
    && !Volta._closest(e.target, '.' + _class.panel, '.' + _class.panel)) {
    this.dismiss(e, false);
  } else if(this.modal) {
    this.modal.addEventListener('click', clickHandler, { once: true });
  }
}

/**
 *    @public
 *
 *    @description Create the modal object
 *  @param {HTMLElement|string} elementOrId Reference to the modal element or the id
 *. @return {Object} A modal object
 */
function create(elementOrId) {
  if(!body) {
    body = document.querySelector('body');
  }
  var modal = Object.create(Modal.prototype, {})
  modal.init(elementOrId);
  return modal;
}

/**
 * Private functions to disable body scroll when modal is open
 */
function disableScroll() {
  body.classList.add(_class.bodyModalOpen);
  body.addEventListener('touchmove', preventScroll);
  body.querySelector('main').addEventListener('touchmove', preventScroll);
  body.querySelector('.' + _class.content).addEventListener('touchmove', allowScroll);
}

function enableScroll() {
  body.classList.remove(_class.bodyModalOpen);
  body.removeEventListener('touchmove', preventScroll);
  body.querySelector('main').removeEventListener('touchmove', preventScroll);
  var modalContent = body.querySelector('.' + _class.content);
  if(modalContent) modalContent.removeEventListener('touchmove', allowScroll);
}

function allowScroll(e) {
  e.stopPropagation();
}

function preventScroll(e) {
  e.preventDefault();
}

/**
 *    @private
 *
 *    @description Remove the modal after dismiss, makes sure to delete the modal properties so it can be garbage collected, and removes event listeners
 *  @param {HTMLElement|string} elementOrId Reference to the modal element or the id
 */
function removeModal(modal) {
  delete modal.modal;

  if(modal.dismissBtn) {
    modal.dismissBtn.removeEventListener('click', dismissModalHandler);
  }

  if(modal.cancelBtn) {
    modal.cancelBtn.removeEventListener('click', cancelModalHandler);
  }

  if(modal.confirmBtn) {
    modal.confirmBtn.removeEventListener('click', confirmModalHandler);
  }

  if(clickHandler) {
    body.removeEventListener('click', clickHandler);
  }

  if(escHandler) {
    body.removeEventListener('keyup', escHandler);
    escAttached = false;
  }
}

}();