const NAME = 'off-canvas'
const CLASSES = {
  active:    'in',
  close:     'fa-times',
  container: `${NAME}-container`,
  exit:      `${NAME}-exit`,
  wrapper:   `${NAME}-wrapper`,
}
const DATA = {
  icon:   'fa',
  target: 'target',
}
const EVENTS = {
  click: 'click.ui.offcanvas',
  hide:  'hide.ui.offcanvas',
  show:  'show.ui.offcanvas',
}
const REGEX = {
  ICON: /(fa-[a-zA-Z]+)/g,
}

/**
 * Class that handles off-canvas elements
 * @param  {string} sel The selector matching elements to initialize
 * @return {object}     jQuery object representing the off-canvas elements
 */
const OffCanvas = function OffCanvas(sel) {
  this.$element = $(sel)
  this.$wrapper = this.$element.closest(`.${CLASSES.wrapper}`)
  this.$container = this.$element.closest(`.${CLASSES.container}`)
  this.$button = getTrigger(DATA.target, sel)
  this.$button.data(DATA.icon, getIcon(this.$button))

  this.$exit = $(`<a href="#" role="button" class="${CLASSES.exit}" />`)
  this.$exit.appendTo(this.$wrapper)

  bindEvents(this)

  return this
}

/**
 * Toggles off-canvas item's state between in and out
 * @param  {boolean}   isOpen  A flag indicating whether to activate
 * @return {OffCanvas}         The OffCanvas instance
 */
OffCanvas.prototype.toggle = function toggle(isOpen) {
  const icon = this.$button.data(DATA.icon)

  this.$container.toggleClass(CLASSES.active, isOpen)
  this.$button.attr('aria-expanded', isOpen)
  this.$button.find('.icon').toggleClass(icon, !isOpen)
                            .toggleClass(CLASSES.close, isOpen)

  return this
}

/**
 * Makes the off-canvas element visible
 * @return {this}
 */
OffCanvas.prototype.show = function show() {
  this.$element.trigger(EVENTS.show)
  return this.toggle(true)
}

/**
 * Hides the off-canvas element
 * @return {this}
 */
OffCanvas.prototype.hide = function hide() {
  this.$element.trigger(EVENTS.hide)
  return this.toggle(false)
}

function bindEvents(obj) {
  obj.$button.on(EVENTS.click, (e) => {
    e.preventDefault()
    if (obj.$container.hasClass(CLASSES.active)) {
      obj.hide()
    } else {
      obj.show()
    }
  })

  obj.$exit.on(EVENTS.click, (e) => {
    e.preventDefault()
    obj.hide()
  })
}

function getIcon($el) {
  const iconClass = $el.find('.icon').attr('class')
  const match = REGEX.ICON.exec(iconClass)
  if (match && match.length) {
    return match[0]
  }
  return ''
}

function getTrigger(attr, value) {
  return $(`[data-toggle=${NAME}][data-${attr}=${value}]`)
}

module.exports = OffCanvas
