<template>
  <b-overlay :show="nodeTree.nodes.length === 0" class="h-100">
    <map-zoom id="library-tree" :min-zoom="0.3" :max-zoom="1">
      <path
        v-for="link in nodeTree.links"
        :key="`${link.source.data.id}_${link.target.data.id}`"
        :d="lineGenerator([link.source, link.target])"
        :class="['svg-link', (link.linkType || link.target.data.linkType)]"
      />

      <circle
        v-for="node in nodeTree.nodes"
        :key="'circle' + node.data.id"
        :cx="node.x"
        :cy="node.y"
        class="svg-dot"
        :class="['svg-dot-' + node.data.variant, { 'origin': node.parent === null }]"
        tabindex="0"
        @click="onNodeClick(node.data)"
        @keyup.enter="onNodeClick(node.data)"
        @mouseenter="activeNode = node"
      />

      <g>
        <rect class="svg-overlay" />
        <foreignObject
          v-if="activeNode"
          :x="activeNode.x"
          :y="activeNode.y"
        >
          <dot-button
            :variant="activeNode.data.variant"
            class="active"
            @click="onNodeClick(activeNode.data)"
            @mouseleave="activeNode = null"
          >
            <template v-if="activeNode.data.variant !== 'depart'">
              {{ $t('variants.' + activeNode.data.variant) }}<br>
            </template>
            {{ toCommaList(activeNode.data.authors) }},<br>
            <span v-if="activeNode.data.preTitle" v-html="trim(activeNode.data.preTitle) + ','" />
            <span v-html="trim(activeNode.data.title) || '<em>pas de titre ital</em>'" />
          </dot-button>
        </foreignObject>
      </g>
    </map-zoom>
  </b-overlay>
</template>

<script>
import { mapGetters } from 'vuex'
import { line } from 'd3-shape'
import { forceSimulation, forceLink, forceManyBody, forceX, forceY } from 'd3-force'

import { trim, toCommaList } from '@/helpers/common'
import { MapZoom } from '@/components/layouts'


export default {
  name: 'LibraryTree',

  components: {
    MapZoom
  },

  data () {
    return {
      activeNode: null
    }
  },

  computed: {
    ...mapGetters(['nodeTree']),

    // ONE TIME GETTER
    simulation () {
      return forceSimulation()
        .force('charge', forceManyBody().strength((d) => {
          if (d.data.linkType === 'parents') return -2000
          if (d.data.linkType === 'siblings') return -500
          return -1000
        }))
        .force('link', forceLink().id(d => d.id).distance((d) => {
          if (d.linkType === 'parents') return 200
          if (d.linkType === 'siblings') return 100
          return 0
        }).strength(0.5))
        .force('x', forceX())
        .force('y', forceY())
    },

    // ONE TIME GETTER
    lineGenerator () {
      return line().x(node => node.x).y(node => node.y)
    }
  },

  watch: {
    nodeTree (tree) {
      this.activeNode = null
      this.simulation.nodes(tree.nodes)
      this.simulation.force('link').links(tree.links)
      this.simulation.alpha(0.5).restart()
    }
  },

  methods: {
    toCommaList,
    trim,

    onNodeClick (node) {
      if (node.parents && node.parents.length) {
        this.$emit('open-node', { parentId: node.parents[0].id, childId: node.id })
      } else {
        this.$emit('open-node', { parentId: node.id })
      }
    }
  },

  created () {
    this.$store.dispatch('INIT_LIBRARY_TREE')
  }
}
</script>

<style lang="scss" scoped>
.svg {
  &-link {
    stroke: grey;
    vector-effect: non-scaling-stroke;

    &.siblings {
      stroke-dasharray: 4;
    }

    &.parents {
      stroke: red;
      opacity: .3;
    }
  }

  &-dot {
    r: 9.5px;

    @each $color, $value in $theme-colors {
      &-#{$color} {
        fill: $value;

        @if $color == 'depart' {
          stroke: $black;
          stroke-width: 3px;
          vector-effect: non-scaling-stroke;
        }
      }
    }

    &.origin {
      r: 15px;
    }
  }

  &-overlay {
    width: 100%;
    height: 100%;
    x: -50%;
    y: -50%;
    fill: transparent;
    pointer-events: none;
  }
}

foreignObject {
  height: 1px;
  width: 1px;
  overflow: visible;
}

.dot-btn {
  transform: translate(-50%, -50%);
}
</style>
