<template>
  <div class="cesium-page-css">
    <basis-cesium ref="basisCesium" :access-token="this.$setting.cesiumSetting.defaultAccessToken" />
    <main-view ref="mainView" :speed="speed" :heading="heading2" :v2xname="v2xname" :driveMode="driveMode"
      :endTime="endTime" />
  </div>
</template>

<script>
import Worker from "@/assets/js/bessel.worker.js";
import basisCesium from "@/components/cesium/basis-cesium.vue";
import mainView from "@/components/other/main-view.vue";
import websocket from "@/utils/ws/websocket.js";
import axios from "axios";
import SpaceData from "@/assets/SpaceJSON.json";
import CarJSON from "@/assets/CarJSON.json";
let v2xdata = {
  v2xArray: [],
};
let baseData = {
  mainCarID: "",
  perceiveList: [],
  mainLocation: {
    lon: 116.50304817785404,
    lat: 39.80882415169232,
  },
};
let plainData = {
  lon: 0,
  lat: 0,
};
const ParkingSpace = [
  { P: "C002", lon: "120.70663538", lat: "31.32409565" },
  { P: "C003", lon: "120.70663038", lat: "31.32407265" },
  { P: "C004", lon: "120.70662538", lat: "31.32404965" },
  { P: "C005", lon: "120.70661838", lat: "31.32401665" },
  { P: "C006", lon: "120.70661338", lat: "31.32399365" },
  { P: "C007", lon: "120.70660838", lat: "31.32397065" },
];
let pValue = "";
let worker = null;
let postData = [];
let AllTingCheChang = [];

let preWsTime = 0;
let preHMITime = 0;

// 是否需要进行路径规划
let needFindPath = true;

