<template>
  <g class="link" :class="{ detailed: isDetailed, highlighted: isHighlighted }">
    <line
      :id="`link-${link.id}`"
      :x1="source.x"
      :y1="source.y"
      :x2="target.x"
      :y2="target.y"
      class="link-line"
      :class="{
        hovered: isHovering,
        'with-arrows': link.direction === true,
        'user-defined': link.vis && link.vis.isUserDefined === true,
        transferred: isTransferred,
        multilink: link.vis && link.vis.isMultilink === true,
        'source-to-target': link.direction && link.direction.sourceToTarget,
        'target-to-source': link.direction && link.direction.targetToSource,
        'non-directional': link.direction && link.direction.nonDirectional
      }"
    ></line>

    <g v-if="!isNaN(pawSourcePosition.x)" class="link-paws">
      <circle
        v-for="pos in [pawSourcePosition, pawTargetPosition]"
        :key="`${pos.x}-${pos.y}`"
        :class="{ hovered: isHovering, detailed: isDetailed, highlighted: isHighlighted }"
        :r="graphVisuals.linkPawRadius"
        :cx="pos.x"
        :cy="pos.y"
      ></circle>
    </g>

    <text
      v-if="inDebug"
      class="label-id"
      :dy="(source.y + target.y) / 2"
      :dx="(source.x + target.x) / 2"
      >{{ link.id }} {{ link.type == 'regular' ? link.type : '' }}</text
    >

    <line
      :x1="source.x"
      :y1="source.y"
      :x2="target.x"
      :y2="target.y"
      class="support-link"
      @mouseover="isHovering = true"
      @mouseover.ctrl.exact="
        SET_LINK_HIGHLIGHT(dataId)
        SET_NODE_HIGHLIGHT(link.source)
        SET_NODE_HIGHLIGHT(link.target)
      "
      @mouseout="
        CLEAR_NODE_HIGHLIGHT()
        CLEAR_LINK_HIGHLIGHT()
        isHovering = false
      "
      @mousedown.prevent
      @mousedown.left.exact="switchDetailedView()"
    ></line>
  </g>
</template>

<script>
import { mapMutations, mapActions, mapState, mapGetters } from 'vuex'
import { getLinkSource, getLinkTarget } from '@/store/modules/data.js'
import * as d3 from 'd3' // FIXME

export default {
  props: {
    dataId: { type: Number, required: true },
    graphVisuals: { type: Object, required: true },
    // all d3-force calculated data:
    source: { type: Object, required: true },
    target: { type: Object, required: true }
  },

  data() {
    return {
      isHovering: false
    }
  },

  computed: {
    ...mapGetters('data', ['getNodeById', 'getLinkById']),
    ...mapState('interaction', ['inDebug']),
    ...mapGetters('interaction', ['isLinkDetailed']),
    link() {
      return this.getLinkById(this.dataId)
    },
    isDetailed() {
      return this.isLinkDetailed(this.dataId)
    },
    isHighlighted() {
      return this.$store.getters['interaction/isLinkHighlighted'](this.dataId)
    },
    pawSourcePosition() {
      return this.calculatePawPosition(this.target, this.source)
    },
    pawTargetPosition() {
      return this.calculatePawPosition(this.source, this.target)
    },
    showLabel() {
      return this.isDetailed || this.isHovering
    },
    isTransferred() {
      const source = this.getNodeById(getLinkSource(this.link))
      const target = this.getNodeById(getLinkTarget(this.link))
      if (source === undefined | target === undefined) throw Error("Failed to fetch node data.")

      switch (source.type) {
        case 'regular':
          switch (target.type) {
            case 'regular':
            case 'alias':
              return false
            case 'group':
              break
            case 'bundle':
              if (source === this.link.source || target === this.link.target) return false
              break
            default:
              throw Error('Undefined link type')
          }
        case 'alias':
          switch (target.type) {
            case 'regular':
            case 'alias':
              return false
            case 'group':
              break
            case 'bundle':
              if (source === this.link.source || target === this.link.target) return false
              break
            default:
              throw Error('Undefined link type')
          }
        case 'group':
          switch (target.type) {
            case 'regular':
            case 'alias':
            case 'group':
              break
            case 'bundle':
              if (source === this.link.source || target === this.link.target) return false
              break
            default:
              throw Error('Undefined link type')
          }
        case 'bundle':
          if (source.id === this.link.id)
          switch (target.type) {
            case 'regular':
            case 'alias':
              if (source === this.link.source || target === this.link.target) return false
              break
            case 'group':
              break
            case 'bundle':
              if (source === this.link.source || target === this.link.target) return false
              break
            default:
              throw Error('Undefined link type')
          }
          return true
      }
      return true
    }
  },

  watch: {
    link: function(link) {
      if (!link) throw Error('Graph is trying to display unknown link')
    }
  },

  methods: {
    ...mapMutations('interaction', [
      'SHOW_LINK_DETAIL',
      'HIDE_LINK_DETAIL',
      'SET_TOOL_SHOW',
      'SET_NODE_HIGHLIGHT',
      'CLEAR_NODE_HIGHLIGHT',
      'SET_LINK_HIGHLIGHT',
      'CLEAR_LINK_HIGHLIGHT'
    ]),
    ...mapActions('interaction', 
      ['showLinkDetail', 'hideLinkDetail']
    ),

    switchDetailedView() {
      this.isDetailed ? this.hideLinkDetail() : this.showLinkDetail(this.link.id)
    },
    setHighlighted(id) {
      this.isHighlighed ? this.CLEAR_LINK_HIGHLIGHT() : this.SET_LINK_HIGHLIGHT(id)
    },
    calculatePawPosition(source, target) {
      let x, y

      let x_diff = target.x - source.x
      let y_diff = target.y - source.y

      let length = Math.sqrt(Math.pow(x_diff, 2) + Math.pow(y_diff, 2))
      let x_diff_norm = x_diff / length
      let y_diff_norm = y_diff / length

      // TODO: handle group
      // if (d.source.type == 'group')
      //    return d.source.x + x_diff_norm * (this.visualProp.node_icon_rad/2.0 + this.visualProp.group_rad_diff);
      x = source.x + x_diff_norm * this.graphVisuals.nodeRadius
      y = source.y + y_diff_norm * this.graphVisuals.nodeRadius
      return { x, y }
    }
  }
}
</script>

<style lang="sass" scoped>
.link
  line
    stroke: #bbb
    &.with-arrows
      marker-end: url(#single-link-arrow)
    &.multilink
      stroke-width: 3px
      stroke: #ccc
      &.source-to-target
        marker-end: url(#multi-link-arrow)
        &.non-directional
          marker-end: url(#multi-link-arrow-bar)
      &.target-to-source
        marker-start: url(#multi-link-arrow-opposite)
        &.non-directional
          marker-start: url(#multi-link-arrow-bar-opposite)
    &.user-defined
      stroke-dasharray: 7,7
      stroke-linecap: round
    &.transferred
      stroke-dasharray: 0,6
      stroke-width: 2px
      stroke-linecap: round
      &.multilink
        stroke-width: 4px
    &.highlight.highlightable
      stroke: #444
  line.hovered
    stroke: #757575

.link.detailed line.link-line
    stroke: #757575

.link.highlighted line.link-line
    stroke: #757575

.support-link
  stroke-opacity: 0
  stroke-width: 16px

text.label-id
  font-size: 11pt
  font-weight: 600
  fill: #4903fc
  user-select: none

.link-paws
  circle
    fill: #bbb
  .detailed
    fill: #444
  .hovered
    fill: #757575
  .highlighted
    fill: #757575
</style>
