import * as turf from "@turf/turf";
import DataUtils from '../utils/DataUtils';
import GeoJsonProvider from '../geog/GeoJsonProvider';
import LayerProvider from '../geog/LayerProvider';

/**
 * 折线绘制类
 * @alias PointDrawing
 *
 * @summary <用于动态绘制折线>
 */
export default class PolylineDrawing {
  /**
   * 构造函数
   * @param {Object} options -图层选项
   */
  constructor(options) {
    /**
     * 地图对象
     * @type {Object}
     */
    this._map = options.map;

    /**
     * 最小缩放层级
     * @type {Number}
     */
    this._minzoom = DataUtils.default(options.minzoom, 10);

    this._isMeasure = false; // 是否测量
    this._isDrawing = false;
    /* 事件 */
    this._clickEvent = null;     // 单击事件
    this._dbclickEvent = null;   // 双击事件
    this._mouseMoveEvent = null; // 鼠标移动事件

    /* 数据源ID */
    this._sourceId = 'drawing_polyline';
    this._moveSourceId = this._sourceId + '-move';
    this._pointSourceId = this._sourceId + '-point';

    /* 图层ID */
    this._layerId = this._sourceId;
    this._moveLayerId = this._moveSourceId;
    this._pointLayerId = this._pointSourceId;
    this._labelLayerId = this._pointLayerId + '-label'; // 标注图层

    /* 要素集 */
    // 折线GeoJSON要素集
    this._fc = GeoJsonProvider.getEmptyFC();

    // 移动线GeoJSON要素集
    this._moveFC = GeoJsonProvider.getEmptyFC();
    // 顶点GeoJSON要素集
    this._pointFC = GeoJsonProvider.getEmptyFC();
  }

  /** 公有方法 **/
  /**
   * 开始绘制
   * @param {Boolean} isMeasure -是否测量
   * @param {function} callback -回调函数
   */
  draw(isMeasure, callback) {
    this._isMeasure = isMeasure;

    if (!this._hasLayer()) {
      this._loadLayer();
    }

    const that = this;
    const map = this._map;
    // 改变光标
    map.getCanvas().style.cursor = 'crosshair';

    this._isDrawing = true;
    let clickNum = 0;

    /**
     * 添加顶点
     * @param {Array} lonLat -经纬度
     * @param {Number} startEnd -起止(-1-中间 0-起始 1-终止)
     */
    function addPoint(lonLat, startEnd = -1) {
      /* 线图层 */
      let lastFea;
      if (that._fc.features.length > 0) {
        lastFea = that._fc.features[that._fc.features.length - 1];
      } else {
        lastFea = GeoJsonProvider.getEmptyFeature('LineString');
        that._fc.features = [lastFea];
      }

      if (startEnd !== 1) {
        lastFea.geometry.coordinates.push(lonLat);
      }
      // 更新数据源
      LayerProvider.updateSource(map, that._sourceId, that._fc);

      /* 点图层 */
      if (startEnd !== 1) {
        let lenVal = startEnd === 1 ? '总长: ' : '';
        if (startEnd !== 0) {
          // 计算折线长度
          let len = turf.length(lastFea, {
            units: 'kilometers'
          }).toFixed(4);

          lenVal += len.toString();
          lenVal += ' km';
        }
        // 获取点要素
        let pointFea = GeoJsonProvider.getPointFeature(lonLat, { value: lenVal });
        that._pointFC.features.push(pointFea);
      }
      // 更新数据源
      LayerProvider.updateSource(map, that._pointSourceId, that._pointFC);

      // 回调
      if (startEnd === 1 && callback) {
        callback(lastFea);
      }
    }

    /**
     * 单击事件
     */
    this._clickEvent = function onClickEvent(e) {
      if (!that._isDrawing) return;

      // 改变光标
      map.getCanvas().style.cursor = 'crosshair';

      let lonLat = [e.lngLat.lng, e.lngLat.lat];
      if (clickNum < 1) {
        if (!isMeasure) {
          // 非测量 清空要素集
          that._pointFC.features = [];
          that._moveFC.features = [];
          that._fc.features = [];
        }

        // 定义移动线要素
        let moveFea = GeoJsonProvider.getEmptyFeature('LineString');
        that._moveFC.features.push(moveFea);

        // 定义折线要素
        let feature = GeoJsonProvider.getEmptyFeature('LineString');
        that._fc.features.push(feature);

        // 添加起始点
        addPoint(lonLat, 0);
      } else {
        // 添加顶点
        addPoint(lonLat);
      }

      clickNum += 1;
    }

    /**
     * 鼠标移动事件
     */
    this._mouseMoveEvent = function onMoveEvent(e) {
      if (!that._isDrawing || clickNum === 0) return;

      let lonLat = [e.lngLat.lng, e.lngLat.lat];
      let pointFea = that._pointFC.features[that._pointFC.features.length - 1];

      // 更新移动线要素
      if (that._moveFC.features.length > 0) {
        let lastMoveFea = that._moveFC.features[that._moveFC.features.length - 1];
        lastMoveFea.geometry.coordinates = [pointFea.geometry.coordinates, lonLat];

        LayerProvider.updateSource(map, that._moveSourceId, that._moveFC);
      }
    }

    /**
     * 双击事件
     */
    this._dbclickEvent = function onDbclickEvent(e) {
      if (!that._isDrawing || clickNum === 0) return;

      let lonLat = [e.lngLat.lng, e.lngLat.lat];
      // 添加终止点
      addPoint(lonLat, 1);
      clickNum = 0;

      // 清理临时数据
      if (!isMeasure) {
        that._pointFC.features = [];
        LayerProvider.updateSource(map, that._pointSourceId, that._pointFC);
      }

      that._moveFC.features = [];
      LayerProvider.updateSource(map, that._moveSourceId, that._moveFC);
    }

    // 绑定事件
    map.on('click', this._clickEvent);
    map.on('dblclick', this._dbclickEvent);
    map.on('mousemove', this._mouseMoveEvent);
  }

