<template>
  <div id="map_jk">
    <div id="mapDiv" ref="map">
      <div id="viewDiv" ref="view">
        <div id="menu" class="esri-widget">
        </div>
      </div>
      <div id="viewDiv_2D" ref="view_2D">
        <div id="menu" class="esri-widget">
        </div>
      </div>
      <div id = "overviewDiv" ref = "overview" >

      </div>
    </div>
  </div>
</template>

<script>
import $ from 'jquery';
import {getCurrentInstance, onMounted} from "vue";
import SetMapConfig from "../units/map/SetMapConfig.js"
import InitMap from "../units/map/InitMap.js";
import AddBaseMapLayer from "../units/map/AddBaseMapLayer.js";
import AddSingleLayer from "../units/map/AddSingleLayer.js";
import WaterEffect from "../units/map/WaterEffect.js";
import Measurement from "../units/map/Measurement.js";
import SunshineAnalysis from "../units/map/SunshineAnalysis.js";
import AddPointEvent from "../units/map/AddPointEvent.js";
import SetPopupOptions from "../units/map/SetPopuopOptions";
import AddScaleEvent from "../units/map/AddScaleEvent";
import ViewShedAnalysisWidget from "../units/map/ViewShedAnalysis.js";
import AddLightBallEvent from "../units/map/AddLightBallEvent.js";
import AddThreeGridEvent from "../units/map/addThreeGridEvent.js";
import LimitHeightAnalysis from "../units/map/LimitHeightAnalysis.js";
import SetLocation from "../units/map/SetLocation.js";
import GeometryMeshPrismEffect from "../units/map/GeometryMeshPrismEffect.js";
import ReRenderingEvent from "../units/map/ReRenderingEvent.js";
import PathPipeEvent from "../units/map/PathPipeEvent.js";
import FlyGLTFEvent from "../units/map/FlyGLTFEvent.js";

