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

/**
 * 飞线图层
 * @alias FlylineLayer
 *
 * @summary <用于迁徙图加载>
 */
export default class FlylineLayer {
  /**
   * 构造函数
   * @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, '#00EEFF');

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

    /**
     * 不透明度
     * @type {String}
     */
    this._lineOpacity = DataUtils.default(options.opacity, 0.25);

    // 数据源ID
    this._sourceId = 'flying_line';
    this._animateSourceId = this.sourceId + '-animate';
    // 图层ID
    this._layerId = this._sourceId;
    this._animateLayerId = this._animateSourceId;

    this._timer = 0;

    // 飞线要素集
    this._fc = GeoJsonProvider.getEmptyFC();
    // 动画要素集
    this._animateFC = GeoJsonProvider.getEmptyFC();
  }

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

    // 数据源
    const source = this._map.getSource(this._sourceId);
    const animateSource = this._map.getSource(this._animateSourceId);

    const fc = this._fc;
    fc.features = [];

    const animateFC = this._animateFC;
    animateFC.features = [];

    let lineFC = null;
    if (VerifyUtils.isArray(data)) {
      // 要素数组
      if (VerifyUtils.isGeoJsonFeature(data[0])) {
        lineFC = GeoJsonProvider.getEmptyFC();
        lineFC.features = data;
      }
    } else if (VerifyUtils.isGeoJsonFC(data)) {
      // 要素集
      lineFC = data;
    }

    if (!lineFC) return;

    let counter = 50;
    let index = 0;

    let flylines = [];
    lineFC.features.map(feature => {
      if (feature.geometry.coordinates.length === 2) {
        let start = feature.geometry.coordinates[0];
        let end = feature.geometry.coordinates[1];
        // 计算控制点
        let mid = GeogUtils.calcControlPoint(start, end, 0.16);

        feature.geometry.coordinates = [start, mid, end];
      }
      // 构造贝塞尔曲线
      let bezierFea = turf.bezierSpline(feature);
      fc.features.push(bezierFea);

      let len = turf.length(bezierFea);
      let dis = 0;
      let step = len / counter;
      let flyline = [];

      while (dis < len) {
        dis += step;

        // 计算沿线的点
        const pointFea = turf.along(bezierFea, dis);
        flyline.push(pointFea.geometry.coordinates);
      }

      flylines.push(flyline);

    }); // end of data.features.map()

    this.showLayer(true);

    // 初始化动画要素集
    animateFC.features = flylines.map(flyline => {
      return {
        type: 'Feature',
        properties: {},
        geometry: {
          type: 'LineString',
          coordinates: []
        }
      };
    });

    // 更新数据源
    source.setData(fc);

    /**
     * 动画
     */
    function _animate() {
      if (index > counter - 1) {
        index = 0;
        animateFC.features.forEach(fea => fea.geometry.coordinates = []);
      }

      flylines.forEach((flyline, i) => {
        animateFC.features[i].geometry.coordinates.push(flyline[index]);
      });

      animateSource.setData(animateFC);
      index++;
    }

    let that = this;
    let FRAME_RATE = 20; // 帧率
    (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);
      }
    })();
  }

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

    // 加载飞线图层
    this._loadLineLayer();
    // 加载动画图层
    this._loadAnimateLayer();
  }

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

    // 移除动画图层
    LayerProvider.removeLayer(map, this._animateLayerId);
    LayerProvider.removeSource(map, this._animateSourceId);

    // 移除飞线图层
    LayerProvider.removeLayer(map, this._layerId);
    LayerProvider.removeSource(map, this._sourceId);
  }

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

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

  /** 私有方法 **/
  /**
   * 加载飞线图层
   */
  _loadLineLayer() {
    // 添加数据源
    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: "none",
      },
      paint: {
        "line-color": this._lineColor,
        "line-width": this._lineWidth,
        "line-opacity": this._lineOpacity
      }
    });
  }

  /**
   * 添加动画图层
   */
  _loadAnimateLayer() {
    // 添加数据源
    this._map.addSource(this._animateSourceId, {
      type: "geojson",
      lineMetrics: true,
      data: this._animateFC
    });

    // 添加图层
    this._map.addLayer({
      type: "line",
      id: this._animateLayerId,
      source: this._animateSourceId,
      minzoom: this._minzoom,
      layout: {
        visibility: "none",
      },
      paint: {
        "line-color": "#FFFFFF",
        "line-width": this._lineWidth + 1,
        "line-gradient": [
          "interpolate",
          ["linear"],
          ["line-progress"],
          0,
          "rgba(255, 255, 255, 0.1)",
          0.75,
          "rgba(255, 255, 255, 0.5)",
          1,
          "rgba(255, 255, 255, 0.85)"
        ]
      }
    });
  }
}
