<template>
  <Modal class="mch-create-modal" v-model="dlgShow" :mask-closable="false" title="选择坐标系" width="600">
    <div class="mch-geosys-panel" v-if="dlgShow">
      <Search v-model="keywords" style="width: 100%;"/>
      <div>
        <div class="sys-list">
          <Tree :data="treeList" @on-select-change="selectChange"></Tree>
        </div>
        <div class="sys-wkt">
          <div class="full" v-if="selectedItem">
            <div class="sys-title">
              {{ selectedItem.title || '' }}
              <span class="epsg" v-if="selectedItem.authCode">{{ selectedItem.authName }}:{{ selectedItem.authCode }}</span>
            </div>
            <textarea class="crs-des" name="wkt" v-model="custom_wkt" placeholder="输入WKT字符串" spellcheck="false" v-if="selectedItem.type==='CUSTOM'"></textarea>
            <div class="sys-text crs-des" v-else>{{ selectedItem.wkt || '' }}</div>
            <div class="prj-btn abs cursor" @click="openImportPrj" v-if="selectedItem.type==='CUSTOM'">导入prj文件</div>
            <div class="form rel">
              <div class="switch abs">自定义原点：<Switch v-model="customOrigin" size="small" @on-change="originTypeChange"/></div>
              <div class="tag">原点</div>
              <div class="auto-text" v-if="!offset">系统默认</div>
              <div style="margin-top: 5px;" v-else>
                <div class="form-item inline">
                  <span>经度/X：</span>
                  <Input type="number" v-model="offset[0]" size="small" style="width: 100px;"></Input>
                </div>
                <div class="form-item inline">
                  <span>纬度/Y：</span>
                  <Input type="number" v-model="offset[1]" size="small" style="width: 100px;"></Input>
                </div>
                <div class="form-item inline">
                  <span>高度/Z：</span>
                  <Input type="number" v-model="offset[2]" size="small" style="width: 100px;"></Input>
                </div>
              </div>
            </div>
          </div>
          <div class="empty-text" v-else>未选择坐标系</div>
          <input id="select-prj-file" type="file" accept=".prj" @change="selectPrjFile" style="display: none;">
        </div>
      </div>
    </div>
    <template #footer>
      <div class="footer flex-between">
        <div class="height-crs flex-between tl">
          <div v-if="supportHeight">高程坐标系</div>
          <Select v-model="verticalEpsgCode" transfer @click.stop v-if="supportHeight" style="width: 200px;margin-left: 10px;">
            <Option :value="item.code" v-for="item in heightSystemList" :key="item.code">{{item.name}}</Option>
          </Select>
        </div>
        <div>
          <Button type="text" @click="cancel">取消</Button>
          <Button type="primary" @click="ok">确定</Button>
        </div>
      </div>
    </template>
  </Modal>
</template>

