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

/**
 * 定义路线流向图层
 * @alias FlowingLayer
 *
 * @summary <用于追溯分析>
 */
export default class FlowingLayer {
  /**
   * 构造函数
   * @param {Object} options -图层选项
   */
  constructor(options) {
    /**
     * 地图对象
     * @type {Object}
     */
    this._map = options.map;

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

    /**
     * 管线颜色
     * @type {String}
     */
    this._lineColor = DataUtils.default(options.color, '#2E8B57');

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

    /**
     * 是否固定(线宽)
     * @type {Boolean}
     */
    this._fixed = DataUtils.default(options.fixed, true);

    /**
     * 数据源ID
     * @type {String}
     */
    this._sourceId = DataUtils.default(options.sourceId, 'pipenet_flowing');

    /**
     * 图层ID
     * @type {String}
     */
    this._layerId = DataUtils.default(options.layerId, this._sourceId);

    // 定时器
    this._timer = undefined;

    // 数据源要素集
    this._fc = GeoJsonProvider.getEmptyFC();

    this._routeColorNum = 0; // 路径颜色数
    this._routeColors = [];  // 路径颜色数组
    // 设置颜色带
    this._initColorRamps();
  }

  /** 公有方法 **/
  /**
   * 设置管线路径颜色
   * @param {String} color -16进制颜色字符串
   */
  setColor(color) {
    this._lineColor = color;
    // 设置颜色带
    this._initColorRamps();
  }

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

    // 初始化路线数据
    this._initRouteData(data);

    // 更新数据源
    LayerProvider.updateSource(this._map, this._sourceId, this._fc);
  }

  /**
   * 开始
   */
  start() {
    // 显示图层
    this.showLayer(true);

    let colorNum = 0;
    let that = this;
    /**
     * 动画
     */
    function _animate() {
      colorNum++
      for (let i = 0; i < that._fc.features.length; i++) {
        const countNumShow = colorNum % that._routeColorNum;
        const pageNum = i % that._routeColorNum;
        const totalNum = pageNum - countNumShow;
        if (totalNum <= 0) {
          that._fc.features[i].properties.color = that._routeColors[that._routeColorNum - 1 - Math.abs(totalNum)];
        }
        if (totalNum > 0) {
          that._fc.features[i].properties.color = that._routeColors[totalNum - 1];
        }
      }

      // 更新数据源
      LayerProvider.updateSource(that._map, that._sourceId, that._fc);
    }

    // 设置动画帧
    let FRAME_RATE = 3; // 帧率
    (function _frame() {
      try {
        // 停止定时器
        if (that._timer) {
          clearTimeout(that._timer);
          that._timer = undefined;
        }

        that._timer = setTimeout(function () {
          // 动画
          _animate();
          _frame();
        }, 1000 / FRAME_RATE);
      }
      catch (e) {
        console.error(e);
      }
    })();
  }

  /**
   * 停止
   */
  stop() {
    // 停止定时器
    if (this._timer) {
      clearTimeout(this._timer);
      this._timer = undefined;
    }

    // 隐藏图层
    this.showLayer(false);
  }

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

    const map = this._map;
    const minZoom = this._minzoom;
    const maxZoom = map.getMaxZoom();

    // 添加数据源
    map.addSource(this._sourceId, {
      type: "geojson",
      data: this._fc,
      lineMetrics: true, // 用于渐变线
    });
    // 添加图层
    map.addLayer({
      type: 'line',
      id: this._layerId,
      source: this._sourceId,
      minzoom: minZoom,
      layout: {
        "line-join": "round",
        "line-cap": "butt",
        visibility: "none"
      },
      paint: {
        "line-color": ["get", "color"],
        "line-width": this._fixed
        ? this._lineWidth
        : {
          base: 2.5,
          stops: [
            [minZoom, 2.5],
            [maxZoom, this._lineWidth]
          ]
        }
      }
    }, map._build3dLayerId);
  }

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

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

  /**
   * 移除图层(and数据源)
   */
  removeLayer() {
    this.stop();

    // 移除图层
    LayerProvider.removeLayer(this._map, this._layerId);
    // 移除数据源
    LayerProvider.removeSource(this._map, this._sourceId);
  }

  /** 私有方法 **/
  /**
   * 初始化颜色带
   */
  _initColorRamps() {
    const color = this._lineColor;

    this._routeColorNum = 12; // 路径颜色数
    this._routeColors = [];  // 路径颜色数组

    // 转RGB数组
    let colorArr = ColorUtils.hexToArray(color);
    let op = 0.4; // 透明度

    for (let i = 0; i < this._routeColorNum; i++) {
      op += 0.05;
      let color = 'rgba(' + colorArr[0] + ',' + colorArr[1] + ',' + colorArr[2] + ',' + op.toFixed(2) + ')';

      this._routeColors.push(color);
    }
  }

  /**
   * 初始化路线数据
   * @param {Object} data -GeoJSON要素/要素集
   */
  _initRouteData(data) {
    this._fc.features = [];

    let features = [];
    if (VerifyUtils.isGeoJsonFC(data)) {
      features = data.features;
    } else if (VerifyUtils.isGeoJsonFeature(data)) {
      features.push(data);
    }
    if (features.length === 0) return;

    let routeFeatures = [];
    for (let i = 0; i < features.length; i++) {
      let feature = features[i];
      let geomType = feature.geometry.type.toLowerCase();
      switch (geomType) {
        case 'linestring': {
          routeFeatures.push(feature);
          break;
        }
        case 'multilinestring': {
          let props = feature.properties;
          let lineStrings = feature.geometry.coordinates;
          for (let j = 0; j < lineStrings.length; j++) {
            let lineString = lineStrings[j];
            routeFeatures.push(GeoJsonProvider.getLineStringFeature(lineString, props));
          }
          break;
        }
        default:
          break;
      }
    }
    if (routeFeatures.length === 0) return;

    let chunkFeatures = [];
    routeFeatures.forEach(fea => {
      let points = fea.geometry.coordinates;

      // 分割线段
      let lineCount = turf.lineString(points);
      let chunkFC = turf.lineChunk(lineCount, 0.01, { units: 'kilometers' });

      for (let i = 0; i < chunkFC.features.length; i++) {
        let chunkFea = chunkFC.features[i];

        let ls = chunkFea.geometry.coordinates;
        if (ls.length < 3) {
          let center = turf.midpoint(turf.point(ls[0]), turf.point(ls[1]));
          ls.splice(1, 0, center.geometry.coordinates);
        }

        chunkFeatures.push(chunkFea);
      }
    });

    this._fc.features = chunkFeatures;
  }
}
