import DataUtils from "../utils/DataUtils";
import VerifyUtils from "../utils/VerifyUtils";
import GeoJsonUtils from "../utils/GeoJsonUtils";
import LayerUtils from "../utils/LayerUtils";
import MapUtils from "../utils/MapUtils";

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

    /**
     * 最小缩放层级
     * @type {Number}
     */
    this._minZoom = DataUtils.default(options.minZoom, 9);

    /**
     * 线颜色
     * @type {String|Object|Array}
     */
    this._lineColor = DataUtils.default(options.color, '#00ff00');

    /**
     * 线宽
     * @type {Number}
     */
    this._lineWidth = DataUtils.default(options.width, 1.5);
    
    /**
     * 线端点帽样式
     * @type {String}
     */
    this._lineCap = DataUtils.default(options.cap, 'butt');

    /**
     * 不透明度
     * @type {Number} (0-1)
     */
    this._lineOpacity = DataUtils.default(options.opacity, 1.0);

    /**
     * 短线数组
     * @type {Array}
     */
    this._dasharray = DataUtils.default(options.dasharray, undefined);

    /**
     * 线宽是否固定
     * @type {Boolean}
     */
    this._fixed = DataUtils.default(options.fixed, false);
 
    /**
     * 是否计算度量
     * @type {Boolean} 
     */
    this._lineMetrics = DataUtils.default(options.metrics, false);
 
    /**
     * 是否在3D建筑物图层下面
     * @type {Boolean}
     */
    this._underBuilding = DataUtils.default(options.underBuilding, true);

    /**
     * 筛选器
     * @type {Array}
     */
    this._filter = DataUtils.default(options.filter, undefined);

    /**
     * 数据服务地址
     * @type {String} 
     */
    this._dataUrl = DataUtils.default(options.dataUrl, undefined);

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

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

    // 样式属性数组
    this._styleProperties = [];

    // 要素集
    this._fc = GeoJsonUtils.getEmptyFC();

    // 事件
    this._enterEvent = null;
    this._leaveEvent = null;
    this._clickEvent = null; // 外部实现单击事件
    // 初始化事件
    this._initEvent();
  }
  
  /** 公有方法 **/
  /**
   * 设置数据
   * @param {Object|Array} data -GeoJson要素集/要素/要素列表
   * 
   * @summary <data参数：
   *   Object - GeoJson要素集/要素
   *   Array - GeoJson要素数组/点位数组(包含longitude/lng, latitude/lat字段)
   * >
   */
  setData(data) {
    // 加载图层
    if (!this.hasLayer()) {
      this.loadLayer();
    }

    let fc = GeoJsonUtils.getEmptyFC();

    if (VerifyUtils.isFeatureCollection(data)) { 
      // 要素集
      if (data.features && data.features.length > 0) {
        fc.features = data.features;
      }
    } else if (VerifyUtils.isFeature(data)) { 
      // 要素
      fc.features = [data];
    } else if (VerifyUtils.isArray(data) && data.length > 0) {
      if (VerifyUtils.isFeature(data[0])) { 
        // 要素数组
        fc.features = data;
      }
    }

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

    // 更新数据源
    LayerUtils.updateSource(this._map, this._sourceId, fc);
    // 显示图层
    this.showLayer(true);
  }

  /**
   * 设置筛选器
   * @param {Array} filter -筛选器
   */
  setFilter(filter) {
    if (!this.hasLayer()) return;

    // 空数组
    if (VerifyUtils.isArray(filter) && filter.length === 0) {
      filter = null;
    }

    let newFilter = null;
    if (this._filter) {
      newFilter = this._filter.length === 1
                  ? ['all', this._filter]
                  : [].concat(this._filter);
    }

    if (filter) {
      if (!newFilter) {
        newFilter = filter;
      } else {
        newFilter.push(filter);
      }
    }

    // 设置筛选器
    this._map.setFilter(this._layerId, newFilter);
  }

  /**
   * 设置绘制属性
   * @param {String} name -属性名称
   * @param {String|Object} value -属性值 
   */
  setPaintProperty(name, value) {
    if (!this.hasLayer()) {
      this._styleProperties.push({ style: 'paint', name: name, value: value });
      return;
    }

    this._map.setPaintProperty(this._layerId, name, value);
  }

  /**
   * 设置布局属性
   * @param {String} name -属性名称
   * @param {String|Object} value -属性值 
   */
  setLayoutProperty(name, value) {
    if (!this.hasLayer()) {
      this._styleProperties.push({ style: 'layout', name: name, value: value });
      return;
    }

    this._map.setLayoutProperty(this._layerId, name, value);
  }

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

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

    const sourceId = this._sourceId;
    const layerId = this._layerId;
    // 判断数据源是否存在
    if (!LayerUtils.hasSource(map, sourceId)) {
      // 添加数据源
      map&&map.addSource(sourceId, {
        type: "geojson",
        data: this._dataUrl || GeoJsonUtils.getEmptyFC(),
        lineMetrics: this._lineMetrics, // 用于渐变线
      });
    }
    
    // 3D建筑物图层ID
    const buildingLayerId = this._underBuilding 
                            ? map._params.building3DLayerId 
                            : undefined;    
    // 添加图层
    map.addLayer({
      type: "line",
      id: layerId,
      source: sourceId,
      minzoom: minZoom,
      layout: {
        "line-join": "round",
        "line-round-limit": 0.5,
        "line-cap": this._lineCap,
        visibility: "none"
      },
      paint: {
        "line-color": this._lineColor,
        "line-width": this._fixed
          ? this._lineWidth
          : {
            base: 1.5,
            stops: [
              [minZoom, 0.75],
              [maxZoom, this._lineWidth],
            ]
          },
        "line-opacity": this._lineOpacity
      }
    }, buildingLayerId);

    // 设置Paint属性
    if (this._dasharray && this._dasharray.length === 2) {
      map.setPaintProperty(layerId, 'line-dasharray', this._dasharray);
    }

    // 设置自定义样式
    if (this._styleProperties.length > 0) {
      this._styleProperties.forEach(prop => {
        switch (prop.style) {
          case 'paint':
            map.setPaintProperty(layerId, prop.name, prop.value);
            break;
          case 'layout':
            map.setLayoutProperty(layerId, prop.name, prop.value);
            break;
          default:
            break;
        }
      });
    }

    // 设置筛选器
    if (this._filter) {
      map.setFilter(layerId, this._filter);
    }

    // 绑定事件
    this._onEvent();
  }

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

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

  /**
   * 图层是否可见
   * 
   * @returns {Boolean}
   */
  isLayerVisible() {
    return LayerUtils.isLayerVisible(this._map, this._layerId);
  }

  /**
   * 移除图层 
   */
  removeLayer() {
    // 解除事件绑定
    this.offEvent();

    LayerUtils.removeLayer(this._map, this._layerId);
    this._fc.features = [];
  }

  /**
   * 移除数据源
   */
  removeSource() {
    LayerUtils.removeSource(this._map, this._sourceId);
  }

  /**
   * 绑定单击事件
   * @param {Function} event -事件函数 
   */
  onClick(event) {
    this._clickEvent = event;

    if (this.hasLayer()) {
      LayerUtils.onEvent(this._map, this._layerId, 'click', event);
    }
  }

  /**
   * 绑定事件
   * @param {String} name -事件名称
   * @param {Function} event -事件函数
   * 
   * @summary <name参数取值：
   *   mouseenter-鼠标移入; 
   *   mouseleave-鼠标移除; 
   *   click-鼠标单击
   * > 
   */
  onEvent(name, event) {
    switch (name) {
      case 'mouseenter': {
        this._enterEvent = event;
        break;
      }
      case 'mouseleave': {
        this._leaveEvent = event;

        break;
      }
      case 'click': {
        this._clickEvent = event;
        break;
      }
      default:
        return;
    }

    if (this.hasLayer()) {
      LayerUtils.onEvent(this._map, this._layerId, name, event);
    }
  }

  /**
   * 解除事件绑定
   */
  offEvent() {
    if (!this.hasLayer()) return;

    const map = this._map;
    const layerId = this._layerId;

    LayerUtils.offEvent(map, layerId, 'mouseenter', this._enterEvent);
    LayerUtils.offEvent(map, layerId, 'mouseleave', this._leaveEvent);
    if (this._clickEvent) {
      LayerUtils.offEvent(map, layerId, 'click', this._clickEvent);
    }
  }

  /** 私有方法 **/
  /**
   * 初始化事件 
   */
  _initEvent() {
    const map = this._map;

    /**
     * 移入事件 
     */
    this._enterEvent = (e) => {
      MapUtils.setCursor(map, 'pointer');
    }
    /**
     * 移出事件 
     */
    this._leaveEvent = (e) => {
      MapUtils.setCursor(map);
    }
  }

  /**
   * 绑定事件
   */
  _onEvent() {
    const map = this._map;
    const layerId = this._layerId;

    LayerUtils.onEvent(map, layerId, 'mouseenter', this._enterEvent);
    LayerUtils.onEvent(map, layerId, 'mouseleave', this._leaveEvent);
    if (this._clickEvent) {
      LayerUtils.onEvent(map, layerId, 'click', this._clickEvent);
    }
  }
}