<template>
  <div
    class="main"
    v-loading.fullscreen.lock="loading"
    element-loading-text="数据加载中..."
    element-loading-spinner="el-icon-loading"
    element-loading-background="rgba(0, 0, 0, 0.8)"
  >
    <wMap :mapId="'situation-map'" ref="wMap" />
    <home-left ref="leftVideo" />
    <home-right />
  </div>
</template>

<script>
import wMap from "../../components/Standard/mapboxMap.vue";
import { initWs } from "../../utils/websocket";
import dict from "../../config/holo/dictionary";
import * as mapTools from "../../utils/mapboxTools";
import mapAssets from "../../config/holo/mapAssets";

import HomeLeft from "./left/index.vue";
import HomeRight from "./right/index.vue";
import generalVehiclePopup from "../mapComponents/generalVehicleDetail.vue";
const GeneralVehiclePopup = Vue.extend(generalVehiclePopup);
let map,
  licenseLabel = {},
  vehicleModels = {},
  lastFrameTime = "",
  vehicleModelTypes = {},
  greenPolygonLayer = null,
  passerbyNumLayer = null,
  //---
  vehiclePopups = {},
  popupVises = {},
  vehiclePopupInstances = {},
  //---
  layers = {
    first: {
      vehicle: null,
      license: null,
      trackLineLayer: null,
      trackLineLayer1: null,
    },
    second: {},
  };

