import DataUtils from "../utils/DataUtils";
import IconUtils from "../utils/IconUtils";
import MarkerLayer from "./MarkerLayer";
import LineLayer from "./LineLayer";

/**
 * 定义线流向图层
 * @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, 9);
    
    /**
     * 线颜色
     * @type {String}
     */
    this._lineColor = DataUtils.default(options.lineColor, '#5F9EA0');

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

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

    /**
     * 方向图标ID
     * @type {String}
     */
    this._directionIcon = DataUtils.default(options.directionIcon, undefined);

    /**
     * 过滤条件数组
     * @type {Array}
     */
    this._filter = DataUtils.default(options.filter, undefined);

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

    /**
     * 图层ID
     * @type {String}
     */
    this._lineLayerId = DataUtils.default(options.layerId, this._sourceId);
    this._dashLineLayerId = this._lineLayerId + '-dash';
    this._directionLayerId = this._lineLayerId + '-direction';
    
    this._ratio = 200;    // 比率
    this._playState = 'stop'; // 播放状态(play、stop)
    this._frameId = null;

    /** 图层 **/
    this._lineLayer = null; // 线图层
    this._dashLineLayer = null; // 虚线图层
    this._directionLayer = null; // 方向点图层

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

  /** 公有方法 **/
  /**
   * 设置流向数据
   * @param {Object|Array} data -GeoJson要素集/要素/要素列表
   */
  setData(data) {
    // 加载图层
    if (!this.hasLayer()) {
      this.loadLayer();
    }
    
    // 流向线图层
    this._lineLayer.setData(data);
    this._dashLineLayer.setData(data);

    // 方向点图层
    if (this._directionLayer) {
      this._directionLayer.setData(data);
    }
  }

  /**
   * 加载图层
   */
  loadLayer() {
    if (this.hasLayer()) return;
    
    // 加载方向图标
    if (this._directionIcon) {
      IconUtils.loadArrowIcon(this._map, this._directionIcon);
    }

    // 流向线图层
    this._lineLayer.loadLayer();
    this._dashLineLayer.loadLayer();

    // 方向点图层
    if (this._directionLayer) {
      this._directionLayer.loadLayer();
    }
  }

  /**
   * 显示/隐藏图层
   * @param {Boolean} show -是否显示
   */
  showLayer(show = true) {
    // 流向线图层
    this._lineLayer.showLayer(show);
    this._dashLineLayer.showLayer(show);
    
    // 方向点图层
    if (this._directionLayer) {
      this._directionLayer.showLayer(show);
    }
  }

  /**
   * 判断图层是否已加载
   * 
   * @returns {Boolean}
   */
  hasLayer() {
    return (
      this._lineLayer.hasLayer() &&
      this._dashLineLayer.hasLayer()
    );
  }

  /**
   * 图层是否可见
   * 
   * @returns {Boolean}
   */
  isLayerVisible() {
    return (
      this._lineLayer.isLayerVisible() &&
      this._dashLineLayer.isLayerVisible()
    );
  }

  /**
   * 移除图层
   */
  removeLayer() {
    this.stop(); // 停止动画

    // 流向线图层
    this._lineLayer.removeLayer();
    this._dashLineLayer.removeLayer();
    
    // 方向点图层
    if (this._directionLayer) {
      this._directionLayer.removeLayer();
    }
  }

  /**
   * 移除数据源
   */
  removeSource() {
    this._lineLayer.removeSource();

    // 移除图标
    if (this._directionIcon) {
      IconUtils.removeIcon(this._map, this._directionIcon);
    }
  }

  /**
   * 开始动画
   */
  start() {
    this._playState = 'play';
    // 显示图层
    this.showLayer(true);

    const that = this;
    // technique based on https://jsfiddle.net/2mws8y3q/
    // an array of valid line-dasharray values, specifying the lengths of the alternating dashes and gaps that form the dash pattern
    const dashArraySequence = [
      [0.0, 4, 3.0],
      [0.5, 4, 2.5],
      [1.0, 4, 2.0],
      [1.5, 4, 1.5],
      [2.0, 4, 1.0],
      [2.5, 4, 0.5],
      [3.0, 4, 0.0],
      [0, 0.5, 3, 3.5],
      [0, 1.0, 3, 3.0],
      [0, 1.5, 3, 2.5],
      [0, 2.0, 3, 2.0],
      [0, 2.5, 3, 1.5],
      [0, 3.0, 3, 1.0],
      [0, 3.5, 3, 0.5],
    ];
    
    let step = 0;
    function _animateDashArray(timestamp) {
      if (that._playState === 'play') {
        // Update line-dasharray using the next value in dashArraySequence. 
        // The divisor in the expression `timestamp / 50` controls the animation speed.
        const newStep = parseInt(
          (timestamp / that._ratio) % dashArraySequence.length
        ); 
        if (newStep !== step) {
          that._dashLineLayer.setPaintProperty('line-dasharray', dashArraySequence[step]);
          step = newStep;
        }
 
        // Request the next frame of the animation.
        that._frameId = requestAnimationFrame(_animateDashArray);
      }
    }

    // start the animation
    _animateDashArray(0);
  }
  
  /**
   * 停止动画
   */
  stop() {
    this._playState = 'stop';    
    // 隐藏图层
    this.showLayer(false);

    if (this._frameId) {
      cancelAnimationFrame(this._frameId);
    }
  }

  /** 私有方法 **/
  /**
   * 初始化图层
   */
  _initLayers() {
    const map = this._map;
    const minZoom = this._minZoom;
    
    // 线图层
    this._lineLayer = new LineLayer({
      map: map,
      minZoom: minZoom,
      color: this._lineColor,
      width: this._lineWidth,
      opacity: 0.35,
      fixed: this._fixed,
      filter: this._filter,
      sourceId: this._sourceId,
      layerId: this._lineLayerId
    });
    
    // 虚线图层
    this._dashLineLayer = new LineLayer({
      map: map,
      minZoom: minZoom,
      color: this._lineColor,
      width: this._lineWidth,
      opacity: 1.0,
      dasharray: [0, 4, 3],
      fixed: this._fixed,
      filter: this._filter,
      sourceId: this._sourceId,
      layerId: this._dashLineLayerId
    });
    
    // 方向点图层
    if (this._directionIcon) {
      this._directionLayer = new MarkerLayer({
        map: map,
        minZoom: minZoom,
        icon: this._directionIcon,
        filter: this._filter,
        sourceId: this._sourceId,
        layerId: this._directionLayerId
      });
      // 设置自定义样式
      this._directionLayer.setLayoutProperty('symbol-placement', 'line');
      this._directionLayer.setLayoutProperty('symbol-spacing', [
        "interpolate",
        ["linear"],
        ["zoom"],
        10, 50,
        18, 250
      ]);
    }
  }
}