import DataUtils from "../utils/DataUtils";
import GeogUtils from "../utils/GeogUtils";
import VerifyUtils from "../utils/VerifyUtils";
import MapProvider from "../geog/MapProvider";
import GeoJsonProvider from "../geog/GeoJsonProvider";
import SimpleMarkerLayer from "../common/SimpleMarkerLayer";
import SimpleLineLayer from "../common/SimpleLineLayer";

/**
 * 踏勘提供类
 *
 * @alias SurveyProvider
 *
 * @summary <用于踏勘数据显示>
 */
export default class SurveyProvider {
  /**
   * 构造函数
   * @param {Object} options -图层选项
   */
  constructor(options) {
    /**
     * 地图对象
     * @type {Object}
     */
    this._map = options.map;

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

    /**
     * 线宽
     * @type {Number}
     */
    this._lineWidth = DataUtils.default(options.lineWidth, 10.5);

    /** 要素集 **/
    // 点要素集
    this._pointFC = GeoJsonProvider.getEmptyFC();
    // 线要素集
    this._polylineFC = GeoJsonProvider.getEmptyFC();
    // 线中点要素集
    this._centerPointFC = GeoJsonProvider.getEmptyFC();

    /** 图层 **/
    this._facilityMarkerLayer = null; // 设施点图层
    this._markerLayer = null;         // 气泡点图层

    this._facilityLineLayer = null; // 设施线图层
    this._centerMarkerLayer = null; // 中心点图层

    // 初始化图层
    this._initLayers();
  }

  /** 公有方法 **/
  /**
   * 设置数据
   * @param {Array} data -GeoJSON要素数组
   */
  setData(data) {
    this._pointFC.features = [];
    this._polylineFC.features = [];
    this._centerPointFC.features = [];

    if (!data ||
        !VerifyUtils.isArray(data) || data.length === 0 ||
        (VerifyUtils.isArray(data) && !VerifyUtils.isGeoJsonFeature(data[0]))) return;

    // 点要素集
    this._pointFC.features = data.filter((fea) => {
      return fea.geometry.type.toLowerCase() === 'point';
    });

    // 线要素集
    this._polylineFC.features = data.filter((fea) => {
      return fea.geometry.type.toLowerCase() === 'linestring' ||
             fea.geometry.type.toLowerCase() === 'multilinestring';
    });
    // 线中点要素集
    this._centerPointFC.features = this._polylineFC.features.map((feature) => {
      const coordinates = GeogUtils.calcCenter(feature);
      return GeoJsonProvider.getPointFeature(coordinates, feature.properties);
    });

    // 设置数据
    this._facilityMarkerLayer.setData(this._pointFC);
    this._markerLayer.setData(this._pointFC);

    this._facilityLineLayer.setData(this._polylineFC);
    this._centerMarkerLayer.setData(this._centerPointFC);

    // 缩放到要素范围
    this._fitBounds();
  }

  /**
   * 获取要素
   * @param {String} fid -要素ID
   */
  getData(fid) {
    // 过滤点数据
    let retFeatures = this._pointFC.features.filter((feature) => {
      return feature.properties.fid === fid;
    });

    if (retFeatures.length === 0) {
      // 过滤线数据
      retFeatures = this._polylineFC.features.filter((feature) => {
        return feature.properties.fid === fid;
      });
    }

    return retFeatures.length > 0 ? retFeatures[0] : null;
  }

  /**
   * 移除图层
   */
  removeLayer() {
    // 设施点图层
    this._markerLayer.removeLayer();
    this._facilityMarkerLayer.removeLayer();

    this._facilityMarkerLayer.removeSource();

    // 设施线图层
    this._facilityLineLayer.removeLayer();
    this._facilityLineLayer.removeSource();

    this._centerMarkerLayer.removeLayer();
    this._centerMarkerLayer.removeSource();
  }

  /** 私有方法 **/
  /**
   * 初始化图层
   */
  _initLayers() {
    const map = this._map;
    const minZoom = this._minzoom;

    // 设施点
    this._facilityMarkerLayer = new SimpleMarkerLayer({
      map: map,
      minzoom: minZoom,
      icon: {
        type: 'categorical',
        property: 'layer_code',
        stops: [
          ['manholerain', 'well_rain'],
          ['manholewaste', 'well_sew'],
          ['manholeindustry', 'well_ind'],
          ['interceptionsew', 'faci_intersew'],
          ['interception', 'faci_inter'],
          ['raininlet', 'faci_raininlet'],
          ['storage', 'faci_storage'],
          ['outfall', 'faci_outfall'],
          ['flap', 'faci_outfall'],
          ['gate', 'faci_gate']
        ],
        default: 'marker'
      },
      sourceId: 'survey_marker'
    });
    // 气泡点
    this._markerLayer = new SimpleMarkerLayer({
      map: map,
      minzoom: minZoom,
      icon: 'editor_add',
      offset: [0, -20],
      sourceId: 'survey_marker',
      layerId: 'survey_marker_bubble'
    });

    // 设施线
    this._facilityLineLayer = new SimpleLineLayer({
      map: map,
      minzoom: minZoom,
      color: {
        type: 'categorical',
        property: 'layer_code',
        stops: [
          ['pipelinerain', '#13B55C'],
          ['pipelinewaste', '#FF4500'],
          ['pipelineindustry', '#FF00FF'],
          ['ditch', '#138585'],
        ],
        default: '#FF4500'
      },
      width: this._lineWidth,
      opacity: 0.75,
      sourceId: 'survey_line'
    });
    // 线中点
    this._centerMarkerLayer = new SimpleMarkerLayer({
      map: map,
      minzoom: minZoom,
      icon: 'editor_add',
      offset: [0, -14],
      sourceId: 'survey_line_center',
    });
  }

  /**
   * 缩放到要素范围
   */
  _fitBounds() {
    const map = this._map;
    const pointFC = this._pointFC;
    const lineFC = this._polylineFC;

    // 计算包围盒
    let bboxP = [], bboxL = [];
    if (pointFC.features.length > 0) {
      let pntFea = pointFC.features[0]
      bboxP = pointFC.features.length === 1
              ? [pntFea.geometry.coordinates, pntFea.geometry.coordinates]
              : GeogUtils.calcBBox(pointFC);
    }
    if (lineFC.features.length > 0) {
      bboxL = GeogUtils.calcBBox(lineFC);
    }

    // 缩放至要素范围
    const zoom = 15.75;
    if (bboxP.length > 0 || bboxL.length > 0) {
      let bbox = [];
      let isJumpTo = false;
      if (bboxP.length === 1 && bboxL.length === 0) {
        isJumpTo = true;
      } else if (bboxP.length > 0 && bboxL.length === 0) {
        bbox = bboxP;
      } else if (bboxP.length === 0 && bboxL.length > 0) {
        bbox = bboxL;
      } else {
        bbox = [
          [Math.min(bboxP[0][0], bboxL[0][0]), Math.min(bboxP[0][1], bboxL[0][1])],
          [Math.max(bboxP[1][0], bboxL[1][0]), Math.max(bboxP[1][1], bboxL[1][1])]
        ];
      }

      if (isJumpTo) {
        MapProvider.jumpTo(map, bboxP[0], zoom);
      } else {
        MapProvider.fitBounds(map, bbox, zoom, true);
      }
    }
  }
}
