<template>
  <div class="init-speed-track" v-loading="loading" element-loading-background="rgba(0, 0, 0, 0.5)">
    <EasyMapComponent
        class="map"
        :showBaseSwitch="true"
        @easyMapLoad="mapLoad"
    />
    <div class="track">
      <el-card shadow="always">
        <template #header>
          <div class="card-header">
            <span>轨迹列表</span>
            <el-button-group>
              <template v-for="[key, value] in SourceMap">
                <el-button :color="value.color" size="small" @click="drawTrack(key)" style="color: white">{{value.label}}</el-button>
              </template>
            </el-button-group>
          </div>
        </template>
        <div class="track-line">
          <template v-for="(item, index) in trackList">
            <div class="line">
              <div class="label" :style="`color: ${SourceMap.get(item.type).color};`">{{SourceMap.get(item.type).label}}</div>
              <el-tooltip :enterable="false" placement="top" content="隐藏" v-if="item.show">
                <img class="__hover" src="./ship-track-visible.svg" @click="handleShow(false, item)"/>
              </el-tooltip>
              <el-tooltip :enterable="false" placement="top" content="显示" v-else>
                <img class="__hover" src="./ship-track-invisible.svg" @click="handleShow(true, item)"/>
              </el-tooltip>
            </div>
          </template>
        </div>
      </el-card>
      <el-card shadow="always">
        <template #header>
          <div class="card-header">
            <span>轨迹点列表</span>
            <el-button v-if="trackPointList.length > 0" type="primary" size="small" @click="onSubmit" style="color: white">保存</el-button>
          </div>
        </template>
        <div class="track-point">
          <template v-for="item in formParams">
            <div class="item">
              <span>{{item.label}}：</span><el-input v-model="form[item.value]" clearable/>
            </div>
          </template>
          <template v-for="(item, index) in trackPointList">
            <div class="point">
              <div class="position">
                <span>{{item.position[0]}}</span><br/>
                <span>{{item.position[1]}}</span>
              </div>
              <div class="speed">
                <el-input-number v-model="item.speed" :precision="2" :step="0.1" :max="100" :min="0" @focus="onPointFocus(trackPointList[index - 1], item, trackPointList[index + 1])"/>
              </div>
            </div>
          </template>
        </div>
      </el-card>
    </div>
  </div>
</template>

<script lang="ts">
import {
  defineComponent,
  ref,
  nextTick,
  onMounted,
  watch,
  computed,
  ComponentInternalInstance,
  reactive,
  toRefs,
  getCurrentInstance
} from 'vue'
import {useStore} from 'vuex'
import * as source from "ol/source";
import * as layer from "ol/layer";
import * as style from "ol/style";
import * as ol from "ol";
import * as sphere from "ol/sphere";
import * as interaction from "ol/interaction";
import {createBox} from "ol/interaction/Draw";
import {unByKey} from "ol/Observable";
import { Geometry } from 'ol/geom';
import { EventsKey } from 'ol/events';
import { Coordinate } from 'ol/coordinate';
import TrackStyle from './track-style'
import axios from "axios";
import {ElMessage} from "element-plus";

