<template>
  <div>
    <Row class="artifact-management">
      <Col span="6">
        <span style="margin-right: 10px">{{ $t('system') }}</span>
        <Select
          filterable
          clearable
          @on-change="onSystemDesignSelect"
          @on-clear="onClearDesignSelect"
          v-model="systemVersion"
          label-in-name
          style="width: 85%;"
        >
          <Option v-for="item in systems" :value="item.guid" :key="item.guid">{{ item.key_name }}</Option>
        </Select>
      </Col>
      <Col span="3">
        <Button type="info" @click="querySysTree">{{ $t('query') }}</Button>
      </Col>
    </Row>
    <div v-show="showDefaultTabs" style="margin: 10px 0">
      <Tabs type="card" :value="currentTab" :closable="false" @on-click="handleTabClick">
        <TabPane :label="$t('application_logic_diagram')" name="logic-graph" :index="1">
          <Spin size="large" fix v-if="spinShow">
            <Icon type="ios-loading" size="44" class="spin-icon-load"></Icon>
            <div>{{ $t('loading') }}</div>
          </Spin>
          <!-- <div v-else-if="!appLogicData.length" class="no-data">
            {{ $t('no_data') }}
          </div> -->
          <Alert show-icon closable v-if="isDataChanged">
            Data has beed changed, click Reload button to reload graph.
            <Button slot="desc" @click="reloadHandler">Reload</Button>
          </Alert>
          <div v-show="showApplicationDeploymentComponent">
            <ApplicationDeploymentComponent ref="applicationDeploymentComponent"></ApplicationDeploymentComponent>
          </div>
          <div v-if="!showApplicationDeploymentComponent" class="no-data">
            {{ $t('no_data') }}
          </div>
        </TabPane>
        <TabPane :label="$t('application_logic_tree_diagram')" name="logic-tree-graph" :index="2">
          <Alert show-icon closable v-if="isDataChanged">
            Data has beed changed, click Reload button to reload graph.
            <Button slot="desc" @click="reloadHandler">Reload</Button>
          </Alert>

          <div v-show="showApplicationLogicTree" class="graph-container" id="graphTree">
            <Spin size="large" fix v-if="treeSpinShow">
              <Icon type="ios-loading" size="44" class="spin-icon-load"></Icon>
              <div>{{ $t('loading') }}</div>
            </Spin>
          </div>
        </TabPane>
        <TabPane
          v-for="ci in tabList"
          :key="ci.id"
          :name="ci.id"
          :label="ci.name"
          v-if="isShowTabs"
          :index="ci.seqNo + 3"
        >
          <CMDBTable
            :tableData="ci.tableData"
            :tableOuterActions="ci.outerActions"
            :tableInnerActions="ci.innerActions"
            :tableColumns="ci.tableColumns"
            :pagination="ci.pagination"
            :ascOptions="ci.ascOptions"
            :showCheckbox="needCheckout"
            :isRefreshable="true"
            @actionFun="actionFun"
            @sortHandler="sortHandler"
            @handleSubmit="handleSubmit"
            @getSelectedRows="onSelectedRowsChange"
            @pageChange="pageChange"
            @pageSizeChange="pageSizeChange"
            @confirmAddHandler="confirmAddHandler"
            @confirmEditHandler="confirmEditHandler"
            tableHeight="650"
            :ref="'table' + ci.id"
          ></CMDBTable>
        </TabPane>
      </Tabs>
    </div>
  </div>
</template>

<script>
import * as d3 from 'd3-selection'
// eslint-disable-next-line no-unused-vars
import * as d3Graphviz from 'd3-graphviz'
import {
  getDeployCiData,
  getDeployDesignTabs,
  getCiTypeAttributes,
  deleteCiDatas,
  createCiDatas,
  updateCiDatas,
  getSystems,
  getEnumCodesByCategoryId,
  getAllDeployTreesFromSystemCi,
  startProcessInstancesWithCiDataInbatch,
  getAllCITypes,
  operateCiState,
  getIdcImplementTreeByGuid,
  getAllZoneLinkGroupByIdc,
  queryCiData
} from '@/api/server.js'
import { pagination, components, newOuterActions } from '@/const/actions.js'
import { resetButtonDisabled } from '@/const/tableActionFun.js'
import { formatData } from '../util/format.js'
import { getExtraInnerActions } from '../util/state-operations.js'
import PhysicalGraph from './physical-graph'
import { colors, stateColor } from '../../const/graph-configuration'
import ApplicationDeploymentComponent from '@/pages/designing/application-deployment-component'
import {
  VIEW_CONFIG_PARAMS,
  UNIT_ID,
  BUSINESS_APP_INSTANCE_ID,
  INVOKE_ID,
  INVOKE_UNIT,
  INVOKED_UNIT
} from '@/const/init-params.js'
import { baseURL } from '@/api/base.js'

