    import { Zondy, Evented, SketchDataType, Projection } from '../../base'
    import { defaultValue, Log } from '../../util'
    import {
      Point,
      LineString,
      Polygon,
      SpatialReference,
      Circle,
      Extent
    } from '../../base/geometry'
    import SketchStyle from './SketchStyle'
    import SketchPointDrawTool from './SketchPointDrawTool'
    import SketchPolygonDrawTool from './SketchPolygonDrawTool'
    import SketchSnappingTool from './SketchSnappingTool'
    import SketchPolylineDrawTool from './SketchPolylineDrawTool'
    import SketchCircleDrawTool from './SketchCircleDrawTool'
    import SketchRectangleDrawTool from './SketchRectangleDrawTool'
    import SketchTopologyTool from './SketchTopologyTool'
    import UndoRedoManager from './UndoRedoManager'
    /**
     * 草图编辑基类
     * @class SketchEditorNew
     * @moduleEX SketchEditorModule
     * @extends Evented
     * @param {Object} options 构造参数
     * @param {MapView|SecenView}  [options.mapView]  地图视图对象
     * @param {GraphicsLayer}  [options.layer]  草图图层管对象
     * @param {SketchStyle}  [options.sketchStyle]  草图符号
     * @param {Object}  [options.snappingOption]  草图捕获配置项
     *
     * @summary <h5>支持如下方法：</h5>
     * <a href='#start'>[1、开始绘制草图]</a><br/>
     * <a href='#stop'>[2、停止绘制]</a><br/>
     * <a href='#remove'>[3、移除当前草图]</a><br/>
     * <a href='#update'>[4、更新当前草图]</a><br/>
     * <a href='#addVertex'>[5、向当前线或面草图中插入新的顶点]</a><br/>
     * <a href='#updateVertex'>[6、更新草图图形的某个顶点]</a><br/>
     * <a href='#removeVertex'>[7、移除草图图形的某个顶点]</a><br/>
     * <a href='#getSketchDataType'>[8、获取草图图形类型]</a><br/>
     * <a href='#setSketchStyle'>[9、设置草图样式]</a><br/>
     * <a href='#getSketchStyle'>[10、获取草图样式]</a><br/>
     * <a href='#getGeometry'>[11、获取草图几何对象]</a><br/>
     * <a href='#union'>[12、合并多个区几何]</a><br/>
     * <a href='#split'>[13、分割草图对象或区几何对象]</a><br/>
     * <a href='#undo'>[14、撤销当前编辑操作]</a><br/>
     * <a href='#redo'>[15、恢复被撤销的草图]</a><br/>
     * @example
     * // ES5引入方式
     * const { SketchEditorNew } = Zondy
     * // ES6引入方式
     * import { SketchEditorNew } from "@mapgis/webclient-common"
     */
    /**
     * @event SketchEditorNew#草图绘制完成事件
     * @property {Object} event 事件对象
     * @property {LayerEventType} [event.type = 'drawn'] 事件类型
     * @property {Geometry} [event.geometry] 绘制的几何对象
     * @example <caption><h7>鼠标绘制完成事件</h7></caption>
     * sketchEditor.on('drawn', (event) => {
     *   console.log("绘制的几何对象:", event.geometry)
     * })
     */
    /**
     * @event SketchEditorNew#标绘制线或区的一个顶点完成事件
     * @property {Object} event 事件对象
     * @property {LayerEventType} [event.type = 'drawn-vertex'] 事件类型
     * @property {Geometry} [event.geometry] 绘制的几何对象
     * @example <caption><h7>鼠标绘制线或区的一个顶点完成事件</h7></caption>
     * sketchEditor.on('drawn-vertex', (event) => {
     *   console.log("绘制的几何对象:", event.geometry)
     * })
     */
    /**
     * @event SketchEditorNew#草图被选中事件
     * @property {Object} event 事件对象
     * @property {LayerEventType} [event.type = 'selected'] 事件类型
     * @property {SketchEditorLeaflet|SketchEditorCesium} [event.selectedSketch] 被选中的草图对象
     * @example <caption><h7>草图被鼠标选中事件</h7></caption>
     * sketchEditor.on('selected', (event) => {
     *   console.log("被选中事件:", event.selectedSketch)
     * })
     */

    class SketchEditorNew extends Evented {
      constructor(options) {
        super()
        options = defaultValue(options, {})
        if (!options.mapView) {
          Log.error('options.mapView is null!', options)
        }
        /**
         * 地图视图
         * @member {MapView|SecenView} SketchEditor.prototype._mapView
         */
        this._mapView = options.mapView
        this._spatialReference = options.mapView.crs
          ? new SpatialReference(options.mapView.crs.code)
          : new SpatialReference('EPSG:4326')
        /**
         * 草图图层
         * @member {GraphicsLayer} SketchEditor.prototype._layer
         */
        this._layer = defaultValue(options.layer, undefined)
        /**
         * 草图符号
         * @member {SketchStyle} SketchEditor.prototype._sketchStyle
         */
        this._sketchStyle = defaultValue(options.sketchStyle, new SketchStyle())
        /**
         * 草图是否可编辑
         * @member {SketchStyle} SketchEditor.prototype._editable
         */
        this._editable = defaultValue(options.editable, true)
        /**
         * 草图捕获配置项
         * @member {Object} SketchEditor.prototype.snappingOption
         */
        const snappingOption = {
          showSelectBox: false,
          showSelectVertex: false,
          canEditFeature: false,
          canEditVertex: false
        }
        this.snappingOption = Object.assign(snappingOption, options.snappingOption)
        /**
         * 草图量算配置项
         * @member {Number} SketchEditor.prototype.measureOption
         */
        this.measureOption = defaultValue(options.measureOption, undefined)
        /**
         * 当前选中草图绘制工具
         * @member {Number} SketchEditor.prototype._drawTool
         */
        this._drawTool = null
        /**
         * 草图回撤管理器
         * @member {Number} SketchEditor.prototype._redoUndoManager
         */
        this._redoUndoManager = undefined
        /**
         * 草图绘制类型
         * @member {Number} SketchEditor.prototype._sketchDataType
         */
        this._sketchDataType = null
        /**
         * 草图捕获工具
         * @member {Number} SketchEditor.prototype._sketchDataType
         */
        this._sketchSnappingTool = {}
        /**
         * 草图拓扑分析工具
         * @member {Number} SketchEditor.prototype._sketchTopologyTool
         */
        this._sketchTopologyTool = {}

        /**
         * 撤销回退管理器
         * @member {Strign} SketchEditor.prototype.undoRedoManager
         */
        this._undoRedoManager = new UndoRedoManager()
        this._editorState = {
          editMode: 0,
          undoRedoManager: this.undoRedoManager,
          _hitTestEvent: this._hitTestEvent
        }
        if (this._layer) {
          const layerExist = this._mapView._map.findLayerById(this._layer.id)
          if (!layerExist) {
            this._mapView._map.add(this._layer)
            // const self = this
            // this._layer.on('layerview-created', function (result) {
            //   self._layerView = result.layerView
            //   // self._hitTestEvent()
            // })
          }

          // 有图层存在，初始化捕捉和拓扑分析工具
          this._sketchSnappingTool = new SketchSnappingTool(this.snappingOption)
          this._sketchTopologyTool = new SketchTopologyTool()
        } else {
          // 没有图层存在，草图捕获置为空
          this._hitTestEvent = {}
        }
      }

      /**
       * 开始(鼠标)绘制草图<a id='start'></a>
       * 根据传入绘制草图类型，开始鼠标绘制。<br/>
       * 绘制点图形，鼠标单击即绘制。<br/>
       * 绘制线图形，鼠标单击绘制线的一个顶点；鼠标移动，延长线图形；鼠标双击，完成线图形绘制。<br/>
       * 绘制区图形，鼠标单击绘制区的一个顶点；鼠标移动，区图形随鼠标位置变动；鼠标双击，完成区图形绘制。<br/>
       * @param {SketchDataType} dataType 绘制的草图类型
       */
      start(data) {
        if (this._drawTool) {
          this._drawTool._stopHitTest()
        }
        let dataType = ''
        let isGeometry = false
        if (typeof data === 'number') {
          dataType = data
        } else if (data instanceof Point) {
          dataType = SketchDataType.POINT
          isGeometry = true
        } else if (data instanceof LineString) {
          dataType = SketchDataType.POLYLINE
          isGeometry = true
        } else if (data instanceof Polygon) {
          dataType = SketchDataType.POLYGON
          isGeometry = true
        } else if (data instanceof Circle) {
          dataType = SketchDataType.CIRCLE
          isGeometry = true
        } else if (data instanceof Extent) {
          dataType = SketchDataType.RECTANGLE
          isGeometry = true
        }
        switch (dataType) {
          case SketchDataType.POINT:
            // 新建草图点实例
            this._drawTool = new SketchPointDrawTool({
              mapView: this._mapView,
              sketchStyle: this._sketchStyle,
              layer: this._layer,
              _hitTestEvent: this._hitTestEvent,
              undoRedoManager: this._undoRedoManager,
              _sketchEditor: this
            })
            break
          case SketchDataType.POLYLINE:
            // 新建草图线实例
            this._drawTool = new SketchPolylineDrawTool({
              mapView: this._mapView,
              sketchStyle: this._sketchStyle,
              layer: this._layer,
              _hitTestEvent: this._hitTestEvent,
              undoRedoManager: this._undoRedoManager,
              _sketchEditor: this
            })
            break
          case SketchDataType.POLYGON:
            // 新建草图区实例
            this._drawTool = new SketchPolygonDrawTool({
              mapView: this._mapView,
              sketchStyle: this._sketchStyle,
              layer: this._layer,
              _hitTestEvent: this._hitTestEvent,
              undoRedoManager: this._undoRedoManager,
              _sketchEditor: this
            })
            break
          case SketchDataType.CIRCLE:
            // 新建草图区实例
            this._drawTool = new SketchCircleDrawTool({
              mapView: this._mapView,
              sketchStyle: this._sketchStyle,
              layer: this._layer,
              _hitTestEvent: this._hitTestEvent,
              undoRedoManager: this._undoRedoManager,
              _sketchEditor: this
            })
            break
          case SketchDataType.RECTANGLE:
            // 新建草图区实例
            this._drawTool = new SketchRectangleDrawTool({
              mapView: this._mapView,
              sketchStyle: this._sketchStyle,
              layer: this._layer,
              _hitTestEvent: this._hitTestEvent,
              undoRedoManager: this._undoRedoManager,
              _sketchEditor: this
            })
            break
          default:
            break
        }
        if (this._drawTool) {
          this._drawTool._sketchDataType = dataType
          if (isGeometry) {
            this._addGeometry(
              data,
              this._drawTool._hitTestEvent.bind(this._drawTool)
            )
            // 注册hitTest事件移动图形
            // this._drawTool._hitTestDrawToolStack.push(this._drawTool)
            // setTimeout(() => {
            //   this._drawTool._hitTestEvent()
            // }, 200)
            this._drawTool._hitTestEvent(false)
          } else {
            this._drawTool.start(this._sketchDataType)
          }
          // 响应草图被选中事件
          this._selectEvent()
          this._drawEvent()
        }
      }

      /**
       * 停止鼠标绘制草图<a id='stop'></a>
       */
      stop() {
        if (this._drawTool) {
          this._drawTool.stop()
          if (this._drawTool._editMode === 3) {
            this.remove()
          }
        }
      }

      /**
       * 移除当前草图<a id='remove'></a>
       */
      remove() {
        this._drawTool.removeDrawTool()
        this._drawTool = null
      }

      /**
       * 更新当前草图<a id='update'></a>
       * @private
       * @param {Object} data 更新的数据
       * @param {Number} index 新增/新增点的序号
       */
      update(data, featureId) {
        this._drawTool.updateFeature(data, featureId)
      }

      /**
       * 向当前线或区草图图形中插入新的顶点
       * @private
       * @param {Point} point 新增/插入顶点
       * @param {Number} index 新增/新增点的序号
       */
      _addGeometry(geometry) {
        this._drawTool.addFeatureByGeometry(geometry)
      }

      /**
       * 向当前线或区草图中插入新的顶点<a id='addVertex'></a>
       * @param {Point} point 新增/插入顶点
       * @param {Number} index 新增/新增点的序号
       * @returns {Geometry} 改变后的图形几何
       */
      addVertex(point, index) {
        const geometry = this._drawTool.addVertex(point, index)
        return geometry
      }

      /**
       * 更新当前选中或区草图图形的某个顶点<a id='updateVertex'></a>
       * @param {Point} point 新的顶点
       * @param {Number} index 需更新的顶点的序号
       * @returns {Geometry} 改变后的图形几何
       */
      updateVertex(point, index) {
        const geometry = this._drawTool.updateVertex(point, index)
        return geometry
      }

      /**
       * 移除草图图形的某个顶点<a id='removeVertex'></a>
       * @param {Number} index 需更新的顶点的序号
       * @returns {Geometry} 改变后的图形几何
       */
      removeVertex(index) {
        const geometry = this._drawTool.removeVertex(index)
        return geometry
      }

      /**
       * 获取草图图形类型<a id='getSketchDataType'></a>
       * @returns {SketchDataType}
       */
      getSketchDataType() {
        return this._sketchDataType
      }

      /**
       * 设置草图样式<a id='setSketchStyle'></a>
       * @param {SketchStyle} sketchStyle
       */
      setSketchStyle(sketchStyle) {
        this._sketchStyle = sketchStyle
      }

      /**
       * 获取草图样式<a id='getSketchStyle'></a>
       * @returns {SketchStyle}
       */
      getSketchStyle() {
        return this._sketchStyle
      }

      /**
       * 清空全部草图
       * @private
       */
      clearAllSketch() {
        this._mapView._map.remove(this._layer)
        this._drawTool = null
        // 临时测试用
        this._mapView._map.layers.forEach((layer) => {
          if (layer.graphics) {
            this._mapView._map.remove(layer)
          }
        })
      }

      /**
       * 合并多个区几何<a id='union'></a>
       * @param {Polygon} polygons 被合并的区几何对象
       * @returns {Polygon} 合并后的几何对象
       */
      union(polygons) {
        const unionPolygon = Projection.project(
          this._sketchTopologyTool.unionPolygons(polygons),
          this._spatialReference
        )
        // 创建合并后的草图图形
        const polygonDrawTool = new SketchPolygonDrawTool({
          mapView: this._mapView,
          layer: this._layer,
          snappingOption: {
            showSelectBox: true,
            _hitTestMode: 1
          },
          _hitTestEvent: this._hitTestEvent,
          _sketchEditor: this
        })
        this._drawTool = polygonDrawTool
        // 注册hitTest事件移动图形
        // this._drawTool._hitTestDrawToolStack.push(polygonDrawTool)
        // setTimeout(() => {
        //   this._drawTool._hitTestEvent()
        // }, 200)
        this._drawTool._hitTestEvent(false)
        polygonDrawTool.addFeatureByGeometry(unionPolygon)

        // 响应草图被选中事件
        this._selectEvent()
        this._drawEvent()
        const polygon = polygonDrawTool._sketchStage.entityGraphic
        return polygon
      }

      /**
       * 分割草图对象或区几何对象<a id='split'></a>
       * @param {Polygon|SketchEditorNew} target 被分割的几何/草图对象
       * @param {Polyline} splitPolyline 线几何对象
       * @returns {Array<SketchEditorNew>} 合并后的几何对象
       */
      split(target, splitPolyline) {
        let polygon = null
        const self = this
        if (target instanceof Polygon) {
          polygon = target
        } else if (
          target instanceof SketchEditorNew &&
          target.drawTool._sketchDataType === SketchDataType.POLYGON
        ) {
          polygon = target._sketchStage.entityGraphic
        } else {
          Log.error('传入对象不符合要求，请检查')
          return
        }
        const splitPolygon = function (polygon, splitPolyline) {
          const sketchEditors = []
          const splitPolygons = self._sketchTopologyTool.splitPolygonByPolyline(
            polygon,
            splitPolyline
          )
          if (splitPolygons.length > 0) {
            // 创建分割后的草图
            splitPolygons.forEach((polygon) => {
              // if (i != 0) return
              const sketchEditor = new SketchEditorNew({
                mapView: self._mapView,
                layer: self._layer
              })
              const polygonDrawTool = new SketchPolygonDrawTool({
                mapView: self._mapView,
                layer: self._layer,
                snappingOption: {
                  showSelectBox: true,
                  _hitTestMode: 1
                },
                _hitTestEvent: self._hitTestEvent,
                _sketchEditor: self
              })
              sketchEditor._drawTool = polygonDrawTool
              polygonDrawTool.addFeatureByGeometry(polygon)
              // 注册hitTest事件移动图形
              polygonDrawTool._hitTestDrawToolStack.push(polygonDrawTool)
              sketchEditors.push(sketchEditor)
            })
          }
          return sketchEditors
        }
        return splitPolygon(polygon, splitPolyline)
      }

      /**
       * 撤销当前编辑操作<a id='undo'></a>
       * @returns {Geometry} 撤销后的几何对象
       */
      undo() {
        const stage = this._undoRedoManager.undo()
        if (stage) {
          this._updateByStage(stage)
          return stage.entityGraphic.geometry
        } else {
          return null
        }
      }

      /**
       * 恢复被撤销的草图<a id='redo'></a>
       * @returns {Geometry} 恢复后的几何对象
       */
      redo() {
        const stage = this._undoRedoManager.redo()
        if (stage) {
          this._updateByStage(stage)
          return stage.entityGraphic.geometry
        } else {
          return null
        }
      }

      /**
       * 草图是否可执行撤销操作<a id='canUndo'></a>
       * @returns {Boolean}
       */
      canUndo() {
        return this._undoRedoManager.canUndo()
      }

      /**
       * 草图是否可执行恢复操作<a id='canRedo'></a>
       * @returns {Boolean}
       */
      canRedo() {
        return this._undoRedoManager.canRedo()
      }

      /**
       * 根据sketchStage状态更新草图
       * @private
       * @param {SketchStage} stage 被合并的区几何对象
       */
      _updateByStage(stage) {
        this._drawTool._sketchStage.getAllFeatures().forEach((feature) => {
          this._drawTool._removeFeatureFromMap(feature)
        })
        this._drawTool._setSketchStage(stage)
        // this._mapView.sketchFeatures = [] // 临时
        const drawTools = []
        stage.getAllFeatures().forEach((feature) => {
          const drawTool = this._updateDrawToolByFeature(feature)
          if (drawTool) {
            drawTools.push(drawTool)
            drawTool._addFeaturesToMap(feature)
            this._drawTool._hitTestDrawToolStack.push(drawTool)
          }
        })
      }

      /**
       * 根据sketchStage状态更新草图
       * @private
       * @param {SketchStage} stage 被合并的区几何对象
       */
      getDrawToolByFeatureId(id) {
        let drawTool = null
        for (let i = 0; i < this._drawTool._drawTools.length; i++) {
          if (this._drawTool._drawTools[i]._sketchStage.entityGraphic.id === id) {
            drawTool = this._drawTool._drawTools[i]
            break
          }
        }
        return drawTool
      }

      /**
       * 根据feature图形更新所属草图绘制工具drawTool
       * @private
       * @param {Feature} feature
       */
      _updateDrawToolByFeature(feature) {
        let drawTool = null
        const drawTools = this._drawTool._drawTools
        for (let i = 0; i < drawTools.length; i++) {
          if (drawTools[i]._sketchStage.entityGraphic.id === feature.id) {
            drawTools[i]._sketchStage.entityGraphic = feature
            drawTool = drawTools[i]
            break
          }
        }
        return drawTool
      }

      /**
       * 响应草图被选中事件
       * @private
       */
      _selectEvent() {
        this._drawTool.on('selected', (event) => {
          const selectedSketch = event.isSelected ? this : null
          this.fire(
            'selected',
            { selectedSketch, isSelected: event.isSelected },
            this
          )
        })
      }

      /**
       * 响应草图绘制完毕事件
       * @private
       */
      _drawEvent() {
        this._drawTool.on('drawn', (event) => {
          this.fire('drawn', { geometry: event.geometry }, this)
        })
        this._drawTool.on('drawn-vertex', (event) => {
          this.fire('drawn-vertex', { geometry: event.geometry }, this)
        })
      }

      /**
       * 获取草图几何对象<a id='getGeometry'></a>
       * @returns {Geometry}
       */
      getGeometry() {
        return this._sketchStage.entityGraphic.geometry
      }
    }
    Zondy.SketchEditorNew = SketchEditorNew
    export default SketchEditorNew