/*
 * @Author: your name
 * @Date: 2022-01-11 13:45:12
 * @LastEditTime: 2022-02-26 09:55:44
 * @LastEditors: Please set LastEditors
 * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 * @FilePath: /test/hello-world/src/utils/mapClass.js
 */
import { pipeColor, svgUrl } from "@/utils/mapClass/config.js";

// 编辑类
// 在地图上新增的设备可以直接编辑，
// 已经保存完成的设备需要点编辑才可以编辑
export class EditorMap {
  // 地图的对象实例
  map = null;
  // 父vue的实例
  vue = null;
  // 操作 新建，编辑，删除，编辑跟删除只对已经在图上的设备有效 默认值：0， 新建：1，编辑：2, 删除: 3。
  // 新建的时候会把未保存的线条清空
  control = 0;
  // 鼠标事件对象，用来将点跟线上图
  mousetool = null;
  // 当前正在手动绘制的对象
  nowMouseTarget = null;
  // 当线mousetool线被按下的时候的flag 当线被按下的时候为true，就不询问是否删除了
  mosueToolPolineDownFlag = false;
  // 绘制marer的时候的配置，在绘制完挂载事件的时候需要使用
  mouseToolMarkerOptions = null;
  // 绘制poline的时候的配置，在绘制完挂载事件的时候需要使用
  mouseToolPolineOptions = null;

  // 存放所有的设备的数组集合，这是一个对象，对象里面是各种设备的数组
  allDevice = {};
  // 存放所有的管道
  pipeArr = {};
  // 当前的infowindow的组件
  infowindowComponent = null;
  // infowindow本身
  infowindow = null;

  constructor(contaienr, config = {}, vue) {
    this.map = new AMap.Map(contaienr, {
      viewMode: "3D",
      center: [114.196007, 38.260288],
      layers: [AMap.createDefaultLayer()], // layers 字段为空或者不赋值将会自动创建默认底图。
      zoom: 14,
      ...config,
    });
    this.vue = vue;
    this.init();
  }

  init() {
    // 地图事件
    this.mapEvent();
    // 手动点线上图准备,编辑模式
    this.mouseAddDevice();
    // this.mouseAddMarker();
    // this.mouseAddPipeline();
  }
  // map的事件监听
  mapEvent() {
    this.map.on("click", () => {
      // mousetool对象画出的对象的操作
      // 如果有手动绘制对象，要手动清楚一下，因为画线的时候不好清除旧线，这其实是用来清楚旧线的
      // 当画出来的线被mousedown，不删除，但是mouseToolPipeLineFlag要归位，在移出线的时候统一归位
      // 如果对象是marker，直接删除
      if (this.nowMouseTarget?.type == "AMap.Marker") {
        this.mouseToolDrawClear();
      } else {
        // 当地图上已经画了线，并且没有点在线上，询问是否删除
        if (this.nowMouseTarget && !this.mosueToolPolineDownFlag) {
          this.confirm("是否重新绘制管道", { type: "warning" })
            .then(() => {
              // 删除原来的线
              this.mouseToolDrawClear();
              // 鼠标事件开启，并且赋值原来的属性，this.mouseToolMarkerOptions是开启绘制的时候记录的
              this.mousetool.polyline(this.mouseToolPolineOptions);
            })
            .catch(() => {});
        }
      }
    });
    this.map.on("moveend", () => {
      console.log("地图停止移动");
      if (this.flag) {
        console.log("弹框");
        this.flag = false;
      }
    });
    window.panTo = () => {
      this.flag = true;
      this.map.panTo([116.428285, 39.886129]);
    };
  }
  // 弹框工具
  confirm(message, obj) {
    return this.vue.$confirm(message, obj);
  }

  // 改变操作状态
  changeControl(num) {
    this.control = num;
  }

  // 点线编辑上图准备
  mouseAddDevice() {
    this.map.plugin(["AMap.MouseTool"], () => {
      this.mousetool = new AMap.MouseTool(this.map);
    });
    // 挂载绘制结束的事件
    this.mouseDrawEvent();
  }

