/* eslint-disable prettier/prettier */ /* eslint-disable */
<template>
  <div class="group-table">
    <div class="columns group-table--header">
      <div class="column is-1 checkbox" style="padding-left: 1.2rem">
        <div class="field">
          <b-checkbox
            type="is-dark"
            :value="mainCheckbox"
            :indeterminate="isMainCheckboxIndeterminate"
            @input="checkAllCheckboxes()"
          />
        </div>
      </div>
      <div class="column is-7">
        Group name
      </div>
      <div class="column">
        nodes / links
      </div>
    </div>

    <!-- TABLE CONTENT -->
    <div
      v-for="(entry, i) in data"
      :key="i"
      class="columns group-table--row"
      :class="isGroupGloballyHighlighted(entry.tag, i) ? 'group-hover' : ''"
    >
      <div class="column is-1 checkbox" style="padding-left: 1.2rem">
        <div class="columns">
          <div class="field">
            <b-checkbox
              type="is-dark"
              :value="checkboxes[i].isChecked"
              :indeterminate="checkboxes[i].isIndeterminate"
              @input="changeCheckboxIsChecked(entry.tag, i)"
            />
          </div>
        </div>
      </div>
      <div class="column">
        <div class="columns">
          <div class="column is-10">
            <!-- G R O U P  R O W -->
            <div class="columns group-table--row--summary">
              <!-- Aggregated icon -->
              <div class="column is-1">
                <div class="columns">
                  <font-awesome-icon
                    :icon="entry.tag.properties.get('isGrouped') ? 'expand-alt' : 'compress-alt'"
                    size="lg"
                    class="icon-aggregate"
                    @click="
                      entry.tag.properties.get('isGrouped')
                        ? commitDisaggregateNodes(entry.tag, i)
                        : commitAggregateNodes(entry.tag, i)
                    "
                  />
                </div>
              </div>
              <!-- Group title + collapse icon -->
              <div class="column is-10">
                <div
                  class="columns pointer"
                  @mouseover.stop="highlightGroup(i)"
                  @mouseout="clearHighlights()"
                >
                  <span style="font-weight: bold;">
                    {{ entry.tag.name }}
                    <!-- TODO show only outline if tag is not visible in vis -->
                    <!-- TODO show only gray outline if no color is selected for tag -->
                    <Tag :instance-id="instanceId" :tag="entry.tag" style="display: inline;" />

                    <font-awesome-icon
                      :icon="checkboxes[i].isOpened.main ? 'chevron-up' : 'chevron-down'"
                      size="sm"
                      class="icon-chevron"
                      @click="checkboxes[i].isOpened.main = !checkboxes[i].isOpened.main"
                    />
                  </span>
                  <div class="minimize" @click="toggleNodeSize(entry.tag)">
                    {{
                      isTagMiniaturized()(instanceId, entry.tag.uuid) ? 'mini nodes' : 'full nodes'
                    }}
                  </div>
                </div>
              </div>
              <!-- nodes / links -->
              <div class="column">
                <div class="columns">{{ entry.nodes.length }} / {{ entry.links.length }}</div>
              </div>
            </div>

            <!-- G R O U P   D E T A I L -->
            <!-- FIXME: i think maybe this should maybe be in separate component (Marko) -->
            <div v-if="checkboxes[i].isOpened.main" class>
              <div class>
                <div style="padding-bottom: 0.5rem;">
                  <div v-if="entry.groups || false" class="groups group-table--row--detail">
                    <div class="group-table--row--detail--title pointer">
                      GROUPS
                      <!-- TODO Collapse/Expand individually when user clicks only the chevron icon -->
                      <font-awesome-icon
                        :icon="checkboxes[i].isOpened.groups ? 'chevron-up' : 'chevron-down'"
                        size="sm"
                        class="icon-chevron"
                        @click="checkboxes[i].isOpened.groups = !checkboxes[i].isOpened.groups"
                      />
                    </div>
                  </div>
                  <div
                    v-if="entry.nodes && entry.nodes.length > 0"
                    class="nodes group-table--row--detail"
                  >
                    <div class="group-table--row--detail--title">
                      NODES
                      <!-- TODO Collapse/Expand individually on users interaction -->
                      <font-awesome-icon
                        :icon="checkboxes[i].isOpened.nodes ? 'chevron-up' : 'chevron-down'"
                        size="sm"
                        class="icon-chevron"
                        @click="checkboxes[i].isOpened.nodes = !checkboxes[i].isOpened.nodes"
                      />
                    </div>
                    <!-- On hover, highlight corresponding node / link / group -->
                    <div v-if="checkboxes[i].isOpened.nodes">
                      <div
                        v-for="(node, index) in entry.nodes"
                        :key="index"
                        :class="
                          isObjectGloballyHighlighted(node.uuid) ? 'listitem-hover' : 'listitem'
                        "
                        class="group-table--row--detail--list pointer"
                        @mouseover.stop="highlightNodeOrGroup(i, node.uuid)"
                        @mouseout="clearHighlights()"
                      >
                        {{ node.properties.get('label') }}
                      </div>
                    </div>
                  </div>
                  <div
                    v-if="entry.links && entry.links.length > 0"
                    class="links group-table--row--detail"
                  >
                    <div class="group-table--row--detail--title">
                      LINKS
                      <!-- Collapse/Expand individually on users interaction -->
                      <font-awesome-icon
                        :icon="checkboxes[i].isOpened.links ? 'chevron-up' : 'chevron-down'"
                        size="sm"
                        class="icon-chevron"
                        @click="checkboxes[i].isOpened.links = !checkboxes[i].isOpened.links"
                      />
                    </div>
                    <!-- On hover, highlight corresponding node / link / group -->
                    <div v-if="checkboxes[i].isOpened.links">
                      <div
                        v-for="(link, index) in entry.links"
                        :key="index"
                        class="group-table--row--detail--list pointer"
                        :class="
                          isObjectGloballyHighlighted(link.uuid) ? 'listitem-hover' : 'listitem'
                        "
                        @mouseover.stop="setLinkHighlights([link.uuid])"
                        @mouseout="
                          removeLinkHighlights([link.uuid])
                          clearHighlights()
                        "
                      >
                        UUID: {{ link.uuid }}
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- HIDE BIN -->
    <div class="columns group-table--row hide-bin">
      <div class="column is-1 checkbox" style="padding-left: 1.2rem">
        <div class="columns">
          <div class="field">
            <!-- TODO: figure out how hide bin's checkbox should work (add functionality) -->
            <b-checkbox
              type="is-dark"
              :value="hideBin.isChecked"
              :indeterminate="hideBin.isIndeterminate"
              @input="$root.$set(hideBin, 'isChecked', !hideBin.isChecked)"
            />
          </div>
        </div>
      </div>

      <div class="column">
        <div class="columns">
          <div class="column is-10">
            <div class="columns group-table--row--summary">
              <!-- HIDE ROW -->
              <div class="column is-11">
                <div class="columns">
                  <span>Hide bin</span>
                  <font-awesome-icon
                    :icon="hideBin.isHidden ? 'eye-slash' : 'eye'"
                    size="lg"
                    class="icon-eye"
                    @click="$root.$set(hideBin, 'isHidden', !hideBin.isHidden)"
                  />
                </div>
              </div>

              <!-- nodes / links -->
              <div class="column">
                <div class="columns">{{ hideBin.nodes.length }} / {{ hideBin.links.length }}</div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import Vue from 'vue'
