<template>
  <Modal class="mch-create-modal" v-model="dlgShow" :mask-closable="false" title="选择坐标系" width="600">
    <div class="mch-geosys-panel">
      <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">
        <Button type="text" @click="cancel">取消</Button>
        <Button type="primary" @click="ok">确定</Button>
      </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'
export default {
  components: {
    Search
  },
  methods: {
    selectChange(nodes) {
      if (!nodes.length) {
        this.selectedItem = null
      } else {
        this.selectedItem = nodes[0]
        if(this.options.coordinate_system?.offset) { // 给了自定义原点偏移
          this.customOrigin = true
          this.offset = this._getDefaultOffset()
        }
      }
    },
    show(options) {
      this.options = options
      if (this.options.coordinate_system) {
        let {type, label, wkt, offset, epsg_code} = this.options.coordinate_system
        if (type === -1) {
          this.selectedItem = {
            type: 'CUSTOM',
            title: '自定义坐标系'
          }
          this.custom_wkt = wkt
        } else {
          this.selectedItem = {
            title: label,
            wkt,
            authCode: epsg_code,
            authName: 'EPSG'
          }
          for(let key in crsTypes) {
            if (crsTypes[key].code === type) {
              this.selectedItem.type = key
            }
          }
        }
        if (offset) {
          this.customOrigin = true
          this.offset = this._getDefaultOffset()
        }
      }
      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.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
    },
    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) {
          crs.origin_point = this.origin
        } else {
          crs.epsg_code = authCode
        }
      }
      if (this.customOrigin) {
        crs.offset = this.offset || [0, 0, 0]
      }
      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 = ''
    }
  },
  data() {
    return {
      dlgShow: false,
      selectedItem: null,
      keywords: '',
      customOrigin: false,
      origin: null,
      offset: null,
      custom_wkt: '',
      options: {}
    }
  },
  computed: {
    treeList() {
      let ignores = this.options.ignores || []
      ignores.push('LOCAL')
      let list = _.cloneDeep(crsList.filter(d => !ignores.includes(d.type)))
      let keywords = this.keywords.split(' ').map(d => d.trim()).filter(d => !!d)
      if (!keywords.length) {
        return list
      }
      list = list.filter(d => d.children)
      list.forEach(group => {
        group.expand = true
        for(let i = 0;i < group.children.length;i++) {
          if (group.children[i].children) {
            group.children[i].expand = true
            for(let j = 0;j < group.children[i].children.length;j++) {
              let item = group.children[i].children[j]
              let text = `${item.title} ${item.authName}:${item.authCode}`
              if (!this.isSearchedItem(text, keywords)) {
                group.children[i].children.splice(j, 1)
                j--
              }
            }
            if (!group.children[i].children.length) {
              group.children.splice(i, 1)
              i--
            }
          } else {
            let item = group.children[i]
            let text = `${item.title} ${item.authName}:${item.authCode}`
            if (!this.isSearchedItem(text, keywords)) {
              group.children.splice(i, 1)
              i--
            }
          }
        }
      })
      return list.filter(d => d.children.length)
    }
  },
  watch: {
    custom_wkt() {
      if (this.custom_wkt && this.customOrigin) {
        this.offset = this._getDefaultOffset()
      }
    }
  }
}
</script>