  // 点或者线上图结束后触发的事件
  mouseDrawEvent() {
    this.mousetool.on("draw", (e) => {
      const target = e.obj;
      // console.log([target._position.lng, target._position.lat]);
      const { type: targetType } = target;
      // 当这个点是marker的时候
      if (targetType == "AMap.Marker") {
        this.mouseToolMarkerEvent(target);
      } else {
        // 如果是线,挂上编辑
        this.lineEditor(target);
        this.mousetool.close();
        this.mouseToolPolineEvent(target);
        console.log(targetType, "当前对象是管道");
      }
      this.nowMouseTarget = target;
    });
  }

  // 绘制marker结束后，在marker身上添加的事件
  mouseToolMarkerEvent(target) {
    // 由于画出来的marker点击会换位置，所以当移入的时候删除绘制事件，移出去在增加绘制事件
    target.on("mouseover", (e) => {
      // 鼠标事件关闭
      this.mousetool.close(false);
    });
    target.on("mouseout", (e) => {
      // 这里不方便获取原来的属性，因为position不好解决，还是设置一个值吧
      // 鼠标事件开启，并且赋值原来的属性，this.mouseToolMarkerOptions是开启绘制的时候记录的
      this.mousetool.marker(this.mouseToolMarkerOptions);
    });
    // 点
    target.on("click", (e) => {
      // 弹框
    });
  }
  // 挂上线以及线的事件
  lineEditor(line) {
    // line.editor && line.editor.close();
    // 当前点击次数，1次为编辑，2次为弹框
    line.editorNum = 0;
    line.editor = new AMap.PolyEditor(this.map, line);
  }
  // 绘制管道的时候，挂载的事件
  mouseToolPolineEvent(target) {
    // 线按下的时候会变成编辑，mousetool事件会清空 移出线的时候 在把polyline事件加上
    target.on("mouseover", (e) => {
      // 鼠标事件关闭
      // this.mousetool.close(false);
    });
    target.on("mouseout", (e) => {
      // 有时候按在线上移动地图，map点击事件中mosueToolPolineDownFlag无法归位，在这里归位
      this.mosueToolPolineDownFlag = false;
      // 鼠标事件开启，并且赋值原来的属性，this.mouseToolMarkerOptions是开启绘制的时候记录的
      // this.mousetool.polyline(this.mouseToolPolineOptions);
    });
    // 线
    target.on("mousedown", (e) => {
      const line = e.target;
      // mosueTool按下的flag,按在线上，不询问是否删除
      this.mosueToolPolineDownFlag = true;
      // 按下的时候要关闭事件
      this.mousetool.close(false);
      // 如果当前状态不是编辑，则进入编辑状态
      if (line.editorNum < 1) {
        // 打开并且++
        line.editor.open();
        line.editorNum++;
      } else {
        // 这里就要弹框了
        console.log(line.getPath());
      }
    });
  }
  // 设备点击上图开启
  mouseAddMarker(markerObj = {}) {
    // 清空已经绘制完的对象
    this.mousetoolClose(true);
    // 记录一下配置项，在挂载点击的时候，需要使用
    this.mouseToolMarkerOptions = {
      draggable: true,
      ...markerObj,
    };
    this.mousetool.marker(this.mouseToolMarkerOptions);
  }
  // 管线点击上图开启
  mouseAddPipeline(pipeObj = {}) {
    this.mousetoolClose(true);
    // 开始画线
    this.mosuetoolPolineFlag = true;
    this.mouseToolPolineOptions = {
      strokeWeight: 5,
      ...pipeObj,
    };
    this.mousetool.polyline(this.mouseToolPolineOptions);
  }

  // 手动清除map上绘制的对象
  mouseToolDrawClear() {
    if (this.nowMouseTarget) {
      this.map.remove(this.nowMouseTarget);
      // 如果有editor,则关闭
      this.nowMouseTarget.editor && this.nowMouseTarget.editor.close();
      this.nowMouseTarget = null;
    }
  }
  // 关闭点击上图事件 true清除之前绘制的图像，false 仅关闭上图事件
  mousetoolClose(boolean) {
    //  清空地图上的绘制对象的同时,也要清楚这个nowMouseTarget控制对象
    if (this.nowMouseTarget) {
      // 如果有editor,则关闭
      this.nowMouseTarget.editor && this.nowMouseTarget.editor.close();
      this.nowMouseTarget = null;
    }
    this.mousetool.close(boolean);
  }

