<template>
  <b-collapse class="card card-right">
    <div slot="trigger" slot-scope="props" class="card-header" role="button">
      <p class="card-header-title">Group list</p>
      <a class="card-header-icon">
        <b-icon :icon="props.open ? 'menu-down' : 'menu-up'"></b-icon>
      </a>

      <i class="el-icon-close clickable-icon" style="float: right; padding: 3px 0"></i>
    </div>

    <div slot="header" class="clearfix">
      <span>Group list</span>
    </div>

    <div class="label-buefy-style">
      <p class="alignleft">Name</p>
      <p class="alignright"># nodes / links</p>
    </div>

    <div class="card-content">
      <div class="content">
        <div
          v-for="(t, i) in tags"
          :key="t.id"
          @mouseover="highlightTag(t.name, i)"
          @mouseout="
            CLEAR_NODE_HIGHLIGHT()
            CLEAR_LINK_HIGHLIGHT()
          "
        >
          <div class="field" style="display: inline;">
            <b-collapse :open="false" aria-id="lists">
              <p slot="trigger" aria-controls="lists">
                <b-checkbox
                  size="is-small"
                  :value="checkboxes[i].isChecked"
                  :indeterminate="checkboxes[i].isIndeterminate"
                  @click.native.stop
                  @input="
                    checkboxes[i].isChecked = !checkboxes[i].isChecked
                    checkboxes[i].isChecked
                      ? t.nodesWithTag.forEach(n => {
                          selectNode(n.id)
                          checkboxes[i].selected++
                        })
                      : t.nodesWithTag.forEach(n => {
                          deselectNode(n.id)
                          checkboxes[i].selected--
                        })
                  "
                >{{ t.name }}</b-checkbox>

                <svg
                  style="height:22; width:34;"
                  @click.stop="
                    switchTagVisibility(t.name)
                    checkboxes[i].isTagVisible = !checkboxes[i].isTagVisible
                  "
                >
                  <defs>
                    <linearGradient
                      id="grad1"
                      x1="0%"
                      y1="100%"
                      x2="0%"
                      y2="0%"
                      gradientTransform="rotate(45 .5 .5)"
                    >
                      <stop offset="40%" style="stop-color:rgba(255, 255, 255, 0);" />
                      <stop offset="50%" style="stop-color:rgba(222, 8, 10, 1);" />
                      <stop offset="60%" style="stop-color:rgba(255, 255, 255, 0);" />
                    </linearGradient>
                  </defs>
                  <circle
                    id="t.id"
                    :class="checkboxes[i].isTagVisible ? 'visible' : 'halftransparent'"
                    :cx="15"
                    :cy="10"
                    :r="10"
                    :fill="t.color"
                    :stroke="t.stroke"
                  />
                  <circle
                    id="t.id"
                    :cx="15"
                    :cy="10"
                    :r="10"
                    :class="checkboxes[i].isTagVisible ? 'invisible' : 'visible'"
                    fill="url(#grad1)"
                    :stroke="t.stroke"
                  />
                </svg>

                <span style="display: inline;">
                  <swatches
                    v-model="checkboxes[i].tagColor"
                    :colors="colors"
                    class="pls"
                    :trigger-style="{ width: '20px', height: '20px' }"
                    shapes="circles"
                    popover-to="left"
                    style="display: inline;"
                    @input="dispatchChangeTagColor(t.name, checkboxes[i].tagColor)"
                  />
                </span>

                <b-icon style="vertical-align: middle;" icon="menu-down"></b-icon>
                <span class="alignright" style="float: right;">
                  {{
                  t.nodesWithTag.length + ' / ' + computedLinks[i].length
                  }}
                </span>

                <b-icon
                  v-if="t.nodesWithTag.length > 1"
                  style="vertical-align: middle;"
                  :icon="checkboxes[i].isGrouped ? 'arrow-expand-all' : 'arrow-collapse-all'"
                  @click.native.stop="
                    checkboxes[i].isGrouped
                      ? commitDisaggregateNodes(t, i)
                      : commitAggregateNodes(t, i)
                  "
                ></b-icon>
              </p>

              <b-collapse
                v-if="t.nodesWithTag.length > 0"
                :open="false"
                class="nodeslist"
                aria-id="nodes-list"
              >
                <p slot="trigger" class="small-title" aria-controls="nodes-list">
                  NODES
                  <b-icon style="vertical-align: middle;" icon="menu-down"></b-icon>
                </p>
                <li
                  v-for="(node, index) in t.nodesWithTag"
                  class="listitem"
                  :class="getHoveredNode === node.id ? 'listitem-hover' : 'listitem'"
                  @mouseover.stop="
                    SET_NODE_HIGHLIGHT(node.id)
                    highlightGroupNode(t.groupNode)
                  "
                  @mouseout="CLEAR_NODE_HIGHLIGHT()"
                >{{ node.label }}</li>
              </b-collapse>

              <b-collapse
                v-if="computedLinks[i].length > 0"
                class="linkslist"
                :open="false"
                aria-id="links-list"
              >
                <p slot="trigger" class="small-title" aria-controls="links-list">
                  LINKS
                  <b-icon style="vertical-align: middle;" icon="menu-down"></b-icon>
                </p>
                <li
                  v-for="(link, index) in computedLinks[i]"
                  class="listitem"
                  @mouseover.stop="
                    SET_LINK_HIGHLIGHT(link.id)
                    highlightGroupNode(t.groupNode)
                  "
                  @mouseout="CLEAR_LINK_HIGHLIGHT()"
                >{{ link.description }}</li>
                <!-- TODO there is only hoveredNode in vuex -->
                <!-- :class="getHoveredLink === link.id ? 'listitem-hover' : 'listitem'" -->
              </b-collapse>
            </b-collapse>
          </div>
        </div>
      </div>
    </div>
  </b-collapse>
