import {
  Feature,
  createSimpleFillSymbolCanvas,
  GeometryType,
  MultiLineString,
  Log,
  SimpleFillSymbol
} from '@mapgis/webclient-common'
import { BaseGraphic, SimpleLineGraphic } from './index'

const {
  Cartesian2,
  ColorGeometryInstanceAttribute,
  GeometryInstance,
  Primitive,
  Material,
  PolygonGeometry,
  PolygonHierarchy,
  MaterialAppearance
} = Cesium

/**
 * SimpleFillGraphic
 * @private
 * @param option - {Object} 构造参数
 * @param {Feature} [option.feature = null] 构造Cesium几何的要素对象
 * */
class SimpleFillGraphic extends BaseGraphic {
  constructor(options) {
    super(options)
  }

  /**
   * 重载基类的checkSymbol方法
   * @public
   * @return {Boolean} 是否为支持的符号
   * */
  checkSymbol() {
    if (!(this._feature.symbol instanceof SimpleFillSymbol)) {
      Log.info('要素的符号类型不是SimpleFillSymbol！')
      return false
    }
    return true
  }

  /**
   * 重载基类的_createPrimitive方法
   * @private
   * */
  _createPrimitive() {
    // 不存在style，则不绘制几何
    if (!this._feature.symbol.style) return
    this._createAllPolygonPrimitive()
    this._createAllOutlinePrimitive()
  }

  /**
   * 创建并返回所有的cesium的多边形Primitive对象
   * @private
   * @return {Array<Primitive>} Cesium的多边形Primitive对象数组
   * */
  _createAllPolygonPrimitive() {
    // 获取几何
    const _geometry = this._feature.geometry
    // 获取cesium几何坐标
    const _positions = this._getPositions()
    // 获取所有的polygon的primitive数组
    switch (_geometry.type) {
      case GeometryType.polygon:
      case GeometryType.extent:
      case GeometryType.circle:
        const _primitive = this._createPolygonPrimitive(_positions)
        _primitive.id = this._feature.id
        this._primitives.push(_primitive)
        break
      case GeometryType.multiPolygon:
        for (let i = 0; i < _positions.length; i++) {
          const _primitive = this._createPolygonPrimitive(_positions[i])
          _primitive.id = this._feature.id
          this._primitives.push(_primitive)
        }
        break
      default:
        break
    }
  }

  /**
   * 创建并返回一个cesium的多边形Primitive对象
   * @private
   * @param {Array<Cartesian3>} positions 线坐标数组
   * @return {Primitive} cesium的多边形Primitive对象
   * */
  _createPolygonPrimitive(positions) {
    // 获取symbol
    const _symbol = this._feature.symbol
    // 获取color
    const _color = this._getCesiumColor(_symbol.color)
    // 构造cesium几何对象
    // 构造多边形内圈
    const holes = []
    for (let i = 1; i < positions.length; i++) {
      holes.push(new PolygonHierarchy(positions[i]))
    }
    // 获取拉伸高度
    let _extrudedHeight = undefined
    const _geometry = this._feature.geometry
    if (_geometry.type === GeometryType.extent) {
      _extrudedHeight = _geometry.zmax
    }
    const _polygonGeometry = new PolygonGeometry({
      // 多边形几何结构
      polygonHierarchy: new PolygonHierarchy(positions[0], holes),
      // 额外抬升高度高度
      height: 0,
      // 拉伸高度
      extrudedHeight: _extrudedHeight,
      // 是否使用单个点的高度
      perPositionHeight: true
    })

    // 构造多边形外观
    const _appearance = new MaterialAppearance({
      // 几何材质
      material: this._createPolygonMaterial(),
      // 是否透明
      translucent: false,
      // 是否参与深度检测
      renderState: {
        depthTest: {
          enabled: true
        }
      }
    })
    // 构造cesium的多边形primitive对象
    let _polygonPrimitive = new Primitive({
      // 几何实例
      geometryInstances: new GeometryInstance({
        geometry: _polygonGeometry,
        attributes: {
          color: ColorGeometryInstanceAttribute.fromColor(_color)
        }
      }),
      // 几何外观
      appearance: _appearance,
      asynchronous: false
    })

    _polygonPrimitive = this._primitivesCollection.add(_polygonPrimitive)

    return _polygonPrimitive
  }

  /**
   * 创建并返回所有的cesium的线Primitive对象数组
   * @private
   * @return {Array<Primitive>} Cesium的线Primitive对象数组
   * */
  _createAllOutlinePrimitive() {
    // 获取几何
    const _geometry = this._feature.geometry
    // 构造所有外边线
    let _primitives = []
    switch (_geometry.type) {
      case GeometryType.polygon:
        _primitives = this._createPolygonOutlineGraphic(_geometry.coordinates)
        break
      case GeometryType.extent:
        const _positions = this._getPositions()
        _primitives = this._createPolygonOutlineGraphic(_positions)
        break
      case GeometryType.circle:
        _primitives = this._createPolygonOutlineGraphic([])
        break
      case GeometryType.multiPolygon:
        for (let i = 0; i < _geometry.coordinates.length; i++) {
          const _lines = this._createPolygonOutlineGraphic(
            _geometry.coordinates[i]
          )
          _primitives = _primitives.concat(_lines)
        }
        break
      default:
        Log.info('要素为未支持的几何类型')
        break
    }
    this._primitives = this._primitives.concat(_primitives)
  }