  /**
   *
   *
   *
   *
   *
   *
   * 地图上add设备
   *
   *
   * @description:
   * @param {*} deviceData marker的数据
   * @param {*} compontent marker点击弹出的infowindow的组件
   * @return {*}
   */
  addDevice(deviceData, compontent) {
    const { longitude: lng, latitude: lat, iconType } = deviceData;
    const icon = svgUrl[iconType];
    let device = this.createMarker({
      map: this.map,
      anchor: "bottom-center",
      icon,
      position: [lng, lat],
      extData: deviceData,
    });
    // device.hide();
    // 如果没有有这个公司的数组，就创建，有就直接push
    if (!Array.isArray(this.allDevice[iconType])) {
      this.allDevice[iconType] = [];
    }
    this.allDevice[iconType].push(device);

    // 设备的事件函数
    this.deviceEvent(device, compontent);
  }
  deviceEvent(device, compontent) {
    device.on("click", (e) => {
      const target = e.target;
      // 如果control==0就是默认值，没有使用123功能，就显示infowindow
      if (this.control == 0) {
        this.markerClick(target, compontent);
      } else if (this.control == 2) {
        // 2是已经上图的设备拥有的编辑功能
      } else if (this.control == 3) {
        // 3是删除操作
      }
    });
  }
  /** 点击marker出现infowindow
   * @description:
   * @param {*} target 点击的对象
   * @param {*} compontent marker点击弹出的infowindow的组件
   * @return {*}
   */
  markerClick(target, compontent) {
    const deviceExtData = target.getExtData();

    const { longitude: lng, latitude: lat } = deviceExtData;

    // 创建一个可以控制的组件，将其dom插入infowindow
    this.infowindowComponent = this.createInfowindowDom(
      this.vue,
      this,
      deviceExtData,
      compontent
    );

    // 没恩么用，控制台测试的时候用着玩的
    window.func = () => {
      const { longitude: lng, latitude: lat } = target.getExtData();
      const cd = {
        id: 1,
        name: "9",
        lng,
        lat,
      };
      this.infowindowComponentChange(cd);
      target.setExtData(cd);
    };
    this.infowindow = new AMap.InfoWindow({
      isCustom: true,
      content: this.infowindowComponent.$el,
      position: [lng, lat],
      // anchor: "top-left",
      // offset: [20, -45],
      anchor: "middle-left",
      offset: [20, -10],
    });

    this.infowindow.open(this.map);
  }
  // 创建要加入到infowindow里的
  createInfowindowDom(vueRoot, mapClass, deviceData, compontent) {
    const Component = this.vue.$Vue.extend(compontent, {});
    return new Component({
      data() {
        return {
          // 当前vue实例
          vueRoot,
          // 自己写的map类
          mapClass,
          // 数据
          deviceData,
        };
      },
    }).$mount();
  }
  // 当前显示的infowindow内部的数据发生变化，一般在socket传回数据的时候使用
  infowindowComponentChange(data) {
    this.infowindowComponent.deviceData = data;
  }
  // 创建marker
  createMarker(MarkerOptions) {
    return new AMap.Marker(MarkerOptions);
  }
  // 地图上add管道
  addPipeLine(objData, component) {
    const { path, pipePressure, iconType } = objData;
    console.log(path);
    // 根据压力获取颜色
    const color = pipeColor[pipePressure + 1];
    const pipe = this.createPipeLine({
      path: eval(path),
      strokeWeight: 4,
      strokeColor: color,
      extData: objData,
      cursor: "pointer",
    });

    this.map.add(pipe);
    console.log(pipe.getExtData());
    // pipe.hide();
    if (!Array.isArray(this.pipeArr[iconType])) {
      this.pipeArr[iconType] = [];
    }
    this.pipeArr[iconType].push(pipe);
    // console.log(this.pipeArr);
    // this.map.panTo([path[0][0], path[0][1]]);
    this.pipeEvent(pipe, component);
  }
  createPipeLine(pipeLineOptions) {
    return new AMap.Polyline(pipeLineOptions);
  }
  pipeEvent(pipe, compontent) {
    pipe.on("mouseover", (e) => {
      const target = e.target;
      // 获取当前颜色
      const options = target.getOptions();
      options.strokeColor = "blue";
      target.setOptions(options);
    });

    pipe.on("mouseout", (e) => {
      const target = e.target;
      // 根据管道压力获取颜色
      const { pipePressure } = target.getExtData();
      const color = pipeColor[pipePressure + 1];
      // 获取当前颜色
      const options = target.getOptions();
      options.strokeColor = color;
      target.setOptions(options);
    });
    pipe.on("click", (e) => {
      const target = e.target;
      target.lnglat = e.lnglat;
      // 如果control==0就是默认值，没有使用123功能，就显示infowindow
      if (this.control == 0) {
        this.pipeClick(target, compontent);
      } else if (this.control == 2) {
        // 2是已经上图的设备拥有的编辑功能
      } else if (this.control == 3) {
        // 3是删除操作
      }
    });
  }

