    import { Evented, ViewEventType } from '../../base'
    import { defaultValue, getGUID } from '../../util'
    import { SpatialReference } from '../../base/geometry'
    import SketchStage from './SketchStage'
    /**
     * 草图基础绘图工具类
     * @class SketchBaseDrawTool
     * @moduleEX SketchEditorModule
     * @param {Object} options 构造参数
     * @param {MapView|SceneView}  [options.view]  地图视图对象
     * @param {GraphicsLayer}  [options.layer]  草图图层管对象
     * @param {SketchStyle}  [options.sketchStyle]  草图符号
     */

    class SketchBaseDrawTool extends Evented {
      constructor(options) {
        super()
        this._id = defaultValue(options.id, getGUID())
        /**
         * 地图视图
         * @member {MapView|SceneView} SketchBaseDrawTool.prototype.view
         */
        this.view = defaultValue(options.view, null)
        /**
         * 草图图层
         * @member {GraphicsLayer} SketchBaseDrawTool.prototype.layer
         */
        this.layer = defaultValue(options.layer, undefined)
        /**
         * 草图绘图形集合
         * @member {SketchStage} SketchBaseDrawTool.prototype.sketchStage
         */
        this.sketchStage = new SketchStage()
        /**
         * 草图符号
         * @member {SketchStyle} SketchBaseDrawTool.prototype.sketchStyle
         */
        this.sketchStyle = defaultValue(options.sketchStyle, undefined)
        // 草图编辑状态
        // 0:没有画图或编辑状态
        // 1:图形编辑
        // 2:节点编辑
        // 3:画图中
        this._editMode = 0
        // 当前空间参考系
        this._spatialReference = options.view.crs
          ? new SpatialReference(options.view.crs.code)
          : new SpatialReference('EPSG:4326')
        // 草图绘制事件处理集
        this._drawEventHandlers = []
        // 草图拾取事件处理集
        this._hitTestEventHandlers = []
        // 草图类型
        this._sketchDataType = null
        // 所属父级绘图工具
        this._parent = defaultValue(options._parent, undefined)
        /**
         * 草图撤销回退管理器
         * @member {String} SketchBaseDrawTool.prototype.undoRedoManager
         */
        this.undoRedoManager = defaultValue(options.undoRedoManager, undefined)

        /**
         * 草图选中编辑配置项
         * @member {Object} SketchBaseDrawTool.prototype.editOption
         * @param {Object} [editOption.showSelectBox = {}] 捕捉时是否展示选中编辑框
         * @param {Object} [editOption.showSelectVertex = {}] 捕捉时是否展示顶点可编辑图形
         * @param {Object} [editOption._hitTestMode = {}] 捕捉拾取方式，0：click鼠标拾取。1：pointerDown鼠标按下拾取
         */
        const editOption = {
          showSelectBox: true,
          showSelectVertex: false,
          canEditFeature: true,
          canEditVertex: true,
          _hitTestMode: 0
        }
        this.editOption = defaultValue(options.editOption, editOption)

        // todo sketchFeatures需要删掉
        this.view.sketchFeatures = this.view.sketchFeatures
          ? this.view.sketchFeatures
          : []
        this._drawTools = []
        this._hitTestDrawToolStack = []
        this._clampToGround = true
        // this._hight = 1000

        this.snapAndReferGeometries = []

        // 所属sketchEditor对象
        this._sketchEditor = defaultValue(options._sketchEditor, undefined)
        if (this._sketchEditor) {
          this.sketchSnappingTool = this._sketchEditor._sketchSnappingTool
          this.snapAndReferGeometries = this._sketchEditor.snapAndReferGeometries
        }
      }

      /**
       * 开始绘制草图
       */
      start() {
        this.stop()
        this.drawFeature()
      }

      /**
       * 停止绘制草图
       */
      stop() {
        if (this._editMode === 3 || this._editMode === 0) {
          this._stopDraw()
        } else if (this._editMode === 1 || this._editMode === 2) {
          this._stopHitTest()
        } else {
          this._stopDraw()
          this._stopHitTest()
        }
      }

      /**
       * 停止所有鼠标事件
       * @private
       */
      _stopAll() {
        this._stopDraw()
        this._stopHitTest()
      }

      /**
       * 停止所有鼠标绘制相关事件
       * @private
       */
      _stopDraw() {
        if (this._drawEventHandlers) {
          this._drawEventHandlers.forEach((handler) => {
            this.view.off(ViewEventType.immediateClick, handler)
            this.view.off(ViewEventType.pointerUp, handler)
            this.view.off(ViewEventType.pointerMove, handler)
            this.view.off(ViewEventType.pointerDown, handler)
            this.view.off(ViewEventType.doubleClick, handler)
            this.view.off(ViewEventType.drag, handler)
          })
          this._drawEventHandlers = []
        }
      }

      /**
       * 停止所有拾取相关事件
       * @private
       */
      _stopHitTest() {
        if (this._hitTestEventHandlers && this._hitTestILayer) {
          this._hitTestEventHandlers.forEach((handler) => {
            this._hitTestILayer.off(ViewEventType.click, handler)
            this.view.off(ViewEventType.pointerUp, handler)
            this.view.off(ViewEventType.pointerMove, handler)
            this.view.off(ViewEventType.pointerDown, handler)
            // 确定hitTest事件是click,还是immediateClick
            this.view.off(ViewEventType.click, handler)
          })
          this._hitTestEventHandlers = null
        }
      }

      /**
       * 设置草图样式
       * @param {SketchStyle} sketchStyle
       */
      setSketchStyle(sketchStyle) {
        this.sketchStyle = sketchStyle
      }

      /**
       * @description 删除某编辑状态的辅助图形
       * @private
       * @param {Number} editMode 编辑状态码
       */
      _clearEditGraphics(editMode) {
        const clearSelectFeature = () => {
          const features = this.sketchStage.selectBoxGraphics.concat(
            this.sketchStage.selectBoxVertexGraphics
          )
          features.forEach((feature) => {
            this._removeFeatureFromMap(feature)
          })
          this._otherDrawTools = []
          this.sketchStage.selectBoxGraphics = []
          this.sketchStage.selectBoxVertexGraphics = []
        }
        const clearSelectFeatureVertex = () => {
          let target = null
          if (this._parent) {
            target = this._parent
          } else {
            target = this
          }
          const features = target.sketchStage.vertexGraphics.concat(
            target.sketchStage.midVertexGraphics
          )
          features.forEach((feature) => {
            target._removeFeatureFromMap(feature)
          })

          target._otherDrawTools = []
          target.sketchStage.vertexGraphics = []
          target.sketchStage.midVertexGraphics = []
        }
        if (editMode === 1) {
          clearSelectFeature()
        } else if (editMode === 2) {
          clearSelectFeatureVertex()
        } else {
          clearSelectFeature()
          clearSelectFeatureVertex()
        }
      }

      /**
       * 判断feature是否是绘制图形中
       * @private
       * @param {SketchStyle} sketchStyle
       */
      _isDrawToolFeature(feature) {
        const id = feature.id
        let isDrawTool = false
        if (this.sketchStage.entityGraphic.id === id) {
          isDrawTool = true
          this._editMode = 1
        }
        this.sketchStage.vertexGraphics.forEach((item) => {
          if (item.id === id) {
            isDrawTool = true
            this._editMode = 2
          }
        })
        this.sketchStage.midVertexGraphics.forEach((item) => {
          if (item.id === id) {
            isDrawTool = true
            this._editMode = 2
          }
        })
        if (!isDrawTool) {
          this._editMode = 0
        }
        return isDrawTool
      }

      _getDrawToolByFeature(feature) {
        const id = feature.id
        let drawTool = null
        if (this.sketchStage.entityGraphic.id === id) {
          drawTool = this.sketchStage.entityGraphic
        }
        return drawTool.length > 0 ? drawTool[0] : null
      }

      /**
       * 将图形渲染到地图中
       * @private
       * */
      _addFeaturesToMap(feature) {
        if (this.layer) {
          // 判断this._clampToGround，三维中贴地设置
          this.layer.add(feature)
        }
      }

      _removeFeatureFromMap(feature) {
        if (this.layer) {
          this.layer.remove(feature)
        }
      }

      /**
       * 草图事件分发
       * @private
       * @param {String} type 事件类型
       * @param {object} data 传递数据
       */
      _dispatchEvent(type, data, propagate) {
        // 父级草图更新
        if (this._parent) {
          this._parent.fire(type, data, propagate)
        }
        return this
      }

      /**
       * 更新feature
       * @param {Point} point 待更新的位置
       * @param {Feature} feature 被更新的feature
       */
      updateFeature(point, feature) {
        const id = feature.id
        if (this.sketchStage.entityGraphic.id === id) {
          this.sketchStage.entityGraphic.coordinates = point.coordinates
          this.sketchStage.entityGraphic.geometry = point
          feature = this.sketchStage.entityGraphic
        }
      }

      updateSketchStage(sketchStage) {
        this.sketchStage = sketchStage
        const features = this.sketchStage.getAllFeatures()
        this.view.sketchFeatures = features
        this._addFeaturesToMap()
      }

      /**
       * @description 清除草图工具
       */
      removeDrawTool() {
        this.sketchStage.getAllFeatures().forEach((feature) => {
          this._removeFeatureFromMap(feature)
        })
        this._stopAll()
      }

      /**
       * @description 清除实体图形
       * @private
       */
      removeEntityGraphic() {
        this._removeFeatureFromMap(this.sketchStage.entityGraphic)
        this.sketchStage.entityGraphic = null
      }

      /**
       * @description 清除顶点图形
       * @private
       */
      removeVertexGraphics() {
        this.sketchStage.vertexGraphics.forEach((feature) => {
          this._removeFeatureFromMap(feature)
        })
        this.sketchStage.vertexGraphics = []
      }

      /**
       * 当前草图图形中插入新的顶点
       * @param {Point} point 新增/插入顶点
       * @param {Number} index 新增/新增点的序号
       */
      addVertex(point, index) {}

      /**
       * 更新当前草图图形的某个顶点
       * @param {Point} point 新的顶点
       * @param {Number} index 需更新的顶点的序号
       */
      updateVertex(point, index) {}

      /**
       * 移除草图图形的某个顶点
       * @param {Number} index 需更新的顶点的序号
       */
      removeVertex(point, index) {}

      /**
       * @description 删除选中的顶点
       * @private
       */
      deleteSelectedVertex() {}

      // 临时用于更新图形
      removeAddGraphic(newFeature) {
        // test
        // 更新sketchFeatures
        this.view.sketchFeatures = this.view.sketchFeatures
          ? this.view.sketchFeatures
          : []
        let haveFeature = false
        this.view.sketchFeatures.forEach((feature) => {
          if (feature.id === newFeature.id) {
            feature = newFeature
            haveFeature = true
          }
        })
        if (!haveFeature) {
          this.view.sketchFeatures.push(newFeature)
        }
        this._addFeaturesToMap(true)
      }

      updateAllFeature(point) {
        this.sketchStage.entityGraphic.coordinates = point.coordinates
        this.sketchStage.entityGraphic.geometry = point
        this.view.sketchFeatures.forEach((item) => {
          if (item.id === this.sketchStage.entityGraphic.id) {
            item = this.sketchStage.entityGraphic
          }
        })
        this._addFeaturesToMap()
      }

      getDistanceByPixel(pixel) {
        if (this.view.getResolution) {
          return this.view.getResolution() * pixel
        } else {
          return 1000
        }
      }

      getPanCoordinates(coordinates, deltaX, deltaY) {
        let newCoordinates = []
        if (coordinates.length > 2) {
          newCoordinates = [
            coordinates[0] + deltaX,
            coordinates[1] + deltaY,
            coordinates[2]
          ]
        } else {
          newCoordinates = [coordinates[0] + deltaX, coordinates[1] + deltaY]
        }
        return newCoordinates
      }

      getScaleCoordinates(
        coordinates,
        direction,
        extent,
        startPoint,
        movePoint,
        oriCoordinates
      ) {
        const getXY = function (xy, extent, direction, oriCoordinate) {
          let scaleX1 = 1
          let scaleY1 = 1
          let newX = Number(xy[0].toString())
          let newY = Number(xy[1].toString())
          const sCoordinate = startPoint.coordinates
          const mCoordinate = movePoint.coordinates
          oriCoordinate = oriCoordinate || []
          if (direction === 'ne') {
            scaleX1 =
              (mCoordinate[0] - extent.xmin) / (sCoordinate[0] - extent.xmin)
            newX = ([oriCoordinate[0]] - extent.xmin) * scaleX1 + extent.xmin

            scaleY1 =
              (mCoordinate[1] - extent.ymin) / (sCoordinate[1] - extent.ymin)
            newY = (oriCoordinate[1] - extent.ymin) * scaleY1 + extent.ymin
          }
          if (direction === 'se') {
            scaleX1 =
              (mCoordinate[0] - extent.xmin) / (sCoordinate[0] - extent.xmin)
            newX = ([oriCoordinate[0]] - extent.xmin) * scaleX1 + extent.xmin

            scaleY1 =
              (mCoordinate[1] - extent.ymax) / (sCoordinate[1] - extent.ymax)
            newY = (oriCoordinate[1] - extent.ymax) * scaleY1 + extent.ymax
          }
          if (direction === 'sw') {
            scaleX1 =
              (mCoordinate[0] - extent.xmax) / (sCoordinate[0] - extent.xmax)
            newX = ([oriCoordinate[0]] - extent.xmax) * scaleX1 + extent.xmax

            scaleY1 =
              (mCoordinate[1] - extent.ymax) / (sCoordinate[1] - extent.ymax)
            newY = (oriCoordinate[1] - extent.ymax) * scaleY1 + extent.ymax
          }
          if (direction === 'nw') {
            scaleX1 =
              (mCoordinate[0] - extent.xmax) / (sCoordinate[0] - extent.xmax)
            newX = ([oriCoordinate[0]] - extent.xmax) * scaleX1 + extent.xmax

            scaleY1 =
              (mCoordinate[1] - extent.ymin) / (sCoordinate[1] - extent.ymin)
            newY = (oriCoordinate[1] - extent.ymin) * scaleY1 + extent.ymin
          }
          return [newX, newY]
        }
        const newCoordinates = []
        oriCoordinates = oriCoordinates || []
        coordinates.forEach((coordinate, i) => {
          const result = getXY(coordinate, extent, direction, oriCoordinates[i])
          if (coordinate[2] !== undefined) {
            result[2] = coordinate[2]
          }
          newCoordinates.push(result)
        })
        return newCoordinates
      }

      getMidScaleCoordinates(
        coordinates,
        direction,
        extent,
        startPoint,
        movePoint,
        oriCoordinates
      ) {
        const getXY = function (xy, extent, direction, oriCoordinate) {
          let scaleX1 = 1
          let scaleY1 = 1
          let newX = xy[0]
          let newY = xy[1]
          const sCoordinate = startPoint.coordinates
          const mCoordinate = movePoint.coordinates
          oriCoordinate = oriCoordinate || []
          if (direction === 'e') {
            // 判断是否超过边缘坐标
            scaleX1 =
              (mCoordinate[0] - extent.xmin) / (sCoordinate[0] - extent.xmin)
            newX = ([oriCoordinate[0]] - extent.xmin) * scaleX1 + extent.xmin
          }
          if (direction === 's') {
            scaleY1 =
              (mCoordinate[1] - extent.ymax) / (sCoordinate[1] - extent.ymax)
            newY = (oriCoordinate[1] - extent.ymax) * scaleY1 + extent.ymax
          }
          if (direction === 'w') {
            scaleX1 =
              (mCoordinate[0] - extent.xmax) / (sCoordinate[0] - extent.xmax)
            newX = ([oriCoordinate[0]] - extent.xmax) * scaleX1 + extent.xmax
          }
          if (direction === 'n') {
            scaleY1 =
              (mCoordinate[1] - extent.ymin) / (sCoordinate[1] - extent.ymin)
            newY = (oriCoordinate[1] - extent.ymin) * scaleY1 + extent.ymin
          }
          return [newX, newY]
        }
        const newCoordinates = []
        oriCoordinates = oriCoordinates || []
        coordinates.forEach((coordinate, i) => {
          const result = getXY(coordinate, extent, direction, oriCoordinates[i])
          if (coordinate[2]) {
            result[2] = coordinate[2]
          }
          newCoordinates.push(result)
        })
        return newCoordinates
      }

      getCenterScaleCoordinates(
        coordinates,
        direction,
        extent,
        startPoint,
        movePoint,
        oriCoordinates
      ) {
        const getXY = function (xy, extent, direction, oriCoordinate) {
          let scaleX1 = 1
          let scaleY1 = 1
          let newX = xy[0]
          let newY = xy[1]
          const sCoordinate = startPoint.coordinates
          const mCoordinate = movePoint.coordinates
          oriCoordinate = oriCoordinate || []
          if (direction === 'e') {
            // 判断是否超过边缘坐标
            scaleX1 =
              (mCoordinate[0] - extent.xmin) / (sCoordinate[0] - extent.xmin)
            newX = ([oriCoordinate[0]] - extent.xmin) * scaleX1 + extent.xmin
          }
          if (direction === 's') {
            scaleY1 =
              (mCoordinate[1] - extent.ymax) / (sCoordinate[1] - extent.ymax)
            newY = (oriCoordinate[1] - extent.ymax) * scaleY1 + extent.ymax
          }
          if (direction === 'w') {
            scaleX1 =
              (mCoordinate[0] - extent.xmax) / (sCoordinate[0] - extent.xmax)
            newX = ([oriCoordinate[0]] - extent.xmax) * scaleX1 + extent.xmax
          }
          if (direction === 'n') {
            scaleY1 =
              (mCoordinate[1] - extent.ymin) / (sCoordinate[1] - extent.ymin)
            newY = (oriCoordinate[1] - extent.ymin) * scaleY1 + extent.ymin
          }
          return [newX, newY]
        }
        const newCoordinates = []
        oriCoordinates = oriCoordinates || []
        coordinates.forEach((coordinate, i) => {
          const result = getXY(coordinate, extent, direction, oriCoordinates[i])
          if (coordinate[2]) {
            result[2] = coordinate[2]
          }
          newCoordinates.push(result)
        })
        return newCoordinates
      }

      addByFeature(feature) {
        this.sketchStage.entityGraphic = feature
        this.view.sketchFeatures.push(feature)
        // // 更新图层图形
        // this._addFeaturesToMap()
      }

      _setSketchStage(stage) {
        this.sketchStage = stage
      }

      // 临时方法
      _removeFromSketchFeatures(removedFeatures) {
        this.view.sketchFeatures.forEach((feature, i) => {
          if (removedFeatures.filter((item) => item.id === feature.id).length > 0) {
            delete this.view.sketchFeatures[i]
          }
        })
        this.view.sketchFeatures = this.view.sketchFeatures.filter(
          (item) => item !== undefined
        )
      }

      _getDrawToolByFeatureId(id) {
        const drawTool = this._drawTools.find(
          (drawTool) =>
            drawTool.sketchStage.entityGraphic &&
            drawTool.sketchStage.entityGraphic.id === id
        )
        return drawTool
      }

      // 清除编辑辅助图形
      _removeEditGraphics() {
        const removedFeatures = this.sketchStage.selectBoxGraphics
          .concat(this.sketchStage.selectBoxVertexGraphics)
          .concat(this.sketchStage.vertexGraphics)
          .concat(this.sketchStage.midVertexGraphics)
        removedFeatures.forEach((feature) => {
          this._removeFeatureFromMap(feature)
        })
        this.sketchStage.selectBoxGraphics = []
        this.sketchStage.selectBoxVertexGraphics = []
        this.sketchStage.vertexGraphics = []
        this.sketchStage.midVertexGraphics = []
      }
    }
    export default SketchBaseDrawTool