<template>
  <b-overlay :show="nodes === undefined" class="h-100" z-index="0">
    <map-zoom
      id="library-map" ref="map"
      :min-zoom="0.2" :max-zoom="2" :initial-zoom="0.5"
    >
      <foreignObject
        v-for="node in filteredNodes" :key="'f-' + node.data.id"
        :class="{ 'safari': isSafari }"
        :width="size.w" :height="size.h"
        :x="node.x" :y="node.y"
        :transform="`rotate(${node.rotate}) translate(-${size.w / 2}, -${size.h / 2})`"
        :transform-origin="`${node.x} ${node.y}`"
      >
        <node-view
          :id="'preview-node-' + node.data.id"
          :class="{ 'hidden': previewNode === node.data }"
          :node="node.data"
          mode="card"
          :hidden="node.hidden"
          @click.native="onNodeClick(node.data)"
          :style="`--opacity: ${getStrangenessOpacity(strangeness, node.data)};`"
        />
      </foreignObject>
    </map-zoom>

    <legend-toggle>
      <h6>Mode Aléatoire</h6>
      <p>Ce mode vous propose 3 textes de départ tirés aléatoirement ainsi que leurs textes produits et leurs textes rebonds.</p>
      <p>Pour tirer aléatoirement 3 nouveaux textes, cliquez sur <i>Mélanger</i> dans le menu d'options.</p>
    </legend-toggle>

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

<script>
import { randomUniform } from 'd3'
import { forceSimulation, forceCollide, forceManyBody } from 'd3-force'
import { mapGetters } from 'vuex'

import { searchInNode, tagsInNode, getRelation, getStrangenessOpacity } from '@/store/utils'
import { MapZoom, NodePreviewZone } from '@/components/layouts'
import { NodeView } from '@/components/nodes'


export default {
  name: 'LibraryMap',

  components: {
    MapZoom,
    NodePreviewZone,
    NodeView
  },

  data () {
    return {
      simulation: forceSimulation(),
      nodes: undefined,
      previewNode: null
    }
  },

  computed: {
    ...mapGetters(['randomNodes', 'search', 'tags', 'strangeness']),

    filteredNodes () {
      if (!this.nodes) return
      const search = this.search.toLowerCase()
      this.nodes.forEach(node => {
        Object.assign(node, {
          hidden: !(tagsInNode(this.tags, node.data.tags) && searchInNode(search, node.data))
        })
      })
      return this.nodes
    },

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

    isSafari () {
      return /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
    },

    size () {
      return window.innerWidth < 1200
        ? { w: 560 / 1.5, h: 350 / 1.5 }
        : { w: 560, h: 350 }
    }
  },

  methods: {
    getStrangenessOpacity,

    onOpen (node) {
      this.$parent.$emit('open-node', getRelation(node))
    },

    onNodeClick (node) {
      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
    }
  },

  watch: {
    randomNodes (randomNodes) {
      if (!randomNodes) {
        this.nodes = undefined
        return
      }

      // JS-BP
      const radius = window.innerWidth < 769 ? 700 / 1.5 : 700
      this.nodes = randomNodes.map((node, i) => {
        return { x: 0, rotate: randomUniform(-25, 25)(), data: node }
      })

      this.simulation.nodes(this.nodes)
        .force('attract', forceManyBody().strength(1))
        .force('collision', forceCollide().radius(radius / 2))
        .alpha(0.5).restart()

      this.$refs.map.reset()
    }
  },

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

<style lang="scss">
#library-map {
  foreignObject {
    // width: $node-card-width-sm;
    // height: $node-card-height-sm;
    // x: var(--x);
    // y: var(--y);
    // transform-origin: var(--x) var(--y);
    // transform: rotate(var(--r)) translate(-#{$node-card-width / 2}, -#{$node-card-height / 2});
    overflow: visible;

    @include media-breakpoint-up($size-bp) {
      // width: $node-card-width;
      // height: $node-card-height;
    }

    &.safari .node-view {
      position: static;

      .node-view-footer {
        display: none;
      }
    }

    .node-view {
      cursor: pointer;
    }
  }

  .node-view {
    width: $node-card-width-sm;
    opacity: var(--opacity);

    @include media-breakpoint-up($size-bp) {
      width: $node-card-width;
    }

    &-wrapper {
      height: $node-card-height-sm;

      @include media-breakpoint-up($size-bp) {
        height: $node-card-height;
      }
    }

    &.hidden {
      border: $line;
      border-style: dashed;
      background-color: transparent;

      .node-view-wrapper {
        opacity: 0;
      }
    }
  }
}
</style>