<script>
import {crsList, transform, crsTypes} from '@mapcatch/util'
import Search from '../search'
import _ from 'lodash'
import satellite_geo_calc from 'satellite-geo-calc'
import proj4 from 'proj4'
import heightSystemList from './height_system'
export default {
  components: {
    Search
  },
  methods: {
    selectChange(nodes, currentNode) {
      if (!currentNode.selected) {
        this.selectedItem = null
      } else {
        this.selectedItem = currentNode
        if(this.options.coordinate_system?.offset) { // 给了自定义原点偏移
          this.customOrigin = true
          this.offset = this._getDefaultOffset()
        }
      }
    },
    show(options) {
      this.keywords = ''
      this.options = options
      this.originalCrsList = _.cloneDeep(crsList)
      this.verticalEpsgCode = -1
      if (this.options.coordinate_system) {
        let {type, label, wkt, offset, epsg_code, vertical_epsg_code} = this.options.coordinate_system
        if (type === -1) {
          this.selectedItem = {
            type: 'CUSTOM',
            title: '自定义坐标系'
          }
          this.custom_wkt = wkt
        } else {
          this.selectedItem = {
            title: label,
            wkt: transform.getWKTString({type, epsg_code}),
            authCode: epsg_code,
            authName: 'EPSG'
          }
          for(let key in crsTypes) {
            if (crsTypes[key].code === type) {
              this.selectedItem.type = key
            }
          }
        }
        if (vertical_epsg_code) {
          this.verticalEpsgCode = vertical_epsg_code
        }
        if (offset) {
          this.customOrigin = true
          this.offset = this._getDefaultOffset()
        }
      } else {
        this.selectedItem = null
        this.customOrigin = false
        this.offset = null
        this.origin = null
      }
      this.recommendedCrs = []
      if (this.options.location) {
        let lng = this.options.location[0]
        let initCode = 32600
        let n = Math.ceil((lng + 180) / 6)
        let node = this.getNode(initCode + n, crsList)
        node && this.recommendedCrs.push(node)
        if (lng > 73.5 && lng < 136.5) {
          let gk_init = 4534
          let gk_n = Math.floor((lng - 73.5) / 3)
          let gk_node = this.getNode(gk_init + gk_n, crsList)
          gk_node && this.recommendedCrs.push(gk_node)
        }
      }
      this.getTreeList()
      this.dlgShow = true
    },
    ok() {
      if (!this.selectedItem) {
        this.$Message.warning('未选择坐标系！')
        return
      }
      if (this.selectedItem.type === 'CUSTOM' && !this.custom_wkt) {
        this.$Message.warning('请输入坐标系信息')
        return
      }
      if (this.customOrigin && this.offset && this.offset.findIndex(d => d === '' || Number.isNaN(+d)) !== -1) {
        this.$Message.warning('请输入正确的原点坐标')
        return
      }
      if (this.options?.onOk) {
        let selectedItem = _.cloneDeep(this.selectedItem)
        let {type} = selectedItem
        if (type === 'CUSTOM') {
          selectedItem.wkt = this.custom_wkt
        }
        if (this.customOrigin) {
          selectedItem.offset = this.offset
        }
        this.options.onOk(this._getCrsFromItem(selectedItem))
      }
      this.dlgShow = false
      if (this.selectedItem.authCode && this.selectedItem.authCode !== 4326 && this.selectedItem.authCode !== 4490) {
        let item = _.cloneDeep(this.selectedItem)
        delete item.selected
        delete item.nodeKey
        let cachedStr = localStorage.getItem('cached_crs')
        let cached = cachedStr ? JSON.parse(cachedStr) : []
        let index = cached.findIndex(d => d.authCode === item.authCode)
        if (index === -1) {
          cached.splice(0, 0, item)
          if (cached.length > 5) {
            cached.pop()
          }
        } else {
          cached.splice(index, 1)
          cached.splice(0, 0, item)
        }
        localStorage.setItem('cached_crs', JSON.stringify(cached))
      }

    },
    cancel() {
      if (this.options?.onCancel) {
        this.options.onCancel()
      }
      this.dlgShow = false
    },
    _getCrsFromItem(item) {
      let {type, authCode, wkt, title} = item
      let crs = {}
      if (type === 'CUSTOM') {
        crs = {
          type: -1,
          type_name: '自定义',
          label: title,
          wkt: this.custom_wkt
        }
      } else {
        crs = {
          type: crsTypes[type].code,
          type_name: crsTypes[type].name,
          label: title,
          wkt
        }
        if (!authCode) {
          if (this.origin) {
            crs.origin_point = this.origin
          }
          crs.origin_point = this.origin
        } else {
          crs.epsg_code = authCode
        }
      }
      if (this.customOrigin) {
        crs.offset = (this.offset || [0, 0, 0]).map(d => +d)
      }
      if (this.supportHeight && this.verticalEpsgCode !== -1) {
        crs.vertical_epsg_code = this.verticalEpsgCode
      }
      return crs
    },
    isSearchedItem(text, keywords) {
      for(let i = 0;i < keywords.length;i++) {
        if (!text.toLowerCase().includes(keywords[i].toLowerCase())) {
          return false
        }
      }
      return true
    },
    originTypeChange() {
      if (this.customOrigin) {
        this.offset = this._getDefaultOffset()
      } else {
        this.origin = null
        this.offset = null
      }
    },
    _transformCoordinate(position, sourceCrs, targetCrs) { // 将sourceCrs上的一点position转到targetCrs上
      position = _.cloneDeep(position)
      this.origin = null
      if (!position) {
        return null
      }
      if (!sourceCrs || !targetCrs) {
        return position
      }
      let {type, wkt, origin_point, epsg_code} = sourceCrs
      if (type === 0) {// source是LocalENU
        if (targetCrs.type === 0) { // 目标也是localENU
          this.origin = origin_point
          return position
        }
        // 先将localENU转经纬度
        let lla = satellite_geo_calc.coordinateTransfer.enu_to_lla({x: position[0], y: position[1], z: position[2]}, { lon: origin_point[0], lat: origin_point[1], alt: origin_point[2] })
        position = [lla.lon, lla.lat, lla.alt]
        type = 2,
        epsg_code = 4326
      }
      let sourceWkt = wkt, targetWkt = targetCrs.wkt
      if (!sourceWkt && epsg_code) {
        sourceWkt = transform.getWKTString({type, epsg_code})
      }
      // source不是localENU，target是localENU => 把地理坐标系下的偏移原点转成经纬度作为localENU的原点，偏移设为0
      if (targetCrs.type === 0) {
        this.origin = proj4(sourceWkt, 'EPSG:4326', position)
        return [0, 0, 0]
      }
      // source不是localENU，target也不是localENU => 将原地理坐标系的便宜点转到目标坐标系上作为新的偏移点
      if (!targetWkt && targetCrs.epsg_code) {
        targetWkt = transform.getWKTString(targetCrs)
      }
      if (!sourceWkt || !targetWkt) {
        return null
      }
      return proj4(sourceWkt, targetWkt, position)
    },
    _getDefaultOffset() {
      if (!this.options.coordinate_system) {
        return [0, 0, 0]
      }
      let selectedCrs = this._getCrsFromItem(this.selectedItem)
      return this._transformCoordinate(this.options.coordinate_system.offset, this.options.coordinate_system, selectedCrs) || [0, 0, 0]
    },
    openImportPrj() {
      document.querySelector('#select-prj-file').click()
    },
    selectPrjFile(e) {
      let file = e.target.files[0]
      if (!file) {
        return
      }
      let fileReader = new FileReader()
      fileReader.readAsText(file)
      fileReader.onload = () => {
        this.custom_wkt = fileReader.result
      }
      e.target.value = ''
    },
    reduceTreeItem(keywords, children) {
      let result = []
      children.forEach(item => {
        if (item.children) {
          let filtedChildren = this.reduceTreeItem(keywords, item.children)
          if (!filtedChildren.length) {
            return
          }
          item.children = filtedChildren
          result.push(item)
        } else {
          if (this.selectedItem && this.selectedItem.title === item.title && (!this.selectedItem.authCode || this.selectedItem.authCode === item.authCode)) {
            item.selected = true
          } else {
            item.selected = false
          }
          if (!keywords.length) {
            return result.push(item)
          }
          let text = `${item.title} ${item.authName}:${item.authCode}`
          if (this.isSearchedItem(text, keywords)) {
            result.push(item)
          }
        }
      })
      if (result.length) {
        result[0].expand = true
      }
      return result
    },
    getNode(epsg_code, list) {
      for(let i = 0;i < list.length;i++) {
        if (list[i].children?.length) {
          let node = this.getNode(epsg_code, list[i].children)
          if (node) {
            return node
          }
        } else if (list[i].authCode == epsg_code) {
          return list[i]
        }
      }
      return null
    },
    getTreeList() {
      let ignores = this.options.ignores || []
      //ignores.push('LOCAL')
      let list = _.cloneDeep(crsList).filter(d => !ignores.includes(d.type))
      if (this.recommendedCrs.length) {
        this.recommendedCrs.forEach(crs => {
          if (!list[0].children.find(d => d.authCode == crs.authCode)) {
            list[0].children.push(_.cloneDeep(crs))
          }
        })
      }
      let cachedStr = localStorage.getItem('cached_crs')
      let cached = cachedStr ? JSON.parse(cachedStr) : []
      cached.forEach(item => {
        if (!list[0].children.find(d => d.authCode == item.authCode)) {
          list[0].children.push(item)
        }
      })
      let keywords = this.keywords.split(' ').map(d => d.trim()).filter(d => !!d)
      this.treeList = this.reduceTreeItem(keywords, list)
    }
  },
  data() {
    return {
      dlgShow: false,
      selectedItem: null,
      keywords: '',
      customOrigin: false,
      origin: null,
      offset: null,
      custom_wkt: '',
      options: {},
      recommendedCrs: [],
      inited: false,
      verticalEpsgCode: -1,
      heightSystemList,
      treeList: []
    }
  },
  computed: {
    supportHeight() {
      if (!this.options.supportHeight || !this.selectedItem) {
        return false
      }
      let {type, wkt} = this.selectedItem
      if (type === 'CUSTOM') {
        wkt = this.custom_wkt
      }
      if (!wkt) {
        return false
      }
      return wkt.startsWith('GEOGCS') || wkt.startsWith('PROJCS')
    }
  },
  watch: {
    custom_wkt() {
      if (this.custom_wkt && this.customOrigin) {
        this.offset = this._getDefaultOffset()
      }
    },
    keywords() {
      this.getTreeList()
    }
  }
}
</script>
