import DataUtils from '../utils/DataUtils';
import VerifyUtils from '../utils/VerifyUtils';
import LayerProvider from '../geog/LayerProvider';
import GeoJsonProvider from '../geog/GeoJsonProvider';

/**
 * 选中图层
 * @alias SelectionLayer
 *
 * @summary <用于选中要素加载>
 */
export default class SelectionLayer {
  /**
   * 构造函数
   * @param {Object} options -图层选项
   */
  constructor(options) {
    /**
     * 地图对象
     * @type {Object}
     */
    this._map = options.map;

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

    /**
     * 线宽
     */
    this._lineWidth = DataUtils.default(options.lineWidth, 7.5);

    /**
     * 线颜色
     */
    this._lineColor = DataUtils.default(options.lineColor, '#87CEFA');

    /**
     * 点数据源ID
     * @type {String}
     */
    this._sourceId = DataUtils.default(options.sourceId, 'selection');
    // 线数据源ID
    this._lineSourceId = this._sourceId + '_line';
    // 线顶点数据源ID
    this._vertexSourceId = this._lineSourceId + '-vertex';

    /**
     * 点图层ID
     * @type {String}
     */
    this._layerId = DataUtils.default(options.layerId, this._sourceId);
    // 线图层ID
    this._lineLayerId = this._layerId + '_line';
    // 线顶点图层ID
    this._vertexLayerId = this._lineLayerId + '-vertex';

    // 数据源
    this._pointFC = GeoJsonProvider.getEmptyFC();

    this._vertexFC = GeoJsonProvider.getEmptyFC();
    this._lineFC = GeoJsonProvider.getEmptyFC();
  }

  /** 公有函数 **/
  /**
   * 设置数据
   * @param {Object|Array} data -GeoJSON要素/要素集/要素集合
   */
  setData(data) {
    // 加载图层
    if (!this.hasLayer()) {
      this.loadLayer();
    }
    // 隐藏图层
    this.showLayer(false);

    // 更新数据源
    this._updateDataSource(data);

    // 显示图层
    this.showLayer(true);
  }

  /**
   * 添加数据
   *@param {Object|Array} data -GeoJSON要素/要素集/要素集合
   */
  appendData(data) {
    // 加载图层
    if (!this.hasLayer()) {
      this.loadLayer();
      // 显示图层
      this.showLayer(true);
    }

    // 更新数据源
    this._updateDataSource(data, true);
  }

  /**
   * 清除数据
   */
  clearData() {
    this._pointFC.features = [];
    this._lineFC.features = [];

    const map = this._map;
    // 更新数据源
    LayerProvider.updateSource(map, this._sourceId, this._pointFC);
    LayerProvider.updateSource(map, this._lineSourceId, this._lineFC);
  }

  /**
   * 加载图层
   */
  loadLayer() {
    if (this.hasLayer()) return;

    // 加载线图层
    this._loadLineLayer();
    // 加载线顶点图层
    //this._loadVertexLayer();

    // 加载点图层
    this._loadPointLayer();
  }

  /**
   * 显示/隐藏图层
   * @param {Boolean} show -是否显示
   */
  showLayer(show) {
    LayerProvider.showLayer(this._map, this._layerId, show);
    LayerProvider.showLayer(this._map, this._lineLayerId, show);
  }

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

  /**
   * 移除图层(and数据源)
   */
  removeLayer() {
    const map = this._map;

    // 移除图层
    LayerProvider.removeLayer(map, this._layerId);
    LayerProvider.removeLayer(map, this._lineLayerId);

    // 移除数据源
    LayerProvider.removeSource(map, this._sourceId);
    LayerProvider.removeSource(map, this._lineSourceId);
  }

  /** 私有方法 **/
  /**
   * 加载点图层
   */
  _loadPointLayer() {
    const map = this._map;
    const minZoom = this._minzoom;

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

    // 添加图层
    map.addLayer({
      type: "symbol",
      id: this._layerId,
      source: this._sourceId,
      minzoom: minZoom,
      layout: {
        "symbol-placement": "point",
        "symbol-avoid-edges": true,
        "icon-allow-overlap": true,
        "icon-image": "busi_focus",
        "icon-offset": [0, 0],
        visibility: "none"
      }
    }, map._build3dLayerId);
  }

  /**
   * 加载线图层
   */
  _loadLineLayer() {
    const map = this._map;
    const minZoom = this._minzoom;
    const maxZoom = map.getMaxZoom();

    // 添加数据源
    map.addSource(this._lineSourceId, {
      type: "geojson",
      data: this._lineFC
    });
    // 添加图层
    map.addLayer({
      type: "line",
      id: this._lineLayerId,
      source: this._lineSourceId,
      minzoom: minZoom,
      layout: {
        "line-join": "round",
        "line-cap": "butt",
        visibility: "none"
      },
      paint: {
        "line-color": this._lineColor,
        "line-width": {
          base: 1.5,
          stops: [
            [minZoom, 0.75],
            [maxZoom, this._lineWidth],
          ]
        },
        "line-opacity": 0.75
      }
    }, map._build3dLayerId);
  }

  /**
   * 加载线顶点图层
   */
  _loadVertexLayer() {
    const map = this._map;
    const minZoom = this._minzoom;

    // 添加数据源
    map.addSource(this._vertexSourceId, {
      type: "geojson",
      data: this._vertexFC
    });

    // 添加图层
    map.addLayer({
      type: "circle",
      id: this._vertexLayerId,
      source: this._vertexSourceId,
      minzoom: minZoom,
      layout: {
        visibility: "none"
      },
      paint: {
        "circle-radius": 5.5,
        "circle-color": "#176BC9",
        "circle-opacity": 0.75,
        "circle-stroke-width": 2,
        "circle-stroke-color": "#78B7FF"
      }
    }, map._build3dLayerId);
  }

  /**
   * 更新数据源
   * @param {Object|Array} data -GeoJSON要素集/集合
   * @param {Boolean} isAdd - 是否添加
   */
  _updateDataSource(data, isAdd = false) {
    let fc = GeoJsonProvider.getEmptyFC();

    if (VerifyUtils.isObject(data)) {
      if (VerifyUtils.isGeoJsonFC(data)) {
        fc.features = data.features;
      } else if (VerifyUtils.isGeoJsonFeature(data)) {
        fc.features = [data];
      }
    } else if (VerifyUtils.isArray(data)) {
      if (data.length > 0 && VerifyUtils.isGeoJsonFeature(data[0])) {
        fc.features = data;
      }
    }

    if (!fc.features || fc.features.length === 0) return;

    const map = this._map;

    if (!isAdd) {
      this._pointFC.features = [];
      this._lineFC.features = [];
    }

    switch (fc.features[0].geometry.type) {
      case 'Point': {
        this._pointFC.features = this._pointFC.features.concat(fc.features);
        break;
      }
      case 'LineString':
      case 'MultiLineString': {
        this._lineFC.features = this._lineFC.features.concat(fc.features);
        break;
      }
      default:
        break;
    }

    // 更新数据源
    LayerProvider.updateSource(map, this._sourceId, this._pointFC);
    LayerProvider.updateSource(map, this._lineSourceId, this._lineFC);
  }
}