import { mapActions, mapGetters, mapMutations } from 'vuex'
import { cloneDeep } from 'lodash'
import Tag from './Tag.vue'

export default {
  components: { Tag },

  props: {
    columns: {
      type: Array,
      required: false,
      default: () => []
    },
    instanceId: {
      type: Number,
      required: true
    }
  },

  data() {
    return {
      mainCheckbox: false,
      isMainCheckboxIndeterminate: false,
      checkboxes: [],
      data: [],
      hideBin: {
        isChecked: false,
        isIndeterminate: false,
        isHidden: false,
        nodes: [],
        links: []
      },
      isDataReady: false
    }
  },

  computed: {
    ...mapGetters('data', [
      'getNodesInAggregation',
      'getLinkIdsConnectedToNode',
      'getNodesByIds',
      'getLastTagId',
      'getTagByTagId',
      // 'isTagMiniaturized',
      // 'getIsImported',
      'getTags'
    ]),
    ...mapGetters('data', {
      _getSelectedNodes: 'getSelectedNodes',
      _isNodeSelected: 'isNodeSelected'
    }),

    lastTagId: {
      get() {
        return this.getLastTagId(this.instanceId)
      },
      set(tag) {
        return tag
      }
    },

    tags: {
      get() {
        return this.getTags(this.instanceId)
      },
      set(tags) {
        return tags
      }
    },

    selectedNodes: {
      get() {
        return this._getSelectedNodes(this.instanceId)
      },
      set(tag) {
        return tag
      }
    }
  },

  watch: {
    tags: {
      deep: true,
      handler() {
        this.tags.forEach(tag => {
          if (!this.checkboxes.find(ch => ch.tagId === tag.uuid)) {
            this.createTagData(tag)
          }
        })
      }
    },

    /* lastTagId() {
       let tagId = this.lastTagId
       if (tagId === null) return // can be 0 so we can't do !tagId

       let lastTag = this.getTagByTagId(this.instanceId, tagId)
       if (!lastTag) return

       // FIXME: add some way to update existing tag (what if name/groupNode/... changes?)
       this.createTagData(this.lastTag)
     },*/
    // determines if checkbox is indeterminate and checked
    selectedNodes() {
      let nodes = this.selectedNodes
      let nodesLen = nodes.length
      // console.log('selected nodes', nodes)

      if (nodesLen > 0) {
        // O(n^2) algorithm for checking if all nodes from the group are selected
        // this.checkboxes.forEach(ch => {
        for (var i = 0; i < this.checkboxes.length; i++) {
          let selected = 0
          let groupNode = this.data[i].tag.groupNodeId
          if (groupNode && nodes.includes(groupNode)) {
            selected = this.checkboxes[i].count
          } else {
            this.checkboxes[i].nodeIds.forEach(id => {
              if (nodes.includes(id)) selected++
            })
          }

          let isIndeterminate = selected != 0 && selected < this.checkboxes[i].count
          let isChecked = selected === this.checkboxes[i].count
          Vue.set(this.checkboxes[i], 'selected', selected)
          Vue.set(this.checkboxes[i], 'isIndeterminate', isIndeterminate)
          Vue.set(this.checkboxes[i], 'isChecked', isChecked)
        }
      }
      if (nodesLen === 0) {
        for (i = 0; i < this.checkboxes.length; i++) {
          this.checkboxes[i].isChecked = false
          this.checkboxes[i].selected = 0
          this.checkboxes[i].isIndeterminate = false
        }
        this.mainCheckbox = false
        this.isMainCheckboxIndeterminate = false
      }
      this.updateMainCheckbox()
    }
  },

  mounted() {
    this.tags.forEach(tag => {
      if (!this.checkboxes.find(ch => ch.tagId === tag.uuid)) {
        this.createTagData(tag)
      }
    })
  },

  methods: {
    ...mapActions('data', [
      'groupNodes',
      'ungroupNode',
      'bundleNodes',
      'unbundleNode',
      'updateNodes',
      'switchTagVisibility',
      'switchTagIsGrouped',
      'miniaturizeNodesByTag',
      'unminiaturizeNodesByTag'
    ]),
    ...mapActions('data', {
      _selectNodes: 'selectNodes',
      _deselectNodes: 'deselectNodes',
      _deselectAllNodes: 'deselectAllNodes'
    }),
    ...mapGetters('data', ['getNodes', 'getNodeById', 'getLinkById', 'isTagMiniaturized']),
    ...mapMutations('interaction', [
      'SET_GLOBAL_HIGHLIGHTS',
      'UNSET_GLOBAL_HIGHLIGHTS',
      'CLEAR_GLOBAL_HIGHLIGHTS'
    ]),
    ...mapGetters('interaction', {
      _isObjectGloballyHighlighted: 'isObjectGloballyHighlighted'
    }),

    createTagData(tag) {
      let nodes = this.getNodesByIds(this.instanceId, tag.properties.get('assignedObjectsIds'))
      let links = this.linksBetweenNodes(
        tag.properties.get('assignedObjectsIds'),
        tag.properties.get('groupNodeId')
      )
      let entry = { tag: tag, links: links, nodes: nodes }
      this.data.push(entry)
      this.checkboxes.push({
        isChecked: false,
        isGrouped: tag.properties.get('isGrouped'), //tag.groupNodeId ? true : false,
        isOpened: { main: false, groups: false, nodes: true, links: true },
        isIndeterminate: false,
        nodeIds: tag.properties.get('assignedObjectsIds'),
        selected: 0,
        count: tag.properties.get('assignedObjectsIds').length,
        tagId: tag.uuid
      })
    },

    checkAllCheckboxes() {
      this.mainCheckbox = this.isMainCheckboxIndeterminate ? true : !this.mainCheckbox
      this.isMainCheckboxIndeterminate = false

      for (var i = 0; i < this.checkboxes.length; i++) {
        //Vue.set(this.checkboxes[i], 'isChecked', this.mainCheckbox)

        this.mainCheckbox
          ? this.selectNodes(this.data[i].tag, i)
          : this.deselectNodes(this.data[i].tag, i)
      }
    },

    // eslint-disable-next-line no-unused-vars
    selectNodes(tag, checkboxIndex) {
      // let checkbox = this.checkboxes[checkboxIndex]
      if (tag.properties.get('isGrouped')) {
        this._selectNodes({
          slotId: this.instanceId,
          nodeIds: [tag.properties.get('groupNodeId')]
        })
      } else {
        this._selectNodes({
          slotId: this.instanceId,
          nodeIds: tag.properties.get('assignedObjectsIds')
        })
      }
      // Vue.set(this.checkboxes[checkboxIndex], 'selected', checkbox.count)
    },

    // eslint-disable-next-line no-unused-vars
    deselectNodes(tag, checkboxIndex) {
      // let checkbox = this.checkboxes[checkboxIndex]
      if (tag.properties.get('isGrouped')) {
        this._deselectNodes({
          slotId: this.instanceId,
          nodeIds: [tag.properties.get('groupNodeId')]
        })
      } else {
        this._deselectNodes({
          slotId: this.instanceId,
          nodeIds: tag.properties.get('assignedObjectsIds')
        })
      }
      // let selected = checkbox.selected
      // selected -= tag.assignedObjectsIds
      // if (selected < 0) selected = 0

      // Vue.set(this.checkboxes[checkboxIndex], 'selected', selected)
    },

    changeCheckboxIsChecked(tag, i) {
      // Vue.set(this.checkboxes[i], 'isChecked', !this.checkboxes[i].isChecked)
      !this.checkboxes[i].isChecked ? this.selectNodes(tag, i) : this.deselectNodes(tag, i)
      this.updateMainCheckbox()
    },

    // checks if all checkboxes are checked and sets main checkbox to true, false or indeterminate
    updateMainCheckbox() {
      if (this.checkboxes.length === 0) return
      let foundIndeterminate = false
      let count = 0
      this.checkboxes.forEach(ch => {
        if (ch.isIndeterminate) {
          this.mainCheckbox = true
          this.isMainCheckboxIndeterminate = true
          foundIndeterminate = true
          return
        }
        if (ch.isChecked) count++
      })

      if (foundIndeterminate) return // because you can't exit for loop...

      this.mainCheckbox = count === this.checkboxes.length
      this.isMainCheckboxIndeterminate = count !== 0 && count < this.checkboxes.length
    },

    linksBetweenNodes(nodeIdsArray, groupNodeId) {
      let clonedNodeIds = cloneDeep(nodeIdsArray) // needed so that we can push into it without changing vuex
      if (groupNodeId) clonedNodeIds.push(groupNodeId)
      let links = []
      clonedNodeIds.forEach(uuid => {
        let linkIds = this.getLinkIdsConnectedToNode(this.instanceId, uuid)
        linkIds.forEach(uuid => {
          let link = this.getLinkById()(this.instanceId, uuid)
          if (clonedNodeIds.includes(link.source) && clonedNodeIds.includes(link.target)) {
            links.push(link)
          }
        })
      })
      return links
    },

    toggleNodeSize(tagObj) {
      this.isTagMiniaturized()(this.instanceId, tagObj.uuid)
        ? this.unminiaturizeNodesByTag({
            slotId: this.instanceId,
            tagId: tagObj.uuid
          })
        : this.miniaturizeNodesByTag({
            slotId: this.instanceId,
            tagId: tagObj.uuid
          })
    },

    //
    // HIGHLIGHTS
    //
    isObjectGloballyHighlighted(uuid) {
      if (uuid === null) return false
      return this._isObjectGloballyHighlighted()(uuid)
    },

    isGroupGloballyHighlighted(tag, index) {
      let res = false
      if (this.isNodeGloballyHighlighted(tag.properties.get('groupNodeId'))) return true
      else if (this.checkboxes[index].isOpened.main) return false
      else {
        tag.properties
          .get('assignedObjectsIds')
          .map(uuid => this.getNodeData(uuid))
          .forEach(el => {
            if (el && el.uuid !== null && this.isObjectGloballyHighlighted(el.uuid)) {
              res = true
              return //true // foreach already a function @todo FIX ME
            }
          })
      }
      return res
    },

    isNodeGloballyHighlighted(id) {
      if (id === null) return false
      let node = this.getNodeData(id)
      if (!node) return false
      return this.isObjectGloballyHighlighted(node.uuid)
    },

    setNodeHighlights(nodeIds) {
      let data = nodeIds.map(id => this.getNodeData(id))
      let uuids = []
      data.forEach(d => {
        if (d && d.uuid !== null) uuids.push(d.uuid)
      })
      this.SET_GLOBAL_HIGHLIGHTS(uuids)
      // this.SET_GLOBAL_HIGHLIGHTS(nodeIds.map(id => this.getNodeData(id)).map(el => el.uuid))
    },

    removeNodeHighlights(nodeIds) {
      let data = nodeIds.map(id => this.getNodeData(id))
      let uuids = []
      data.forEach(d => {
        if (d && d.uuid !== null) uuids.push(d.uuid)
      })
      this.UNSET_GLOBAL_HIGHLIGHTS(uuids)
      // this.UNSET_GLOBAL_HIGHLIGHTS(nodeIds.map(id => this.getNodeData(id)).map(el => el.uuid))
    },

    setLinkHighlights(linkIds) {
      let data = linkIds.map(id => this.getLinkData(id))
      let uuids = []
      data.forEach(d => {
        if (d && d.uuid !== null) uuids.push(d.uuid)
      })
      this.SET_GLOBAL_HIGHLIGHTS(uuids)
      // this.SET_GLOBAL_HIGHLIGHTS(linkIds.map(id => this.getLinkData(id)).map(el => el.uuid))
    },

    removeLinkHighlights(linkIds) {
      let data = linkIds.map(id => this.getLinkData(id))
      let uuids = []
      data.forEach(d => {
        if (d && d.uuid !== null) uuids.push(d.uuid)
      })
      this.UNSET_GLOBAL_HIGHLIGHTS(uuids)
      // this.UNSET_GLOBAL_HIGHLIGHTS(linkIds.map(id => this.getLinkData(id)).map(el => el.uuid))
    },

    clearHighlights() {
      this.CLEAR_GLOBAL_HIGHLIGHTS()
    },

    highlightGroup(index) {
      if (!this.checkboxes[index]) return
      let entry = this.data[index]
      let group = entry.tag.properties.get('assignedObjectsIds')
      if (entry.tag.properties.get('isGrouped')) {
        group = group.concat(entry.tag.properties.get('groupNodeId'))
      }
      // TODO make general for all objectsW
      this.setNodeHighlights(group)
      //console.log(JSON.stringify(entry.links))
      this.setLinkHighlights(entry.links.map(l => l.uuid))
    },

    highlightNodeOrGroup(index, nodeId) {
      let entry = this.data[index]
      if (entry.tag.properties.get('isGrouped')) {
        this.highlightGroup(index)
      } else {
        this.setNodeHighlights([nodeId])
      }
    },

    getNodeData(id) {
      return this.getNodeById()(this.instanceId, id)
    },

    getLinkData(id) {
      return this.getLinkById()(this.instanceId, id)
    },

    //
    // AGGREGATIONS
    //
    commitAggregateNodes(tag, checkboxIndex) {
      this.deselectNodes(tag, checkboxIndex)

      if (tag.type === 'bundle') {
        this.bundleNodes({
          slotId: this.instanceId,
          representativeNodeId: tag.properties.get('groupNodeId'),
          nodeIds: tag.properties.get('assignedObjectsIds')
        })
      } else {
        //let label = tag.groupNodeId ? this.getNodeById(tag.groupNodeId).label : tag.name
        // TODO: does groupNode have label/name which we would want instead of tag.name?
        this.groupNodes({
          slotId: this.instanceId,
          action: tag.type,
          nodeIds: tag.properties.get('assignedObjectsIds'),
          label: tag.name
        })
      }
      this.switchTagIsGrouped({
        slotId: this.instanceId,
        uuid: tag.uuid
      })
    },

    commitDisaggregateNodes(tag, checkboxIndex) {
      this.deselectNodes(tag, checkboxIndex)

      tag.type === 'bundle'
        ? this.unbundleNode({
            slotId: this.instanceId,
            nodeId: tag.properties.get('groupNodeId')
          })
        : this.ungroupNode({
            slotId: this.instanceId,
            nodeId: tag.properties.get('groupNodeId')
          })

      this.switchTagIsGrouped({
        slotId: this.instanceId,
        uuid: tag.uuid
      })
    }
  }
}
</script>