export default {
  name: "home6",
  components: {
    HomeRight,
    HomeLeft,
    wMap,
  },
  props: {},
  computed: {},
  data() {
    return {
      msgStart: true,
      bounds: [],
      situationTimeVal: "",
      selectVehicle: null,
      lastLocation: [],
      sockets: [],
      licenseState: false,
      layerShowRenders: true,

      loading: true,
      slowLines: {},
      slowTrafficIds: [],
    };
  },
  watch: {},
  mounted() {
    this.$nextTick(() => {
      this.initDictAndLoad();
    });
  },
  created() {
    this.slowTrafficIds = situation_slowTraffic.slowIds;
  },
  methods: {
    //---
    addVehicleLicenses(option) {
      if (option.picLicense) {
        let ele = document.createElement("div");
        ele.style.color = "white";
        ele.innerText = option.picLicense;
        ele.style.backgroundImage = `url('${
          mapAssets.mapIcons[`license${option.licenseColor}`]
        }')`;
        ele.style.backgroundSize = "100% 100%";
        ele.style.fontSize = "8px";
        ele.style.textAlign = "center";
        ele.style.padding = "2px 4px 8px 4px";
        let license = window.tb.label({
          htmlElement: ele,
          alwaysVisible: true,
          topMargin: 2,
        });
        license.setCoords([option.longitude, option.latitude, 4]);
        license.userData.data = { picLicense: option.picLicense };
        window.tb.add(license, `license${option.id}`);
        licenseLabel[`license${option.id}`] = license;
      }
    },
    // 选中模型改变
    onSelectedChangeVehicle(e) {
      if (e.detail.selected) {
        this.removeVehiclePopup();
        this.clearSelectVehicle();
        setTimeout(() => {
          this.selectVehicle = e.detail.userData.data;
          this.addCheckDetail(this.selectVehicle);
        }, 0);
      }
    },
    removeVehiclePopup() {
      for (let key in vehiclePopups) {
        vehiclePopups[key]?.remove();
      }
      vehiclePopups = {};
      popupVises = {};
      vehiclePopupInstances = {};
    },
    // 清理选中车辆数据及其对应的轨迹
    clearSelectVehicle() {},
    // 车辆详情弹窗内容
    addCheckDetail(data) {
      if (vehiclePopups[`popup${data.id}`]) {
        if (popupVises[`popup${data.id}`]) {
          vehiclePopups[`popup${data.id}`].setLngLat([
            data.longitude,
            data.latitude,
          ]);
          vehiclePopupInstances[`popup${data.id}`].$props.model = data;
        }
      } else {
        // 创建popup及初始化选中车辆轨迹
        vehiclePopups[`popup${data.id}`] = new mapboxgl.Popup({
          closeButton: true,
          anchor: "bottom",
          offset: [0, -20],
        });
        vehiclePopups[`popup${data.id}`]
          .setLngLat([data.longitude, data.latitude])
          .setHTML(`<div id="vehicle_popup${data.id}"></div>`)
          .addTo(map)
          .addClassName("vehicleDetailPopup");
        vehiclePopups[`popup${data.id}`].on("close", () => {
          vehiclePopups[`popup${data.id}`] = null;
          delete vehiclePopups[`popup${data.id}`];
          popupVises[`popup${data.id}`] = false;
          delete popupVises[`popup${data.id}`];
          this.clearSelectVehicle();
        });
        popupVises[`popup${data.id}`] = true;
        vehiclePopupInstances[`popup${data.id}`] = new GeneralVehiclePopup({
          propsData: {
            model: data,
          },
        });
        vehiclePopupInstances[`popup${data.id}`].$mount(
          `#vehicle_popup${data.id}`
        );
      }
    },
    //---
    initDictAndLoad() {
      let needDicts = [
        "CarColor",
        "CarType",
        "PlateColor",
        "CrossInfo",
        "EventType",
      ];
      let queue = [];
      for (let item of needDicts) {
        queue.push(
          this.$store.dispatch("QUERY_DICT", {
            type: item,
          })
        );
      }
      Promise.all(queue).then(() => {
        this.init();
      });
    },
    init() {
      map = this.$refs.wMap.initMap();
      map.on("style.load", () => {
        this.loading = false;
        map.flyTo(map_config.alt5);
        for (let key in mapAssets.mapIcons) {
          if (map) {
            map.loadImage(mapAssets.mapIcons[key], (error, image) => {
              if (map && !map.hasImage(key)) map.addImage(key, image);
            });
          }
        }
        map.addControl(
          new mapboxgl.NavigationControl({ showZoom: false }),
          "bottom-right"
        );
        this.refreshBounds();
        // document
        //   .getElementsByClassName("mapboxgl-ctrl-top-right")[0]
        //   .classList.add("mapboxgl-ctrl-top-right-hide-box");
        map.addLayer({
          id: "vehicle3D",
          type: "custom",
          renderingMode: "3d",
          onAdd: (map, mbxContext) => {
            window.tb = new Threebox(map, mbxContext, {
              defaultLights: true,
              enableSelectingObjects: true, //3D objects selection
            });
            for (let item of this.$store.state.dicts.CarType) {
              let targetType = dict.carTypeGlbMap[item.code];
              let options = {
                obj: `gltf/car${targetType}.glb`,
                type: "gltf",
                units: "meters",
                scale: 0.8,
                adjustment: { x: 0.5, y: 1, z: -0.5 },
                bbox: true,
              };
              window.tb.loadObj(options, (model) => {
                vehicleModelTypes[`car${item.code}`] = model;
              });
            }
          },
          render: function (gl, matrix) {
            window.tb.update();
          },
        });
        this.initWebS();
      });
      map.on("zoomend", () => {
        this.refreshBounds();
      });
      map.on("moveend", () => {
        this.refreshBounds();
      });
    },
    initWebS() {
      // 注册车辆实时ws
      let socket = initWs({
        name: "callCar",
        url: ws_config.BASE_URL,
        callback: this.callCar,
      });
      socket.ws.onopen = () => {
        if (socket.ws.readyState === 1) {
          socket.ws.send('{ dataType: "BIG_SCREEN_MXJT_DATA"}');
          this.sockets.push(socket);
        }
      };
    },
    removeLayers(names) {
      if (map) {
        for (let layerId of names.split(",")) {
          if (map.getLayer(layerId)) {
            console.log("remove", layerId);
            map.removeLayer(layerId);
          }
          if (map.getSource(layerId)) {
            map.removeSource(layerId);
          }
        }
      }
    },
    hideTb() {
      if (window.tb) {
        for (let key in vehicleModels) {
          window.tb.clear(key, true);
        }
        for (let key in licenseLabel) {
          window.tb.clear(key, true);
        }
        window.tb.update();
        vehicleModels = {};
        this.lastLocation = [];
        this.videoListData = [];
        this.currentNearestCrossId = "";
      }
    },
    clearLicense() {
      if (!this.licenseState) {
        for (let key in licenseLabel) {
          window.tb.clear(key, null);
        }
        licenseLabel = {};
      }
    },
    callCar(msg) {
      lastFrameTime = new Date().getTime();
      let zoom = map?.getZoom();
      // 车牌号状态
      if (!this.licenseState && Object.keys(licenseLabel).length) {
        for (let key in licenseLabel) {
          window.tb.clear(key, null);
        }
        licenseLabel = {};
      }
      if (this.layerShowRenders) {
        // 筛选可见区域
        for (let i = 0; i < msg.length; i++) {
          if (!msg[i].picLicense) {
            msg[i].picLicense = "";
          }
          let pt = turf.point([msg[i].longitude, msg[i].latitude]);
          let poly = turf.polygon(this.bounds);
          if (!turf.booleanPointInPolygon(pt, poly)) {
            msg.splice(i, 1);
            i = i - 1;
          }
        }
        if (msg.length > 0) {
          if (
            this.lastLocation.length &&
            new Date(msg[0].dateTime).getTime() <
              new Date(this.lastLocation[0].dateTime).getTime()
          ) {
            this.$refs.leftVideo.startVideo();
            for (let key in this.slowLines) {
              this.removeLayers(`slowLine${key}`);
            }
            this.slowLines = {};
          }
          // if (this.msgStart) {
          //   this.$refs.leftVideo.startVideo();
          //   this.msgStart = false;
          // }
          // 第一帧 || 时间戳不相同 => 放行
          if (
            this.lastLocation.length === 0 ||
            this.lastLocation[0].dateTime !== msg[0].dateTime
          ) {
            this.situationTimeVal = msg[0].dateTime;
            // zoom 大于 18
            if (zoom >= 18) {
              this.removeLayers("vehiclePic,vehiclePoint");
            }
            // zoom 小于 18：隐藏 threebox ；大于17且小于18的部分使用图片图层 其余部分使用圆点
            if (zoom < 18) {
              this.hideTb();
              if (zoom > 17) {
                this.removeLayers("vehiclePoint");
                mapTools.addOrUpdateVehiclePic(map, "vehiclePic", msg);
              } else {
                this.clearLicense();
                this.removeLayers(
                  "lightLayer,lightLayerText,vehicleSelectWave,license,licenseBack,vehiclePic"
                );
                mapTools.addOrUpdateVehicle(map, "vehiclePoint", msg);
              }
            }
            let allData = this.diff(this.lastLocation, msg);
            for (let item of allData) {
              // 如果选中车辆存在 则弹窗更新  否则删除弹窗
              if (this.selectVehicle && item.id === this.selectVehicle.id) {
                if (["add", "com"].includes(item.dill)) {
                  if (popupVises[`popup${item.id}`]) {
                    this.addCheckDetail(item);
                  }
                } else {
                  this.removeLayers("vehicleSelectWave");
                  this.removeVehiclePopup();
                  this.clearSelectVehicle();
                }
              }
              if (zoom > 18) {
                // 新增
                if (
                  item.dill === "add" ||
                  (item.dill === "com" && !vehicleModels[item.id])
                ) {
                  this.addVehicleModels(item);
                  if (this.licenseState) this.addVehicleLicenses(item);
                } else {
                  //   console.log("模型总数", Object.keys(vehicleModels).length);
                  for (let key in vehicleModels) {
                    if (vehicleModels[key].userData.data?.id === item.id) {
                      if (item.dill === "del") {
                        if (licenseLabel[`license${item.id}`]) {
                          window.tb.clear(`license${item.id}`, true);
                          delete licenseLabel[`license${item.id}`];
                        }
                        if (vehicleModels[key]) {
                          window.tb.clear(item.id, true);
                          delete vehicleModels[key];
                        }
                      }
                      if (item.dill === "com") {
                        // 车型中途变化 清除并重新创建
                        if (
                          vehicleModels[key].userData.data.originalType !==
                          item.originalType
                        ) {
                          if (vehicleModels[key]) {
                            window.tb.clear(item.id, true);
                            delete vehicleModels[key];
                          }
                          if (licenseLabel[`license${item.id}`]) {
                            window.tb.clear(`license${item.id}`, true);
                            delete licenseLabel[`license${item.id}`];
                          }
                          this.addVehicleModels(item);
                          if (this.licenseState) this.addVehicleLicenses(item);
                        } else {
                          if (licenseLabel[`license${item.id}`]) {
                            // 如果车牌model存在且未改变 则setCoords
                            if (
                              licenseLabel[`license${item.id}`].userData.data
                                .picLicense == item.picLicense
                            ) {
                              licenseLabel[`license${item.id}`].setCoords([
                                item.longitude,
                                item.latitude,
                                4,
                              ]);
                            }
                            // 否则先删除当前车牌 再创建更新后的车牌
                            else {
                              window.tb.clear(`license${item.id}`, true);
                              delete licenseLabel[`license${item.id}`];
                              this.addVehicleLicenses(item);
                            }
                          } else {
                            if (this.licenseState)
                              this.addVehicleLicenses(item);
                          }
                          this.setModel(vehicleModels[key], item, true);
                        }
                      }
                    }
                  }
                }
              }
            }
            this.lastLocation = msg;
          }
          for (let item of msg) {
            if (this.slowTrafficIds.includes(item.id)) {
              if (!this.slowLines[item.id]) {
                this.slowLines[item.id] = [];
              }
              this.slowLines[item.id].push([item.longitude, item.latitude]);
              if (this.slowLines[item.id].length > 1) {
                mapTools.addOrUpdateSlowLines(
                  map,
                  `slowLine${item.id}`,
                  this.slowLines[item.id]
                );
                if (map.getLayer("vehicle3D")) map.moveLayer("vehicle3D");
              }
            }
          }
        }
      }
    },
    // 比较websocket车辆前后两次数据差异
    diff(oldData, newData) {
      // id 只在 newData 中存在且不在 oldData 中存在的即为 add
      const add = newData.filter((e) => !oldData.find((c) => c.id === e.id));
      // id 只在 oldData 中存在且不在 newData 中存在的即为 del
      const del = oldData.filter((e) => !newData.find((c) => c.id === e.id));
      const com = newData.filter((e) => oldData.find((c) => c.id === e.id));
      add.forEach((a) => (a.dill = "add"));
      del.forEach((d) => (d.dill = "del"));
      com.forEach((c) => (c.dill = "com"));
      return [...add, ...del, ...com];
    },
    // 更新经纬度-角度-详细信息-弹窗信息
    setModel(model, options, setColor) {
      if (setColor) {
        model.traverse((child) => {
          if (child.isMesh && child.name.includes("_19")) {
            child.material = child.material.clone();
            let colorDesc = this.$store.state.dicts.CarColor.find((item) => {
              return item.code == options.originalColor;
            });
            let realColor = colorDesc
              ? dict.colorMatch[colorDesc.name]
              : "#fff";
            child.material.color.set(realColor);
          }
        });
      }
      model.setCoords([options.longitude, options.latitude]);
      model.userData.data = options;
      model.setRotation({ x: 90, y: 360 - options.courseAngle - 90, z: 0 });
    },
    addVehicleModels(option) {
      if (vehicleModelTypes[`car${option.originalType}`]) {
        let model = vehicleModelTypes[`car${option.originalType}`].duplicate();
        this.setModel(model, option, true);
        model.addEventListener(
          "SelectedChange",
          this.onSelectedChangeVehicle,
          false
        );
        vehicleModels[option.id] = model;
        window.tb.add(model, option.id);
      }
    },
    refreshBounds() {
      let mapBounds = map.getBounds();
      let leftDownXy = [mapBounds._sw.lng, mapBounds._sw.lat];
      let rightUpXy = [mapBounds._ne.lng, mapBounds._ne.lat];
      let mid1 = [mapBounds._sw.lng, mapBounds._ne.lat];
      let mid2 = [mapBounds._ne.lng, mapBounds._sw.lat];
      this.bounds = [[leftDownXy, mid1, rightUpXy, mid2, leftDownXy]];
    },
    closeAllWs() {
      this.layerShowRenders = false;
      const closePromises = this.sockets.map((socket, index) => {
        return new Promise((resolve) => {
          if (socket.ws.readyState !== 1) {
            resolve();
          } else {
            socket.ws.onclose = () => {
              resolve();
            };
            socket.ws.close();
          }
        });
      });
      return Promise.all(closePromises).then(() => {
        // for (let key in this.layers) {
        //   for (let layer of this.layers[key]) {
        //     this.removeLayers(layer);
        //   }
        // }
        this.sockets = [];
      });
    },
  },
  beforeDestroy() {
    this.closeAllWs();
    window.tb.dispose();
    window.tb = null;
    map = null;
  },
};
</script>

<style lang="less" scoped>
.main {
  height: 100%;
  position: relative;
}

.legendsGeneral {
  right: 730px;
  position: absolute;
  bottom: 8px;
  transition: 0.5s all ease;
  z-index: 11;
}
</style>
<style lang="less"></style>