  pipeClick(target, compontent) {
    const deviceExtData = target.getExtData();
    const { lng, lat } = target.lnglat;
    // 创建一个可以控制的组件，将其dom插入infowindow
    this.infowindowComponent = this.createInfowindowDom(
      this.vue,
      this,
      deviceExtData,
      compontent
    );
    // 没恩么用，控制台测试的时候用着玩的
    // window.func = () => {
    //   const { lng, lat } = target.getExtData();
    //   const cd = {
    //     id: 1,
    //     name: "9",
    //     lng,
    //     lat,
    //   };
    //   this.infowindowComponentChange(cd);
    //   target.setExtData(cd);
    // };
    this.infowindow = new AMap.InfoWindow({
      isCustom: true,
      content: this.infowindowComponent.$el,
      position: [lng, lat],
      // anchor: "top-left",
      // offset: [20, -15],
      anchor: "middle-left",
      offset: [20, 0],
    });
    this.infowindow.open(this.map);
  }
  infowindowClose() {
    if (!this.infowindow) return;
    this.infowindow.close();
  }
  // 根据公司过滤是否显示 公司由一个数组传过来
  companyFilter(companyArr) {
    for (let pipeItem in this.pipeArr) {
      // 如果item属于数组说明要显示，凑则就是隐藏
      // if (companyArr.indexOf(+pipeItem+'') >= 0) {
      //   this.pipeArr[pipeItem].forEach((pipe) => {
      //     pipe.show();
      //   });
      // } else {
      //   this.pipeArr[pipeItem].forEach((pipe) => {
      //     pipe.hide();
      //   });
      // }
      this.pipeArr[pipeItem].forEach((pipe) => {
        const data = pipe.getExtData();
        if (companyArr.indexOf(data.companyType + "") >= 0) {
          pipe.show();
        } else {
          pipe.hide();
        }
      });
    }
    for (let deviceItem in this.allDevice) {
      // if (companyArr.indexOf(+deviceItem+'') >= 0) {
      //   this.allDevice[deviceItem].forEach((device) => {
      //     device.show();
      //   });
      // } else {
      //   this.allDevice[deviceItem].forEach((device) => {
      //     device.hide();
      //   });
      // }
      console.log(this.allDevice);
      this.allDevice[deviceItem].forEach((device) => {
        const data = device.getExtData();

        // 燃气没有公司，所以没有device.companyType不收到公司的控制

        if (
          companyArr.indexOf(data.companyType + "") >= 0 ||
          !data.companyType
        ) {
          device.show();
        } else {
          device.hide();
        }
      });
    }
  }
  // 卫星图切换
  satellite = null;
  changeMap(bool) {
    // 卫星图
    if (!bool) {
      if (this.satellite) return;
      this.satellite = new AMap.TileLayer.Satellite();
      this.map.addLayer(this.satellite);
    } else {
      if (this.satellite) {
        this.map.removeLayer(this.satellite);
        this.satellite = null;
      }
    }
  }
}
