export class Display {
  constructor(baseUrl, dispatch, target) {
    this.baseUrl = baseUrl
    this.target = target
    const findA = target => {
      while (target.nodeName !== 'A') {
        target = target.parentNode
        if (!target) return
      }
      return target
    }
    target.addEventListener('click', e => {
      let target = findA(e.target)
      if (!target) return
      window.history.pushState(null, "", target.href)
      dispatch(target.getAttribute('href'))
      e.preventDefault()
    })
    target.addEventListener('dragstart', e => {
      let target = findA(e.target)
      if (!target || !target.draggable) return
      e.dataTransfer.setData('application/prs.x', target.dataset['id'])
      e.dataTransfer.effectAllowed = 'link'
    })
    target.addEventListener('dragenter', e => {
      let target = findA(e.target)
      if (!target) return
      e.preventDefault()
    })
    target.addEventListener('dragover', e => {
      let target = findA(e.target)
      if (!target) return
      e.preventDefault()
    })
    target.addEventListener('drop', e => {
      let target = findA(e.target)
      if (!target || !target.draggable) return
      dispatch({ action: 'link', from: e.dataTransfer.getData("application/prs.x"), to: target.dataset['id']})
      && e.preventDefault()
    })

    this.graph = new Springy.Graph()
    this.layout = new Springy.Layout.ForceDirected(
      this.graph,
      15,
      1000.0, // Node repulsion
      0.5 // Damping
    )
  }
  render(state) {
    const target = document.createElement('div')
    target.className = 'wrapper'
    const field = document.createElement('ul')
    field.className = 'items'

    const graph = this.graph
    for (const item of state.items) {
      graph.addNode(new Springy.Node(item.id, item))
    }
    for (const item of state.links) {
      graph.addEdge(new Springy.Edge(item.id, graph.nodeSet[item.from], graph.nodeSet[item.to], {
        text: state.items[item.from].linkable.filter(i => state.items[item.to].linkable.includes(i)).join(', ')
      }))
    }
    let currentBB = this.layout.getBoundingBox()
    let width = this.target.scrollWidth || 100
    let height = this.target.scrollHeight || 100
    var toScreen = function(p) {
      var size = currentBB.topright.subtract(currentBB.bottomleft);
      var sx = p.subtract(currentBB.bottomleft).divide(size.x).x * (width - 60) + 30;
      var sy = p.subtract(currentBB.bottomleft).divide(size.y).y * (height - 60) + 30;
      return new Springy.Vector(sx, sy);
    };

    var renderer = new Springy.Renderer(
      this.layout,
      () => {
        currentBB = this.layout.getBoundingBox()
        width = this.target.scrollWidth
        height = this.target.scrollHeight
        field.innerHTML = ''
      },
      function drawEdge(edge, p1, p2) {
        const dom = document.createElement('span')
        dom.innerText = edge.data.text
        p1 = toScreen(p1)
        p2 = toScreen(p2)
        if (p1.y > p2.y) [p1, p2] = [p2, p1]
        const a = p2.x - p1.x
        const b = p2.y - p1.y
        const negative = (a < 0) != (b < 0)
        let rad = Math.atan(b / a)
        if (negative) rad = rad + Math.PI
        if (rad > Math.PI / 2) {
          rad += Math.PI
          ;[p2, p1] = [p1, p2]
        }

        dom.className = 'line'
        dom.style.transform = 'rotate(' + rad + 'rad) translateY(-1em)'
        dom.style.left = p1.x + 'px'
        dom.style.top = p1.y + 'px'
        dom.style.right = p2.x + 'px'
        dom.style.bottom = p2.y + 'px'
        dom.style.width = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2)) + 'px'
        // FIXME eigentlich falsches parent
        field.appendChild(dom)
      },
      function drawNode(item, p) {
        const target = toScreen(p)
        const dom = document.createElement('li')
        const a = document.createElement('a')
        const action = item.data.state == 'face-down' ? 'flip' : 'show'
        a.href = `/${item.id}/${action}`
        a.draggable = false
        if (item.data.state !== 'face-down') {
          a.style.backgroundImage = `url(/img/${item.data.img})`
          a.dataset['id'] = item.id
          a.draggable = true
        }
        dom.className = item.data.state
        dom.style.position = 'absolute'
        dom.style.left = (target.x - 60) + 'px'
        dom.style.top = (target.y - 60) + 'px'
        dom.appendChild(a)
        field.appendChild(dom)
      }, undefined, undefined,
      () => {
        const dd = new diffDOM.DiffDOM()
        const diff = dd.diff(this.target.children[0], field)
        dd.apply(this.target.children[0], diff)
      }
    );

    target.appendChild(field)
    if (state.show !== null) {
      const wrapper = document.createElement('a')
      wrapper.href = '/'
      const fullview = document.createElement('img')
      fullview.src = '/img/Kartendesign.svg'
      wrapper.className = 'fullview'
      wrapper.appendChild(fullview)
      target.appendChild(wrapper)
    }

    const dd = new diffDOM.DiffDOM()
    const diff = dd.diff(this.target, target)
    dd.apply(this.target, diff)

    renderer.start();
  }
}