export default {
  name: "HomeView",
  components: {
    basisCesium,
    mainView,
  },
  //L
  data() {
    return {
      heading2: "—— ——", //航向角显示
      v2xname: "异常车辆预警", //预警事件名称
      driveMode: "—— ——", //驾驶模式
      speed: 0, //速度
      endTime: false, //用于判断预警事件是否展示完毕，false为没有预警事件
      // 是否是车内视角
      firstPerspective: false,
      audioSrc: "@/assets/11582.mp3",
    };
  },
  //A
  mounted() {
    // 120.70487827, 31.32469438 176.6541769857891
    // 120.70486427, 31.32469337 176.68233785573705
    // 120.70450226, 31.32472483 140.1278723424079
    // 120.7044951, 31.32471744 125.72534272264176
    // 120.70449184, 31.32471254 116.59055210401831
    // 120.70448881, 31.32470443 103.82035744116246
    // 120.70448773, 31.32469666 92.04861226425777
    // 120.70448812, 31.32469172 84.64731549277309
    // 120.70448989, 31.32468488 74.0716768319416
    // 120.7044918, 31.32468057 67.23386687836239
    // 120.70449568, 31.32467475 57.28430640874274
    // 120.70449925, 31.3246713 50.56300411447833
    // 120.70450527, 31.32466652 40.423499499135175
    // 120.70451002, 31.32466347 33.654283427843154
    // 120.70451755, 31.32466059 23.63138380201046
    // 120.70452293, 31.32465874 17.30164259248454
    // 120.70453232, 31.32465719 9.975568028350523
    // 120.70454182, 31.3246563 5.34004158206794
    // 120.70454854, 31.32465612 3.2548804511114184
    // 120.70455936, 31.32465585 1.1908997367711152
    // 120.70456667, 31.32465606 0.3411149209948121
    // 120.70457733, 31.32465623 -0.3316792028189468
    // const music = new Audio(
    //   "http://downsc.chinaz.net/Files/DownLoad/sound1/201906/11582.mp3"
    // );
    // music.play();
    this.initMap();

    this.websocketClient();
    worker = new Worker();
    worker.onmessage = (e) => {
      if (this.avpStatus) {
        let result = this.$refs.basisCesium.drawLine(e.data[0], e.data[1]);
        // if (result.code) {
        //   this.moveCar(result.data.lon, result.data.lat, e.data[2]);
        // } else {
        //   this.moveCar(e.data[0], e.data[1], e.data[2]);
        // }

        this.moveCar(e.data[0], e.data[1], e.data[2]);
      } else {
        this.moveCar(e.data[0], e.data[1], e.data[2]);
      }
    };
    // 规划
    // this.$refs.basisCesium.findPathPlanning("origin", "destination");
    this.$refs.basisCesium.addParkingSpace(30.7065927, 114.3241276, 0);
    // this.$refs.basisCesium.moveParkingSpace(120.7065927, 31.3241276, 100);
    setTimeout(this.getSpaceData, 5000);
    setInterval(this.getSpaceData, 20000);

    // this.addTest()
  },
  methods: {
    /**
     * 模拟入库
     */
    addTest() {
      this.$refs.basisCesium.addTest();
    },

    initMap() {
      this.$refs.basisCesium.buildCesiumWorld();
      // this.$refs.basisCesium.setGaoDeBasemap();
      this.$refs.basisCesium.inject3DtilesMapByUrl("unit/tileset.json");
      this.$refs.basisCesium.inject3DtilesMapByUrl_two("garage/tileset.json");
      this.$refs.basisCesium.addWmsDT();
      this.$refs.basisCesium.addWmsGQDT();
      this.$refs.basisCesium.cesiumCameraflyTo(
        120.7065927,
        31.3241276,
        150,
        -150,
        -52,
        0
      );
      this.$refs.basisCesium.initLine();
    },
    async websocketClient() {
      this.websocketHeartCheck = {
        lastSecond: 0,
        heartTimer: null
      }

      await websocket.connectSocket();
      // 2.2. 联网车辆位姿数据topic
      websocket.stompClient.subscribe(
        this.$setting.webSocket.dic["/topic/vehicle"],
        (message) => {
          // 更新接收消息时间
          this.websocketHeartCheck.lastSecond = new Date().getTime();

          var bodyData = JSON.parse(message.body);
          this.topicVehicle(bodyData);

          // let curTime = new Date().getTime();
          // console.log('接收后台时间', bodyData.wsTime, 'hmi时间', curTime, '相差时间', curTime - bodyData.wsTime)
          // console.log('后台两帧时间差', bodyData.wsTime - preWsTime, 'hmi接收时间差', curTime - preHMITime)
          // console.log('车辆位置', bodyData.vehicleData[0].longitude + ',' + bodyData.vehicleData[0].latitude)
          // console.log('')

          // preWsTime = bodyData.wsTime
          // preHMITime = curTime
        }
      );

      // 2.3. 联网车辆状态数据topic
      websocket.stompClient.subscribe(
        this.$setting.webSocket.dic["/topic/vehicleStatus"],
        (message) => {
          // 更新接收消息时间
          this.websocketHeartCheck.lastSecond = new Date().getTime();

          var bodyData = JSON.parse(message.body);
          this.topicVehicleStatus(bodyData);
          //AAAAAA
        }
      );
      // 2.4. 感知目标物数据topic
      websocket.stompClient.subscribe(
        this.$setting.webSocket.dic["/topic/dataMerge"],
        (message) => {
          // 更新接收消息时间
          this.websocketHeartCheck.lastSecond = new Date().getTime();

          var bodyData = JSON.parse(message.body);
          this.topicDataMerge(bodyData);
        }
      );
      // 2.5. V2X预警开始topic
      websocket.stompClient.subscribe(
        this.$setting.webSocket.dic["/topic/v2xStart"],
        (message) => {
          // 更新接收消息时间
          this.websocketHeartCheck.lastSecond = new Date().getTime();

          var bodyData = JSON.parse(message.body);
          this.topicv2xStart(bodyData);
        }
      );
      // 2.6. V2X预警结束topic
      websocket.stompClient.subscribe(
        this.$setting.webSocket.dic["/topic/v2xEnd"],
        (message) => {
          // 更新接收消息时间
          this.websocketHeartCheck.lastSecond = new Date().getTime();

          var bodyData = JSON.parse(message.body);
          this.topicv2xEnd(bodyData);
        }
      );
      websocket.stompClient.subscribe(
        this.$setting.webSocket.dic["/topic/points"],
        (message) => {
          // 更新接收消息时间
          this.websocketHeartCheck.lastSecond = new Date().getTime();

          var bodyData = JSON.parse(message.body);
          pValue = bodyData.parkingSpace;

          // 需要进行路径规划，此场景出现在先接收到泊车指令，后接收车位指令
          if (needFindPath) {
            this.findPathPlanning()
          }

          // 更新停车位
          const lonLat = this.getLonLatByP(pValue);
          this.$refs.basisCesium.moveParkingSpace(lonLat.lon, lonLat.lat, 190);
        }
      );

      // if (this.websocketHeartCheck.heartTimer) {
      //   return
      // }
      // this.websocketHeartCheck.heartTimer = setInterval(() => {
      //   let newSecond = new Date().getTime();
      //   if (newSecond - this.websocketHeartCheck.lastSecond > 1000 * 30) {
      //     // 0:正在连接中，1：已连接，2：正在关闭，3：已关闭
      //     if (websocket.stompClient.readyState == 2 && websocket.stompClient.readyState == 3) {
      //       clearInterval(this.websocketHeartCheck.heartTimer)
      //       this.websocketHeartCheck.heartTimer = null;

      //       // 重新开始连接
      //       this.websocketClient()
      //     }
      //   }
      // }, 1000)
    },
    topicVehicleStatus(msg) {
      if (msg.vehicleStatusList.length != 0) {
        let driveMode1 = msg.vehicleStatusList[0].driveMode;
        switch (driveMode1) {
          case 0:
            this.driveMode = "自动驾驶";
            break;
          case 1:
            this.driveMode = "人工驾驶";
            break;
          case 2:
            this.driveMode = "远程驾驶";
            break;
          default:
            this.driveMode = "—— ——";
            break;
        }
      }
    },
    topicv2xStart(msg) {
      let v2xStartName = msg.v2xStartData[0].name;
      if (
        v2xStartName == "异常车辆预警" ||
        v2xStartName == "车辆入场预警" ||
        v2xStartName == "前向碰撞预警" ||
        v2xStartName == "盲区/变道预警" ||
        v2xStartName == "交叉路口碰撞预警" ||
        v2xStartName == "弱势交通参与者碰撞预警"
      ) {
        v2xdata.v2xArray.push({
          id: msg.v2xStartData[0].id,
          name: msg.v2xStartData[0].name,
          priority: msg.v2xStartData[0].priority,
          no: msg.v2xStartData[0].no,
        });
        //通过冒泡排序对插入在v2xArray的数组按照priority优先级由低到高进行排序
        const n = v2xdata.v2xArray.length;
        if (n > 1) {
          for (let i = 0; i < n - 1; i++) {
            let swapped = false; // 优化：如果某一轮没有进行交换，则说明数组已经有序，可以提前结束循环
            for (let j = 0; j < n - 1 - i; j++) {
              if (
                parseInt(v2xdata.v2xArray[j].priority) >
                parseInt(v2xdata.v2xArray[j + 1].priority)
              ) {
                // 交换位置
                const temp = v2xdata.v2xArray[j];
                v2xdata.v2xArray[j] = v2xdata.v2xArray[j + 1];
                v2xdata.v2xArray[j + 1] = temp;
                swapped = true;
              }
            }
            if (!swapped) {
              break; // 优化：如果没有进行交换，则说明数组已经有序，可以提前结束排序
            }
          }
        }
        this.v2xname = v2xdata.v2xArray[n - 1].name;
        this.endTime = true;
      }
    },
    topicv2xEnd(msg) {
      v2xdata.v2xArray.forEach((item, index) => {
        if (item.id === msg.v2xEndData[0].id) {
          v2xdata.v2xArray.splice(index, 1); // 如果找到匹配的id，则删除该数组
        }
      });
      const n = v2xdata.v2xArray.length;
      if (n == 0) {
        //如果数组为空，则将endTime变为false，表示预警事件全部结束，隐藏预警
        this.endTime = false;
      } else {
        this.v2xname = v2xdata.v2xArray[n - 1].name;
        this.endTime = true;
        //否则会将优先级最高的事件进行展示
      }
    },
    //A
    topicVehicle(msg) {
      // #region L
      this.speed = msg.vehicleData[0].speed;
      let heading1 = Math.floor(msg.vehicleData[0].heading);
      if (heading1 < 0) {
        heading1 += 360;
      }
      switch (true) {
        case heading1 === 0:
          this.heading2 = "正北";
          break;
        case heading1 === 90:
          this.heading2 = "正东";
          break;
        case heading1 === 180:
          this.heading2 = "正南";
          break;
        case heading1 === 270:
          this.heading2 = "正西";
          break;
        case heading1 > 0 && heading1 <= 45:
          this.heading2 = "北偏东 " + heading1 + "°";
          break;
        case heading1 > 45 && heading1 < 90:
          this.heading2 = "东偏北 " + (90 - heading1) + "°";
          break;
        case heading1 > 90 && heading1 <= 135:
          this.heading2 = "东偏南 " + (heading1 - 90) + "°";
          break;
        case heading1 > 135 && heading1 < 180:
          this.heading2 = "南偏东 " + (180 - heading1) + "°";
          break;
        case heading1 > 180 && heading1 <= 225:
          this.heading2 = "南偏西 " + (heading1 - 180) + "°";
          break;
        case heading1 > 225 && heading1 < 270:
          this.heading2 = "西偏南 " + (270 - heading1) + "°";
          break;
        case heading1 > 270 && heading1 <= 315:
          this.heading2 = "西偏北 " + (heading1 - 270) + "°";
          break;
        case heading1 > 315 && heading1 < 360:
          this.heading2 = "北偏西 " + (360 - heading1) + "°";
          break;
        default:
          break;
      }
      // #endregion A

      plainData.lon = msg.vehicleData[0].longitude;
      plainData.lat = msg.vehicleData[0].latitude;

      let longitude = msg.vehicleData[0].longitude;
      let latitude = msg.vehicleData[0].latitude;
      let heading = msg.vehicleData[0].heading - 90;
      if (baseData.mainCarID == "") {
        let id = msg.vehicleData[0].vehicleId;
        let url = "cesium/XC60.glb";
        this.$refs.basisCesium.addOneModelById(
          id,
          url,
          longitude,
          latitude,
          heading,
          0.8
        );
        baseData.mainCarID = id;
      } else {
        worker.postMessage([longitude, latitude, heading]);
        // this.moveCar(longitude, latitude, heading);
        baseData.mainLocation.lon = longitude;
        baseData.mainLocation.lat = latitude;
      }

      // this.$refs.basisCesium.drawLine(longitude, latitude);
    },
    moveCar(longitude, latitude, heading) {
      if (this.firstPerspective) {
        this.$refs.basisCesium.moveModelById(
          baseData.mainCarID,
          longitude,
          latitude,
          heading,
          true,
          [-1, 0, 0],
          true
        );
      } else {
        this.$refs.basisCesium.moveModelById(
          baseData.mainCarID,
          longitude,
          latitude,
          heading,
          true,
          [-31.5, 0, 10]
        );
      }
    },
    transformGCJ02ToWGS84(lng, lat) {
      var a = 6378245.0;
      var ee = 0.00669342162296594323;
      var pi = Math.PI;

      function outOfChina(lng, lat) {
        if (lng < 72.004 || lng > 137.8347) {
          return true;
        }
        if (lat < 0.8293 || lat > 55.8271) {
          return true;
        }
        return false;
      }

      function transformLng(lng, lat) {
        var ret =
          300.0 +
          lng +
          2.0 * lat +
          0.1 * lng * lng +
          0.1 * lng * lat +
          0.1 * Math.sqrt(Math.abs(lng));
        ret +=
          ((20.0 * Math.sin(6.0 * lng * pi) + 20.0 * Math.sin(2.0 * lng * pi)) *
            2.0) /
          3.0;
        ret +=
          ((20.0 * Math.sin(lng * pi) + 40.0 * Math.sin((lng / 3.0) * pi)) *
            2.0) /
          3.0;
        ret +=
          ((150.0 * Math.sin((lng / 12.0) * pi) +
            300.0 * Math.sin((lng / 30.0) * pi)) *
            2.0) /
          3.0;
        return ret;
      }

      function transformLat(lng, lat) {
        var ret =
          -100.0 +
          2.0 * lng +
          3.0 * lat +
          0.2 * lat * lat +
          0.1 * lat * lng +
          0.2 * Math.sqrt(Math.abs(lng));
        ret +=
          ((20.0 * Math.sin(6.0 * lng * pi) + 20.0 * Math.sin(2.0 * lng * pi)) *
            2.0) /
          3.0;
        ret +=
          ((20.0 * Math.sin(lat * pi) + 40.0 * Math.sin((lat / 3.0) * pi)) *
            2.0) /
          3.0;
        ret +=
          ((160.0 * Math.sin((lat / 12.0) * pi) +
            320 * Math.sin((lat * pi) / 30.0)) *
            2.0) /
          3.0;
        return ret;
      }

      function transform(lng, lat) {
        if (outOfChina(lng, lat)) {
          return [lng, lat];
        }
        var dLng = transformLng(lng - 105.0, lat - 35.0);
        var dLat = transformLat(lng - 105.0, lat - 35.0);
        var radLat = (lat / 180.0) * pi;
        var magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        var sqrtMagic = Math.sqrt(magic);
        dLng = (dLng * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * pi);
        dLat = (dLat * 180.0) / (((a * (1 - ee)) / (magic * sqrtMagic)) * pi);
        var mgLng = lng + dLng;
        var mgLat = lat + dLat;
        return [mgLng, mgLat];
      }

      return transform(lng, lat);
    },
    getDistance(lng1, lat1, lng2, lat2) {
      let radLat1 = (lat1 * Math.PI) / 180.0;
      let radLat2 = (lat2 * Math.PI) / 180.0;
      let a = radLat1 - radLat2;
      let b = (lng1 * Math.PI) / 180.0 - (lng2 * Math.PI) / 180.0;
      let s =
        2 *
        Math.asin(
          Math.sqrt(
            Math.pow(Math.sin(a / 2), 2) +
            Math.cos(radLat1) *
            Math.cos(radLat2) *
            Math.pow(Math.sin(b / 2), 2)
          )
        );
      s = s * 6378137;
      s = Math.round(s * 10000) / 10000;
      return s;
    },
    topicDataMerge(msg) {
      for (let i = 0; i < msg.objectData.length; i++) {
        let allPerceive = [];
        for (let j = 0; j < msg.objectData[i].participant.length; j++) {
          // allPerceive.push({
          //   id: msg.objectData[i].participant[j].ptcId,
          //   type: msg.objectData[i].participant[j].ptcType,
          //   longitude: msg.objectData[i].participant[j].longitude,
          //   latitude: msg.objectData[i].participant[j].latitude,
          //   heading: msg.objectData[i].participant[j].heading,
          // });
          let distance = this.getDistance(
            baseData.mainLocation.lon,
            baseData.mainLocation.lat,
            msg.objectData[i].participant[j].longitude,
            msg.objectData[i].participant[j].latitude
          )
          // console.log('距离:' + distance, '类型:' + msg.objectData[i].participant[j].ptcType, 'id:' + msg.objectData[i].participant[j].ptcId)
          if (distance < 100) {
            allPerceive.push({
              id: msg.objectData[i].participant[j].ptcId,
              type: msg.objectData[i].participant[j].ptcType,
              longitude: msg.objectData[i].participant[j].longitude,
              latitude: msg.objectData[i].participant[j].latitude,
              heading: msg.objectData[i].participant[j].heading,
            });
          }
        }
        this.$refs.basisCesium.beginPerceive(
          msg.objectData[i].deviceCode,
          allPerceive
        );
      }
    },
    getLonLatByP(pValue) {
      const parkingInfo = ParkingSpace.find((item) => item.P === pValue);
      if (parkingInfo) {
        const lon = parseFloat(parkingInfo.lon); // 转换为浮点数
        const lat = parseFloat(parkingInfo.lat); // 转换为浮点数
        return { lon, lat };
      } else {
        // 如果找不到对应的P值，则返回null或者其他适当的值
        return null;
      }
    },
    setAvpStatus(bool) {
      this.avpStatus = bool;
      if (this.avpStatus && pValue != "") {
        // 需要进行路径规划，此场景出现在先接收到车位指令，后接收泊车指令
        if (needFindPath) {
          this.findPathPlanning()
        }
      } else {
        // 泊车结束，下次泊车需要路径规划
        needFindPath = true;

        this.$refs.basisCesium.moveParkingSpace(131.7065927, 40.3241276, 10);
        this.$refs.basisCesium.ClearLine();
      }
    },

    /**
     * 自主泊车+有停车位信息，才能开始进行路径规划
     */
    findPathPlanning() {
      const lonLat = this.getLonLatByP(pValue);
      // 起点
      let origin = [plainData.lon, plainData.lat];
      if (
        this.getDistance(
          plainData.lon,
          plainData.lat,
          120.7062195,
          31.3238778
        ) < 8
      ) {
        origin = [120.7062195, 31.3238778];
      } else {
        console.log("距离不够咧，起点", origin);
        console.log(
          this.getDistance(
            plainData.lon,
            plainData.lat,
            120.7062195,
            31.3238778
          )
        );
      }
      const destination = [lonLat.lon, lonLat.lat];
      const steps = false;
      const waypoints = [];
      const trafficCondition = false;
      const equalDistance = false;
      const distance = 1;
      this.$refs.basisCesium.moveParkingSpace(lonLat.lon, lonLat.lat, 190);
      this.$refs.basisCesium.findPathPlanning(
        origin,
        destination,
        steps,
        waypoints,
        trafficCondition,
        equalDistance,
        distance
      );

      // 泊车开始，不需要再进行路径规划了
      needFindPath = true;
    },

    async getSpaceData() {
      let data = JSON.stringify({
        pageNo: 20,
        pageSize: 1000,
      });
      await axios
        .post(
          "https://sip-avp.isungent.cn:8443/hkapi/pms/v1/parkingSpace/spaceNo",
          data,
          {
            headers: {
              "Content-Type": "application/json",
            },
          }
        )
        .then((response) => {
          AllTingCheChang = [];
          const newData = response.data.data.list;
          postData = newData;
          // 遍历新数据，根据state值添加或移除模型
          postData.forEach((car) => {
            const parkingSpot = SpaceData.find(
              (spot) => spot.spaceCode === car.spaceNo
            );
            if (parkingSpot) {
              //this.removeCarModel(car.spaceNo);
              // 检查该车位是否已经添加模型
              if (car.state === 1) {
                //将车位信息添加到已添加模型的数据中;
                const name = parkingSpot.spaceCode;
                const latlon = [parkingSpot.center[0], parkingSpot.center[1]];
                if (
                  this.getDistance(
                    baseData.mainLocation.lon,
                    baseData.mainLocation.lat,
                    latlon[0],
                    latlon[1]
                  ) > 2
                ) {
                  AllTingCheChang.push({
                    id: name,
                    longitude: latlon[0],
                    latitude: latlon[1],
                    heading: parkingSpot.heading,
                  });
                }
              }
            }
          });
          this.$refs.basisCesium.beginParkingLot(AllTingCheChang);
        });
    },
  },
  destroyed() {
    if (window.viewer) {
      window.viewer.primitives.removeAll();
      window.viewer.destroy();
      Cesium.CameraEventAggregator.prototype.removeInputAction;
      Cesium.Texture.prototype.destroy;
      delete window.viewer;
    }
    worker.postMessage("线程关闭");
    worker.terminate();
  },
};
</script>
<style scoped>
#cesium-page-css {
  position: absolute;
  height: 100%;
  width: 100%;
}
</style>
