    import { Feature, GeometryType, Log } from '@mapgis/webclient-common'

    const { defaultValue, createGuid, Color, Cartesian3 } = Cesium

    /**
     * 三维的几何对象基类
     * @private
     * @param option - {Object} 构造参数
     * @param {Feature} [option.feature = null] 构造Cesium几何的要素对象
     * */
    class BaseGraphic {
      constructor(options) {
        options = defaultValue(options, {})

        // 获取要素对象
        this._feature = options.feature
        if (!this._feature) {
          Log.error('feature不能为空！')
        }
        this._feature = Feature.fromJSON(this._feature.toJSON())
        // 补全Z坐标
        this._addZCoordinate()

        // 检查符号类型
        if (!this.checkSymbol()) {
          return
        }

        // 几何id
        this.id = defaultValue(this._feature.id, createGuid())
        // 是否显示几何
        this.show = defaultValue(this._feature.visible, true)
        // 图层透明度
        this._layerOpacity = defaultValue(options.layerOpacity, 1)
        // 线和区的Ceiusm几何管理容器
        this._primitivesCollection = defaultValue(
          options.primitivesCollection,
          undefined
        )
        // 点的Ceiusm几何管理容器
        this._pointsCollection = defaultValue(options.pointsCollection, undefined)
        // 广告牌的Ceiusm几何管理容器
        this._billboardsCollection = defaultValue(
          options.billboardsCollection,
          undefined
        )
        // 文字的Ceiusm几何管理容器
        this._labelsCollection = defaultValue(options.labelsCollection, undefined)
        // 自身的Cesium点对象数组
        this._points = []
        // 自身的Cesium广告牌对象数组
        this._billboards = []
        // 自身的Cesium文字对象数组
        this._labels = []
        // 自身的Cesium线和区对象数组
        this._primitives = []
        // 私有的canvas对象
        this._canvas = undefined
        // 私有的symbol对象
        this._symbol = this._feature.symbol
        // 创建一个Cesium的PrimitiveCollection对象
        this._createPrimitive()
      }

      /**
       * Graphic的更新方法
       * @public
       * @param {Feature} feature Common的Feature对象
       * */
      update(feature) {
        // 更新内部的要素对象
        this._feature = feature
        // 补全Z坐标
        this._addZCoordinate()
        // 是否显示几何
        this.show = this._feature.visible
        // 删除内部的primitive对象
        this._removePrimitives()
        // 重新创建primitive对象
        this._createPrimitive()
      }

      /**
       * 销毁对象
       * @public
       * */
      destroy() {
        this._removePrimitives()
        this.id = undefined
        this.show = undefined
        this._layerOpacity = undefined
        this._feature = undefined
        this._canvas = undefined
        this._symbol = undefined
        this._points = undefined
        this._billboards = undefined
        this._labels = undefined
        this._primitives = undefined
        this._primitivesCollection = undefined
        this._pointsCollection = undefined
        this._billboardsCollection = undefined
        this._labelsCollection = undefined
      }

      /**
       * 检查是否是支持的符号类型，由子类来实现
       * @public
       * @return {Boolean} 是否为支持的符号
       * */
      checkSymbol() {
        return true
      }

      setVisible(visible) {
        for (let i = 0; i < this._points.length; i++) {
          this._points[i].show = visible
        }
        for (let i = 0; i < this._labels.length; i++) {
          this._labels[i].show = visible
        }
        for (let i = 0; i < this._billboards.length; i++) {
          this._billboards[i].show = visible
        }
        for (let i = 0; i < this._primitives.length; i++) {
          this._primitives[i].show = visible
        }
      }

      /**
       * 通过common的color对象获取一个Cesium的color对象
       * @private
       * @param {Color} color common的color对象
       * @return {Cesium.Color} 一个Cesium的color对象
       * */
      _getCesiumColor(color) {
        const _color = new Color(
          color.red / 255,
          color.green / 255,
          color.blue / 255,
          color.alpha
        )
        return _color
      }

      /**
       * 通过feature构造一个Cesium几何的外观对象，子类要重载该方法
       * @private
       * @return {Appearance} Cesium几何的外观对象
       * */
      _createAppearance() {}

      /**
       * 通过feature构造一个Cesium的几何对象，可能是一个组合对象，子类要重载该方法
       * @private
       * */
      _createPrimitive() {}

      /**
       * 从feature中获取Cesium的点坐标数组
       * @private
       * @return {Array<Cartesian3>} Cesium的点坐标数组
       * */
      _getPositions() {
        // 获取几何坐标
        const _geometry = this._feature.geometry
        // 获取点坐标
        const _positions = []
        switch (_geometry.type) {
          case GeometryType.point:
            _positions.push(
              Cartesian3.fromDegrees(
                _geometry.coordinates[0],
                _geometry.coordinates[1],
                _geometry.coordinates[2]
              )
            )
            break
          case GeometryType.multiPoint:
            for (let i = 0; i < _geometry.coordinates.length; i++) {
              _positions.push(
                Cartesian3.fromDegrees(
                  _geometry.coordinates[i][0],
                  _geometry.coordinates[i][1],
                  _geometry.coordinates[i][2]
                )
              )
            }
            break
          case GeometryType.lineString:
            for (let i = 0; i < _geometry.coordinates.length; i++) {
              // 转为笛卡尔坐标
              _positions.push(
                Cartesian3.fromDegrees(
                  _geometry.coordinates[i][0],
                  _geometry.coordinates[i][1],
                  _geometry.coordinates[i][2]
                )
              )
            }
            break
          case GeometryType.multiLineString:
            for (let i = 0; i < _geometry.coordinates.length; i++) {
              _positions.push([])
              for (let j = 0; j < _geometry.coordinates[i].length; j++) {
                // 转为笛卡尔坐标
                _positions[i].push(
                  Cartesian3.fromDegrees(
                    _geometry.coordinates[i][j][0],
                    _geometry.coordinates[i][j][1],
                    _geometry.coordinates[i][j][2]
                  )
                )
              }
            }
            break
          case GeometryType.polygon:
            for (let i = 0; i < _geometry.coordinates.length; i++) {
              _positions.push([])
              for (let j = 0; j < _geometry.coordinates[i].length; j++) {
                // 转为笛卡尔坐标
                _positions[i].push(
                  Cartesian3.fromDegrees(
                    _geometry.coordinates[i][j][0],
                    _geometry.coordinates[i][j][1],
                    _geometry.coordinates[i][j][2]
                  )
                )
              }
            }
            break
          case GeometryType.multiPolygon:
            for (let i = 0; i < _geometry.coordinates.length; i++) {
              _positions.push([])
              for (let j = 0; j < _geometry.coordinates[i].length; j++) {
                _positions[i].push([])
                for (let k = 0; k < _geometry.coordinates[i][j].length; k++) {
                  _positions[i][j].push(
                    Cartesian3.fromDegrees(
                      _geometry.coordinates[i][j][k][0],
                      _geometry.coordinates[i][j][k][1],
                      _geometry.coordinates[i][j][k][2]
                    )
                  )
                }
              }
            }
            break
          case GeometryType.extent:
            _positions.push([])
            _positions[0].push(
              Cartesian3.fromDegrees(_geometry.xmin, _geometry.ymin, _geometry.zmin)
            )
            _positions[0].push(
              Cartesian3.fromDegrees(_geometry.xmax, _geometry.ymin, _geometry.zmin)
            )
            _positions[0].push(
              Cartesian3.fromDegrees(_geometry.xmax, _geometry.ymax, _geometry.zmin)
            )
            _positions[0].push(
              Cartesian3.fromDegrees(_geometry.xmin, _geometry.ymax, _geometry.zmin)
            )
            _positions[0].push(
              Cartesian3.fromDegrees(_geometry.xmin, _geometry.ymin, _geometry.zmin)
            )
            break
          case GeometryType.circle:
            const _circleGeometry = _geometry.toPolygon()
            for (let i = 0; i < _circleGeometry.coordinates.length; i++) {
              _positions.push([])
              for (let j = 0; j < _circleGeometry.coordinates[i].length; j++) {
                // 转为笛卡尔坐标
                _positions[i].push(
                  Cartesian3.fromDegrees(
                    _circleGeometry.coordinates[i][j][0],
                    _circleGeometry.coordinates[i][j][1],
                    _circleGeometry.coordinates[i][j][2]
                  )
                )
              }
            }
            break
          default:
            break
        }

        if (_positions.length === 0) {
          Log.error('顶点数组为空，无法正常创建图形!')
        }

        return _positions
      }

      /**
       * 补全Z坐标
       * @private
       * */
      _addZCoordinate() {
        const _geometry = this._feature.geometry
        if (!_geometry.hasZ) {
          switch (_geometry.type) {
            case GeometryType.point:
              _geometry.coordinates.push(0)
              break
            case GeometryType.multiPoint:
            case GeometryType.lineString:
              for (let i = 0; i < _geometry.coordinates.length; i++) {
                _geometry.coordinates[i].push(0)
              }
              break
            case GeometryType.multiLineString:
            case GeometryType.polygon:
              for (let i = 0; i < _geometry.coordinates.length; i++) {
                for (let j = 0; j < _geometry.coordinates[i].length; j++) {
                  _geometry.coordinates[i][j].push(0)
                }
              }
              break
            case GeometryType.multiPolygon:
              for (let i = 0; i < _geometry.coordinates.length; i++) {
                for (let j = 0; j < _geometry.coordinates[i].length; j++) {
                  for (let k = 0; k < _geometry.coordinates[i][j].length; k++) {
                    _geometry.coordinates[i][j][k].push(0)
                  }
                }
              }
              break
            case GeometryType.extent:
              _geometry.zmin = 0
              _geometry.zmax = 0
              break
            case GeometryType.circle:
              _geometry.center.push(0)
              break
            default:
              break
          }
        }
      }

      /**
       * 移除内部的primitive对象
       * @private
       * */
      _removePrimitives() {
        // 移除点类型的primitive对象
        for (let i = 0; i < this._points.length; i++) {
          this._pointsCollection.remove(this._points[i])
        }
        this._points = []
        // 移除广告牌类型的primitive对象
        for (let i = 0; i < this._billboards.length; i++) {
          this._billboardsCollection.remove(this._billboards[i])
        }
        this._billboards = []
        // 移除文字类型的primitive对象
        for (let i = 0; i < this._labels.length; i++) {
          this._labelsCollection.remove(this._labels[i])
        }
        this._labels = []
        // 移除线和区类型的primitive对象
        for (let i = 0; i < this._primitives.length; i++) {
          this._primitivesCollection.remove(this._primitives[i])
        }
        this._primitives = []
      }
    }

    export default BaseGraphic