export default defineComponent({
  name: 'App',
  components: {},
  setup() {
    const store = useStore()
    const that = (getCurrentInstance() as ComponentInternalInstance).appContext.config.globalProperties
    const SourceMap = new Map(window.cusConfig.trackSource)
    const formParams = window.cusConfig.trackParams
    const state = reactive({
      map: <any>null,
      mapFunc: null,
      trackPointList: [],
      trackList: <any>[],
      formTrackPointStartCount: 0,
      formTrackPointEndCount: 0,
      formTrackPointList: [],
      initTrackPointStartCount: 0,
      initTrackPointEndCount: 0,
      initTrackPointList: [],
      loading: false,
      form: {}
    });
    formParams.forEach(v => {
      state.form[v.value] = v.init
    })
    const mapLoad = (map: null, func: null) => {
      state.map = map
      state.mapFunc = func
    }
    const startDraw = (cb: { (evt: any): void; (arg0: { feature: { getGeometry: () => any; }; }): void; }) => {
      let measureTooltipElement: HTMLDivElement | null;
      let helpTooltipElement: HTMLDivElement | null;
      const realLayer = state.map.getLayers().getArray().filter((v: { get: (arg0: string) => string; }) => v.get('layerName') === 'measureLayer')
      let sketch: { getGeometry: () => { (): any; new(): any; on: { (arg0: string, arg1: (evt: any) => void): any; new(): any; }; }; } | null;
      let helpTooltip: ol.Overlay;
      let measureTooltip: ol.Overlay;
      let continueMsg = '双击结束标绘';
      const createMeasureTooltip = () => {
        const id = 'measureTooltipElementId'
        if (measureTooltipElement) {
          state.map.removeOverlay(state.map.getOverlayById(id))
          measureTooltipElement.parentNode?.removeChild(measureTooltipElement);
        }
        measureTooltipElement = document.createElement('div');
        measureTooltipElement.className = 'tooltip tooltip-measure';
        measureTooltip = new ol.Overlay({
          id,
          element: measureTooltipElement,
          offset: [0, -15],
          positioning: 'bottom-center'
        });
        state.map.addOverlay(measureTooltip);
      }
      const createHelpTooltip = () => {
        const id = 'helpTooltipElementId'
        if (helpTooltipElement) {
          state.map.removeOverlay(state.map.getOverlayById(id))
          helpTooltipElement.parentNode?.removeChild(helpTooltipElement);
        }
        helpTooltipElement = document.createElement('div');
        helpTooltipElement.className = 'tooltip hidden';
        helpTooltip = new ol.Overlay({
          id,
          element: helpTooltipElement,
          offset: [15, 0],
          positioning: 'center-left'
        });
        state.map.addOverlay(helpTooltip);
      }
      const formatLength = (line: Geometry) => {
        // 获取投影坐标系
        const sourceProj = state.map.getView().getProjection();
        // ol/sphere里有getLength()和getArea()用来测量距离和区域面积，默认的投影坐标系是EPSG:3857, 其中有个options的参数，可以设置投影坐标系
        const length = sphere.getLength(line, {projection: sourceProj});
        // const length = getLength(line);
        let output;
        if (length > 100) {
          const km = Math.round((length / 1000) * 100) / 100;
          output = `${km} 千米 <br>${parseFloat(String(km * 0.53995)).toFixed(2)} 海里`;
        } else {
          output = `${Math.round(length * 100) / 100} m`;
        }
        return output;
      };
      const addInteraction = () => {
        const id = 'drawName'
        const draw = new interaction.Draw({
          type: 'LineString',  //几何图形类型
          style: new style.Style({
            fill: new style.Fill({
              color: "rgba(255, 255, 255, 0.2)",
            }),
            stroke: new style.Stroke({
              color: "#f3584a",
              width: 2,
            }),
            image: new style.Circle({
              radius: 5,
              stroke: new style.Stroke({
                color: "rgba(0, 0, 0, 0.7)",
              }),
              fill: new style.Fill({
                color: "rgba(255, 255, 255, 0.2)",
              }),
            }),
          }),
        });
        draw.set(id, id)
        createMeasureTooltip(); //创建测量工具提示框
        createHelpTooltip(); //创建帮助提示框
        state.map.addInteraction(draw);
        let listener: EventsKey | EventsKey[];
        //绑定交互绘制工具开始绘制的事件
        const drawstartHandle = (evt: { feature: { getGeometry: () => { (): any; new(): any; on: { (arg0: string, arg1: (evt: any) => void): any; new(): any; }; }; } | null; coordinate: any; }) => {
          sketch = evt.feature; //绘制的要素
          let tooltipCoord = evt.coordinate;// 绘制的坐标
          //绑定change事件，根据绘制几何类型得到测量长度值或面积值，并将其设置到测量工具提示框中显示
          listener = sketch?.getGeometry().on('change', function (evt) {
            const geom = evt.target
            let output;
            output = formatLength(geom);//长度值
            tooltipCoord = geom.getLastCoordinate();//坐标
            if (measureTooltipElement) measureTooltipElement.innerHTML = output;//将测量值设置到测量工具提示框中显示
            measureTooltip.setPosition(tooltipCoord);//设置测量工具提示框的显示位置
          });
        }
        draw.on('drawstart', drawstartHandle);
        //绑定交互绘制工具结束绘制的事件
        const copy = (value: string) => {
          const str = document.createElement('input')
          str.setAttribute('value', value)
          document.body.appendChild(str)
          str.select()
          document.execCommand('copy')
          document.body.removeChild(str)
        }
        const drawendHandle = (evt: { feature: { getGeometry: () => any; }; }) => {
          state.map.removeInteraction(state.map.getInteractions().getArray().filter((v: { get: (arg0: string) => string; }) => v.get(id) === id)[0]);
          sketch = null; //置空当前绘制的要素对象
          measureTooltipElement?.parentNode?.removeChild(measureTooltipElement);
          measureTooltipElement = null; //置空测量工具提示框对象
          helpTooltipElement?.parentNode?.removeChild(helpTooltipElement);
          helpTooltipElement = null; //置空测量工具提示框对象
          unByKey(listener);
          draw.un('drawstart', drawstartHandle);
          draw.un('drawend', drawendHandle);
          state.map.removeInteraction(state.map.getInteractions().getArray().filter((v: { get: (arg0: string) => string; }) => v.get(id) === id)[0]);
          state.map.un('pointermove', pointerMoveHandler)
          cb(evt)
        }
        draw.on('drawend', drawendHandle);
      }
      addInteraction(); //调用加载绘制交互控件方法，添加绘图进行测量
      const pointerMoveHandler = (evt: { dragging: any; coordinate: Coordinate | undefined; }) => {
        if (evt.dragging) {
          return;
        }
        let helpMsg = '单击开始标绘';//当前默认提示信息
        //判断绘制几何类型设置相应的帮助提示信息
        if (sketch) {
          const geom = sketch.getGeometry()
          helpMsg = continueMsg;
          // if (geom.getType() === 'Polygon') {
          //     helpMsg = continueMsg; //绘制多边形时提示相应内容
          // } else if (geom.getType() === 'LineString') {
          //     helpMsg = continueMsg; //绘制线时提示相应内容
          // }
        }
        if (helpTooltipElement)helpTooltipElement.innerHTML = helpMsg; //将提示信息设置到对话框中显示
        helpTooltip.setPosition(evt.coordinate);//设置帮助提示框的位置
        helpTooltipElement?.classList.remove('hidden');//移除帮助提示框的隐藏样式进行显示
      };
      state.map.on('pointermove', pointerMoveHandler); //地图容器绑定鼠标移动事件，动态显示帮助提示框内容
      //地图绑定鼠标移出事件，鼠标移出时为帮助提示框设置隐藏样式
      // state.map.getViewport().on('mouseout', () => {
      //   helpTooltipElement?.addClass('hidden');
      // });
    }
    const drawTrack = (trackSource: string) => {
      startDraw((evt) => {
        const geom = evt.feature.getGeometry()
        const pMap = new Map()
        state.trackPointList = geom.getCoordinates().map((v: any) => {
          const obj = {
            source: trackSource,
            position: v,
            speed: 0
          }
          pMap.set(`${v[0]}-${v[1]}`, obj)
          return obj
        })
        that.$easyMap.initShape({
          map: state.map,
          layerName: "form-track-point-line",
          layerZIndex: 9,
          list: [
            {
              easyMapParams: {
                id: new Date().getTime(),
                position: that.$easyMap.formatPosition.wptTwl(state.trackPointList.map(v => that.$easyMap.formatPosition.cptTwpt(v.position))),
                normalStyle: (f: any, r: any) => TrackStyle.trackLineStyle(f, r, state.map, SourceMap.get(trackSource)?.color, pMap, (s, p) => {
                  state.formTrackPointStartCount++
                  setTimeout(() => {
                    state.formTrackPointEndCount++
                    state.formTrackPointList.push(...p)
                    if (state.formTrackPointStartCount === state.formTrackPointEndCount) {
                      that.$easyMap.initShape({
                        map: state.map,
                        layerName: 'form-track-point',
                        layerZIndex: 10,
                        list: state.formTrackPointList.map((v, i) => {
                            return {
                                easyMapParams: {
                                    id: `form-track-point-${i}`,
                                    position: that.$easyMap.formatPosition.cptTwpt(v.position),
                                    normalStyle: TrackStyle.trackPointStyle(SourceMap.get(v.source).color, v.speed)
                                }
                            }
                        })
                      })
                      state.formTrackPointStartCount = 0
                      state.formTrackPointEndCount = 0
                      state.formTrackPointList = []
                    }
                  }, 10)
                  return s
                }),
              }
            }
          ]
        });
      })
    }
    const onPointFocus = (p1: any, p2: any, p3: any) => {
      that.$easyMap.getShapeView(state.map, [p1?.position, p2.position, p3?.position].filter(v => v))
      const radius = 25
      const longRadius = radius * Math.SQRT2
      that.$easyMap.initShape({
        map: state.map,
        layerName: "focus",
        layerZIndex: 20,
        list: [
          {
            easyMapParams: {
              id: 'focus',
              position: that.$easyMap.formatPosition.cptTwpt(p2.position),
              normalStyle: [new style.Style({ //图层样式
                image: new style.RegularShape({
                  stroke: new style.Stroke({
                    color: '#9F2EFF',
                    width: 2,
                    lineDash: [
                      (longRadius * 3) / 10,
                      (longRadius * 4) / 10,
                      (longRadius * 3) / 10,
                      0
                    ]
                  }),
                  radius1: radius,
                  rotation: Math.PI / (180 / 45),
                  points: 4
                })
              })]
            }
          }
        ]
      });
    }
    const onSubmit = () => {
      const obj = {
        type: state.trackPointList[0].source,
        lines: state.trackPointList.map(v => {
          return {
            lon: v.position[0],
            lat: v.position[1],
            speed: v.speed
          }
        })
      }
      Object.assign(obj, state.form)
      const result = JSON.parse(JSON.stringify(obj))
      console.log(result)
      state.loading = true
      axios.post("/init-speed-track-api/hujie-track-server/mock", [result], {
        contentType: "application/json"
      }).then(res => {
        console.log(res)
        if (res.status === 200 && res.data) {
          ElMessage.success('添加成功！')
          state.trackList.push(Object.assign(result, {show: false, ID: new Date().getTime()}))
          state.trackPointList = []
          that.$easyMap.initShape({
            map: state.map,
            layerName: "form-track-point-line",
            layerZIndex: 9,
            list: []
          });
          that.$easyMap.initShape({
            map: state.map,
            layerName: "form-track-point",
            layerZIndex: 10,
            list: []
          });
        } else {
          ElMessage.error('添加失败！')
        }
        state.loading = false
      })
    }
    const trackShowListCom = computed(() => {
      return state.trackList.filter((v: { show: any; }) => v.show)
    })
    const initTrack = () => {
      that.$easyMap.initShape({
        map: state.map,
        layerName: "track-point-line",
        layerZIndex: 7,
        list: []
      });
      that.$easyMap.initShape({
        map: state.map,
        layerName: "track-point",
        layerZIndex: 8,
        list: []
      });
      that.$easyMap.initShape({
        map: state.map,
        layerName: "track-point-line",
        layerZIndex: 7,
        list: trackShowListCom.value.map((v: any) => {
          const pMap = new Map()
          v.lines.forEach((p: {
              speed: any; type: any; lon: any; lat: any;
          }) => {
            const obj = {
              source: v.type,
              position: [p.lon, p.lat],
              speed: p.speed
            }
            pMap.set(`${p.lon}-${p.lat}`, obj)
          })
          return {
            easyMapParams: {
              id: v.ID,
              position: that.$easyMap.formatPosition.wptTwl(v.lines.map((c: { lon: any; lat: any; }) => that.$easyMap.formatPosition.cptTwpt([c.lon, c.lat]))),
              normalStyle: (f: any, r: any) => TrackStyle.trackLineStyle(f, r, state.map, SourceMap.get(v.type)?.color, pMap, (s, p) => {
                state.initTrackPointStartCount++
                setTimeout(() => {
                  state.initTrackPointEndCount++
                  state.initTrackPointList.push(...p)
                  if (state.initTrackPointStartCount === state.initTrackPointEndCount) {
                    that.$easyMap.initShape({
                      map: state.map,
                      layerName: 'track-point',
                      layerZIndex: 8,
                      list: state.initTrackPointList.map((v, i) => {
                        return {
                          easyMapParams: {
                            id: `init-track-point-${v.ID}-${i}`,
                            position: that.$easyMap.formatPosition.cptTwpt(v.position),
                            normalStyle: TrackStyle.trackPointStyle(SourceMap.get(v.source).color, v.speed)
                          }
                        }
                      })
                    })
                    state.initTrackPointStartCount = 0
                    state.initTrackPointEndCount = 0
                    state.initTrackPointList = []
                  }
                }, 10)
                return s
              }),
            }
          }
        })
      });
    }
    const handleShow = (show: any, item: any) => {
      item.show = show
      initTrack()
    }
    return {
      ...toRefs(state),
      mapLoad,
      drawTrack,
      onPointFocus,
      SourceMap,
      onSubmit,
      handleShow,
      formParams
    }
  }
})
</script>

<style lang="scss" scoped>
.init-speed-track {
  width: 100%;
  height: 100%;
  position: relative;
  .map {
    width: 100%;
    height: 100vh;
  }
  .track {
    position: absolute;
    z-index: 20;
    top: 0;
    left: 0;
    .track-line {
      overflow-y: auto;
      max-height: 180px;
      .line {
        height: 20px;
        display: flex;
        align-items: center;
        .label {
          width: 90px;
        }

      }
    }
    .track-point {
      overflow-y: auto;
      max-height: 600px;
      .item {
        display: flex;
        align-items: center;
        white-space: nowrap;
      }
      .point {
        display: flex;
        .position {
          font-size: 12px;
        }
        border-bottom: 1px solid black;
      }
    }
  }
}
</style>
