import DataUtils from '../utils/DataUtils';
import VerifyUtils from '../utils/VerifyUtils';
import MapProvider from '../geog/MapProvider';
import LayerProvider from '../geog/LayerProvider';
import GeoJsonProvider from '../geog/GeoJsonProvider';

/**
 * 定义简单填充图层
 * @alias SimpleFillLayer
 *
 * @summary <用于填充图层加载>
 */
export default class SimpleFillLayer {
  /**
   * 构造函数
   * @param {Object} options -图层选项
   */
  constructor(options) {
    // 默认数据源ID
    this._defaultSourceId = 'polygon_simple';
    // 数据源是否存在
    this._hasSource = true;

    /**
     * 地图对象
     * @type {Object}
     */
    this._map = options.map;

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

    /**
     * 填充颜色
     * @type {String}
     */
    this._fillColor = DataUtils.default(options.color, 'green');

    /**
     * 填充不透明度
     * @type {Number}
     */
    this._fillOpacity = DataUtils.default(options.opacity, 0.75);

    /**
     * 是否有边框
     * @type {Boolean}
     */
    this._hasOutline = DataUtils.default(options.outline, false);

    /**
     * 线颜色
     * @type {String}
     */
    this._lineColor = DataUtils.default(options.lineColor, 'green');

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

    /**
     * 线不透明度
     * @type {Number}
     */
    this._lineOpacity = DataUtils.default(options.lineOpacity, 1.0);

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

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

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

    /**
     * 是否显示停留状态
     * @type {Boolean}
     */
    this._isHover = DataUtils.default(options.hover, false);

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

    /**
     * 图层ID
     * @type {String}
     */
    this._layerId = DataUtils.default(options.layerId, this._sourceId);
    // 边框图层ID
    this._outlineLayerId = this._layerId + '-outline';

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

    this._hoveredFeatureId = null; // 鼠标停留的要素ID

    // 事件
    this._enterEvent = null;
    this._leaveEvent = null;
    this._clickEvent = null; // 外部实现单击事件
    // 初始化鼠标事件
    this._initEvent();
  }

  /** 公有方法 **/
  /**
   * 设置数据
   * @param {Object|String|Array} data -GeoJSON要素集/查询语句/过滤条件数组
   *
   * @summary <data参数：
   *   Object - GeoJson要素/要素集
   *   String - cql_filter查询语句
   *   Array - 图层过滤条件数组(如：['==', field, value])
   * >
   */
  setData(data) {
    // 加载图层
    if (!this.hasLayer()) {
      this.loadLayer();
    }
    // 隐藏图层
    this.showLayer(false);

    let fc = null;
    if (VerifyUtils.isGeoJsonFC(data)) {
      // GeoJSON要素集合
      fc = data;
    } else if (VerifyUtils.isGeoJsonFeature(data)) {
      // GeoJSON要素
      fc = GeoJsonProvider.getEmptyFC();
      fc.features = [data];
    } else if (VerifyUtils.isArray(data)) {
      if (data.length > 1 && VerifyUtils.isString(data[0])) {
        // 设置筛选器
        this._map.setFilter(this._layerId, data);
        if (this._hasOutline) {
          this._map.setFilter(this._outlineLayerId, data);
        }
      }
    } else if (VerifyUtils.isString(data)) {
      // 查询语句
      if (this._hasSource) {
        const source = this._map.getSource(this._sourceId);
        fc = source._data + (data ? "&cql_filter=" + data : '');
      }
    }

    fc = fc || GeoJsonProvider.getEmptyFC();

    // 更新数据源
    this._map.getSource(this._sourceId).setData(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 = ['all', this._filter];
    }
    */
    if (this._filter) {
      if (this._filter.length === 1) {
        newFilter = ['all', this._filter];
      } else {
        newFilter = [].concat(this._filter);
      }
    }

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

    // 设置筛选器
    this._map.setFilter(this._layerId, newFilter);
    if (this._hasOutline) {
      this._map.setFilter(this._outlineLayerId, 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 sourceId = this._sourceId;
    const layerId = this._layerId;
    // 判断数据源是否存在
    this._hasSource = LayerProvider.hasSource(map, sourceId);
    if (!this._hasSource) {
      // 添加数据源
      map.addSource(sourceId, {
        type: "geojson",
        data: this._dataUrl || GeoJsonProvider.getEmptyFC()
      });
    }

    // 添加图层
    map.addLayer({
      type: "fill",
      id: layerId,
      source: sourceId,
      minzoom: minZoom,
      paint: {
        "fill-color": this._fillColor,
        "fill-opacity": this._fillOpacity
      },
      layout: {
        visibility: "none"
      }
    }, map._build3dLayerId);
    // 设置筛选器
    if (this._filter) {
      map.setFilter(layerId, this._filter);
    }

    if (this._hasOutline) {
      // 添加边框线图层
      map.addLayer({
        type: "line",
        id: this._outlineLayerId,
        source: sourceId,
        minzoom: minZoom,
        paint: {
          "line-color": this._lineColor,
          "line-width": this._lineWidth,
          "line-opacity": this._lineOpacity
        },
        layout: {
          visibility: "none"
        }
      }, map._build3dLayerId);
      // 更新Paint属性
      if (this._dasharray) {
        map.setPaintProperty(this._outlineLayerId, 'line-dasharray', this._dasharray);
      }

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

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

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

    LayerProvider.showLayer(map, this._layerId, show);
    LayerProvider.showLayer(map, this._outlineLayerId, show);
  }

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

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

    // 解除事件绑定
    this.offEvent();

    LayerProvider.removeLayer(map, this._layerId);
    LayerProvider.removeLayer(map, this._outlineLayerId);
  }

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

  /**
   * 绑定单击事件
   * @param {Function} event -事件函数
   */
  onClick(event) {
    this._clickEvent = event;
    if (this.hasLayer()) {
      LayerProvider.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()) {
      LayerProvider.onEvent(this._map, this._layerId, name, event);
    }
  }

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

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

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

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

    // 移入事件
    this._enterEvent = (e) => {
      MapProvider.setCursor(map, 'pointer');

      if (that._isHover) { // 停留状态
        if (that._hoveredFeatureId) {
          map.setFeatureState({
            source: that._sourceId,
            id: that._hoveredFeatureId
          }, {
            hover: false
          });
        }

        if (e.features[0].id) {
          that._hoveredFeatureId = e.features[0].id;
          map.setFeatureState({
            source: that._sourceId,
            id: that._hoveredFeatureId
          }, {
            hover: true
          });
        }
      }
    }
    // 移出事件
    this._leaveEvent = (e) => {
      MapProvider.setCursor(map);

      if (that._isHover) { // 停留状态
        if (that._hoveredFeatureId) {
          map.setFeatureState({
            source: that._sourceId,
            id: that._hoveredFeatureId
          }, {
            hover: false
          });
        }
      }
    }
  }

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

    // 绑定事件
    LayerProvider.onEvent(map, layerId, 'mouseenter', this._enterEvent);
    LayerProvider.onEvent(map, layerId, 'mouseleave', this._leaveEvent);
    if (this._clickEvent) {
      LayerProvider.onEvent(map, layerId, 'click', this._clickEvent);
    }
  }
}
