export default (codemirror) => {
  (function (mod) {
    mod(codemirror)
  })(function (CodeMirror) {
    CodeMirror.defineOption('placeholder', '', function (cm, val, old) {
      var prev = old && old !== CodeMirror.Init
      if (val && !prev) {
        cm.on('blur', onBlur)
        cm.on('change', onChange)
        cm.on('swapDoc', onChange)
        onChange(cm)
      } else if (!val && prev) {
        cm.off('blur', onBlur)
        cm.off('change', onChange)
        cm.off('swapDoc', onChange)
        clearPlaceholder(cm)
        var wrapper = cm.getWrapperElement()
        wrapper.className = wrapper.className.replace(' CodeMirror-empty', '')
      }

      if (val && !cm.hasFocus()) onBlur(cm)
    })

    function clearPlaceholder (cm) {
      if (cm.state.placeholder) {
        cm.state.placeholder.parentNode.removeChild(cm.state.placeholder)
        cm.state.placeholder = null
      }
    }
    function setPlaceholder (cm) {
      clearPlaceholder(cm)
      var elt = cm.state.placeholder = document.createElement('pre')
      elt.style.cssText = 'height: 0; overflow: visible; color: #80848f;'
      elt.style.direction = cm.getOption('direction')
      elt.className = 'CodeMirror-placeholder'
      var placeHolder = cm.getOption('placeholder')
      if (typeof placeHolder === 'string') placeHolder = document.createTextNode(placeHolder)
      elt.appendChild(placeHolder)
      cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild)
    }

    function onBlur (cm) {
      if (isEmpty(cm)) setPlaceholder(cm)
    }
    function onChange (cm) {
      let wrapper = cm.getWrapperElement()
      let empty = isEmpty(cm)
      wrapper.className = wrapper.className.replace(' CodeMirror-empty', '') + (empty ? ' CodeMirror-empty' : '')

      if (empty) setPlaceholder(cm)
      else clearPlaceholder(cm)
    }

    function isEmpty (cm) {
      return (cm.lineCount() === 1) && (cm.getLine(0) === '')
    }
  })
}