  /**
   * 捕捉绘制
   * @param {Number[]} start -起始点坐标
   * @param {function} callback -回调函数
   */
  snap(start, callback) {
    // 加载图层
    if (!this._hasLayer()) {
      this._loadLayer();
    }

    const that = this;
    const map = this._map;
    // 改变光标
    map.getCanvas().style.cursor = 'crosshair';

    // 初始化要素集
    this._pointFC.features = [];
    this._moveFC.features = [ GeoJsonProvider.getEmptyFeature('LineString') ];
    this._fc.features = [ GeoJsonProvider.getEmptyFeature('LineString') ];

    this._isDrawing = true;
    let clickNum = 0;

    // 添加起点
    addPoint(start);
    clickNum += 1;

    /**
     * 添加点
     * @param {Array} lonLat -经纬度
     * @param {Number} isEnd -是否终止点
     */
    function addPoint(lonLat, isEnd = false) {
      /* 点图层 */
      // 获取点要素
      let pointFea = GeoJsonProvider.getPointFeature(lonLat);

      if (!isEnd) {
        that._pointFC.features.push(pointFea);
      }
      // 更新数据源
      LayerProvider.updateSource(map, that._pointSourceId, that._pointFC);

      /* 线图层 */
      // 获取折线坐标集合
      let lineCoords = that._pointFC.features.map(fea => {
        return fea.geometry.coordinates;
      });
      lineCoords.push(lonLat);

      let lastFea;
      if (that._fc.features.length > 0) {
        lastFea = that._fc.features[that._fc.features.length - 1];
      } else {
        lastFea = GeoJsonProvider.getEmptyFeature('LineString');
        that._fc.features = [lastFea];
      }
      lastFea.geometry.coordinates = lineCoords;
      // 更新数据源
      LayerProvider.updateSource(map, that._sourceId, that._fc);
    }

    /**
     * 单击事件
     */
    this._clickEvent = function onClickEvent(e) {
      if (!that._isDrawing) return;

      // 改变光标
      map.getCanvas().style.cursor = 'crosshair';

      // 添加顶点
      addPoint([e.lngLat.lng, e.lngLat.lat]);
      clickNum += 1;
    }

    /**
     * 鼠标移动事件
     */
    this._mouseMoveEvent = function onMoveEvent(e) {
      if (!that._isDrawing || clickNum === 0) return;

      if (clickNum === 1) {
        map.getCanvas().style.cursor = 'crosshair';
      }

      let lonLat = [e.lngLat.lng, e.lngLat.lat];
      let pointFea = that._pointFC.features[that._pointFC.features.length - 1];

      // 更新移动线要素
      if (that._moveFC.features.length > 0) {
        let lastMoveFea = that._moveFC.features[that._moveFC.features.length - 1];
        lastMoveFea.geometry.coordinates = [pointFea.geometry.coordinates, lonLat];

        LayerProvider.updateSource(map, that._moveSourceId, that._moveFC);
      }
    }

    /**
     * 双击事件
     */
    this._dbclickEvent = function onDbclickEvent(e) {
      if (!that._isDrawing || clickNum === 0) return;

      let lonLat = [e.lngLat.lng, e.lngLat.lat];
      // 添加终止点
      addPoint(lonLat, true);
      clickNum = 0;

      // 捕捉完成
      that.snapEnd(callback);
      /*
      // 清理临时数据
      that._pointFC.features = [];
      LayerProvider.updateSource(map, that._pointSourceId, that._pointFC);

      that._moveFC.features = [];
      LayerProvider.updateSource(map, that._moveSourceId, that._moveFC);
      */
    }

    // 绑定事件
    map.on('click', this._clickEvent);
    map.on('dblclick', this._dbclickEvent);
    map.on('mousemove', this._mouseMoveEvent);
  }