<style lang="sass" scoped>
.group-table
  &--header
    font-weight: bold
  &--row
    margin-left: 0
    margin-bottom: 0 !important
    border: 1px solid #ddd
    border-style: solid none none
    padding-top: 0.3rem
    background-color: $table-background-color // #f3f4f6
    &:hover
      background-color: $table-cell-highlight-color //#eee //#e8eeee
    &--summary
      margin-bottom: 0 !important
    &--detail
      padding-left: 1rem
      padding-bottom: 0.3rem
      &--title
        font-size: 0.7rem
        font-weight: 600
        color: $secondary-text-color
        padding: 0.2rem 0
      &--list
        margin-left: 0.5rem
  &--footer
    position: absolute
    display: block
    padding-top: 10rem
    left: 0
    padding-left: 1.5rem
    &--title
        font-size: 0.7rem
        font-weight: 600
        margin: 0
        color: $secondary-text-color

.group-hover
  background-color: $table-cell-highlight-color

%icon
  cursor: pointer
  color: $secondary-text-color
  &:hover
    opacity: 1

.icon
  &-chevron
    @extend %icon
    margin: 0 0.5rem 0 1rem
    opacity: 0.5
  &-aggregate
    @extend %icon
    opacity: 0.6
    margin-right: 0.2rem
  &-tag
    @extend %icon
    margin-left: 0.5rem
  &-eye
    @extend %icon
    margin-left: 0.5rem

.listitem
  color: #363636
  font-size: 0.7rem
  font-weight: normal
  &:hover
    font-weight: bold
    background: $table-cell-highlight-color

.listitem-hover
  font-weight: bold
  background: $table-cell-highlight-color

.hide-bin
  font-style: italic

.minimize
  display: inline
  color: #919191
  margin: auto 1.5rem auto auto
  &:hover
    color: #363636
</style>
