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
