'use strict'

import { translate } from './i18n'

/**
 * A factory function to create an ShowMoreNode, which depends on a Node
 * @param {function} Node
 */
export function showMoreNodeFactory (Node) {
  /**
   * @constructor ShowMoreNode
   * @extends Node
   * @param {TreeEditor} editor
   * @param {Node} parent
   * Create a new ShowMoreNode. This is a special node which is created
   * for arrays or objects having more than 100 items
   */
  function ShowMoreNode (editor, parent) {
    /** @type {TreeEditor} */
    this.editor = editor
    this.parent = parent
    this.dom = {}
  }

  ShowMoreNode.prototype = new Node()

  /**
   * Return a table row with an append button.
   * @return {Element} dom   TR element
   */
  ShowMoreNode.prototype.getDom = function () {
    if (this.dom.tr) {
      return this.dom.tr
    }

    this._updateEditability()

    // display "show more"
    if (!this.dom.tr) {
      const me = this
      const parent = this.parent
      const showMoreButton = document.createElement('a')
      showMoreButton.appendChild(document.createTextNode(translate('showMore')))
      showMoreButton.href = '#'
      showMoreButton.onclick = event => {
        // TODO: use callback instead of accessing a method of the parent
        parent.visibleChilds = Math.floor(parent.visibleChilds / parent.getMaxVisibleChilds() + 1) *
            parent.getMaxVisibleChilds()
        me.updateDom()
        parent.showChilds()

        event.preventDefault()
        return false
      }

      const showAllButton = document.createElement('a')
      showAllButton.appendChild(document.createTextNode(translate('showAll')))
      showAllButton.href = '#'
      showAllButton.onclick = event => {
        // TODO: use callback instead of accessing a method of the parent
        parent.visibleChilds = Infinity
        me.updateDom()
        parent.showChilds()

        event.preventDefault()
        return false
      }

      const moreContents = document.createElement('div')
      const moreText = document.createTextNode(this._getShowMoreText())
      moreContents.className = 'jsoneditor-show-more'
      moreContents.appendChild(moreText)
      moreContents.appendChild(showMoreButton)
      moreContents.appendChild(document.createTextNode('. '))
      moreContents.appendChild(showAllButton)
      moreContents.appendChild(document.createTextNode('. '))

      const tdContents = document.createElement('td')
      tdContents.appendChild(moreContents)

      const moreTr = document.createElement('tr')
      if (this.editor.options.mode === 'tree') {
        moreTr.appendChild(document.createElement('td'))
        moreTr.appendChild(document.createElement('td'))
      }
      moreTr.appendChild(tdContents)
      moreTr.className = 'jsoneditor-show-more'
      this.dom.tr = moreTr
      this.dom.moreContents = moreContents
      this.dom.moreText = moreText
    }

    this.updateDom()

    return this.dom.tr
  }

  /**
   * Update the HTML dom of the Node
   */
  ShowMoreNode.prototype.updateDom = function (options) {
    if (this.isVisible()) {
      // attach to the right child node (the first non-visible child)
      this.dom.tr.node = this.parent.childs[this.parent.visibleChilds]

      if (!this.dom.tr.parentNode) {
        const nextTr = this.parent._getNextTr()
        if (nextTr) {
          nextTr.parentNode.insertBefore(this.dom.tr, nextTr)
        }
      }

      // update the counts in the text
      this.dom.moreText.nodeValue = this._getShowMoreText()

      // update left margin
      this.dom.moreContents.style.marginLeft = (this.getLevel() + 1) * 24 + 'px'
    } else {
      if (this.dom.tr && this.dom.tr.parentNode) {
        this.dom.tr.parentNode.removeChild(this.dom.tr)
      }
    }
  }

  ShowMoreNode.prototype._getShowMoreText = function () {
    return translate('showMoreStatus', {
      visibleChilds: this.parent.visibleChilds,
      totalChilds: this.parent.childs.length
    }) + ' '
  }

  /**
   * Check whether the ShowMoreNode is currently visible.
   * the ShowMoreNode is visible when it's parent has more childs than
   * the current visibleChilds
   * @return {boolean} isVisible
   */
  ShowMoreNode.prototype.isVisible = function () {
    return this.parent.expanded && this.parent.childs.length > this.parent.visibleChilds
  }

  /**
   * Handle an event. The event is caught centrally by the editor
   * @param {Event} event
   */
  ShowMoreNode.prototype.onEvent = function (event) {
    const type = event.type
    if (type === 'keydown') {
      this.onKeyDown(event)
    }
  }

  return ShowMoreNode
}
