<template>
  <div class="tree-diagram-wrapper">
    <!-- Branch rows -->
    <div
      v-for="branch in branches"
      :key="branch.id"
      class="branch-cell"
      :class="{
        'active-branch': branch.id === activeBranchId
      }"
      @dblclick="$emit('branch-dblclick', branch.id)"
      @mouseover="$emit('branch-mouseover', branch.id)"
      @mouseout="$emit('branch-mouseout', branch.id)"
    >
      <div class="no-select pointer">{{ branch.title }}</div>
    </div>
    <div class="no-select text-button">
      <span
        @click="$emit('create-branch')"
        style="position:relative; top: 15px; padding-top: 3px; font-size: small; border-top: 1px solid #919191"
      >
        <i class="fas fa-plus-circle"></i> New branch
      </span>
    </div>

    <div class="tree-diagram">
      <Tooltip
        v-if="hoveredCommitId !== 0"
        :hoveredId="hoveredCommitId"
        :leftShift="tooltipPosition.x"
        :topShift="tooltipPosition.y"
        :title="hoveredCommit.title"
        :message="hoveredCommit.message"
      />

      <!-- FIXME (Marko) is it possible to get rid of $vss? -->
      <!-- <svg :width="$vssWidth * 0.7" :height="$vssHeight * 0.1"> -->
      <svg :width="$vssWidth * 0.7" :height="`${branches.length * 2 + 2}vh`">
        <g
          v-for="link in links"
          :key="link.sourceId + '-' + link.targetId"
          :data-from="link.sourceId"
          :data-to="link.targetId"
          :class="{
            'in-active-path': isCommitOnActivePath(activeBranch, activeCommitId, link.targetId)
          }"
        >
          <path :d="link.d" class="link shadow" />
          <path :d="link.d" class="link" />
        </g>

        <path v-if="showWipCommit" :d="wipCommit.d" stroke-dasharray="5" class="link wip-commit" />
        <g
          v-for="node in nodes"
          :key="node.id"
          @mouseover="hoveredCommitId = node.id"
          @mouseout="hoveredCommitId = 0"
          @dblclick="$emit('commit-dblclick', { commitId: node.id, branchId: node.branchId })"
          @click.shift="$emit('show-commit-detail', node.id)"
          @click.ctrl="$emit('commit-for-comparison', node.id)"
        >
          <circle
            :cx="node.x"
            :cy="node.y"
            r="12"
            class="commit shadow"
            :class="{
              'close-commit': node.type === 'close-commit',
              'active-commit': node.id === activeCommitId,
              'is-highlighted': node.id === activeCommitId,
              'is-outdated':
                new Date(node.timestamp) < new Date(newNotificationTime) && isOutdated(node),
              'is-highlighted-in-report': highlightCommitsInReport && node.inReport
            }"
          />
          <circle :cx="node.x" :cy="node.y" fill="white" r="9" />
          <font-awesome-icon
            :width="12"
            :height="12"
            :icon="node.icon"
            :x="node.x - 6"
            :y="node.y - 6"
            class="commit"
            :class="{
              'close-commit': node.type === 'close-commit',
              'active-commit': node.id === activeCommitId,
              'is-highlighted': node.id === activeCommitId,
              'is-hovered': node.isHovered,
              'second-commit': node.id === secondCommitId && visMode === 'Comparison',
              'is-outdated':
                new Date(node.timestamp) < new Date(newNotificationTime) && isOutdated(node),
              'is-highlighted-in-report': highlightCommitsInReport && node.inReport
            }"
          />
          <text v-if="showCommitId" :x="node.x - 3" :y="node.y + 3" font-size="10" fill="white">
            {{ node.id }}
          </text>
        </g>
        <g v-if="showWipCommit">
          <!-- v-if="showWipCommit" -->
          <circle :cx="wipCommit.x" :cy="wipCommit.y" r="5" class="commit wip-commit" />
          <foreignObject :x="wipCommit.x + 16" :y="wipCommit.y - 13" width="32" height="32"
            ><i class="fas fa-save"></i
          ></foreignObject>
          <text
            :x="wipCommit.x + 35"
            :y="wipCommit.y + 4"
            class="text-button"
            @click="$emit('open-state-modal')"
          >
            Save analysis state
          </text>
          <foreignObject :x="wipCommit.x + 170" :y="wipCommit.y - 13" width="32" height="32">
            <i class="far fa-sticky-note"></i>
          </foreignObject>
          <text
            v-if="showWipCommit"
            :x="wipCommit.x + 190"
            :y="wipCommit.y + 4"
            class="text-button"
            @click="$emit('open-note-modal')"
          >
            Add note
          </text>
        </g>
      </svg>
    </div>
  </div>
