<template>
  <div :class="{ dashboard: fromMobile }">
    <div class="container-fluid dashboard animated fadeIn px-0 auth-load genealogy">
      <div v-if="showToolbar" class="placement-network-tree-updated-at" :class="{ 'on-mobile': userIdData !== null }">
        {{ $t('Genealogy.PlacementNetworkTree.UpdatedAt', { time: updatedAt }) }}
      </div>
      <div class="row dashboard-header placement-network-tree-toolbar w-100" v-if="userIdData === null && showToolbar">
        <div class="col-7 col-md-3 mt-2">
          <b-input-group class="flex-nowrap border">
            <eshop-autocomplete
              :items="getMemberList"
              v-model="searchMember"
              :get-label="item => (item ? item.name : '')"
              :wait="100"
              variant="primary"
              template-name="member"
              :min-len="0"
              class="flex-grow-1"
              :placeholder="$t('Genealogy.SponsorNetworkTree.Search.SearchDownline')"
              id="myInput"
              input-class="border-0 v-autocomplete-input"
              @updateItems="searchMemberListExcludeSelf"
              @item-selected="searchDownline"
              data-qa="genealogy-placement-network-tree-search-member-autoComplete"
            />
            <b-input-group-append>
              <b-btn
                v-if="searchMember !== ''"
                variant="link"
                @click="getMemberTreeData(userIdData, depth, true)"
                :title="$t('Genealogy.SponsorNetworkTree.Search.ClickToRemove')"
                :disabled="isLoading('memberTreeLoading')"
                data-qa="genealogy-placement-network-tree-clear-member-btn"
              >
                <icon name="clear-icon" class="" />
              </b-btn>
              <div class="d-flex p-0 justify-content-between align-items-center">
                <b-button
                  variant="primary"
                  class="rounded-0"
                  :disabled="searchMember === '' || isLoading('memberTreeLoading')"
                  @click="searchDownline(searchMember)"
                  data-qa="genealogy-placement-network-tree-search-member-btn"
                >
                  <icon name="search" />
                </b-button>
              </div>
            </b-input-group-append>
          </b-input-group>
        </div>
        <div class="col-5 col-md-auto mt-2 text-nowrap">
          <label class="text-lg-right mr-2 d-md-inline d-none">
            {{ $t('Genealogy.SponsorNetworkTree.Search.Display') }}
          </label>
          <b-form-select
            v-model="selectedDepth"
            :options="depthOptions"
            @change="handleSelectedDepth"
            class="w-auto"
            size="md"
            :disabled="viewIboId !== ''"
          />
        </div>
        <div class="col-auto mt-2">
          <button
            class="btn btn-primary btn-md text-nowrap"
            @click="getOuterMember('left')"
            data-qa="genealogy-placement-network-tree-outer-left-tree-btn"
          >
            {{ $t('Genealogy.PlacementTreeDiagram.Search.ViewOuterLeft') }}
          </button>
        </div>
        <div class="col-auto mt-2">
          <button
            class="btn btn-primary btn-md text-nowrap"
            @click="getOuterMember('right')"
            data-qa="genealogy-placement-network-tree-outer-right-tree-btn"
          >
            {{ $t('Genealogy.PlacementTreeDiagram.Search.ViewOuterRight') }}
          </button>
        </div>
        <div class="col mt-2">
          <button class="btn btn-primary btn-md" @click="showLegends()">
            <icon name="info-circle-icon" />
          </button>
        </div>
      </div>
      <div
        class="mt-2 mx-1 placement-network-tree dashboard-header z-0 justify-content-center align-items-center"
        :class="{
          'on-mobile': userIdData !== null,
          'w-100 vh-100 top-0': fullScreenView,
          'd-flex': isLoading('memberTreeLoading'),
        }"
      >
        <template>
          <div
            v-if="isLoading('memberTreeLoading')"
            class="d-flex align-items-center justify-content-center text-primary vh-75"
          >
            <b-spinner class="mx-2" />
            <strong class="h5 m-0">{{ $t('Genealogy.PlacementTreeDiagram.Loading') }}</strong>
          </div>

          <div v-else class="vh-100">
            <div id="memberTreeDiagram" class="fit shadow-1 genealogy-gradient-container" :class="diagramClasses" />
          </div>
        </template>
        <div
          v-if="showBackRoot && !isLoading('memberTreeLoading')"
          class="placement-network-tree-back"
          :class="{ 'on-mobile': userIdData !== null }"
        >
          <b-button
            variant="primary"
            class="rounded-5 ml-3 lifted"
            size="lg"
            @click="getMemberTreeData(userIdData, depth, true)"
            data-qa="genealogy-placement-network-tree-back-to-main-tree-btn"
          >
            <icon name="eshop-back" class="mr-2 icon-size-0"></icon>
            <span>{{ $t('Genealogy.PlacementTreeDiagram.Search.MyPlacementTree') }}</span>
          </b-button>
        </div>
        <div
          v-if="!fromMobile"
          id="zoomController"
          class="mt-2 d-inline-flex bg-white rounded-4 placement-network-tree-zoom"
          :class="{ 'on-mobile': userIdData !== null, 'placement-network-tree-zoom-custom': fullScreenView }"
        >
          <img
            :src="zoominIcon"
            id="zoomingclick"
            class="btn btn-sucess px-0 py-0 ml-0 c-pointer"
            data-qa="genealogy-placement-network-tree-zoom-in-btn"
          />
          <label class="mx-2 col-5 pt-2">
            {{ $t('Genealogy.PlacementNetworkTree.Zoom') }}
          </label>
          <img
            :src="zoomoutIcon"
            id="zoomoutclick"
            class="btn btn-sucess px-0 py-0 ml-0 c-pointer"
            data-qa="genealogy-placement-network-tree-zoom-out-btn"
          />
        </div>
        <div class="vh-50 d-flex justify-content-center align-items-center" v-if="!treeDiagram">
          <h3 v-if="searchMember !== '' && searchedMemberId === null">
            {{ $t('Genealogy.SponsorNetworkTree.Search.DownlineNotFound') }}
          </h3>
          <b-row>
            <b-col class="text-center">
              {{ getGenealogyErrorMessage }}
            </b-col>
          </b-row>
        </div>
      </div>
      <b-modal ref="placementTreeModal" class="eshop-model" ok-only size="sm" hide-header centered>
        <h5>{{ $t('Genealogy.PlacementTreeDiagram.ErrorLoading') }}</h5>
      </b-modal>
      <image-viewer-modal
        id="eshop-tree"
        :title="$t('Genealogy.PlacementTreeDiagram.Legend')"
        :image-path="PlacementNetworkLegend"
        :no-close-on-backdrop="false"
        ref="legendModel"
      />
    </div>
  </div>