export default {
  components: {
    PhysicalGraph,
    ApplicationDeploymentComponent
  },
  data () {
    return {
      initParams: {},
      isShowTabs: false,
      systems: [],
      systemVersion: '',
      env: '',
      currentTab: 'logic-graph',
      selectedDeployItems: [],
      graphSource: [],
      graphs: {},
      showDefaultTabs: false,
      tabList: [],
      payload: {
        filters: [],
        pageable: {
          pageSize: 10,
          startIndex: 0
        },
        paging: true
      },
      spinShow: false,
      graph: {},
      systemData: [],
      systemLines: {},
      graphNodes: {},
      physicalGraphData: [],
      physicalGraphLinks: [],
      serviceCiTypeId: '',
      invokeCiTypeId: '',
      instanceCiTypeId: '',
      isDataChanged: false,
      physicalSpin: false,
      graphTree: {},
      allCiTypes: {},
      systemTreeData: [],
      rankNodes: {},
      treeSpinShow: true,
      copyRows: [],
      copyEditData: null,
      isHandleNodeClick: false,
      instancesInUnit: {},
      showApplicationDeploymentComponent: false,
      showApplicationLogicTree: false
    }
  },
  computed: {
    tableRef () {
      return 'table' + this.currentTab
    },
    needCheckout () {
      return this.$route.name !== 'ciDataEnquiry'
    }
  },
  watch: {
    currentTab () {
      this.copyRows = []
      this.copyEditData = null
    }
  },
  methods: {
    initADGraph () {
      this.spinShow = true
      const initEvent = () => {
        let graph = d3.select('#graph')

        graph
          .on('dblclick.zoom', null)
          .on('wheel.zoom', null)
          .on('mousewheel.zoom', null)
        const width = ((window.innerWidth - 60) / 24) * 16 - 40
        this.graph.graphviz = graph
          .graphviz()
          .width(width)
          .height(window.innerHeight - 260)
          .zoom(true)
          .fit(true)
      }

      initEvent()
      this.renderADGraph(this.systemData)
      this.spinShow = false
    },
    renderADGraph (data) {
      let nodesString = this.genADDOT(data)
      this.graph.graphviz.transition().renderDot(nodesString)
      let svg = d3.select('#graph').select('svg')
      let width = svg.attr('width')
      let height = svg.attr('height')
      svg.attr('viewBox', '0 0 ' + width + ' ' + height)
    },
    genADDOT (data) {
      this.graphNodes = {}
      if (!data.length) {
        return 'digraph G{}'
      }
      let width = 16
      let height = 12
      let dots = [
        'digraph G{',
        'rankdir=LR;nodesep=0.5;',
        'Node[fontname=Arial,fontsize=12,shape=box,style=filled];',
        'Edge[fontname=Arial,minlen="1",fontsize=12,labeldistance=1.5];',
        `size="${width},${height}";`,
        `subgraph cluster_${data[0].guid}{`,
        `style="filled";color="${colors[0]}";`,
        `tooltip="${data[0].data.code}";`,
        `label="${data[0].data.code}";`,
        this.genADChildrenDot(data[0].children || [], 1),
        '}',
        this.genADLines(),
        '}'
      ]
      return dots.join('')
    },
    genADChildrenDot (data, level) {
      const width = 12
      const height = 9
      let dots = []
      if (data.length) {
        data.forEach(_ => {
          let color = ''
          if (!_.fixedDate) {
            color = stateColor[_.data.state.code]
          }
          if (_.children instanceof Array && _.children.length) {
            dots.push(
              `subgraph cluster_${_.guid}{`,
              `id="g_${_.guid}";`,
              `color="${color || colors[level]}";`,
              `style="filled";fillcolor="${colors[level]}";`,
              `label=${_.label};`,
              `tooltip="${_.tooltip}";`,
              this.genADChildrenDot(_.children, level + 1),
              '}'
            )
          } else {
            this.graphNodes[_.guid] = _
            dots.push(
              `"n_${_.guid}"`,
              `[id="n_${_.guid}",shape="none",`,
              `fillcolor="${color || colors[level]}";`,
              `label=${_.label}`,
              '];'
            )
          }
        })
      } else {
        dots.push(`g[label=" ",color="${colors[level - 1]}";width="${width}";height="${height - 3}"];`)
      }
      return dots.join('')
    },
    genADLines () {
      const result = []
      Object.keys(this.systemLines).forEach(guid => {
        const node = this.systemLines[guid]

        let color = '#000'
        if (!node.fixedDate) {
          color = stateColor[node.state]
        }
        result.push(
          `n_${node.from}->n_${node.to}`,
          `[id="gl_${node.id}",`,
          `color="${color}"`,
          `tooltip="${node.label || ''}",`,
          `taillabel="${node.label || ''}"];`
        )

        const formatLabel = (keyName, guid) => {
          if (this.instancesInUnit[guid]) {
            let label = [
              '<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" COLOR="#000">',
              `<TR><TD>${keyName}</TD></TR>`
            ]
            this.instancesInUnit[guid].forEach(_ => {
              label.push(`<TR><TD>${_.key_name}</TD></TR>`)
            })
            label.push('</TABLE>>')
            return label.join('')
          } else {
            return `"${keyName}"`
          }
        }

        if (!this.graphNodes[node.from]) {
          const _fromNode = node.data[this.initParams[INVOKE_UNIT]]
          result.push(
            `n_${_fromNode.guid}`,
            `[label=${formatLabel(_fromNode.key_name, _fromNode.guid)},`,
            this.instancesInUnit[_fromNode.guid] ? 'color="#d3d3d3"' : '',
            `tooltip="${_fromNode.key_name || ''}"];`
          )
        } else if (!this.graphNodes[node.to]) {
          const _fromTo = node.data[this.initParams[INVOKED_UNIT]]
          result.push(
            `n_${_fromTo.guid}`,
            `[label=${formatLabel(_fromTo.key_name, _fromTo.guid)},`,
            this.instancesInUnit[_fromTo.guid] ? 'color="#d3d3d3"' : '',
            `tooltip="${_fromTo.key_name || ''}"];`
          )
        }
      })
      return result.join('')
    },
    async reloadHandler () {
      this.querySysTree()
      this.isDataChanged = false
    },
    onClearDesignSelect () {
      // 清理默认tab显示
      this.showDefaultTabs = false
      this.showApplicationDeploymentComponent = false

      this.showApplicationLogicTree = false
    },
    onSystemDesignSelect (key) {
      this.isShowTabs = false
      this.systemData = []
      this.systemTreeData = []
      this.systemLines = {}
      this.graphNodes = {}
      // this.initADGraph()
      this.currentTab = 'logic-graph'
      this.$refs.applicationDeploymentComponent.clearSvg()
      this.initTreeGraph()
    },
    async getSystems () {
      let { statusCode, data } = await getSystems()
      if (statusCode === 'OK') {
        this.systems = data.contents.map(_ => _.data)
      }
    },
    onTreeCheck (all, current) {
      this.selectedDeployItems = all
    },
    async querySysTree () {
      if (!this.systemVersion) {
        this.$Notice.warning({
          title: 'Warning',
          desc: this.$t('please_select_system')
        })
        return
      }
      this.spinShow = true
      this.treeSpinShow = true
      if (this.currentTab) {
        this.queryCiData()
      }
      this.physicalSpin = true
      await this.getAllDeployTreesFromSystemCi()
      // TODO
      // this.getPhysicalGraphData()
      this.showDefaultTabs = true
      this.spinShow = false
    },
    async getAllDeployTreesFromSystemCi () {
      this.showApplicationDeploymentComponent = true
      const { initParams } = this
      const { statusCode, data } = await getAllDeployTreesFromSystemCi(this.systemVersion)
      this.$refs.applicationDeploymentComponent.getAllDeployTreesFromSystemCi(this.systemVersion, { statusCode, data })
      if (statusCode === 'OK') {
        this.isShowTabs = true
        this.systemTreeData = data
        this.systemLines = {}

        const formatADData = array => {
          return array.map(_ => {
            let result = {
              ciTypeId: _.ciTypeId,
              guid: _.guid,
              data: _.data,
              label: `"${_.data.code}"`,
              tooltip: _.data.description || '',
              fixedDate: +new Date(_.data.fixed_date)
            }
            if (_.children instanceof Array && _.children.length && _.ciTypeId !== initParams[UNIT_ID]) {
              result.children = formatADData(_.children)
            }
            if (_.ciTypeId === initParams[UNIT_ID]) {
              let label = ['<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">', `<TR><TD>${_.data.code}</TD></TR>`]
              if (_.children instanceof Array && _.children.length) {
                _.children.forEach(item => {
                  if (initParams[BUSINESS_APP_INSTANCE_ID].split(',').indexOf(item.ciTypeId + '') >= 0) {
                    label.push(`<TR><TD>${item.data.code}</TD></TR>`)
                  }
                })
              }
              label.push('</TABLE>>')
              result.label = label.join('')
            }
            return result
          })
        }
        const formatADLine = array => {
          array.forEach(_ => {
            if (_.ciTypeId === this.initParams[INVOKE_ID]) {
              this.systemLines[_.guid] = {
                ..._,
                from: _.data[this.initParams[INVOKE_UNIT]].guid,
                to: _.data[this.initParams[INVOKED_UNIT]].guid,
                id: _.guid,
                label: _.data.invoke_type,
                state: _.data.state.code,
                fixedDate: +new Date(_.data.fixed_date)
              }
            }
            if (_.children instanceof Array && _.children.length) {
              formatADLine(_.children)
            }
          })
        }

        const fetchOtherSystemInstances = async () => {
          this.instancesInUnit = {}
          this.graphNodes = {}
          this.genADChildrenDot(this.systemData[0].children || [], 1)
          let instanceGuids = []
          Object.keys(this.systemLines).forEach(guid => {
            const node = this.systemLines[guid]
            if (!this.graphNodes[node.from]) {
              const _fromNode = node.data[this.initParams[INVOKE_UNIT]]
              instanceGuids.push(_fromNode.guid)
            } else if (!this.graphNodes[node.to]) {
              const _fromTo = node.data[this.initParams[INVOKED_UNIT]]
              instanceGuids.push(_fromTo.guid)
            }
          })
          if (instanceGuids.length) {
            const promiseArray = this.initParams[BUSINESS_APP_INSTANCE_ID].split(',').map(_ => {
              const query = {
                id: +_,
                queryObject: {
                  filters: [
                    {
                      name: 'unit',
                      operator: 'in',
                      value: instanceGuids
                    }
                  ]
                }
              }
              return queryCiData(query)
            })
            const instances = await Promise.all(promiseArray)
            let _instancesInUnit = {}
            instances.forEach(_ => {
              _.data.contents.forEach(item => {
                if (_instancesInUnit[item.data.unit.guid]) {
                  _instancesInUnit[item.data.unit.guid].push(item.data)
                } else {
                  _instancesInUnit[item.data.unit.guid] = [item.data]
                }
              })
            })
            this.instancesInUnit = _instancesInUnit
          }
          // this.initADGraph()
          this.initTreeGraph()
        }

        this.systemData = formatADData(data)
        formatADLine(data)
        fetchOtherSystemInstances()
      }
    },
    async getPhysicalGraphData () {
      this.physicalGraphData = []
      const selectedSystem = this.systems.find(_ => _.guid === this.systemVersion)
      if (!selectedSystem) {
        return
      }
      let idcs = []
      if (selectedSystem.data_center instanceof Array) {
        let idcsObj = {}
        selectedSystem.data_center.forEach(_ => {
          idcsObj[_.guid] = _.guid
          if (_.regional_data_center) {
            idcsObj[_.regional_data_center] = _.regional_data_center
          }
        })
        Object.keys(idcsObj).forEach(idc => {
          idcs.push(idc)
        })
      }
      const promiseArray = [getIdcImplementTreeByGuid(idcs), getAllZoneLinkGroupByIdc()]
      const [idcData, links] = await Promise.all(promiseArray)
      if (idcData.statusCode === 'OK' && links.statusCode === 'OK') {
        let _physicalGraphData = []
        let logicNetZone = {}
        idcData.data.forEach(_ => {
          if (!_.data.regional_data_center) {
            let obj = {
              ciTypeId: _.ciTypeId,
              guid: _.guid,
              data: _.data
            }
            if (_.children instanceof Array) {
              obj.children = _.children.filter(zone => zone.ciTypeId !== _.ciTypeId)
            }
            _physicalGraphData.push(obj)
          } else if (_.data.regional_data_center && _.children instanceof Array) {
            _.children.forEach(zone => {
              zone.data.code = `${zone.data.code}(${zone.data.data_center.code})`
              if (logicNetZone[zone.data.vpc_network_zone.guid]) {
                logicNetZone[zone.data.vpc_network_zone.guid].push(zone)
              } else {
                logicNetZone[zone.data.vpc_network_zone.guid] = [zone]
              }
            })
          }
        })
        _physicalGraphData.forEach(_ => {
          if (_.children instanceof Array) {
            _.children.map(zone => {
              if (logicNetZone[zone.guid]) {
                zone.children = logicNetZone[zone.guid]
              }
              return zone
            })
          }
        })

        const sortingTree = array => {
          let obj = {}
          array.forEach(_ => {
            _.text = [_.data.code]
            if (_.data.network_segment) {
              _.text.push(_.data.network_segment.code)
            }
            if (_.children instanceof Array) {
              _.children = sortingTree(_.children)
            }
            obj[_.data.code + _.guid] = _
          })
          return Object.keys(obj)
            .sort()
            .map(_ => obj[_])
        }
        this.physicalGraphData = sortingTree(_physicalGraphData)

        let allZoneLinkObj = {}
        links.data.forEach(_ => {
          if (_.linkList instanceof Array) {
            _.linkList.forEach(link => {
              allZoneLinkObj[link.data.guid] = link.data
            })
          }
        })
        this.physicalGraphLinks = []
        Object.keys(allZoneLinkObj).forEach(guid => {
          const line = {
            guid,
            from: allZoneLinkObj[guid].network_zone_1,
            to: allZoneLinkObj[guid].network_zone_2,
            label: allZoneLinkObj[guid].code,
            state: allZoneLinkObj[guid].state.code
          }
          this.physicalGraphLinks.push(line)
        })
      }
    },
    graphCallback () {
      this.physicalSpin = false
    },
    async executeDeploy () {
      let payload = {
        attach: {
          attachItems: [
            {
              filterName: 'systemVersion',
              filterValue: this.systemVersion
            }
          ]
        },
        requests: this.selectedDeployItems.map(_ => {
          return {
            ciDataId: _.guid,
            ciTypeId: _.ciTypeId,
            processDefinitionKey: _.data.WeCMDBOrchestration.codeId
          }
        })
      }
      const { statusCode, message } = await startProcessInstancesWithCiDataInbatch(payload)
      if (statusCode === 'OK') {
        this.$Notice.success({
          title: this.$t('start_execution'),
          desc: message
        })
      }
    },
    initTreeGraph (filters = {}) {
      this.treeSpinShow = true
      let graph
      const initEvent = () => {
        graph = d3.select('#graphTree')
        graph
          .on('dblclick.zoom', null)
          .on('wheel.zoom', null)
          .on('mousewheel.zoom', null)
        this.graphTree.graphviz = graph
          .graphviz()
          .width(window.innerWidth - 60)
          .height(window.innerHeight - 230)
          .zoom(true)
          .fit(true)
      }

      initEvent()
      this.renderTreeGraph(this.systemTreeData)
      this.showApplicationLogicTree = true
      this.treeSpinShow = false
    },
    loadImage (nodesString) {
      ;(nodesString.match(/image=[^ ;]*(files\/\d*|png)/g) || [])
        .filter((value, index, self) => {
          return self.indexOf(value) === index
        })
        .map(keyvaluepaire => keyvaluepaire.substr(7))
        .forEach(image => {
          this.graphTree.graphviz.addImage(image, '48px', '48px')
        })
    },
    renderTreeGraph (data) {
      let nodesString = this.genTreeDOT(data)
      this.loadImage(nodesString)
      this.graphTree.graphviz.transition().renderDot(nodesString)
      let svg = d3.select('#graphTree').select('svg')
      let width = svg.attr('width')
      let height = svg.attr('height')
      svg.attr('viewBox', '0 0 ' + width + ' ' + height)
    },
    genTreeDOT (data) {
      if (data.length === 0) {
        return 'digraph G {}'
      }
      const width = 16
      const height = 12
      let dots = [
        'digraph G{',
        'rankdir=TB nodesep=0.5;',
        `size="${width},${height}";`,
        this.genlayerDot(data),
        'Node [fontname=Arial, shape="ellipse", fixedsize="true", width="1.3", height="1.1", color="transparent" ,fontsize=10];',
        'Edge [fontname=Arial, arrowhead="t"];',
        `tooltip="${data[0].data.key_name}";`,
        ...this.genChildrenDot(data || [], 1),
        ...this.genRankNodeDot(),
        '}'
      ]
      return dots.join(' ')
    },
    genlayerDot (data) {
      let layerData = []
      let childrenLayer = {}
      const findLayerCi = array =>
        array.forEach(_ => {
          const found = layerData.find(layer => layer.code === _.ciTypeId)
          if (!found) {
            layerData.push({
              code: _.ciTypeId,
              value: this.allCiTypes[_.ciTypeId].name
            })
          }
          if (_.children instanceof Array && _.children.length) {
            if (_.ciTypeId !== this.initParams[UNIT_ID]) {
              findLayerCi(_.children)
            } else {
              _.children.forEach(item => {
                childrenLayer[item.ciTypeId] = {
                  code: item.ciTypeId,
                  value: this.allCiTypes[item.ciTypeId].name
                }
              })
            }
          }
        })
      findLayerCi(data)
      Object.keys(childrenLayer).forEach(key => {
        layerData.push(childrenLayer[key])
      })
      let result = ['{', 'node[shape=plaintext,fontsize=16];']
      this.rankNodes = {}
      layerData.forEach((_, i) => {
        if (i === layerData.length - 1) {
          result.push(`"title_${_.code}"`)
          if (i === 0) {
            result.push('->""')
          }
        } else {
          result.push(`"title_${_.code}"->`)
        }
        this.rankNodes[_.code] = []
        this.rankNodes[_.code].push(_.value)
      })
      result.push('[style=invis]', '}')
      return result.join('')
    },
    genChildrenDot (data, level) {
      let dots = []
      data.forEach(_ => {
        let _label = _.data.code
        _label = _label.length > 21 ? `${_label.slice(0, 1)}...${_label.slice(-15)}` : _label
        dots = dots.concat([
          `"${_.guid}"`,
          `[id="n_${_.guid}";`,
          `label="${_label}";`,
          `image="${baseURL}/files/${_.imageFileId}.png";`,
          'labelloc="b"',
          `tooltip="${_.data.code}"];`
        ])
        this.rankNodes[_.ciTypeId].push(`"${_.guid}"`)
        if (_.children instanceof Array && _.children.length) {
          dots = dots.concat(this.genChildrenDot(_.children, level + 1))
          _.children.forEach(c => {
            dots = dots.concat([`"${_.guid}" -> "${c.guid}";`])
          })
        }
      })
      return dots
    },
    genRankNodeDot () {
      let dot = []
      Object.keys(this.rankNodes).forEach((key, index) => {
        dot.push('{rank=same;')
        this.rankNodes[key].forEach((_, i) => {
          if (i === 0) {
            dot.push(`"title_${key}"[label="${_}";tooltip="${_}"];`)
          } else {
            dot.push(`${_};`)
          }
        })
        dot.push('}')
      })
      return dot
    },
    handleTabClick (name) {
      this.payload.sorting = {}
      this.payload.filters = []
      this.currentTab = name
      if (
        this.currentTab !== 'logic-graph' &&
        this.currentTab !== 'deploy-detail' &&
        this.currentTab !== 'physicalGraph' &&
        this.currentTab !== 'logic-tree-graph'
      ) {
        this.getCurrentData()
      }
    },
    getCurrentData () {
      const found = this.tabList.find(_ => _.id === this.currentTab)
      if (!found.isClicked) {
        found.isClicked = true
        this.queryCiAttrs(this.currentTab)
      }
      this.queryCiData()
    },
    onSelectedRowsChange (rows, checkoutBoxdisable) {
      if (rows.length > 0) {
        let isUpdateableAry = []
        let isDeleteableAry = []

        rows.forEach((r, index) => {
          isUpdateableAry.push(!!r.nextOperations.find(op => op === 'update'))
          isDeleteableAry.push(!!r.nextOperations.find(op => op === 'delete'))
        })
        let isValueTrue = val => {
          return val === true
        }

        this.tabList.forEach(ci => {
          if (ci.id === this.currentTab) {
            ci.outerActions.forEach(_ => {
              switch (_.actionType) {
                case 'add':
                  _.props.disabled = _.actionType === 'add'
                  break
                case 'edit':
                  _.props.disabled = !isUpdateableAry.every(isValueTrue)
                  break
                case 'delete':
                  _.props.disabled = !isDeleteableAry.every(isValueTrue)
                  break
                case 'copy':
                  _.props.disabled = !rows.every(x => x.guid)
                  break
                default:
                  break
              }
            })
          }
        })
      } else {
        this.tabList.forEach(ci => {
          if (ci.id === this.currentTab) {
            ci.outerActions.forEach(_ => {
              _.props.disabled = resetButtonDisabled(_)
            })
          }
        })
      }
    },
    actionFun (type, data, cols) {
      switch (type) {
        case 'export':
          this.exportHandler()
          break
        case 'add':
          this.addHandler()
          break
        case 'edit':
          this.editHandler()
          break
        case 'delete':
          this.deleteHandler(data)
          break
        case 'compare':
          this.compareHandler(data)
          break
        case 'copy':
          this.copyHandler(data, cols)
          break
        default:
          this.defaultHandler(type, data)
          break
      }
    },
    copyHandler (rows = [], cols) {
      this.$refs[this.tableRef][0].showCopyModal()
    },
    handleCopyToNew () {
      this.copyVisible = false
      this.copyTableVisible = true
      this.$nextTick(() => {
        this.$refs['copy' + this.currentTab] && this.$refs['copy' + this.currentTab].pushAllRowsToSelections()
      })
    },
    handleCopyEditData (rows) {
      this.copyEditData = rows
    },
    async handleCopySubmit () {
      this.copyTableVisible = false
      let setBtnsStatus = () => {
        this.tabList.forEach(ci => {
          if (ci.id === this.currentTab) {
            ci.outerActions.forEach(_ => {
              _.props.disabled = resetButtonDisabled(_)
            })
          }
        })
        this.$refs[this.tableRef][0].setAllRowsUneditable()
        this.$nextTick(() => {
          /* to get iview original data to set _ischecked flag */
          let objData = this.$refs[this.tableRef][0].$refs.table.$refs.tbody.objData
          for (let obj in objData) {
            objData[obj]._isChecked = false
            objData[obj]._isDisabled = false
          }
        })
      }
      let payload = {
        id: this.currentTab,
        createData: this.copyEditData.map(x => {
          delete x.isRowEditable
          delete x.weTableForm
          delete x.weTableRowId
          delete x.isNewAddedRow
          delete x.nextOperations
          delete x.forceEdit
          return x
        })
      }
      const { statusCode, message } = await createCiDatas(payload)
      if (statusCode === 'OK') {
        this.$Notice.success({
          title: 'Updated successfully',
          desc: message
        })
        this.isDataChanged = true
        setBtnsStatus()
        this.queryCiData()
      }
    },
    sortHandler (data) {
      if (data.order === 'normal') {
        delete this.payload.sorting
      } else {
        this.payload.sorting = {
          asc: data.order === 'asc',
          field: data.key
        }
      }
      this.getCurrentData()
    },
    handleSubmit (data) {
      this.payload.filters = data
      this.getCurrentData()
    },
    async defaultHandler (type, row) {
      this.$set(row.weTableForm, `${type}Loading`, true)
      const { statusCode, message } = await operateCiState(this.currentTab, row.guid, type)
      this.$set(row.weTableForm, `${type}Loading`, false)
      if (statusCode === 'OK') {
        this.$Notice.success({
          title: type,
          desc: message
        })
        this.queryCiData()
      }
    },

    addHandler () {
      this.tabList.forEach(ci => {
        if (ci.id === this.currentTab) {
          let emptyRowData = {}
          ci.tableColumns.forEach(_ => {
            if (_.inputType === 'multiSelect' || _.inputType === 'multiRef') {
              emptyRowData[_.inputKey] = []
            } else {
              emptyRowData[_.inputKey] = ''
            }
          })
          emptyRowData['isRowEditable'] = true
          emptyRowData['isNewAddedRow'] = true
          emptyRowData['weTableRowId'] = 1
          emptyRowData['nextOperations'] = []
          this.$refs[this.tableRef][0].pushNewAddedRowToSelections(emptyRowData)
          this.$refs[this.tableRef][0].showAddModal()
        }
      })
    },
    deleteHandler (deleteData) {
      this.$Modal.confirm({
        title: this.$t('delete_confirm'),
        'z-index': 1000000,
        onOk: async () => {
          const payload = {
            id: this.currentTab,
            deleteData: deleteData.map(_ => _.guid)
          }
          const { statusCode, message } = await deleteCiDatas(payload)
          if (statusCode === 'OK') {
            this.$Notice.success({
              title: 'Delete data Success',
              desc: message
            })
            this.isDataChanged = true
            this.tabList.forEach(ci => {
              if (ci.id === this.currentTab) {
                ci.outerActions.forEach(_ => {
                  _.props.disabled = _.actionType === 'copy' || _.actionType === 'edit' || _.actionType === 'delete'
                })
              }
            })
            this.getCurrentData()
          }
        },
        onCancel: () => {}
      })
      document.querySelector('.ivu-modal-mask').click()
    },
    editHandler () {
      this.$refs[this.tableRef][0].showEditModal()
    },
    deleteAttr () {
      let attrs = []
      const found = this.tabList.find(_ => _.id === this.currentTab)
      found.tableColumns.forEach(i => {
        if (i.isAuto) {
          attrs.push(i.propertyName)
        }
      })
      return attrs
    },
    async confirmAddHandler (data) {
      const deleteAttrs = this.deleteAttr()
      let addAry = JSON.parse(JSON.stringify(data))
      addAry.forEach(_ => {
        deleteAttrs.forEach(attr => {
          delete _[attr]
        })
        delete _.isRowEditable
        delete _.weTableForm
        delete _.weTableRowId
        delete _.isNewAddedRow
        delete _.nextOperations
      })
      let payload = {
        id: this.currentTab,
        createData: addAry
      }
      const { statusCode, message } = await createCiDatas(payload)
      this.$refs[this.tableRef][0].resetModalLoading()
      if (statusCode === 'OK') {
        this.$Notice.success({
          title: this.$t('add_data_success'),
          desc: message
        })
        this.isDataChanged = true
        this.setBtnsStatus()
        this.getCurrentData()
        this.$refs[this.tableRef][0].closeEditModal(false)
      }
    },
    async confirmEditHandler (data) {
      let editAry = JSON.parse(JSON.stringify(data))
      editAry.forEach(_ => {
        delete _.isRowEditable
        delete _.weTableForm
        delete _.weTableRowId
        delete _.isNewAddedRow
        delete _.nextOperations
      })
      let payload = {
        id: this.currentTab,
        updateData: editAry
      }
      const { statusCode, message } = await updateCiDatas(payload)
      this.$refs[this.tableRef][0].resetModalLoading()
      if (statusCode === 'OK') {
        this.$Notice.success({
          title: this.$t('update_data_success'),
          desc: message
        })
        this.isDataChanged = true
        this.setBtnsStatus()
        this.getCurrentData()
        this.$refs[this.tableRef][0].closeEditModal(false)
      }
    },
    setBtnsStatus () {
      this.tabList.forEach(ci => {
        if (ci.id === this.currentTab) {
          ci.outerActions.forEach(_ => {
            _.props.disabled = resetButtonDisabled(_)
          })
        }
      })
    },
    async exportHandler () {
      let found = this.tabList.find(i => i.code === this.currentTab)
      if (found) {
        found.outerActions.forEach(_ => {
          if (_.actionType === 'export') {
            _.props.loading = true
          }
        })
      }
      let requst = {
        codeId: found.codeId,
        systemGuid: this.systemVersion
      }

      let exportPayload = {
        ...this.payload,
        paging: false
      }
      const { statusCode, data } = await getDeployCiData(requst, exportPayload)
      if (found) {
        found.outerActions.forEach(_ => {
          if (_.actionType === 'export') {
            _.props.loading = false
          }
        })
      }
      if (statusCode === 'OK') {
        this.$refs[this.tableRef][0].export({
          filename: 'Ci Data',
          data: formatData(data.contents.map(_ => _.data))
        })
      }
    },
    pageChange (current) {
      this.tabList.forEach(ci => {
        if (ci.id === this.currentTab) {
          ci.pagination.currentPage = current
        }
      })
      this.getCurrentData()
    },
    pageSizeChange (size) {
      this.tabList.forEach(ci => {
        if (ci.id === this.currentTab) {
          ci.pagination.pageSize = size
        }
      })
      this.getCurrentData()
    },
    async queryCiAttrs (id) {
      const { statusCode, data } = await getCiTypeAttributes(id)
      if (statusCode === 'OK') {
        let columns = []
        data.forEach(_ => {
          let renderKey = _.propertyName
          if (_.status !== 'decommissioned' && _.status !== 'notCreated') {
            columns.push({
              ..._,
              tooltip: true,
              title: _.name,
              renderHeader: (h, params) => {
                const d = {
                  props: {
                    'min-width': '130px',
                    'max-width': '500px'
                  }
                }
                return (
                  <Tooltip {...d} content={_.description} placement="top">
                    <span style="white-space:normal">{_.name}</span>
                  </Tooltip>
                )
              },
              key: renderKey,
              inputKey: _.propertyName,
              inputType: _.inputType,
              referenceId: _.referenceId,
              disEditor: !_.isEditable,
              disAdded: !_.isEditable,
              placeholder: _.name,
              component: 'Input',
              filterRule: !!_.filterRule,
              ciType: { id: _.referenceId, name: _.name },
              type: 'text',
              isMultiple: _.inputType === 'multiSelect',
              ...components[_.inputType]
            })
          }
        })
        this.tabList.forEach(ci => {
          if (ci.id === this.currentTab) {
            ci.tableColumns = this.getSelectOptions(columns)
          }
        })
      }
    },
    getSelectOptions (columns) {
      columns.forEach(async _ => {
        if (_.inputType === 'select') {
          const { data } = await getEnumCodesByCategoryId(0, _.referenceId)
          _['options'] = data
            .filter(j => j.status === 'active')
            .map(i => {
              return {
                label: i.value,
                value: i.codeId
              }
            })
        }
      })
      return columns
    },

    async queryCiData () {
      if (this.systemVersion === '') {
        this.$Notice.warning({
          title: 'Warning',
          desc: this.$t('please_select_system')
        })
        return
      }
      this.payload.pageable.pageSize = 10
      this.payload.pageable.startIndex = 0
      this.tabList.forEach(ci => {
        if (ci.id === this.currentTab) {
          this.payload.pageable.pageSize = ci.pagination.pageSize
          this.payload.pageable.startIndex = (ci.pagination.currentPage - 1) * ci.pagination.pageSize
        }
      })
      let found = this.tabList.find(i => i.code === this.currentTab)
      if (!found) return
      let requst = {
        codeId: found.codeId,
        systemGuid: this.systemVersion
      }
      if (this.$refs[this.tableRef].length > 0) {
        this.$refs[this.tableRef][0].isTableLoading(true)
      }
      const { statusCode, data } = await getDeployCiData(requst, this.payload)
      if (this.$refs[this.tableRef].length > 0) {
        this.$refs[this.tableRef][0].isTableLoading(false)
      }
      if (statusCode === 'OK') {
        this.tabList.forEach(ci => {
          if (ci.id === this.currentTab) {
            ci.tableData = data
              ? data.contents.map(_ => {
                return {
                  ..._.data,
                  nextOperations: _.meta.nextOperations || []
                }
              })
              : []
            ci.pagination.total = data ? data.pageInfo.totalRows : 0
          }
        })
      }
    },
    async getDeployDesignTabs () {
      const promiseArray = [getDeployDesignTabs(), getExtraInnerActions()]
      const [tabs, allInnerActions] = await Promise.all(promiseArray)
      if (tabs.statusCode === 'OK') {
        this.tabList = tabs.data.map(_ => {
          return {
            ..._,
            name: _.value,
            id: _.code,
            tableData: [],
            tableColumns: [],
            outerActions: JSON.parse(JSON.stringify(newOuterActions)),
            innerActions: JSON.parse(JSON.stringify(allInnerActions)),
            pagination: JSON.parse(JSON.stringify(pagination)),
            ascOptions: {},
            isClicked: false
          }
        })
      }
    },
    async queryTreeLayerData () {
      const req = await getAllCITypes()
      if (req.statusCode) {
        req.data.forEach(_ => {
          this.allCiTypes[_.ciTypeId] = _
        })
      }
    },
    async getConfigParams () {
      const { statusCode, data } = await getEnumCodesByCategoryId(0, VIEW_CONFIG_PARAMS)
      if (statusCode === 'OK') {
        this.initParams = {}
        data.forEach(_ => {
          this.initParams[_.code] = Number(_.value) ? Number(_.value) : _.value
        })
        this.getSystems()
        this.getDeployDesignTabs()
        this.queryTreeLayerData()
      }
    }
  },
  created () {
    this.getConfigParams()
  }
}
</script>

<style lang="scss" scoped>
#physicalGraph {
  position: relative;
  min-height: 300px;
}
#graphTree {
  position: relative;
  min-height: calc(50% + 300px);
}
.no-data {
  text-align: center;
}

.copy-modal {
  .ivu-modal-body {
    max-height: 450px;
    overflow-y: auto;
  }

  .copy-form {
    display: flex;
    flex-flow: column nowrap;
  }

  .copy-input {
    display: flex;
    flex-flow: row nowrap;
    margin-top: 20px;
    align-items: center;

    .ivu-input-number {
      flex: 1;
      margin-right: 15px;
    }
  }
}
</style>