export default {
  name: "mapJK",
  setup(){
    const ctx = getCurrentInstance();
    const bus = ctx?.appContext.config.globalProperties.$bus;
    let MapReady = null;
    let m_spatialReference = null;
    let m_fullExtent = null;
    let m_initialExtent = null;
    let m_view;
    let m_map;
    let measureWidget = null;
    let sunshineWidget = null;
    let m_handles = [];
    let viewShedAnalysisWidget = null;
    let addLightBallEvent = null;
    let addThreeGridEvent = null;
    let limitHeightAnalysisEvent = null;
    let reRenderingEvent = null;
    let pathPipeEvent = null;
    let flyGLTFEvent = null;
    onMounted(() =>{
      bus.on('CreateMap',() =>{
        MapReady = $.Deferred();
        createMap();
        $.when((MapReady).done(()=>{
          //发送消息
          this.$bus.$emit('SendMessage',{
            action:"MapIsReady",
            data:{
              "message":"地图初始化完成"
            }
          })
        }))
      })
      //调用方法
      bus.on('InvokeMethod',(data) =>{
        invokeMethod(data);
      })
      function createMap(){
        let setMapConfig = new SetMapConfig({
          m_spatialReference,
          m_fullExtent,
          m_initialExtent,
          m_handles
        })
        m_spatialReference = setMapConfig.m_spatialReference;
        m_fullExtent = setMapConfig.m_fullExtent;
        m_initialExtent = setMapConfig.m_initialExtent;
        m_handles = setMapConfig.m_handles;
        let initMap = new InitMap({
          m_map,
          m_view,
          m_spatialReference
        });
        m_map = initMap.m_map;
        m_view = initMap.m_view;
      }
      function invokeMethod(data){
        //后续设置验证token
        runMethod(data);
      }
      function runMethod(data){
        let methodname = data.methodname;
        let params = data.params;
        if(typeof (params) != "string"&& params)
          params = eval(params);
        switch (methodname) {
          case "SetBackground":
            setBackground(params);
            break;
          case "SetLocation":
            setLocation(params);
            break;
          case "AddBaseMapLayer":
            addBaseMapLayer(params);
            break;
          case "AddSingleLayer":
            addSingleLayer(params);
            break;
          case "ReRendering":
            reRendering(params);
            break;
          case "WaterEffect":
            waterEffect(params);
            break;
          case "Measurement":
            measurement(params);
            break;
          case "SunshineAnalysis":
            sunshineAnalysis(params);
            break
          case "AccessFeaturesWithPointEvents":
            accessFeaturesWithPointEvents(params);
            break;
          case "ShowLayersWithScaleEvents":
            showLayersWithScaleEvents(params);
            break;
          case "ViewshedAnalysis":
            viewshedAnalysis(params);
            break;
          case "FeatureLayerThreeDimension":
            featureLayerThreeDimension(params);
            break;
          case "AddLightBall":
            addLightBall(params);
            break;
          case "ThreeGrid":
            threeGrid(params);
            break;
          case "RealPositionGrid":
            realPositionGrid(params);
            break;
          case "LimitHeightAnalysis":
            limitHeightAnalysis(params);
            break;
          case "GeometryMeshPrismEffect":
            geometryMeshPrismEffect(params);
            break;
          case "PathPipe":
            pathPipe(params);
            break;
          case "FlyGLTF":
            flyGLTF(params);
            break;
        }
      }
      function setBackground(params){

      }
      function setLocation(params){
        let setLocation = new SetLocation({
          view:m_view,
          x:params.x,
          y:params.y,
          z:params.z,
          heading:params.heading,
          tilt:params.tilt,
          isfly:params.isfly,
        });
        setLocation.start();
      }
      function addBaseMapLayer(params){
        let addBaseMapLayer = new AddBaseMapLayer({
          id:params.id,
          title:params.title,
          visible:params.visible,
          opacity:params.opacity,
          url:params.url,
          m_spatialReference,
          m_fullExtent,
        })
        m_view.map.basemap = addBaseMapLayer.basemap;
      }
      function addSingleLayer(params){
        let addSingleLayer = new AddSingleLayer({
          m_map,
          type:params.type,
          id:params.id,
          title:params.title,
          visible:params.visible,
          opacity:params.opacity,
          url:params.url,
          renderer:params.renderer,
          elevationInfo:params.elevationInfo
        })
        let layer = addSingleLayer.layer;
        m_map.add(layer);
      }
      function getSymbol(params){
        return {
          type: "mesh-3d",
          symbolLayers: [{
            type: "fill",
            material: {
              color: params.color
            },
            edges: {
              type: "solid",
              color:[255, 255, 255],
            }
          }]
        };
      }
      function reRendering(params){
        let ids_1 = [];
        for(let i=0;i<10000;i++){
          ids_1.push(i);
        }
        let ids_2 = [];
        for(let i=10000;i<20000;i++){
          ids_2.push(i);
        }
        let renderer = {
          type:"unique-value",
          defaultSymbol: getSymbol({color: [0, 255, 0,0.8]}),
          defaultLabel: "Other",
          field: "OBJECTID",
          uniqueValueInfos: [
          ]
        };
        // 每秒更新一次网格颜色
        setInterval(() => {
          renderer.uniqueValueInfos = []
        // 定义分组和对应的颜色
        const groups = {
          group1: {
            ids: ids_1, // 分组1的 ID 列表
            color: [Math.floor(Math.random() * 256), Math.floor(Math.random() * 256), Math.floor(Math.random() * 256), 0.8] // 红色
          },
          group2: {
            ids: ids_2, // 分组3的 ID 列表
            color: [Math.floor(Math.random() * 256), Math.floor(Math.random() * 256), Math.floor(Math.random() * 256), 0.8] // 蓝色
          }
        };
        // 遍历分组，动态生成渲染规则
        Object.keys(groups).forEach(groupKey => {
          const group = groups[groupKey];
          group.ids.forEach(id => {
            renderer.uniqueValueInfos.push({
              value: id, // 对应的 ID
              symbol: getSymbol(group)
            });
          });
        });
        if(reRenderingEvent == null){
          reRenderingEvent = new ReRenderingEvent({
            m_map,
            type:"scene",
            id:"WhiteMold",
            renderer:renderer
          });
        }
        reRenderingEvent.ReRendering();
        }, 5000);
      }
      function waterEffect(params){
        params.id = "waterLayer";
        if(params.status === "hide"){
          let layer = m_map.layers.find(item => item.id === params.id);
          m_map.remove(layer);
          return
        }
        if(params.status === "show"){
          let layer = m_map.layers.find(item => item.id === params.id);
          if(typeof layer === "undefined"){
            let waterEffect = new WaterEffect({
              id:params.id,
              url:params.url,
              waveDirection:params.waveDirection,
              waveStrength:params.waveStrength,
              color:params.color
            })
            layer = waterEffect.layer;
            m_map.add(layer);
          }else{
            m_view.environment.lighting.waterReflectionEnabled = true;
            const renderer = layer.renderer.clone();
            renderer.symbol.symbolLayers.getItemAt(0).waveDirection = params.waveDirection;
            renderer.symbol.symbolLayers.getItemAt(0).waveStrength = params.waveStrength;
            renderer.symbol.symbolLayers.getItemAt(0).color = params.color;
            layer.renderer = renderer;
          }
        }
      }
      function measurement(params){
        let status = params.status;
        let type = params.type;
        let position = params.position;
        if(status === "hide"){
          if(measureWidget !== null){
            m_view.ui.remove(measureWidget);
            measureWidget.destroy();
            measureWidget = null;
          }
          return
        }
        if(status === "show"){
          if(measureWidget === null){
            let measurement = new Measurement({
              view:m_view,
              type
            })
            measureWidget = measurement.widget;
          }
          m_view.ui.add(measureWidget,position);
        }
      }
      function sunshineAnalysis(params){
        let status = params.status;
        let position = params.position;
        if(status === "hide"){
          if(sunshineWidget !== null){
            m_view.ui.remove(sunshineWidget);
            sunshineWidget.destroy();
            sunshineWidget = null;
          }
          return
        }
        if(status === "show"){
          if(sunshineWidget === null){
            let sunshineAnalysis = new SunshineAnalysis({
              view:m_view
            })
            sunshineWidget = sunshineAnalysis.widget;
          }
          m_view.ui.add(sunshineWidget,position);
        }
      }
      function accessFeaturesWithPointEvents(params){
        let status = params.status;
        let mouse_handle_id = params.mouse_handle_id;
        let highlight_handle_id = params.highlight_handle_id;
        if(status === "hide"){
          if(m_handles.has(mouse_handle_id)){
            m_handles.remove(mouse_handle_id);
          }
          if(m_handles.has(highlight_handle_id)){
            m_handles.remove(highlight_handle_id);
          }
          return
        }
        if(status === "show"){
          let type = params.type;
          let mouseTime = params.mouse_time;
          let popupTitle = params.popup_title;
          if(m_handles.has(mouse_handle_id)){
            m_handles.remove(mouse_handle_id);
          }
          if(m_handles.has(highlight_handle_id)){
            m_handles.remove(highlight_handle_id);
          }
          let addPointEvent = new AddPointEvent({
            m_view,
            type,
            highlightHandleId:highlight_handle_id,
            mouseTime,
            popupTitle,
            callbackFunction:accessFeaturesWithPointEventsReturn
          });
          m_handles.add(addPointEvent.mouseHandle,mouse_handle_id);
        }
      }
      function accessFeaturesWithPointEventsReturn(screenPoint,handleId,popupTitle){
        if(m_handles.has(handleId)){
          m_handles.remove(handleId);
        }
        m_view.hitTest(screenPoint).then((response) =>{
          if(response.results.length > 0){
            let result = response.results[0];
            m_view.whenLayerView(result.graphic.layer).then((lyrView) =>{
              let highlightHandle = lyrView.highlight(result.graphic);
              m_handles.add(highlightHandle,handleId);
            })
            let setPopupOptions = new SetPopupOptions({
              title:popupTitle,
              location:m_view.toMap(screenPoint),
              content:result.graphic.attributes
            })
            m_view.popup.open(setPopupOptions.popupOptions());
          }
        })
      }
      function showLayersWithScaleEvents(params){
        let status = params.status;
        let scale_handle_id = params.scale_handle_id;
        if(status === "hide"){
          if(m_handles.has(scale_handle_id)){
            m_handles.remove(scale_handle_id);
          }
          return
        }
        if(status === "show"){
          if(m_handles.has(scale_handle_id)){
            m_handles.remove(scale_handle_id);
          }
          let addScaleEvent = new AddScaleEvent({
            m_view,
            callBackFunction:showLayersWithScaleEventsReturn
          });
          m_handles.add(addScaleEvent.scaleHandle,scale_handle_id);
        }
      }
      function getEyeExtent() {
        const screenWidth = m_view.width;
        const screenHeight = m_view.height;

        // 四个角的像素坐标
        const screenCorners = [
          { x: 0, y: 0 }, // 左上角
          { x: screenWidth, y: 0 }, // 右上角
          { x: screenWidth, y: screenHeight }, // 右下角
          { x: 0, y: screenHeight }, // 左下角
        ];

        // 将屏幕角坐标转为地图坐标
        const mapPoints = screenCorners.map((screenPoint) => m_view.toMap(screenPoint)).filter(p => p);

        // 添加 camera.position 到 mapPoints
        const cameraPoint = m_view.camera.position;

        if (mapPoints.length < 4) {
          if (cameraPoint) {
            const bufferDistance = 2000; // 2公里
            const spatialReference = m_view.spatialReference;

            const screenExtent = {
              xmin: cameraPoint.x - bufferDistance,
              ymin: cameraPoint.y - bufferDistance,
              xmax: cameraPoint.x + bufferDistance,
              ymax: cameraPoint.y + bufferDistance,
              spatialReference: spatialReference,
            };
            console.warn("视图范围不足4个有效点，使用摄像机位置生成的2公里范围。");
            console.log(screenExtent);
            return screenExtent;
          } else {
            console.warn("无法获取摄像机位置，请检查视图状态。");
            return null;
          }
        } else {
          try {
            // 获取最小和最大坐标值
            const xmin = Math.min(...mapPoints.map((p) => p.x));
            const ymin = Math.min(...mapPoints.map((p) => p.y));
            const xmax = Math.max(...mapPoints.map((p) => p.x));
            const ymax = Math.max(...mapPoints.map((p) => p.y));

            const screenExtent = {
              xmin: xmin,
              ymin: ymin,
              xmax: xmax,
              ymax: ymax,
              spatialReference: m_view.spatialReference,
            };
            console.log(screenExtent);
            return screenExtent;
          } catch (e) {
            console.error("获取地图范围时出错：", e);
            return null;
          }
        }
      }




      function showLayersWithScaleEventsReturn(scaleValue){
        let eyeExtent = getEyeExtent();
        if(!eyeExtent){
          return
        }
        let height = m_view.camera.position.z;
        console.log("height",height,"scale",m_view.scale)
        let size = extentGridLimit({
          eyeExtent,
          height
        })
        let layerHeight;
        if(size > 400){
          layerHeight = 400;
        }else{
          layerHeight = size;
        }
        if(addThreeGridEvent){
          addThreeGridEvent.extent = {minX:eyeExtent.xmin,maxX:eyeExtent.xmax,minY:eyeExtent.ymin,maxY:eyeExtent.ymax};
          addThreeGridEvent.height = height>1200?1200:height;
          addThreeGridEvent.size = size;
          addThreeGridEvent.layerHeight = layerHeight;
          addThreeGridEvent.gridEnabled = true;
          addThreeGridEvent.netEnabled = true;
          addThreeGridEvent.start();
        }else{
          addThreeGridEvent = new AddThreeGridEvent({
            view:m_view,
            extent: {minX:eyeExtent.xmin,maxX:eyeExtent.xmax,minY:eyeExtent.ymin,maxY:eyeExtent.ymax},
            height:height>1200?1200:height,
            size:size,
            gridEnabled : true,
            netEnabled : true,
            layerHeight:layerHeight,
          })
          addThreeGridEvent.start();
        }

      }

      function extentGridLimit(params){
        try{
          let size = [0.97,7.73,61.84,123.69,1850];
          params.eyeExtent = {
            xmin: params.eyeExtent.xmin < -60000?-60000:params.eyeExtent.xmin,
            ymin: params.eyeExtent.ymin < -60000?-60000:params.eyeExtent.ymin,
            xmax: params.eyeExtent.xmax > 60000?60000:params.eyeExtent.xmax,
            ymax: params.eyeExtent.ymax > 70000?70000:params.eyeExtent.ymax,
          }
          for(let i = 0;i<size.length;i++){
            let xCount = Math.floor((params.eyeExtent.xmax - params.eyeExtent.xmin) / size[i]);
            let yCount = Math.floor((params.eyeExtent.ymax - params.eyeExtent.ymin) / size[i]);
            let zCount = Math.floor(params.height / size[i]);
            let count = xCount * yCount * zCount;
            if(count < 200000){
              return size[i]
            }
          }
        }catch(e){
          debugger
          console.log("params",params)
        }
      }

      // function showLayersWithScaleEventsReturn(scaleValue){
      //   let layer = m_map.layers.find(item => item.id === "WhiteMold");
      //   if(scaleValue > 50000){
      //     if(layer){
      //       layer.visible = false;
      //     }
      //   }else{
      //     if(layer){
      //       layer.visible = true;
      //     }
      //   }
      // }
      function viewshedAnalysis(params){
        let status = params.status;
        if(status === "hide"){
          if(viewShedAnalysisWidget !== null){
            viewShedAnalysisWidget.clearAnalysis();
          }
          return
        }
        if(status === "show"){
          if(viewShedAnalysisWidget === null){
            viewShedAnalysisWidget = new ViewShedAnalysisWidget({  view:m_view  });
            viewShedAnalysisWidget.startAnalysis();
          }
        }
      }
      function featureLayerThreeDimension(params){
        let status = params.status;

      }
      function addLightBall(params){
        let status = params.status;
        if(addLightBallEvent){
          addLightBallEvent.clear();
          addLightBallEvent = null;
        }
        if(status === "hide"){
          return
        }
        addLightBallEvent = new AddLightBallEvent({
          view:m_view
        })
        addLightBallEvent.start()
      }
      function threeGrid(params){
        let status = params.status;
        if(status == "hide"){
          if(addThreeGridEvent){
            addThreeGridEvent.clear();
            addThreeGridEvent = null;
          }
          return
        }
        let animationEnabled = false;
        if(params.animationEnabled){
          animationEnabled = params.animationEnabled;
        }
        if(addThreeGridEvent){
          addThreeGridEvent.height = params.height;
          addThreeGridEvent.size = params.size;
          addThreeGridEvent.layerHeight = params.layerHeight;
          addThreeGridEvent.animationEnabled = animationEnabled;
          addThreeGridEvent.gridEnabled = true;
          addThreeGridEvent.netEnabled = true;
          addThreeGridEvent.start();
        }else{
          addThreeGridEvent = new AddThreeGridEvent({
            view:m_view,
            extent : {minX:2176,maxX:6048,minY:-1024,maxY:1352},
            height : params.height,
            size : params.size,
            layerHeight :params.layerHeight,
            gridEnabled:true,
            netEnabled:true,
            animationEnabled
          })
          addThreeGridEvent.start();
        }
      }

      function realPositionGrid(params){
        let status = params.status;

      }

      function limitHeightAnalysis(params){
        let status = params.status;
        if(limitHeightAnalysisEvent){
          limitHeightAnalysisEvent.clear();
          limitHeightAnalysisEvent =null;
        }
        if(status == "hide"){
          return
        }
        limitHeightAnalysisEvent = new LimitHeightAnalysis({
          view:m_view,
          map:m_map,
          layerId:params.layerId,
          limitH:params.limitH,
          maxLimitH:params.maxLimitH,
          rings:params.rings,
        });
        limitHeightAnalysisEvent.start()
      }

      function geometryMeshPrismEffect(params){
        let status = params.status;
        let f_layer = m_map.layers.find(item => item.id === "geometryMeshPrismEffect");
        if (f_layer) {
          m_map.remove(f_layer);
        }
        if(status == "hide"){
          return
        }
        let geometryMeshPrismEffect = new GeometryMeshPrismEffect({
          view:m_view,
          m_map,
          items:params.items,
          startHeight:params.startHeight,
          rings:params.rings
        })
      }

      function pathPipe(params){
        let status = params.status;
        if(pathPipeEvent){
          pathPipeEvent.clear();
          pathPipeEvent = null;
        }
        if(status == "hide"){
          return
        }
        pathPipeEvent = new PathPipeEvent({
          view:m_view,
          paths:params.paths,
          color:params.color,
          pipeRadius:params.pipeRadius
        });
        pathPipeEvent.start()
      }
      function flyGLTF(params){
        let status = params.status;
        if(flyGLTFEvent){
          flyGLTFEvent.clear();
          flyGLTFEvent = null;
        }
        if(status == "hide"){
          return
        }
        flyGLTFEvent = new FlyGLTFEvent({
          view:m_view,
          path:params.paths,
          speed:0.0001
        })
        flyGLTFEvent.start();
        if(params.isFollow){
          flyGLTFEvent.followPath();
        }
      }
    })
  }
}
</script>

<style scoped lang="scss">
#map_jk,#mapDiv,#viewDiv{
  height: 100%;
}
:deep(.esri-view-surface--touch-none::after){
  outline: none !important;
}
</style>