    import { Zondy } from '@mapgis/webclient-common'
    import * as L from '@mapgis/leaflet'
    // eslint-disable-next-line import/no-extraneous-dependencies
    import { LevelRenderer, modifyDOMElement } from '@mapgis/webclient-graphic-render'

    /**
     * @class Zondy.ThemeLayer.ThemeLayer
     * @classdesc 专题图层基类，调用建议使用其子类实现类。
     * @extends {L.Layer}
     * @param {string} name - 专题图图层名称。
     * @param {Object} options - 可选参数。
     * @param {string} [options.id] - 专题图层 ID。默认使用 CommonUtil.createUniqueID("themeLayer_") 创建专题图层 ID。
     * @param {number} [options.opacity=1] - 图层透明度。
     * @fires Zondy.ThemeLayer.ThemeLayer#featuresremoved
     */
    const ThemeLayer = L.Layer.extend({
      options: {
        name: null,
        opacity: 1,
        // {Array} 专题要素事件临时存储，临时保存图层未添加到 map 前用户添加的事件监听，待图层添加到 map 后把这些事件监听添加到图层上，清空此图层。
        // 这是一个二维数组，组成二维数组的每个一维数组长度为 2，分别是 event, callback。
        TFEvents: null
      },

      initialize(name, options) {
        L.Util.setOptions(this, options)
        this.options.name = name
        this.features = []
        this.TFEvents = options && options.TFEvents ? options.TFEvents : []
        this.levelRenderer = new LevelRenderer()
        this.movingOffset = [0, 0]
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.getEvents
       * @description 获取图层事件。
       * @returns {Object} 返回图层支持的事件。
       */
      getEvents() {
        const me = this
        const events = {
          zoomend: me._reset,
          moveend: me._reset,
          resize: me._resize
        }
        if (this._map._zoomAnimated) {
          events.zoomanim = me._zoomAnim
        }
        return events
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.onRemove
       * @description 删除某个地图。
       * @param {L.Map} map - 要删除的地图。
       */
      onRemove(map) {
        const me = this
        L.DomUtil.remove(me.container)
        map.off('mousemove', me.mouseMoveHandler)
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.onAdd
       * @description 添加专题图。
       * @param {L.Map} map - 要添加的地图。
       * @private
       */
      onAdd(map) {
        const me = this
        me.map = me._map = map
        me._initContainer()
        if (!me.levelRenderer) {
          map.removeLayer(me)
          return
        }
        // 初始化渲染器
        const size = map.getSize()
        me.container.style.width = `${size.x}px`
        me.container.style.height = `${size.y}px`
        me._updateOpacity()

        me.renderer = me.levelRenderer.init(me.container)
        me.renderer.clear()
        if (me.features && me.features.length > 0) {
          me._reset()
        }

        // 处理用户预先（在图层添加到 map 前）监听的事件
        me.addTFEvents()
        me.mouseMoveHandler = function (e) {
          const xy = e.layerPoint
          me.currentMousePosition = L.point(
            xy.x + me.movingOffset[0],
            xy.y + me.movingOffset[1]
          )
        }
        map.on('mousemove', me.mouseMoveHandler)

        me.update()
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.addFeatures
       * @description 向专题图图层中添加数据。
       * @param {Object} features - 待转要素。
       */
      addFeatures(features) {
        // eslint-disable-line no-unused-vars
        // 子类实现此方法
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.redrawThematicFeatures
       * @description 抽象方法，可实例化子类必须实现此方法。
       * @param {L.bounds} bounds - 重绘专题要素范围。
       */
      redrawThematicFeatures(bounds) {
        // eslint-disable-line no-unused-vars
        // 子类必须实现此方法
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.destroyFeatures
       * @description 销毁要素。
       * @param {Array.<Zondy.Feature.Vector>} features - 将被销毁的要素。
       */
      destroyFeatures(features) {
        if (features === undefined) {
          features = this.features
        }
        if (!features) {
          return
        }
        this.removeFeatures(features)
        for (let i = features.length - 1; i >= 0; i--) {
          features[i].destroy()
        }
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.removeFeatures
       * @description 从专题图中删除 feature。这个函数删除所有传递进来的矢量要素。
       * @param {Array.<Zondy.Feature.Vector>} features - 将被删除的要素。
       */
      removeFeatures(features) {
        const me = this
        if (!features || features.length === 0) {
          return
        }
        if (features === me.features) {
          return me.removeAllFeatures()
        }
        if (!L.Util.isArray(features)) {
          features = [features]
        }

        const featuresFailRemoved = []

        for (let i = features.length - 1; i >= 0; i--) {
          var feature = features[i]

          // 如果我们传入的feature在features数组中没有的话，则不进行删除，
          // 并将其放入未删除的数组中。
          const findex = L.Util.indexOf(me.features, feature)

          if (findex === -1) {
            featuresFailRemoved.push(feature)
            continue
          }
          me.features.splice(findex, 1)
        }

        const drawFeatures = []
        for (let hex = 0, len = me.features.length; hex < len; hex++) {
          feature = me.features[hex]
          drawFeatures.push(feature)
        }
        me.features = []
        me.addFeatures(drawFeatures)
        // 绘制专题要素
        if (me.renderer) {
          if (me._map) {
            me.redrawThematicFeatures(me._map.getBounds())
          } else {
            me.redrawThematicFeatures()
          }
        }

        const succeed = featuresFailRemoved.length === 0
        /**
         * @event Zondy.ThemeLayer.ThemeLayer#featuresremoved
         * @description 删除的要素成功之后触发。
         * @property {Array.<Zondy.Feature.Vector>} features - 事件对象。
         * @property {boolean} succeed - 要输是否删除成功，true 为删除成功，false 为删除失败。
         */
        me.fire('featuresremoved', {
          features: featuresFailRemoved,
          succeed
        })
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.removeAllFeatures
       * @description 清除当前图层所有的矢量要素。
       */
      removeAllFeatures() {
        const me = this
        if (me.renderer) {
          me.renderer.clear()
        }
        me.features = []
        me.fire('featuresremoved', {
          features: [],
          succeed: true
        })
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.getFeatures
       * @description 查看当前图层中的有效数据。
       * @returns {Array} 返回图层中的有效数据。
       */
      getFeatures() {
        const me = this
        const len = me.features.length
        const clonedFeatures = new Array(len)
        for (let i = 0; i < len; ++i) {
          clonedFeatures[i] = me.features[i]
        }
        return clonedFeatures
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.getFeatureBy
       * @description 在专题图的要素数组 features 里面遍历每一个 feature，当 feature[property] === value 时，返回此 feature（并且只返回第一个）。
       * @param {string} property - 要的某个属性名。
       * @param {string} value - 对应属性名得值。
       */
      getFeatureBy(property, value) {
        const me = this
        return me.features.find((feature) => {
          const attributes = feature.attributes
          if (feature[property] === value || attributes[property] === value) {
            return feature
          }
        })
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.getFeatureById
       * @description 通过给定一个 ID，返回对应的矢量要素,如果不存在则返回 null。
       * @param {number} featureId - 要素 ID。
       */
      getFeatureById(featureId) {
        return this.getFeatureBy('id', featureId)
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.getFeaturesByAttribute
       * @description 通过给定一个属性的 key 值和 value 值，返回所有匹配的要素数组。
       * @param {string} attrName - key 值。
       * @param {string} attrValue - value 值。
       * @returns {Array} 返回所有匹配的要素数组。
       */
      getFeaturesByAttribute(attrName, attrValue) {
        const me = this
        let feature
        const foundFeatures = []
        for (const id in me.features) {
          feature = me.features[id]
          if (
            feature &&
            feature.attributes &&
            feature.attributes[attrName] === attrValue
          ) {
            foundFeatures.push(feature)
          }
        }
        return foundFeatures
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.update
       * @description 更新图层。
       * @param {L.bounds} bounds - 图层范围。
       */
      update(bounds) {
        const mapOffset = this._map.containerPointToLayerPoint([0, 0])
        L.DomUtil.setPosition(this.container, mapOffset)

        const me = this
        //  var bounds = me._map.getBounds();
        //  var topLeft = me._map.latLngToLayerPoint(bounds.getNorthWest());
        //  var mapOffset = [parseInt(topLeft.x, 10) || 0, parseInt(topLeft.y, 10) || 0]
        // // var offsetLeft = parseInt(me._map.getContainer().style.left, 10);
        // // offsetLeft = -Math.round(offsetLeft);
        //  //var offsetTop = parseInt(me._map.getContainer().style.top, 10);
        //  //offsetTop = -Math.round(offsetTop);
        //  me.container.style.left = mapOffset[0] + 'px';
        //  me.container.style.top = mapOffset[1] + 'px';

        // 绘制专题要素
        if (me.renderer) {
          me.redrawThematicFeatures(bounds)
        }

        if (me.currentMousePosition) {
          me.currentMousePosition = L.point(
            me.currentMousePosition.x - me.movingOffset[0],
            me.currentMousePosition.y - me.movingOffset[1]
          )
        }
        me.movingOffset = [0, 0]
        me._zoom = me._map.getZoom()
        me._center = me._map.getCenter()
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.setOpacity
       * @description 设置图层的不透明度,取值 [0-1] 之间。
       * @param {number} opacity - 不透明度。
       */
      setOpacity(opacity) {
        const me = this
        if (opacity === me.options.opacity) {
          return
        }
        if (!isNaN(opacity)) {
          me.options.opacity = opacity
          me._updateOpacity()
        }
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.redraw
       * @description 重绘该图层。
       * @returns {boolean} 返回是否重绘成功。
       */
      redraw() {
        const me = this
        if (!me.renderer) {
          return false
        }
        if (me._map) {
          me.redrawThematicFeatures(me._map.getBounds())
        } else {
          me.redrawThematicFeatures()
        }
        return true
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.on
       * @description 添加专题要素事件监听。添加专题要素事件监听。
       * @param {Event} event - 监听事件。
       * @param {Function} callback - 回调函数。
       * @param {string} context - 信息。
       */
      on(event, callback, context) {
        // eslint-disable-line no-unused-vars
        if (this.renderer) {
          this.renderer.on(event, callback)
        } else {
          L.Layer.prototype.on.call(this, event, callback)
        }
        return this
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.off
       * @description 移除专题要素事件监听。
       * @param {Event} event - 监听事件。
       * @param {Function} callback - 回调函数。
       * @param {string} context -  信息。
       */
      off(event, callback, context) {
        // eslint-disable-line no-unused-vars
        const me = this
        if (me.renderer) {
          me.renderer.un(event, callback)
        } else {
          L.Layer.prototype.off.call(this, event, callback)
        }
        return this
      },
      fire(type, data, propagate) {
        // eslint-disable-line no-unused-vars
        if (this.renderer) {
          this.renderer.trigger(type, data)
        }
        L.Layer.prototype.fire.call(this, type, data, propagate)
        return this
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.addTFEvents
       * @description 将图层添加到地图上之前用户要求添加的事件监听添加到图层。
       * @private
       */
      addTFEvents() {
        const me = this
        const tfEs = me.TFEvents
        const len = tfEs.length

        for (let i = 0; i < len; i++) {
          me.renderer.on(tfEs[i][0], tfEs[i][1])
        }
      },

      /**
       * @function Zondy.ThemeLayer.ThemeLayer.prototype.getLocalXY
       * @description 地理坐标转为像素坐标。
       * @param {Array} coordinate
       */
      getLocalXY(coordinate) {
        if (!this._map) {
          return coordinate
        }
        let coor = coordinate
        if (L.Util.isArray(coordinate)) {
          coor = L.point(coordinate[0], coordinate[1])
        } else if (!(coordinate instanceof L.Point)) {
          if (coordinate instanceof Zondy.LonLat) {
            coor = L.point(coordinate.lon, coordinate.lat)
          } else {
            coor = L.point(coordinate.x, coordinate.y)
          }
        }
        const point = this._map.latLngToContainerPoint(
          this._map.options.crs.unproject(coor)
        )
        return [point.x, point.y]
      },

      _initContainer() {
        const parentContainer = this.getPane()
        const animated = this._map.options.zoomAnimation && L.Browser.any3d
        let className = this.options.name || 'themeLayer'
        className += ` leaflet-layer leaflet-zoom-${animated ? 'animated' : 'hide'}`
        this.container = L.DomUtil.create('div', className, parentContainer)

        const originProp = L.DomUtil.testProp([
          'transformOrigin',
          'WebkitTransformOrigin',
          'msTransformOrigin'
        ])
        this.container.style[originProp] = '50% 50%'

        this.container.style.position = 'absolute'
        this.container.style.zIndex = 200
      },

      _zoomAnim(e) {
        const scale = this._map.getZoomScale(e.zoom)
        const offset = this._map
          ._getCenterOffset(e.center)
          ._multiplyBy(-scale)
          .subtract(this._map._getMapPanePos())

        if (L.DomUtil.setTransform) {
          L.DomUtil.setTransform(this.container, offset, scale)
        } else {
          this.container.style[
            L.DomUtil.TRANSFORM
          ] = `${L.DomUtil.getTranslateString(offset)} scale(${scale})`
        }
      },

      _updateOpacity() {
        const me = this
        modifyDOMElement(
          me.container,
          null,
          null,
          null,
          null,
          null,
          null,
          me.options.opacity
        )
        if (me._map !== null) {
          /**
           * @event Zondy.ThemeLayer.ThemeLayer#changelayer
           * @description 图层属性改变之后触发。
           * @property {Object} layer - 图层。
           * @property {string} property - 图层属性。
           */
          me._map.fire('changelayer', {
            layer: me,
            property: 'opacity'
          })
        }
      },

      // 缩放移动重绘
      _reset() {
        const me = this
        const latLngBounds = me._map.getBounds()
        me.update(latLngBounds)
        const size = me._map.getSize()
        const mapOffset = this._map.containerPointToLayerPoint([0, 0])
        L.DomUtil.setPosition(this.container, mapOffset)

        if (parseFloat(me.container.width) !== parseFloat(size.x)) {
          me.container.width = `${size.x}px`
        }
        if (parseFloat(me.container.height) !== parseFloat(size.y)) {
          me.container.height = `${size.y}px`
        }
        me.redraw()
      },

      // 通知渲染器的尺寸变化
      _resize() {
        const me = this
        const newSize = me._map.getSize()
        me.container.style.width = `${newSize.x}px`
        me.container.style.height = `${newSize.y}px`
        me.renderer.resize()
      }
    })

    Zondy.ThemeLayer.ThemeLayer = ThemeLayer
    export default ThemeLayer