<template>
  <div class="tree-wrap w-100 h-100">
    <div class="loader-wrap w-100 h-100" v-if="isLoading">
      <loading :active.sync="isLoading"
      :is-full-page="fullPage">
      </loading>
    </div>
    <mads-tree
      v-else
      ref="tree"
      :treeData="treeData"
      :treeView="treeView"
      :treeOptions="options"
      :isAnyNodeSelected="isAnyNodeSelected"
      :showSensorGateway="showSensorGateway"
      :treeMapping="treeMapping"
      :isViewMappingLabel="isViewMappingLabel"
      @on-add-sibling-node="onAddSiblingNode"
      @on-add-child-node="onAddChildNode"
      @on-node-click="onNodeClick"
      @on-node-select="onNodeSelect"
      @on-node-mouse-over="onNodeMouseOver"
      @on-node-mouse-leave="onNodeMouseLeave"
      @on-node-drag-start="onNodeDragStart"
    ></mads-tree>
  </div>
</template>

<script>
import Loading from 'vue-loading-overlay'
import madsTree from './madsTree.vue'
import TreeEventBus from './treeEventBus'
import dashobardEventBus from '../../dashboardBus'

export default {
  components: {
    madsTree,
    Loading
  },
  data () {
    return {
      orgData: null,
      treeData: null,
      treeDataDuplicate: null,
      relativeEntity: {},
      entityRelation: '',
      options: {
        childrenKey: 'entities',
        selectable: false,
        showHoverOptions: false,
        singleSelect: false
      },
      showSensorGateway: false,
      isLoading: false,
      fullPage: false,
      sensorParameterPathMapping: {}
    }
  },
  props: {
    treeView: {
      type: String
    },
    treeOptions: {
      type: Object,
      default: () => {
        return {}
      }
    },
    selectedNodes: {
      type: Array,
      default: () => {
        return []
      }
    },
    hiddenEntities: {
      type: Array,
      default: () => {
        return ['SensorParameter']
      }
    },
    selectableEntities: {
      type: Array,
      default: () => {
        return ['Organisation', 'Asset']
      }
    },
    isAnyNodeSelected: {
      type: Boolean,
      default: false
    },
    editingEntity: {
      default: null
    },
    type: {
      type: String,
      default: 'project'
    },
    treeMapping: {
      type: Object,
      default: () => {
        return {}
      }
    },
    isViewMappingLabel: {
      type: Boolean,
      default: false
    },
    isExportedDashboard: {
      type: Boolean,
      default: false
    },
    apiKey: {
      type: String,
      default: 'role_mgmt'
    },
    currentUser: {},
    selectedDashboard: {},
    selectedProject: {},
    treeService: {},
    entityService: {},
    orgService: {},
    dataInsightService: {},
    dashboardService: {}
  },
  methods: {
    initData (data) {
      this.orgData = data
      this.treeData = this.treeService.initData(this.orgData, {
        selectedNodes: this.selectedNodes,
        hiddenEntities: this.hiddenEntities,
        selectableEntities: this.selectableEntities,
        editingEntity: this.editingEntity,
        childrenKey: this.options.childrenKey
      }, this.sensorParameterPathMapping)
      this.isLoading = false
      this.$emit('set-parameter-path-mapping', this.sensorParameterPathMapping)
    },
    loadProjectEntities () {
      this.isLoading = true
      let config = { orgId: this.currentUser.org.id, projectId: this.selectedProject.id, apiKey: this.apiKey }
      this.entityService
        .read(config)
        .then(response => {
          this.initData(response)
        })
    },
    loadGatewayEntities () {
      this.isLoading = true
      let config = { orgId: this.currentUser.org.id, projectId: this.selectedProject.id }
      this.entityService
        .readWithGateways(config)
        .then(response => {
          this.initData(response)
        })
    },
    loadOrgEntities () {
      this.isLoading = true
      let config = {}
      if (this.isExportedDashboard) {
        let dashboardUUID = localStorage.getItem('dashboard_uuid')
        config = { orgId: this.selectedDashboard.org_id, uuid: dashboardUUID }
      } else {
        config = { orgId: this.currentUser.org.id, apiKey: this.apiKey }
      }
      let dashboardToken = localStorage.getItem('dashboard_token')

      let request = this.isExportedDashboard ? this.dashboardService.readExportedDashboardEntities(config, dashboardToken) : this.orgService.readEntities(config)

      request
        .then(response => {
          this.initData(response)
        })
    },
    loadTopologyEntities () {
      this.isLoading = true
      let config = { orgId: this.currentUser.org.id, id: this.selectedProject.id }
      this.dataInsightService
        .readTopology(config)
        .then(response => {
          this.initData(response)
        })
        .catch((error) => {
          this.$toastr.error(error.title, 'Error', { closeButton: true, closeDuration: 0 })
        })
        .finally(() => {
          this.isLoading = false
        })
    },
    getTreeData () {
      return this.treeData
    },
    setTreeData (data) {
      this.treeData = data
    },
    getDuplicateTreeData () {
      return this.treeDataDuplicate
    },
    getSelectedNodes () {
      return this.$refs.tree.getCheckedNodes()
    },
    // In case of single select
    getSingleSelectedNode () {
      let selectedNodes = this.getSelectedNodes()
      return (this.$_.size(selectedNodes) > 0) ? selectedNodes[0] : null
    },
    getParentNode () {
      return (this.entityRelation === 'sibling') ? this.relativeEntity.parentNode : this.relativeEntity.node
    },

    // Event Emitter Functions
    onNodeClick (event, data) {
      this.$emit('on-node-click', event, data)
    },
    onAddSiblingNode (event, data) {
      // this.$emit('on-add-sibling-node', event, data)
      this.entityRelation = 'sibling'
      this.relativeEntity = data
      TreeEventBus.$emit('show-entity-modal', 'sibling')
    },
    onAddChildNode (event, data) {
      // this.$emit('on-add-child-node', event, data)
      this.entityRelation = 'child'
      this.relativeEntity = data
      TreeEventBus.$emit('show-entity-modal', 'child')
    },
    onNodeSelect (event, data) {
      this.$emit('on-node-select', event, data)
    },
    onNodeMouseOver (event, data) {
      this.$emit('on-node-mouse-over', event, data)
    },
    onNodeMouseLeave (event, data) {
      this.$emit('on-node-mouse-leave', event, data)
    },
    onNodeDragStart (event, data) {
      this.$emit('on-node-drag-start', event, data)
    },

    // Tree Event Bus Functions
    addEntity (entityData, entityType) {
      if (this.treeDataDuplicate === null) {
        this.treeDataDuplicate = this.$_.cloneDeep(this.treeData)
      }
      let parentNode = (this.entityRelation === 'sibling') ? this.relativeEntity.parentNode : this.relativeEntity.node
      let node = this.$_.assign(entityData, { action: 'create', type: entityType, parent_id: parentNode.id || null }, {
        options: {
          label: entityData.name,
          classes: [entityType],
          expanded: false,
          selected: false,
          hoverOptions: { sibling: true, child: entityType === 'Asset' },
          visible: true,
          selectable: false,
          icon: entityType === 'Asset' ? '/assets/img/mads-entity-manager-icons.svg#assets' : '/assets/img/mads-entity-manager-icons.svg#sensors',
          isLeafNode: true
        }
      })
      let entities = this.$_.concat(parentNode.entities || [], node)
      this.$set(parentNode, 'entities', entities)
      this.$set(parentNode.options, 'expanded', true)
      this.$set(parentNode.options, 'isLeafNode', false)

      this.treeData = this.$_.assign({}, this.treeData)

      if (this.$_.isEqual(this.treeData, this.treeDataDuplicate)) {
        dashobardEventBus.$emit('set-compare-tree-data', false)
      } else {
        dashobardEventBus.$emit('set-compare-tree-data', true)
      }
    }
  },
  mounted () {
    this.options = this.$_.merge(this.options, this.treeOptions)

    if (this.type === 'project') {
      this.loadProjectEntities()
    } else if (this.type === 'gateways') {
      this.showSensorGateway = true
      this.loadGatewayEntities()
    } else if (this.type === 'topology') {
      this.loadTopologyEntities()
    } else {
      this.loadOrgEntities()
    }

    TreeEventBus.$on('add-entity', (entityData, entityType) => {
      this.addEntity(entityData, entityType)
    })

    TreeEventBus.$on('reload-entities', () => {
      this.loadProjectEntities()
    })
  },
  beforeDestroy () {
    TreeEventBus.$off()
  }
}
</script>

<style lang="scss" scoped>
  .tree-wrap {
    position: relative;
    .loader-wrap {
      position: absolute;
    }
  }
</style>