</template>

<script>
import VueScreenSize from 'vue-screen-size'
import { isCommitOnActivePath } from '@/utils/progress-diagram'
import Tooltip from '@/components/shared/Tooltip.vue'

export default {
  mixins: [VueScreenSize.VueScreenSizeMixin],
  components: { Tooltip },
  props: {
    commits: {
      type: Array,
      required: true
    },
    branches: {
      type: Array,
      required: true
    },
    branchRowHeight: {
      type: Number,
      default: 20
    },
    activeCommitId: {
      type: Number,
      default: 5
    },
    activeBranchId: {
      type: Number,
      default: 2
    },
    showWipCommit: {
      type: Boolean,
      default: true
    },
    showCommitId: {
      type: Boolean,
      default: false
    },
    newNotificationTime: {
      type: String,
      default: '0'
    },
    highlightCommitsInReport: {
      type: Boolean,
      default: false
    },
    secondCommitId: {
      type: Number,
      default: 0
    },
    visMode: {
      type: String,
      default: 'Exploration'
    }
  },
  data() {
    return {
      hoveredCommitId: 0,
      types: {
        note: 'sticky-note',
        misc: 'database',
        'close-commit': 'times',
        'merge-commit': 'circle',
        branches: 'circle',
        commit: 'circle'
      }
    }
  },
  computed: {
    tooltipPosition() {
      return { x: this.hoveredCommit.x + 8 /*- 10*/, y: this.hoveredCommit.y - 50 }
    },
    hoveredCommit() {
      return this.nodes.find(n => n.id === this.hoveredCommitId)
    },
    activeBranch() {
      return this.branches.find(b => b.id === this.activeBranchId)
    },
    nodes() {
      let nodeList = []
      this.commits.forEach(c => {
        nodeList.push({
          ...c,
          x: c.time * 5,
          y: (c.branchId - 1) * this.branchRowHeight + this.branchRowHeight / 2,
          icon: this.types[c.type]
        })
      })
      return nodeList
    },
    links() {
      let linkList = []
      this.commits.forEach(c => {
        let x1, y1, x2, y2, x3, y3
        let sourceNode1, sourceNode2
        let targetNode = this.nodes.find(n => n.id === c.id)
        if (c.type === 'merge-commit') {
          sourceNode1 = this.nodes.find(n => n.id === c.previousCommitId[0])
          sourceNode2 = this.nodes.find(n => n.id === c.previousCommitId[1])

          x3 = sourceNode2 ? sourceNode2.x : targetNode.x - 20
          y3 = sourceNode2 ? sourceNode2.y : targetNode.y
        } else {
          sourceNode1 = this.nodes.find(n => n.id === c.previousCommitId[0])
        }

        x1 = sourceNode1 ? sourceNode1.x : targetNode.x - 20
        y1 = sourceNode1 ? sourceNode1.y : targetNode.y
        x2 = targetNode.x
        y2 = targetNode.y

        let newLink = {
          targetId: c.id
        }

        if (c.type === 'merge-commit') {
          // with merge-commit, create two links coming from two commits
          let straightLink = newLink
          let polylineLink = { ...newLink }

          straightLink.key = 'link-' + (c.previousCommitId[0] || 0) + '-' + c.id
          straightLink.sourceId = c.previousCommitId[0] || 0 // = commitId
          straightLink.d = 'M' + x1 + ' ' + y1 + 'L' + x2 + ' ' + y1
          linkList.push(straightLink)

          polylineLink.key = 'link-' + (c.previousCommitId[1] || 0) + '-' + c.id
          polylineLink.sourceId = c.previousCommitId[1] || 0
          polylineLink.d = 'M' + x2 + ' ' + y2 + 'L' + (x2 - 5) + ' ' + y3 + 'L' + x3 + ' ' + y3
          linkList.push(polylineLink)
        } else {
          // polyline
          newLink.key = 'link-' + (c.previousCommitId[0] || 0) + '-' + c.id
          newLink.sourceId = c.previousCommitId[0] || 0 // = commitId
          newLink.d = 'M' + x1 + ' ' + y1 + 'L' + (x1 + 5) + ' ' + y2 + 'L' + x2 + ' ' + y2
          linkList.push(newLink)
        }
      })
      return linkList
    },
    wipCommit() {
      let activeCommit = this.commits.find(c => c.id === this.activeCommitId)
      let sourceNode = this.nodes.find(n => n.id === activeCommit.id)
      let targetNode = {
        x: (activeCommit.time + 5) * 5, // temp
        y: (this.activeBranchId - 1) * this.branchRowHeight + this.branchRowHeight / 2
      }
      let x1 = sourceNode ? sourceNode.x : targetNode.x - 20
      let y1 = sourceNode ? sourceNode.y : targetNode.y
      let x2 = targetNode.x
      let y2 = targetNode.y
      return {
        key: 'wipCommit',
        x: x2,
        y: y2,
        d: 'M' + x1 + ' ' + y1 + 'L' + (x1 + 5) + ' ' + y2 + 'L' + x2 + ' ' + y2
      }
    }
  },
  methods: {
    // tmp hotfix for highlighting commits on new notification
    isOutdated(node) {
      return node.id >= 5 && node.id <= 8
    },
    isCommitOnActivePath
  }
}
</script>