  /**
   * 捕捉完成
   */
  snapEnd(callback) {
    this.finish();

    const pointFeatures = this._pointFC.features;

    // 清理临时数据
    this._pointFC.features = [];
    LayerProvider.updateSource(map, this._pointSourceId, this._pointFC);

    this._moveFC.features = [];
    LayerProvider.updateSource(map, this._moveSourceId, this._moveFC);

    if (this._fc.features.length > 0) {
      callback(this._fc.features[this._fc.features.length - 1]);
    } else {
      let ls = pointFeatures.map((fea) => {
        return fea.geometry.coordinates;
      });
      callback(GeoJsonProvider.getLineStringFeature(ls));
    }
  }

  /**
   * 绘制结束
   */
  finish() {
    const map = this._map;

    // 改变光标
    map.getCanvas().style.cursor = '';

    // 解除事件绑定
    map.off('click', this._clickEvent);
    map.off('dblclick', this._dbclickEvent);
    map.off('mousemove', this._mouseMoveEvent);

    this._isDrawing = false;
  }

  /**
   * 获取GeoJSON要素集
   *
   * @returns {Object} GeoJSON对象
   */
  getData() {
    return this._fc;
  }

  /**
   * 清空数据
   */
  clearData() {
    this._fc.features = [];
    // 更新数据源
    LayerProvider.updateSource(this._map, this._sourceId, this._fc);
  }

  /**
   * 移除图层
   */
  removeLayer() {
    if (this._isMeasure) {
      this._removeLayer(this._labelLayerId, null);
    }
    this._removeLayer(this._pointLayerId, this._pointSourceId);
    this._removeLayer(this._moveLayerId, this._moveSourceId);
    this._removeLayer(this._layerId, this._sourceId);

    // 数据设置为空
    this._pointFC.features = [];
    this._moveFC.features = [];
    this._fc.features = [];
  }

  /** 私有方法 **/
  /**
   * 加载图层
   */
  _loadLayer() {
    // 加载移动线图层
    this._loadMoveLineLayer();

    // 加载折线图层
    this._loadLineLayer();

    // 加载点图层
    this._loadPointLayer();
    if (this._isMeasure) {
      // 加载标注图层
      this._loadLabelLayer();
    }
  }