</template>

<script>
import Vue from 'vue'
import { mapActions, mapGetters, mapMutations } from 'vuex'
import { cloneDeep } from 'lodash'
import Swatches from 'vue-swatches'
import 'vue-swatches/dist/vue-swatches.min.css'

export default {
  components: {
    Swatches
  },
  data() {
    return {
      checkboxes: [],
      colors: [
        '',
        '#e6194B',
        '#3cb44b',
        '#ffe119',
        '#4363d8',
        '#f58231',
        '#911eb4',
        '#42d4f4',
        '#f032e6',
        '#bfef45',
        '#fabebe',
        '#469990',
        '#e6beff',
        '#9A6324',
        '#fffac8',
        '#800000',
        '#aaffc3',
        '#808000',
        '#ffd8b1',
        '#000075',
        '#a9a9a9',
        '#000000'
      ]
    }
  },

  computed: {
    ...mapGetters('interaction', ['isShownTagCreation', 'getSelectedNodes', 'getHoveredNode']),
    ...mapGetters('data', ['getNodesInAggregation', 'getLinkIdsConnectedToNode', 'getLinkById']),

    tags: {
      get() {
        return this.$store.getters['data/getTags']
      },
      set(tags) {
        return tags
      }
    },

    nodes: {
      get() {
        return this.getNodes()
      },
      set(nodes) {
        return nodes
      }
    },

    computedLinks() {
      let links = []
      this.tags.forEach(t => {
        // TODO probably unnecessary clone - it's because we don't want to change vuex array
        // but still want the group node to be inside
        // but it can be just a second parameter in linksBetweenNodes
        let nodesWithGroupNode = cloneDeep(t.nodesWithTag)
        if (t.groupNode) nodesWithGroupNode.push(t.groupNode)
        links.push(this.linksBetweenNodes(nodesWithGroupNode))
      })
      return links
    },

    selectedNodes() {
      return this.$store.getters['interaction/getSelectedNodes']
    }
  },

  watch: {
    nodes() {
      this.checkboxes.forEach(ch => {
        ch.isGrouped = false
        ch.nodeIds.forEach(id => {
          let found = this.nodes.find(n => n.id === id)
          if (found && found.isGrouped) {
            ch.isGrouped = true
            // TODO this needs to be more complex, what if only few nodes in a group tag are grouped elsewhere?
          }
        })
      })
    },

    /*checkboxes: {
      handler() {
        this.checkboxes.forEach(ch => {
          ch.nodeIds.forEach(id => {
            console.log('hmmmmmmmmm', ch.isGrouped)
            console.log('hmmmmmmmmm', id)
            this.updateNodeIsGroupedAttr(id, ch.isGrouped)
          })
        })
      },
      deep: true
    },*/

    // shows/hides NodeSelectionCard and determines if checkbox is indeterminate and checked
    selectedNodes() {
      let nodes = this.selectedNodes
      let nodesLen = nodes.length

      if (nodesLen > 0) {
        this.showNodeSelection()

        // O(n^2) algorithm for checking if all nodes from the group are selected
        this.checkboxes.forEach(ch => {
          ch.selected = 0
          ch.nodeIds.forEach(id => {
            if (nodes.find(nId => nId === id)) {
              ch.selected++
            }
          })
          ch.isIndeterminate = ch.selected != 0 && ch.selected < ch.count
          ch.isChecked = ch.selected === ch.count
        })
      }
      if (nodesLen === 0) {
        this.checkboxes.forEach(ch => {
          ch.isChecked = false
          ch.selected = 0
          ch.isIndeterminate = false
        })
        this.hideNodeSelectionIfEmpty()
      }
    },

    tags() {
      //let index = 0 // if checkboxes would be a map we could just use name
      this.tags.forEach(t => {
        if (!this.checkboxes.find(ch => ch.tagName === t.name)) {
          let nodeIds = []
          t.nodesWithTag.forEach(n => {
            nodeIds.push(n.id)
          })
          this.checkboxes.push({
            isChecked: true, // toggles checkmark
            isOpen: false, // toggles menu arrow icon
            isGrouped: t.groupNode ? true : false, // toggles expand/collapse icon
            isTagVisible: t.isVisualized, // toggles class for visibility of tag circles
            selected: t.nodesWithTag.length, // selected nodes count, used to calculate isIndeterminate
            count: t.nodesWithTag.length, // all nodes count, used to calculate isIndeterminate
            nodeIds: nodeIds, // used to calculate isIndeterminate
            isIndeterminate: false, // toggles indeterminate value
            tagName: t.name, // used for checking if the tag already has checkbox
            tagColor: t.color === 'none' ? '' : t.color // used for swatches
          })
        }

        /*let selectedCount = 0
        t.nodesWithTag.forEach(n => {
          if (n.isSelected) selectedCount++
        })

        console.log('fml', this.checkboxes[index])
        console.log('fml', this.checkboxes)

        // welp, I forgot with reactivity we need to do vue.set, but it's not really working for nested items
        //Vue.set(this.checkboxes[0].object('isChecked', selectedCount > 0))

        this.checkboxes[index].isIndeterminate =
          selectedCount > 0 && selectedCount < this.checkboxes[index].count
        this.checkboxes[index].isChecked = selectedCount === this.checkboxes[index].count

        index++*/
      })
    }
  },

  methods: {
    ...mapActions('data', [
      'groupNodes',
      'ungroupNode',
      'bundleNodes',
      'unbundleNode',
      'updateNodes',
      'switchTagVisibility'
    ]),
    ...mapActions('interaction', [
      'selectNode',
      'deselectNode',
      'showNodeSelection',
      'hideNodeSelectionIfEmpty'
    ]),
    ...mapGetters('data', ['getNodes']),
    ...mapMutations('interaction', [
      'SET_NODE_HIGHLIGHT',
      'CLEAR_NODE_HIGHLIGHT',
      'SET_LINK_HIGHLIGHT',
      'CLEAR_LINK_HIGHLIGHT',
      'SELECT_NODE',
      'DESELECT_NODES',
      'SET_NODE_HOVER',
      'UNSET_NODE_HOVER'
    ]),

    updateNodeIsGroupedAttr(nodeId, isGrouped) {
      this.updateNodes([{ id: nodeId, isGrouped: isGrouped }])
    },

    updateNodeIsSelectedAttr(nodeId, isSelected) {
      this.updateNodes([{ id: nodeId, isSelected: isSelected }])
    },

    dispatchChangeTagColor(name, color) {
      this.$store.dispatch('data/changeTagColorOfTag', { tagName: name, color: color })
    },

    highlightTag(name, i) {
      let tag = this.tags.find(t => t.name === name)
      tag.nodesWithTag.forEach(n => {
        this.SET_NODE_HIGHLIGHT(n.id)
      })
      this.highlightGroupNode(tag.groupNode)
      this.computedLinks[i].forEach(l => {
        this.SET_LINK_HIGHLIGHT(l.id)
      })
    },

    highlightGroupNode(groupNode) {
      if (groupNode) this.SET_NODE_HIGHLIGHT(groupNode.id)
    },

    test(test = 'test') {
      console.log(test)
    },

    linksBetweenNodes(nodeIdsArray) {
      let links = []
      nodeIdsArray.forEach(n => {
        let linkIds = this.getLinkIdsConnectedToNode(n.id)
        linkIds.forEach(id => {
          let link = this.getLinkById(id)
          if (
            nodeIdsArray.find(n => n.id === link.source) &&
            nodeIdsArray.find(n => n.id === link.target) &&
            !links.find(n => n.id === link.id)
          ) {
            links.push(link)
          }
        })
      })
      return links
    },

    commitAggregateNodes(tag, checkboxIndex) {
      let nodeIds = []
      tag.nodesWithTag.forEach(n => {
        nodeIds.push(n.id)
      })

      if (tag.bundleNode) {
        this.bundleNodes({
          representativeNodeId: tag.bundleNode,
          nodeIds: nodeIds
        })
      } else {
        let name = tag.groupNode ? tag.groupNode.label : tag.name
        this.groupNodes({ nodes: nodeIds, label: name })
      }
      this.checkboxes[checkboxIndex].isGrouped = true
      this.checkboxes[checkboxIndex].isChecked = false
    },

    commitDisaggregateNodes(tag, checkboxIndex) {
      tag.bundleNode ? this.unbundleNode(tag.bundleNode) : this.ungroupNode(tag.groupNode.id)
      this.checkboxes[checkboxIndex].isGrouped = false
    }
  }
}
</script>

