<template>
  <b-overlay :show="nodeTree.nodes.length === 0" class="h-100" z-index="0">
    <map-zoom
      id="library-tree"
      :min-zoom="0.3" :max-zoom="1" :center="center"
      :key="nodeDepartId"
    >
      <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"
        :id="'preview-node-' + node.data.id"
        :class="['svg-dot-' + node.data.variant, { 'origin': node.parent === null }]"
        tabindex="0"
        @focus="activeNode = node"
        @mouseenter="activeNode = node"
        @mouseleave="activeNode = null"
        @blur="activeNode = null"
        @click.stop="onNodeClick(node.data)"
        @keyup.enter="onNodeClick(node.data)"
      />

      <g>
        <rect class="svg-overlay" />
        <foreignObject
          v-if="activeNode"
          :x="activeNode.x"
          :y="activeNode.y"
        >
          <dot-button
            :variant="activeNode.data.variant"
            active hovered
            @click="onNodeClick(activeNode.data)"
          >
            <template v-if="activeNode.data.type === 'prod' && !(activeNode.data.preTitle || activeNode.data.italTitle)">
              {{ $t('variants.' + activeNode.data.variant) }}<br>
            </template>

            <node-view-title v-else :node="activeNode.data" block />
          </dot-button>
        </foreignObject>
      </g>
    </map-zoom>

    <legend-toggle>
      <h6>Mode Arborescent</h6>
      <p>Ce mode vous permet d'observer l'arbre des relations d'un texte de départ.</p>

      Types de relation :
      <ul>
        <li><span class="children" /> Textes produits</li>
        <li><span class="siblings" /> Textes rebonds</li>
      </ul>
    </legend-toggle>

    <node-preview-zone v-model="previewNode" :nodes="dataNodes" @open-node="onPreviewNodeClick" />
  </b-overlay>
</template>

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

import { MapZoom, NodePreviewZone } from '@/components/layouts'
import { NodeViewTitle } from '@/components/nodes'


export default {
  name: 'LibraryTree',

  components: {
    MapZoom,
    NodePreviewZone,
    NodeViewTitle
  },

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

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

    dataNodes () {
      return this.nodeTree.nodes.map(node => node.data)
    },

    // 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())
    },

    center () {
      const { x, y } = this.nodeTree.nodes.length ? this.nodeTree.nodes[0] : { x: 0, y: 0 }
      return { x, y }
    },

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

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

  methods: {
    onNodeClick (node) {
      this.$store.dispatch('GET_NODE', { id: node.id, dataLevel: 'partial' })
      this.previewNode = node
      this.$root.$emit('bv::show::popover', 'preview-node-' + node.id)
    },

    onPreviewNodeClick (ids) {
      this.$root.$emit('bv::hide::popover', 'preview-node-' + this.previewNode.id)
      this.$emit('open-node', ids)
      this.previewNode = null
    }
  },

  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 {
    cursor: pointer;
    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 {
  @media (hover: none) {
    display: none;
  }

  transform: translate(-50%, -50%);
  pointer-events: none;
  min-width: 200px;
  word-break: unset;
  white-space: unset;
  border-radius: 19px !important;

  .node-view-title {
    min-width: 200px;
    max-width: 400px;
    padding-bottom: .25rem;
  }

  &-depart {
    box-shadow: none;
  }

  h6 {
    margin: 0;
  }
}

.legend-toggle {
  ul {
    list-style: none;
    padding: 0;
    margin-top: .5rem;

    li {
      font-style: italic;
      margin-left: 1rem;
    }
  }

  span {
    display: inline-block;
    height: 0px;
    width: 15px;
    margin-right: .5rem;
  }
  .children {
    border-top: 3px dashed grey;
  }
  .siblings {
    border-top: 3px solid grey;
  }
}
</style>