  /**
   * 判断图层是否已加载
   *
   * @returns {Boolean}
   */
  _hasLayer() {
    return (
      LayerProvider.hasLayer(this._map, this._layerId) &&
      LayerProvider.hasLayer(this._map, this._moveLayerId) &&
      LayerProvider.hasLayer(this._map, this._pointLayerId)
    );
  }

  /**
   * 添加点图层
   */
  _loadPointLayer() {
    if (LayerProvider.hasLayer(this._map, this._pointLayerId)) {
      return;
    }

    // 添加数据源
    this._map.addSource(this._pointSourceId, {
      type: "geojson",
      data: this._pointFC
    });

    // 添加图层
    this._map.addLayer({
      type: "circle",
      id: this._pointLayerId,
      source: this._pointSourceId,
      minzoom: this._minzoom,
      layout: {
        visibility: "visible",
      },
      paint: {
        "circle-radius": 3.5,
        "circle-color": "#176BC9",
        "circle-opacity": 0.75,
        "circle-stroke-width": 2,
        "circle-stroke-color": "#78B7FF"
      }
    });
  }

  /**
   * 加载标注图层
   */
  _loadLabelLayer() {
    if (LayerProvider.hasLayer(this._map, this._labelLayerId)) {
      return;
    }

    const map = this._map;
    // 自定义字体颜色
    let textColor = map._customStyle ? map._customStyle.textColor : '#F8F8FF';

    // 加载图层
    map.addLayer({
      type: "symbol",
      id: this._labelLayerId,
      source: this._pointSourceId,
      minzoom: this._minzoom,
      layout: {
        "symbol-placement": "point",
        "text-ignore-placement": true,
        "text-field": "{value}",
        "text-offset": [1.5, 1.0],
        "text-font": ["Microsoft YaHei"],
        "text-max-width": 32,
        "text-max-angle": 30,
        "text-size": {
          base: 1,
          stops: [
            [16, 14],
            [18, 20],
          ],
        },
        visibility: "visible",
      },
      paint: {
        "text-color": textColor,
        "text-halo-color": "#8B8B8B",
        "text-halo-width": 0.1,
        "text-halo-blur": 0.5,
      }
    });
  }

  /**
   * 添加移动线图层
   */
  _loadMoveLineLayer() {
    if (LayerProvider.hasLayer(this._map, this._moveLayerId)) {
      return;
    }

    // 添加数据源
    this._map.addSource(this._moveSourceId, {
      type: "geojson",
      data: this._moveFC
    });

    // 添加图层
    this._map.addLayer({
      type: "line",
      id: this._moveLayerId,
      source: this._moveSourceId,
      minzoom: this._minzoom,
      layout: {
        visibility: "visible",
      },
      paint: {
        "line-color": "#176BC9",
        "line-width": 2,
        "line-opacity": 0.75,
        "line-dasharray": [2.5, 1.5],
      }
    });
  }

  /**
   * 添加线图层
   */
  _loadLineLayer() {
    if (LayerProvider.hasLayer(this._map, this._layerId)) {
      return;
    }

    // 添加数据源
    this._map.addSource(this._sourceId, {
      type: "geojson",
      data: this._fc
    });

    // 添加图层
    this._map.addLayer({
      type: "line",
      id: this._layerId,
      source: this._sourceId,
      minzoom: this._minzoom,
      layout: {
        visibility: "visible",
      },
      paint: {
        "line-color": "#176BC9",
        "line-width": 2,
        "line-opacity": 0.85
      }
    });
  }

  /**
   * 移除图层
   * @param {String} layerId -图层ID
   * @param {String} sourceId -数据源ID
   */
  _removeLayer(layerId, sourceId) {
    // 移除图层
    LayerProvider.removeLayer(this._map, layerId);

    // 移除数据源
    if (sourceId) {
      LayerProvider.removeSource(this._map, sourceId);
    }
  }
}