<style lang="sass" scoped>
@import ../_workspace

.card-right
  width: $card-right-width
  margin-bottom: 20px

.el-card__header
  padding: 12px 10px

.item
  margin-bottom: 18px

.clickable-icon
  cursor: pointer

.header-title
  padding: 10px
  margin-top: 50px
  position: relative
  top: 5px

.card-header-btn
  float: right
  padding: 8px 4px

.card-content
  padding: 0.5rem 1rem 0 1rem

.clearfix:before,
.clearfix:after
  display: table
  content: ''

.clearfix:after
  clear: both

.label-buefy-style
  color: #363636;
  display: flex;
  justify-content: space-between;
  font-size: 1rem;
  font-weight: 600;
  padding: 1rem 1rem 0 1rem

.alignleft
	display: inline
  padding: 0 0 8px 4px

.alignright
  display: inline

.small-title
  color: #363636;
  font-size: 0.7rem;
  font-weight: 500;
  padding: 0px 30px

.listitem
  color: #363636;
  font-size: 0.7rem;
  font-weight: normal;
  padding: 0px 50px

.listitem:hover
  font-weight: bold;

.listitem-hover
  font-weight: bold;

.visible
  opacity: 100%

.invisible
  opacity: 0%;

.halftransparent
  opacity: 60%;

.pls > div
  display: inline !important;
</style>