  /**
   * 创建并返回一个SimpleLineGraphic对象
   * @private
   * @param {Array<Cartesian3>} positions 线坐标数组
   * @return {SimpleLineGraphic} SimpleLineGraphic对象
   * */
  _createPolygonOutlineGraphic(positions) {
    // 获取symbol
    const _symbol = this._feature.symbol
    // 构造所有外边线
    let _positions = []
    const _geometry = this._feature.geometry
    if (_geometry.type === GeometryType.extent) {
      _positions.push([])
      _positions[0].push([_geometry.xmin, _geometry.ymin, _geometry.zmin])
      _positions[0].push([_geometry.xmax, _geometry.ymin, _geometry.zmin])
      _positions[0].push([_geometry.xmax, _geometry.ymax, _geometry.zmin])
      _positions[0].push([_geometry.xmin, _geometry.ymax, _geometry.zmin])
      _positions[0].push([_geometry.xmin, _geometry.ymin, _geometry.zmin])
      _positions[0].push([
        _positions[0][0][0] +
          (_positions[0][1][0] - _positions[0][0][0]) / 10000,
        _positions[0][0][1] +
          (_positions[0][1][1] - _positions[0][0][1]) / 10000,
        _positions[0][0][2] +
          (_positions[0][1][2] - _positions[0][0][2]) / 10000
      ])
    } else if (_geometry.type === GeometryType.circle) {
      const _circleGeometry = _geometry.toPolygon()
      _positions = _circleGeometry.coordinates
    } else {
      for (let i = 0; i < positions.length; i++) {
        _positions.push([])
        for (let j = 0; j < positions[i].length; j++) {
          _positions[i].push(positions[i][j])
        }
        _positions[i].push([
          _positions[i][0][0] +
            (_positions[i][1][0] - _positions[i][0][0]) / 10000,
          _positions[i][0][1] +
            (_positions[i][1][1] - _positions[i][0][1]) / 10000,
          _positions[i][0][2] +
            (_positions[i][1][2] - _positions[i][0][2]) / 10000
        ])
      }
    }

    // 重新构造一个线几何
    const _lineString = new MultiLineString({
      coordinates: _positions
    })
    // 构造一个线要素
    const _outLineFeature = new Feature({
      geometry: _lineString,
      symbol: _symbol.outline
    })
    const _outline = new SimpleLineGraphic({
      feature: _outLineFeature,
      layerOpacity: this._layerOpacity,
      primitivesCollection: this._primitivesCollection
    })
    return _outline._primitives
  }

  /**
   * 根据要素创建多边形材质
   * @private
   * @return {Cesium.Material} 一个创建好的多边形材质
   * */
  _createPolygonMaterial() {
    const _symbol = this._feature.symbol
    let _material
    switch (_symbol.style) {
      case 'backward-diagonal':
      case 'cross':
      case 'diagonal-cross':
      case 'forward-diagonal':
      case 'horizontal':
      case 'vertical':
        // 没有构造canvas，则构造并保存canvas
        if (!this._canvas) {
          this._canvas = createSimpleFillSymbolCanvas(_symbol)
        }
        // canvas已经构造过了
        else {
          // 初始化时，会调用一次此方法，需要个this._symbol赋值
          if (!this._symbol) {
            this._symbol = this._feature.symbol
          }
          // 判断新旧两个symbol是否相等
          const _isSymbolEqual = this._symbolEquals(_symbol, this._symbol)
          // 不相等，则重新构造canvas
          if (!_isSymbolEqual) {
            this._canvas = createSimpleFillSymbolCanvas(_symbol)
            this._symbol = _symbol
          }
        }
        _material = Material.fromType('TextImage', {
          image: this._canvas,
          repeat: new Cartesian2(4.0, 4.0),
          alpha: this._layerOpacity
        })
        break
      default:
        const _color = this._getCesiumColor(_symbol.color)
        // 设置图层透明度
        _color.alpha *= this._layerOpacity
        _material = Material.fromType('Color', {
          color: _color
        })
        break
    }
    return _material
  }

  /**
   * 判断新旧两个符号的属性是否相等
   * @private
   * @param {Symbol} symbol1 第一个符号
   * @param {Symbol} symbol2 第二个符号
   * @return {Boolean} 符号是否相等
   * */
  _symbolEquals(symbol1, symbol2) {
    if (
      symbol1.style !== symbol2.style ||
      symbol1.color.red !== symbol2.color.red ||
      symbol1.color.green !== symbol2.color.green ||
      symbol1.color.blue !== symbol2.color.blue ||
      symbol1.color.alpha !== symbol2.color.alpha ||
      symbol1.outline.width !== symbol2.outline.width ||
      symbol1.outline.color.red !== symbol2.outline.color.red ||
      symbol1.outline.color.green !== symbol2.outline.color.green ||
      symbol1.outline.color.blue !== symbol2.outline.color.blue ||
      symbol1.outline.color.alpha !== symbol2.outline.color.alpha
    ) {
      return false
    }

    return true
  }
}

export default SimpleFillGraphic