</template>

<script>
import { mapGetters, mapActions } from 'vuex'
import d3 from 'd3'
import moment from 'moment'
import EshopAutocomplete from '@/app/_global/components/elements/EshopAutocomplete'
import helpers from '@/helpers'
import constants from '@/config/const'
import { setDefaultToken } from '@/store/utils/api'
import ImageViewerModal from '@/app/_global/components/elements/ImageViewerModal'
import Const from '@/config/const'

export default {
  name: 'PlacementNetworkTree',
  props: {
    userIdData: {
      type: Number,
      default: null,
    },
    token: {
      type: String,
      default: null,
    },
    depth: {
      type: String,
      default: null,
    },
    selectedId: {
      type: String,
      default: null,
    },
    showOuter: {
      type: String,
      default: null,
    },
    fullScreenView: {
      type: Boolean,
      default: false,
    },
    showToolbar: {
      type: Boolean,
      default: true,
    },
    hasExternalRootTreeData: {
      type: Boolean,
      default: false,
    },
    enableDirectEnrol: {
      type: Boolean,
      default: true,
    },
  },
  $_veeValidate: {
    validator: 'new',
  },
  components: {
    ImageViewerModal,
    EshopAutocomplete,
  },
  beforeRouteEnter(to, from, next) {
    if (to.query.token !== undefined) {
      setDefaultToken(to.query.token)
    }
    next(vm => {
      // access to component instance via `vm`
    })
  },
  data() {
    return {
      PlacementNetworkLegend: Const.constLinks.PLACEMENT_NETWORK_LEGEND,
      zoominIcon: '/static/misc/icn-zoomin.png',
      zoomoutIcon: '/static/misc/icn-zoomout.png',
      scrolldownIcon: '/static/misc/icn-to-bottom.png',
      scrollupIcon: '/static/misc/icn-to-up.png',
      updatedAt: '08 Sept 2017, 09.08 AM',
      searchMember: '',
      tempSearchMember: '',
      searchStatus: false,
      viewIboId: '',
      viewIboName: '',
      selectedDepth: 5,
      depthOptions: [
        { value: 5, text: this.$t('Genealogy.Level', { level: 5 }) },
        { value: 10, text: this.$t('Genealogy.Level', { level: 10 }) },
        { value: 11, text: this.$t('Genealogy.Level', { level: 11 }) },
        { value: 12, text: this.$t('Genealogy.Level', { level: 12 }) },
        { value: 13, text: this.$t('Genealogy.Level', { level: 13 }) },
        { value: 14, text: this.$t('Genealogy.Level', { level: 14 }) },
        { value: 15, text: this.$t('Genealogy.Level', { level: 15 }) },
        { value: 16, text: this.$t('Genealogy.Level', { level: 16 }) },
        { value: 17, text: this.$t('Genealogy.Level', { level: 17 }) },
        { value: 18, text: this.$t('Genealogy.Level', { level: 18 }) },
        { value: 19, text: this.$t('Genealogy.Level', { level: 19 }) },
        { value: 20, text: this.$t('Genealogy.Level', { level: 20 }) },
        { value: 50, text: this.$t('Genealogy.Level', { level: 50 }) },
      ],
      treeDataSource: null,
      rootTreeData: {},
      treeDiagram: false,
      treeSearchFunctions: false,
      treeMore: false,
      icon: '',
      erIcon: '',
      scrollStatus: false,
      showBackRoot: false,
      showScroll: true,
      searchedMemberId: null,
      sponsorIboId: null,
      fromMobile: false,
      mobileType: '',
      teamBonusRankMap: new Map([
        ['DRT', 'drt'],
        ['2SDRT', '2sdrt'],
        ['3SDRT', '3sdrt'],
        ['DM', 'dm'],
        ['2SDM', '2sdm'],
        ['3SDM', '3sdm'],
        ['PSD', 'psd'],
        ['2PSD', '2spsd'],
        ['3PSD', '3spsd'],
        ['CRO', 'cro'],
        ['2CRO', '2scro'],
        ['3CRO', '3scro'],
      ]),
      tvcRankCodeMap: new Map([
        ['TVC10', 'rnk-10-'],
        ['TVC15', 'rnk-15-'],
        ['TVC20', 'rnk-20-'],
      ]),
    }
  },
  methods: {
    ...mapActions([
      'getMemberTreeActionGenealogy',
      'getMembersOuterTreeActionGenealogy',
      'getMemberSearchTreeActionGenealogy',
      'searchDownlineTreeActionGenealogy',
      'clearSearchTreeResult',
      'searchMemberListExcludeSelf',
      'searchMemberSponsor',
      'loadMemberDashboard',
      'isMobile',
      'getMobileDeviceType',
    ]),
    handleListItem(obj) {
      this.searchStatus = false
      this.showBackRoot = true
      this.tempSearchMember = obj.name
      this.searchedMemberId = obj.id
      this.getMemberTreeData(obj.id)
    },
    searchDownline(val) {
      this.searchedMemberId = val.user_id
      this.tempSearchMember = val.name
      this.handleListItem({ id: val.user_id, name: val.name })
    },
    // tree data
    getMemberTreeData(inputUserId = null, inputDepth = null, backToRoot = false) {
      let data = {
        user_id: inputUserId === null ? this.getLoggedInUser.member.user_id : inputUserId,
        depth: inputDepth === null ? this.selectedDepth : inputDepth,
      }
      this.getMemberTreeActionGenealogy(data).then(res => {
        if (res) {
          this.treeSearchFunctions = true
          this.treeDiagram = true
          this.rootTreeData = this.getMemberTreeDataTemp
          if (backToRoot) {
            this.showBackRoot = false
            this.searchedMemberId = null
            this.searchStatus = false
            this.searchMember = ''
            this.searchMemberListExcludeSelf('')
          }
        } else {
          this.treeSearchFunctions = false
          this.treeDiagram = false
          this.rootTreeData = {}
        }
      })
    },

    // get more tree data from last depth level
    getMoreTreeData(d) {
      let input = {
        depth: this.selectedDepth,
        user_id: d.parent.member[0].user_id === null ? this.getLoggedInUser.member.user_id : d.parent.member[0].user_id,
      }
      this.getMemberTreeActionGenealogy(input).then(res => {
        if (res) {
          this.showBackRoot = true
          this.tempSearchMember = d.parent.member[0].name
          this.searchedMemberId = d.parent.member[0].user.old_member_id
          this.treeSearchFunctions = true
          this.treeDiagram = true
          this.treeMore = true
          this.rootTreeData = this.getMemberTreeDataTemp
        }
      })
    },

    // draw tree diagram
    renderTreeGraph: function(data) {
      let that = this
      // assign data to root value
      var root = JSON.parse(JSON.stringify(data))
      var level = this.selectedDepth

      var getRootUpdate = this.getMoreTreeData

      var zm
      var duration = 750
      var rectW = 200
      var rectH = 80

      var w = window
      var d = document
      var e = d.documentElement
      var g = d.getElementsByTagName('#memberTreeDiagram')[0]
      var x = w.innerWidth || e.clientWidth || g.clientWidth
      var y = w.innerHeight || e.clientHeight || g.clientHeight
      var width = 960
      var height = this.fromMobile ? 1500 : w.screen.height

      if (this.fullScreenView) {
        height = 2000
      }

      if (typeof root.user_id !== 'undefined') {
        var tree = d3.layout
          .tree()
          .nodeSize([180, 75])
          .separation(function separation(a, b) {
            return a.parent === b.parent ? 1 : 1
          })
        var svg = d3
          .select('#memberTreeDiagram')
          .append('svg')
          .attr('preserveAspectRatio', 'xMinYMin meet')
          .attr('viewBox', '0 0 ' + width + ' ' + height)
          .call(
            (zm = d3.behavior
              .zoom()
              .scaleExtent([0.2, 2.5])
              .on('zoom', redraw))
          )
          .append('g')
          .attr('transform', `translate(${400},${this.fromMobile ? 200 : 100})scale(${1.0})`)

        // necessary so that zoom knows where to zoom and un zoom from
        zm.translate([400, 40])

        // Define the div for the tooltip
        var div = d3
          .select('#memberTreeDiagram')
          .append('div')
          .attr('class', 'tooltip')
          .style('opacity', 0)

        if (that.fromMobile) {
          d3.select('#memberTreeDiagram').style('height', '1500px')
        }

        update(root)
      }

      // update sources
      function update(source) {
        // Compute the new tree layout.
        var nodes = tree.nodes(root).reverse()
        var links = tree.links(nodes)

        // Normalize for fixed-depth.
        nodes.forEach(function(d) {
          d.y = d.depth * 120
        })

        // Update the nodes…
        var node = svg.selectAll('g.node').data(nodes)

        // Enter any new nodes at the parent's previous position.
        var nodeEnter = node
          .enter()
          .append('g')
          .attr('class', 'node')
          .style('fill', function(d) {
            if (typeof d.member !== 'undefined' && d.member !== null) {
              if (typeof d.member[0].status !== 'undefined') {
                return 'white'
              } else {
                return 'var(--gray-light-extra)'
              }
            } else {
              return 'var(--gray-light-extra)'
            }
          })

        if (!that.$appSettings.evo.enable) {
          nodeEnter
            .append('image')
            .attr('x', -130)
            .attr('y', 0)
            .attr('width', 60)
            .attr('height', 45)
            .attr('class', function(d) {
              if (d.depth === 0 && d.user_id !== (that.getLoggedInUser.id || that.userIdData)) {
                return 'rotate-c-180'
              }
              return 'd-none'
            })
            .attr('xlink:href', function(d) {
              if (d.depth === 0 && d.user_id !== that.getLoggedInUser.id) {
                return require(`@/assets/tree/icons/new_rank/arrow-down.png`)
              }
            })
            .on('click', function(d) {
              if (d.depth === 0 && d.user_id !== that.getLoggedInUser.id && d.placement_parent_user_id) {
                that.getMemberTreeData(d.placement_parent_user_id)
              }
            })
        }

        nodeEnter
          .append('rect')
          .attr('width', rectW)
          .attr('height', rectH)
          .attr('x', function(d) {
            return d.children || d._children ? 0 : 0
          })
          .attr('y', function(d) {
            return d.children || d._children ? 10 : 10
          })
          .attr('rx', 10)
          .attr('ry', 10)
          .attr('class', function(d) {
            if (typeof d.member === 'undefined' || d.member === '') {
              return 'emptyNodeIcn'
            }
          })
          .style('position', 'absolute')
          .style('z-index', 1)
          .on('mousemove', function(d) {
            onMouseMoveEvent(d)
          })
          .on('mouseout', function() {
            // Remove the info text on mouse out.
            div
              .transition()
              .duration(200)
              .style('opacity', 0)
          })
        nodeEnter
          .append('image')
          .attr('x', 70)
          .attr('y', 15)
          .attr('width', 60)
          .attr('height', 45)
          .attr('class', function(d) {
            if (typeof d.member === 'undefined' || d.member === '') {
              return 'emptyNodeIcn '
            }
          })
          .attr('xlink:href', function(d) {
            if (d.depth === level) {
              this.icon = 'arrow-down'
            } else {
              this.icon = 'add-enrol'
            }

            if (helpers.getValue(d, 'member').length > 0) {
              const rankData = d.member[0]
              let memberStatus = helpers.getValue(rankData, 'status.title')
              let enrolmentRankCode = helpers.getValue(rankData, 'enrollment_rank.rank_code', '').toUpperCase()
              let highestRankCode = helpers.getValue(rankData, 'highest_rank.rank_code', '').toUpperCase()

              // Check If the Member Fall Under Our Sponsor
              if (memberStatus) {
                // Check Member Status (Active, Expired, Suspended, Terminated/Resign)
                if (memberStatus === constants.masterData.MEMBER_STATUS_ACTIVE) {
                  this.icon = that.classifyMemberEnrolmentRank(
                    memberStatus,
                    d.is_active_ba,
                    enrolmentRankCode,
                    highestRankCode
                  )
                } else if (memberStatus === constants.masterData.MEMBER_STATUS_EXPIRED) {
                  this.icon = 'rnk-expired'
                } else if (memberStatus === constants.masterData.MEMBER_STATUS_SUSPENDED) {
                  this.icon = 'rnk-suspended'
                } else {
                  this.icon = 'rnk-terminated-resigned'
                }
              } else {
                this.icon = that.classifyMemberEnrolmentRank(
                  memberStatus,
                  d.is_active_ba,
                  enrolmentRankCode,
                  highestRankCode
                )
              }
            }

            try {
              return require(`@/assets/tree/icons/new_rank/${this.icon}.png`)
            } catch {
              return require(`@/assets/tree/icons/new_rank/rnk-unknown.png`)
            }
          })
          .on('mousemove', function(d) {
            onMouseMoveEvent(d)
          })
          .on('mouseout', function() {
            // Remove the info text on mouse out.
            div
              .transition()
              .duration(200)
              .style('opacity', 0)
          })
          .on('click', d => {
            if (!helpers.isEmpty(d, 'parent.member') && that.enableDirectEnrol) {
              if (d.member === undefined) {
                if (d.depth === level) {
                  getRootUpdate(d)
                } else {
                  // Todo this section removed temporally
                  // Todo https://elkengit.atlassian.net/browse/GST-2345
                  // let leg = d.parent.children[0].x === d.x ? 1 : 2
                  // let toEnrolment = that.$router.resolve({
                  //   name: 'New Enrolment',
                  //   params: { sponsorID: d.parent.member[0].user.old_member_id, leg: leg },
                  // })
                  // if (that.fromMobile) {
                  //   var result = {
                  //     ibo_id: d.parent.member[0].user.old_member_id.toString(),
                  //     user_id: d.parent.member[0].user.id,
                  //     name: d.parent.member[0].user.name,
                  //     ic_passport_number: d.parent.member[0].ic_passport_number,
                  //     leg: leg,
                  //   }
                  //   if (that.mobileType === 'ios') {
                  //     if (
                  //       window.webkit === undefined ||
                  //       window.webkit.messageHandlers === undefined ||
                  //       window.webkit.messageHandlers.newEnrol === undefined
                  //     ) {
                  //       window.open(toEnrolment.href, '_blank')
                  //     } else {
                  //       window.webkit.messageHandlers.newEnrol.postMessage(JSON.stringify(result))
                  //     }
                  //   } else if (that.mobileType === 'android') {
                  //     if (window.nativeMethod === undefined || window.nativeMethod.newEnrol === undefined) {
                  //       window.open(toEnrolment.href, '_blank')
                  //     } else {
                  //       window.nativeMethod.newEnrol(JSON.stringify(result))
                  //     }
                  //   } else {
                  //     window.open(toEnrolment.href, '_blank')
                  //   }
                  // } else {
                  //   window.open(toEnrolment.href, '_blank')
                  // }
                }
              }
            }
          })

        nodeEnter
          .append('text')
          .attr('font-size', '11px')
          .attr('x', 100)
          .attr('y', 80)
          .attr('dy', '.35em')
          .attr('class', 'about name')
          .attr('text-anchor', 'middle')
          .text(function(d) {
            if (typeof d.member !== 'undefined' && d.member !== null) {
              return d.member[0].name
            } else {
              return ''
            }
          })
          .on('mousemove', function(d) {
            onMouseMoveEvent(d)
          })
          .on('mouseout', function() {
            // Remove the info text on mouse out.
            div
              .transition()
              .duration(200)
              .style('opacity', 0)
          })

        nodeEnter
          .append('text')
          .attr('x', 100)
          .attr('y', 65)
          .attr('dy', '.35em')
          .attr('class', 'about code')
          .attr('text-anchor', 'middle')
          .text(function(d) {
            // Remove member IBO ID if the downline is not direct sponsored by the distributor
            if (typeof d.member !== 'undefined' && d.member.length > 0 && typeof d.member[0].status !== 'undefined') {
              return d.member[0].country.code + '-' + d.member[0].user.old_member_id
            } else {
              return ''
            }
          })
          .on('mousemove', function(d) {
            onMouseMoveEvent(d)
          })
          .on('mouseout', function() {
            // Remove the info text on mouse out.
            div
              .transition()
              .duration(200)
              .style('opacity', 0)
          })

        // Transition nodes to their new position.
        var nodeUpdate = node
          .transition()
          .duration(duration)
          .attr('transform', function(d) {
            return 'translate(' + d.x + ',' + d.y + ')'
          })

        nodeUpdate
          .select('rect')
          .attr('width', function(d) {
            if (typeof d.member !== 'undefined' && d.member !== '') {
              return rectW
            } else {
              return '0'
            }
          })
          .attr('height', function(d) {
            if (typeof d.member !== 'undefined' && d.member !== '') {
              return rectH
            } else {
              return '0'
            }
          })
          .attr('stroke', 'white')
          .attr('stroke-width', function(d) {
            if (typeof d.member !== 'undefined' && d.member !== '') {
              return '1'
            } else {
              return '0'
            }
          })

        nodeUpdate.select('text').style('fill-opacity', 1)

        // Transition exiting nodes to the parent's new position.
        var nodeExit = node
          .exit()
          .transition()
          .duration(duration)
          .attr('transform', function(d) {
            return 'translate(' + source.x + ',' + source.y + ')'
          })
          .remove()

        nodeExit
          .select('rect')
          .attr('width', rectW)
          .attr('height', rectH)
          .attr('stroke', 'white')
          .attr('stroke-width', function(d) {
            if (typeof d.member !== 'undefined' && d.member !== '') {
              return '1'
            } else {
              return '0'
            }
          })

        nodeExit.select('text')

        // Update the links
        var link = svg.selectAll('path.link').data(links)
        // Enter any new links at the parent's previous position.
        link
          .enter()
          .insert('path', 'g')
          .attr('class', 'link')
          .attr('fill', 'transparent')
          .attr('stroke', 'gray')
          .attr('stroke-width', 0.5)
          .attr('x', rectW / 2)
          .attr('y', rectH / 2)
          .attr('d', elbow)
          .attr('rx', function(d) {
            return Math.abs(d.target.x - d.source.x) / 2
          })

        // Transition links to their new position.
        link
          .transition()
          .duration(duration)
          .attr('d', elbow)

        // Transition exiting nodes to the parent's new position.
        link
          .exit()
          .transition()
          .duration(duration)
          .attr('d', elbow)
          .remove()
      }

      function onMouseMoveEvent(d) {
        if (d.member !== undefined && d.member !== null && d.member[0].status !== undefined) {
          if (that.fromMobile) {
            if (that.mobileType === 'ios') {
              if (
                window.webkit === undefined ||
                window.webkit.messageHandlers === undefined ||
                window.webkit.messageHandlers.memberDetails === undefined
              ) {
                getMemberHoverDetails(d)
              } else {
                window.webkit.messageHandlers.memberDetails.postMessage(JSON.stringify(collectMemberHoverDetails(d)))
              }
            } else if (that.mobileType === 'android') {
              if (window.nativeMethod === undefined || window.nativeMethod.memberDetails === undefined) {
                getMemberHoverDetails(d)
              } else {
                window.nativeMethod.memberDetails(JSON.stringify(collectMemberHoverDetails(d)))
              }
            } else {
              getMemberHoverDetails(d)
            }
          } else {
            getMemberHoverDetails(d)
          }
        }
      }

      function getMemberHoverDetails(d) {
        var left = d3.event.clientX + 30
        var top = d3.event.clientY - 120

        var screenWidth = document.documentElement.clientWidth
        var screenHeight = document.documentElement.clientHeight
        if (left + 240 > screenWidth) {
          left = screenWidth - 240 - 20
        }
        if (top + 500 > screenHeight) {
          if (screenHeight > 430) {
            top = screenHeight - 430
          } else {
            top = 50
          }
        }
        div
          .transition()
          .duration(200)
          .style('opacity', 1)
        var view = ''
        collectMemberHoverDetails(d).forEach(data => {
          view +=
            '<div class="member-hover-details"><span class="member-label">' +
            data.title +
            '</span><span class="member-label-data">' +
            data.value +
            '</span></div>'
        })
        div
          .html(`<div class="member-details">` + view + `</div>`)
          .style('left', left + 'px')
          .style('top', top + 'px')
      }

      function collectMemberHoverDetails(d) {
        let payLeg = ''
        let powerLeg = ''
        let carryForward = ''
        if (d.gcv_details !== undefined && d.gcv_details.length > 0) {
          d.gcv_details.forEach(item => {
            let cv =
              Math.round(item.gcv) + Math.round(item.gcv_bring_forward) + Math.round(item.optimising_personal_sales)
            let location = item.gcv_bring_forward_position === 1 ? '(L)' : '(R)'
            if (item.gcv_leg_group === 'PAY') {
              payLeg = cv + ' ' + location
            }
            if (item.gcv_leg_group === 'POWER') {
              powerLeg = cv + ' ' + location
              carryForward = Math.round(item.gcv_bring_forward) + ' ' + location
            }
          })
        }
        return [
          {
            title: that.$t('Common.IboId'),
            value: d.member[0].user.old_member_id,
          },
          {
            title: that.$t('Common.IboName'),
            value: d.member[0].user.name,
          },
          {
            title: that.$t('Genealogy.PlacementTreeDiagram.PopupDetail.MembershipStatus'),
            value:
              d.member[0].status.title === 'Active'
                ? that.$t('Genealogy.PlacementTreeDiagram.PopupDetail.MembershipStatus.Valid')
                : d.member[0].status.title,
          },
          {
            title: that.$t('Common.JoinDate'),
            value: d.member[0].join_date,
          },
          {
            title:
              that.$t('Genealogy.PlacementTreeDiagram.PopupDetail.CW') +
              ' ' +
              d.member[0].sale_activity_status_cw.current_cw.cw_name,
            value: d.member[0].sale_activity_status_cw.current_cw.status.title,
          },
          {
            title:
              that.$t('Genealogy.PlacementTreeDiagram.PopupDetail.CW') +
              ' ' +
              d.member[0].sale_activity_status_cw.previous_cw.cw_name,
            value: d.member[0].sale_activity_status_cw.previous_cw.status.title,
          },
          {
            title: that.$t('Common.MembershipType'),
            value: helpers.getValue(d, 'member[0].enrollment_rank.rank_code', '-'),
          },
          {
            title: that.$t('Common.HighestRank'),
            value: d.member[0].highest_rank !== null ? d.member[0].highest_rank.rank_name : '-',
          },
          {
            title: that.$t('Common.Terminology.PaidAsRank'),
            value: d.member[0].effective_rank !== null ? d.member[0].effective_rank.rank_name : '-',
          },
          {
            title: that.$t('Common.Terminology.PersonalSalesPV'),
            value: d.member[0].personal_sales_cv !== null ? d.member[0].personal_sales_cv : 0,
          },
          {
            title: that.$t('Genealogy.PlacementTreeDiagram.PopupDetail.CFwdPowerLegCV'),
            value: carryForward,
          },
          {
            title: that.$t('Genealogy.PlacementTreeDiagram.PopupDetail.PowerLegGCV'),
            value: powerLeg,
          },
          {
            title: that.$t('Genealogy.PlacementTreeDiagram.PopupDetail.PayLegGCV'),
            value: payLeg,
          },
        ]
      }

      // Redraw for zoom
      function redraw() {
        svg.attr('transform', 'translate(' + d3.event.translate + ')' + ' scale(' + d3.event.scale + ')')
      }

      function elbow(d, i) {
        return (
          'M' +
          (d.source.x + 100) +
          ',' +
          d.source.y +
          'V' +
          d.target.y +
          'H' +
          (d.target.x + 100) +
          (d.target.children ? '' : 'v' + 15)
        )
      }

      function updateWindow() {
        x = w.innerWidth || e.clientWidth || g.clientWidth
        y = w.innerHeight || e.clientHeight || g.clientHeight
        if (svg !== undefined) {
          svg.attr('width', x).attr('height', y)
        }
      }

      // Handler for zooming button
      function zoomClick() {
        var direction = 1
        var factor = 0.2
        var targetZoom = 1
        var center = [width / 2, height / 6]
        var extent = zm.scaleExtent()
        var translate = zm.translate()
        var translate0 = []
        var l = []
        var view = { x: translate[0], y: translate[1], k: zm.scale() }

        direction = this.id === 'zoomingclick' ? 1 : -1
        targetZoom = zm.scale() * (1 + factor * direction)
        if (targetZoom < extent[0] || targetZoom > extent[1]) {
          return false
        }
        translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k]
        view.k = targetZoom
        l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y]

        view.x += center[0] - l[0]
        view.y += center[1] - l[1]
        interpolateZoom([view.x, view.y], view.k)
      }

      function interpolateZoom(translate, scale) {
        return d3
          .transition()
          .duration(350)
          .tween('zoom', function() {
            var iTranslate = d3.interpolate(zm.translate(), translate)
            var iScale = d3.interpolate(zm.scale(), scale)
            return function(t) {
              zm.scale(iScale(t)).translate(iTranslate(t))
              zoomed()
            }
          })
      }

      function zoomed() {
        svg.attr('transform', 'translate(' + zm.translate() + ')' + 'scale(' + zm.scale() + ')')
      }

      d3.select('#zoomingclick').on('click', zoomClick)
      d3.select('#zoomoutclick').on('click', zoomClick)
      // -
      window.onresize = updateWindow
    },
    classifyMemberEnrolmentRank(memberStatus, baStatus, enrolmentRank, highestRank) {
      let rankIconName = ''
      if (enrolmentRank === 'PREFERRED CUSTOMER') {
        rankIconName = 'rnk-pc'
      } else {
        // Check if a Member is an Active BA or a Member who doesn't fall under Our Sponsor
        if (baStatus === 1 || !memberStatus) {
          // Check if HighestRank and EnrolmentRank not equals to null / '' / undefined
          if (!!highestRank && !!enrolmentRank) {
            //Set Rank Icon
            let rank = this.tvcRankCodeMap.get(enrolmentRank)
            let entitlement = this.teamBonusRankMap.get(highestRank)

            if (!!rank && !!entitlement) {
              rankIconName = rank + entitlement
            } else if (highestRank === 'BA') {
              rankIconName = 'rnk-ba-active'
            } else {
              // Not under Our Sponsor
              rankIconName = 'icn-watermark'
            }
          }
        } else {
          rankIconName = 'rnk-inactive'
        }
      }
      return rankIconName
    },
    getOuterMember(outerType) {
      let self = this
      let inputData = {
        user_id:
          this.showBackRoot && this.searchedMemberId !== null
            ? this.searchedMemberId
            : this.userIdData !== null
            ? this.userIdData
            : this.getLoggedInUser.member.user_id,
        depth: this.selectedDepth,
        outer: outerType,
      }
      this.getMembersOuterTreeActionGenealogy(inputData).then(async res => {
        if (res && !helpers.getValue(self.getMemberTreeDataTemp, 'errors.message')) {
          self.treeSearchFunctions = true
          self.treeDiagram = true
          self.treeMore = true
          self.showBackRoot = true
          self.rootTreeData = self.getMemberTreeDataTemp
        } else {
          self.treeSearchFunctions = false
          self.treeDiagram = false
          self.treeMore = false
          self.showBackRoot = false
          self.rootTreeData = []
          await self
            .$swal({
              title:
                helpers.getValue(self.getMemberTreeDataTemp, 'errors.message') ||
                self.$t('Genealogy.PlacementTreeDiagram.ErrorLoading'),
              type: helpers.getValue(self.getMemberTreeDataTemp, 'errors.message') ? 'info' : 'error',
            })
            .then(() => {
              self.getMemberTreeData(self.userIdData, self.depth, true)
            })
        }
      })
    },
    handleSelectedDepth(value) {
      this.selectedDepth = value
      if (this.searchedMemberId !== null) {
        this.getMemberTreeData(this.searchedMemberId)
      } else {
        this.getMemberTreeData()
      }
    },
    hidePopover() {
      this.searchStatus = false
      this.searchedMemberId = null
      this.tempSearchMember = ''
    },
    showLegends() {
      this.$bvModal.show('eshop-tree')
    },
    newclick(id) {
      return id
    },
  },
  mounted() {
    if (this.hasExternalRootTreeData) {
      this.renderTreeGraph(this.getMemberTreeDataTemp)
    } else {
      if (this.userIdData === null) {
        this.searchMemberListExcludeSelf('')
        this.getMemberTreeData()
      } else {
        this.searchedMemberId = this.selectedId
        if (this.selectedId !== null && this.selectedId !== '') {
          if (this.showOuter !== null && this.showOuter !== '') {
            this.getOuterMember(this.showOuter)
          } else {
            this.searchDownline({ user_id: this.selectedId, name: '' })
          }
        } else {
          if (this.showOuter !== null && this.showOuter !== '') {
            this.getOuterMember(this.showOuter)
          } else {
            this.getMemberTreeData(this.userIdData, this.depth)
          }
        }
      }
      this.renderTreeGraph(this.rootTreeData)
      this.sponsorIboId = this.getLoggedInUser.old_ibs_user_id || this.getLoggedInUser.old_member_id
      this.loadMemberDashboard().then(() => {
        this.updatedAt = moment(this.getDashboardUpdatedAt).format('DD/MM/YYYY LTS')
      })
    }
  },
  created() {
    this.isMobile().then(mobile => {
      this.fromMobile = mobile
      this.getMobileDeviceType().then(type => {
        this.mobileType = type
      })
    })
    window.onscroll = e => {
      let container = document.getElementById('memberTreeDiagram')
      if (container !== null && window.pageYOffset > container.scrollHeight - 20) {
        window.pageYOffset = container.scrollHeight / 2
      }
    }
  },
  watch: {
    rootTreeData: function(val) {
      jQuery('#memberTreeDiagram').empty()
      this.renderTreeGraph(val)
    },
  },
  computed: {
    ...mapGetters([
      'getMemberTreeDataTemp',
      'getLoggedInUser',
      'getMemberSearchGenealogy',
      'isLoading',
      'getGenealogyErrorMessage',
      'getMemberList',
      'getMemberDashboard',
      'getDashboardUpdatedAt',
    ]),
    diagramClasses() {
      let classes = []
      if (!this.fromMobile && !this.fullScreenView) {
        classes = ['border']
      }

      return classes
    },
  },
}
</script>
