'use strict'

var $ = require('jquery')
var yo = require('yo-yo')
var css = require('./styles/renderer-styles')
var globlalRegistry = require('../../global/registry')

/**
 * After refactor, the renderer is only used to render error/warning
 * TODO: This don't need to be an object anymore. Simplify and just export the renderError function.
 *
 */
function Renderer (localRegistry) {
  const self = this
  self._components = {}
  self._components.registry = localRegistry || globlalRegistry
  // dependencies
  self._deps = {
    fileManager: self._components.registry.get('filemanager').api,
    config: self._components.registry.get('config').api
  }
  if (document && document.head) {
    document.head.appendChild(css)
  }
}

Renderer.prototype._error = function (file, error) {
  const self = this
  const editor = self._components.registry.get('editor').api
  if (file === self._deps.config.get('currentFile')) {
    editor.addAnnotation(error)
  }
}

Renderer.prototype._errorClick = function (errFile, errLine, errCol) {
  const self = this
  const editor = self._components.registry.get('editor').api
  if (errFile !== self._deps.config.get('currentFile')) {
    // TODO: refactor with this._components.contextView.jumpTo
    var provider = self._deps.fileManager.fileProviderOf(errFile)
    if (provider) {
      provider.exists(errFile, (error, exist) => {
        if (error) return console.log(error)
        self._deps.fileManager.open(errFile)
        editor.gotoLine(errLine, errCol)
      })
    }
  } else {
    editor.gotoLine(errLine, errCol)
  }
}

/**
 * format msg like error or warning,
 *
 * @param {String or DOMElement} message
 * @param {DOMElement} container
 * @param {Object} options {
 *  useSpan,
 *  noAnnotations,
 *  click:(Function),
 *  type:(
 *    warning,
 *    error
 *  ),
 *  errFile,
 *  errLine,
 *  errCol
 * }
 */
Renderer.prototype.error = function (message, container, opt) {
  if (!message) return
  if (container === undefined) return
  opt = opt || {}

  var text
  if (typeof message === 'string') {
    text = message
    message = yo`<span>${message}</span>`
  } else if (message.innerText) {
    text = message.innerText
  }

  // ^ e.g:
  // browser/gm.sol: Warning: Source file does not specify required compiler version! Consider adding "pragma solidity ^0.6.12
  // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.2.0/contracts/introspection/IERC1820Registry.sol:3:1: ParserError: Source file requires different compiler version (current compiler is 0.7.4+commit.3f05b770.Emscripten.clang) - note that nightly builds are considered to be strictly less than the released version

  // extract line / column
  let position =  text.match(/^(.*?):([0-9]*?):([0-9]*?)?/)
  opt.errLine = position ? parseInt(position[2]) - 1 : -1
  opt.errCol = position ? parseInt(position[3]) : -1
    

  // extract file
  position = text.match(/^(https:.*?|http:.*?|.*?):/)
  opt.errFile = position ? position[1] : ''
  
  if (!opt.noAnnotations && opt.errFile) {
    this._error(opt.errFile, {
      row: opt.errLine,
      column: opt.errCol,
      text: text,
      type: opt.type
    })
  }

  var $pre = $(opt.useSpan ? yo`<span></span>` : yo`<pre></pre>`).html(message)

  let classList = opt.type === 'error' ? 'alert alert-danger' : 'alert alert-warning'
  var $error = $(yo`<div class="sol ${opt.type} ${classList}"><div class="close" data-id="renderer"><i class="fas fa-times"></i></div></div>`).prepend($pre)
  $(container).append($error)

  $error.click((ev) => {
    if (opt.click) {
      opt.click(message)
    } else if (opt.errFile !== undefined && opt.errLine !== undefined && opt.errCol !== undefined) {
      this._errorClick(opt.errFile, opt.errLine, opt.errCol)
    }
  })

  $error.find('.close').click(function (ev) {
    ev.preventDefault()
    $error.remove()
    return false
  })
}

module.exports = Renderer