<style lang="sass" scoped>
$stroke-width-default: 1
$stroke-width-highlight: 2

$almost-dark-gray: #666

$highlight-color: $primary-highlight-color // #ff8a70
$highlight-color-light: #979aff // $primary-highlight-color // #f45633

.in-active-path
  .link
    stroke-opacity: 1
    stroke: $highlight-color-light
    stroke-width: 3

.tree-diagram
  position: absolute
  left: 100px
  top: 0px

.branch-cell
  line-height: $tree-diagram-line-height
  height: $tree-diagram-line-height
  font-size: $small-font-size
  border-radius: 5px
  padding-left: 5px
  color: $secondary-text-color
  &.even
    // background: #fafafa

  &.active-branch
    color: $primary-text-color
    font-weight: 500

  &:hover
    // background: #eee
    color: $highlight-color
    font-weight: 700


.commit
  // fill: #ddd
  color: #bbb //$light-gray
  // stroke: $dark-gray
  stroke: #fff
  stroke-width: $stroke-width-default
  cursor: pointer

  &.active-commit
    color: $highlight-color
    &:hover,
    &.is-hovered
      fill: $primary-highlight-color // #f45633
      color: $primary-highlight-color // #f45633

  &.wip-commit
    opacity: 0.6
    fill: $primary-highlight-color
    &:hover
      opacity: 0.8

  &.close-commit
    color: #000

  &:hover,
  &.is-hovered
    color: $dark-gray

  &.is-outdated
    color: #ccc000

  &.is-highlighted-in-report
    color: #333 //#ff8a70

  &.shadow
    opacity: 0

  &.second-commit
    color: #ff8a70 //#6F76FF //rgb(30, 45, 255)

%shadow-link
  stroke-opacity: 0
  stroke-width: 20
  &:hover
    stroke-opacity: 0

.link
  stroke-width: 1
  stroke: $mid-gray
  fill: none
  stroke-linecap: round
  cursor: pointer

  &.in-active-branch
    stroke: $almost-dark-gray
    stroke-width: 2
    &.shadow
      @extend %shadow-link
      &:hover
        stroke: $light-gray

  &.shadow
    @extend %shadow-link
    &:hover
      stroke: $light-gray

.text-button
  font-size: small
  cursor: pointer
  fill: #919191
  padding-left: 5px
  &:hover
    font-weight: 500
    fill: #363636


.pointer
  cursor: pointer

.commit-tooltip
  // visibility: hidden
  position: absolute
  padding: 0.2rem
  max-width: 250px
  border-radius: 5px
</style>
