import {
  Zondy,
  defaultValue,
  BaseView,
  ShadowMode,
  Point,
  Extent,
  LayerType,
  showLayerByScale,
  Config,
  isNull,
  ViewEventType,
  SceneMode,
  IGSSceneLayer,
  IGSSceneSubLayer
} from '@mapgis/webclient-common'
import { SceneViewUtil } from './utils'
import { getLayerView } from '../document'

/**
 * 视图类
 * @class SceneView
 * @extends Evented
 * @moduleEX ViewModule
 * @fires BaseView#鼠标点击事件
 * @fires BaseView#鼠标双击事件
 * @fires BaseView#鼠标按下事件
 * @fires BaseView#鼠标抬起事件
 * @fires BaseView#鼠标右键点击事件
 * @fires BaseView#鼠标移动事件
 * @fires BaseView#地图视图改变事件
 * @param {Object} options 构造参数
 * @param {Map}  [options.Map]  图层管理器
 * @param {String} [options.viewId] 图层容器ID
 * @param {Boolean} [options.enableAnimation = true] 视点跳转或漫游时，是否启用动画
 * @param {Boolean | Cesium.SkyBox} [options.skyBox] 天空盒设置，可传入天空盒对象或者布尔值，当该值为false时，不显示天空盒
 * @param {Boolean | Cesium.SkyAtmosphere} [options.skyAtmosphere] 大气设置，可传入大气设置对象或者布尔值，当该值为false时，不显示大气层
 * @param {SceneMode} [options.sceneMode = SceneMode.scene3D] 场景模式
 * @param {Boolean} [options.enableShadows = false] 是否启用阴影效果
 * @param {ShadowMode} [options.terrainShadowMode = ShadowMode.receive] 地形阴影模式
 * @param {Boolean} [options.enableGeocoderWidget = false] 启用地理编码器控件
 * @param {Boolean} [options.enableHomeButtonWidget = false] 启用Home按钮控件
 * @param {Boolean} [options.enableSceneModePickerWidget = false] 启用场景控制器控件
 * @param {Boolean} [options.enableBaseLayerPickerWidget = false] 启用基础图层选择器控件
 * @param {Boolean} [options.enableNavigationHelpButtonWidget = false] 启用导航帮助按钮控件
 * @param {Boolean} [options.enableAnimationWidget = false] 启用动画控件
 * @param {Boolean} [options.enableTimeLineWidget = false] 启用时间轴控件
 * @param {Boolean} [options.enableFullScreenButtonWidget = false] 启用全屏按钮控件
 * @param {Boolean} [options.enableVRButtonWidget = false] 启用VR按钮控件
 * @param {Boolean} [options.enableFPSWidget = false] 启用FPS控件
 * @param {Point} [options.center = new Point({coordinates:[0,0]})] 地图视图中心点
 * @param {Number} [options.scale = undefined] 地图视图比例尺
 * @param {Number} [options.zoom = undefined] 地图视图层级
 * @param {Number} [options.minZoom = 0] 最小层级
 * @param {Number} [options.maxZoom = 19] 最大层级
 *
 * @summary <h5>支持如下方法：</h5>
 * <a href='#flyTo'>[1、视点跳转]</a><br/>
 * <a href='#toJSON'>[2、导出场景视图的配置文件]</a><br/>
 * <a href='#fromJSON'>[3、通过一个配置生成一个场景视图对象]</a><br/>
 * <a href='#toMap'>[4、屏幕像素坐标点转地理坐标点]</a><br/>
 * <a href='#toScreen'>[5、地理坐标点转屏幕像素坐标点]</a><br/>
 * <a href='#getSize'>[6、获取当前视图容器的宽高]</a><br/>
 * <a href='#getCenter'>[7、获取当前视图中心点]</a><br/>
 * <a href='#getExtent'>[8、获取当前视图的地理范围]</a><br/>
 * <a href='#getZoom'>[9、获取当前层级]</a><br/>
 * <a href='#getScale'>[10、获取当前比例尺]</a><br/>
 * <a href='#getZoomByScale'>[11、地图比例尺对应的层级]</a><br/>
 * <a href='#getScaleByZoom'>[12、地图层级对应的比例尺]</a><br/>
 * [13、注册事件]{@link Evented#on}<br/>
 * [14、移除事件]{@link Evented#off}<br/>
 * <a href='#getInnerLayer'>[15、获取实际的M3DSet对象]</a><br/>
 *
 * @example <caption><h7>初始化三维视图对象</h7></caption>
 * // ES5引入方式
 * const { Map, SceneView } = Zondy
 * // ES6引入方式
 * import { Map, SceneView } from "@mapgis/webclient-cesium-plugin"
 * // 初始化图层管理容器
 * const map = new Map();
 * // 初始化地图视图对象
 * const sceneView = new SceneView({
 *   // 视图id
 *   viewId: "mapgis-3d-viewer",
 *   // 图层管理容器
 *   map: map
 * });
 */
class SceneView extends BaseView {
  constructor(options) {
    super(options)
    // eslint-disable-next-line no-param-reassign
    options = defaultValue(options, {})
    /**
     * 视点跳转或漫游时，是否启用动画
     * @readonly
     * @member {Boolean} SceneView.prototype.enableAnimation
     */
    this.enableAnimation = defaultValue(options.enableAnimation, true)
    /**
     * 天空盒设置，可传入天空盒对象或者布尔值，当该值为false时，不显示天空盒
     * @readonly
     * @member {Boolean | Cesium.SkyBox} SceneView.prototype.skyBox
     */
    this.skyBox = defaultValue(options.skyBox, true)
    /**
     * 大气设置，可传入大气设置对象或者布尔值，当该值为false时，不显示大气层
     * @readonly
     * @member {Boolean | Cesium.SkyAtmosphere} SceneView.prototype.skyAtmosphere
     */
    this.skyAtmosphere = defaultValue(options.skyAtmosphere, true)
    /**
     * 场景模式
     * @readonly
     * @member {SceneMode} SceneView.prototype.sceneMode
     */
    this.sceneMode = defaultValue(options.sceneMode, SceneMode.scene3d)
    /**
     * 是否启用阴影效果
     * @readonly
     * @member {Boolean} SceneView.prototype.enableShadows
     */
    this.enableShadows = defaultValue(options.enableShadows, false)
    /**
     * 地形阴影模式
     * @readonly
     * @member {ShadowMode} SceneView.prototype.terrainShadowMode
     */
    this.terrainShadowMode = defaultValue(
      options.terrainShadowMode,
      ShadowMode.receive
    )
    /**
     * 启用地理编码器控件
     * @member {Boolean} SceneView.prototype.enableGeocoderWidget
     */
    this._enableGeocoderWidget = defaultValue(
      options.enableGeocoderWidget,
      false
    )
    /**
     * 启用Home按钮控件
     * @member {Boolean} SceneView.prototype.enableHomeButtonWidget
     */
    this._enableHomeButtonWidget = defaultValue(
      options.enableHomeButtonWidget,
      false
    )
    /**
     * 启用场景控制器控件
     * @member {Boolean} SceneView.prototype.enableSceneModePickerWidget
     */
    this._enableSceneModePickerWidget = defaultValue(
      options.enableSceneModePickerWidget,
      false
    )
    /**
     * 启用基础图层选择器控件
     * @member {Boolean} SceneView.prototype.enableBaseLayerPickerWidget
     */
    this._enableBaseLayerPickerWidget = defaultValue(
      options.enableBaseLayerPickerWidget,
      false
    )
    /**
     * 启用导航帮助按钮控件
     * @member {Boolean} SceneView.prototype.enableNavigationHelpButtonWidget
     */
    this._enableNavigationHelpButtonWidget = defaultValue(
      options.enableNavigationHelpButtonWidget,
      false
    )
    /**
     * 启用动画控件
     * @member {Boolean} SceneView.prototype.enableAnimationWidget
     */
    this._enableAnimationWidget = defaultValue(
      options.enableAnimationWidget,
      false
    )
    /**
     * 启用时间轴控件
     * @member {Boolean} SceneView.prototype.enableTimeLineWidget
     */
    this._enableTimeLineWidget = defaultValue(
      options.enableTimeLineWidget,
      false
    )
    /**
     * 启用全屏按钮控件
     * @member {Boolean} SceneView.prototype.enableFullScreenButtonWidget
     */
    this._enableFullScreenButtonWidget = defaultValue(
      options.enableFullScreenButtonWidget,
      false
    )
    /**
     * 启用VR按钮控件
     * @member {Boolean} SceneView.prototype.enableVRButtonWidget
     */
    this._enableVRButtonWidget = defaultValue(
      options.enableVRButtonWidget,
      false
    )
    /**
     * 启用FPS控件
     * @member {Boolean} SceneView.prototype.enableFPSWidget
     */
    this._enableFPSWidget = defaultValue(options.enableFPSWidget, false)
    /**
     * 地图视图中心点
     * @member {Number} MapView.prototype.center
     */
    // 统一center的类型
    this._center = defaultValue(
      options.center,
      new Point({ coordinates: [0, 0] })
    )
    if (
      this._center &&
      Array.isArray(this._center) &&
      this._center.length > 1
    ) {
      this._center = new Point({
        coordinates: [this._center[0], this._center[1], this._center[2]]
      })
    }
    /**
     * 地图视图比例尺
     * @member {Number} MapView.prototype.scale
     */
    this._scale = defaultValue(options.scale, undefined)
    /**
     * 地图视图层级
     * @member {Number} MapView.prototype.zoom
     */
    this._zoom = defaultValue(options.zoom, undefined)
    /**
     * 地图视图层级
     * @member {Number} MapView.prototype.minZoom
     */
    this.minZoom = defaultValue(options.minZoom, undefined)
    /**
     * 地图视图层级
     * @member {Number} MapView.prototype.maxZoom
     */
    this.maxZoom = defaultValue(options.maxZoom, undefined)
    /**
     * 地图视图宽度
     * @readonly
     * @member {Number} MapView.prototype.width
     */
    this.width = undefined
    /**
     * 地图视图高度
     * @readonly
     * @member {Number} MapView.prototype.height
     */
    this.height = undefined
    // 初始化地图引擎
    const viewOptions = {
      shouldAnimate: this.enableAnimation,
      sceneMode: this.sceneMode,
      shadows: this.enableShadows,
      terrainShadows: this.terrainShadowMode,
      geocoder: this._enableGeocoderWidget,
      homeButton: this._enableHomeButtonWidget,
      sceneModePicker: this._enableSceneModePickerWidget,
      baseLayerPicker: this._enableBaseLayerPickerWidget,
      navigationHelpButton: this._enableNavigationHelpButtonWidget,
      animation: this._enableAnimationWidget,
      timeline: this._enableTimeLineWidget,
      fullscreenButton: this._enableFullScreenButtonWidget,
      vrButton: this._enableVRButtonWidget
    }
    if (this.skyBox instanceof Object) {
      viewOptions.skyBox = this.skyBox
    }
    if (this.skyAtmosphere instanceof Object) {
      viewOptions.skyAtmosphere = this.skyAtmosphere
    }
    this._innerView = new Cesium.Viewer(this._viewId, viewOptions)
    if (this._enableFPSWidget) {
      this._innerView.scene.debugShowFramesPerSecond = true
    }
    this._layersMap = new Cesium.HashMap()
    Cesium.Config(Config)
    // 初始化比例尺
    this._initScale()
    // 获取视图大小
    this._initSize()
    // 获取视图层级
    this._initZoom()
    // 初始化地图事件
    this._initViewEvent()
    // map上是否绑定Cesium
    this._map._initCesiumView = true
  }

  _initViewEvent() {
    const self = this
    // 注册左键点击事件
    this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
      // 发送点击事件
      self.fire(ViewEventType.click, SceneViewUtil.getMouseEvent(event, self))
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

    // 注册左键按下事件
    this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
      // 发送左键按下事件
      self.fire(
        ViewEventType.mouseDown,
        SceneViewUtil.getMouseEvent(event, self)
      )
    }, Cesium.ScreenSpaceEventType.LEFT_DOWN)

    // 注册左键抬起事件
    this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
      // 发送左键抬起事件
      self.fire(ViewEventType.mouseUp, SceneViewUtil.getMouseEvent(event, self))
    }, Cesium.ScreenSpaceEventType.LEFT_UP)

    // 注册左键双击事件
    this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
      // 发送左键双击事件
      self.fire(
        ViewEventType.doubleClick,
        SceneViewUtil.getMouseEvent(event, self)
      )
    }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)

    // 注册右键点击事件
    this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
      // 发送点击事件
      self.fire(ViewEventType.click, SceneViewUtil.getMouseEvent(event, self))
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)

    // 注册右键按下事件
    this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
      // 发送按下事件
      self.fire(
        ViewEventType.mouseDown,
        SceneViewUtil.getMouseEvent(event, self)
      )
      // 发送右键点击事件
      self.fire(
        ViewEventType.rightClickDown,
        SceneViewUtil.getMouseEvent(event, self)
      )
    }, Cesium.ScreenSpaceEventType.RIGHT_DOWN)

    // 注册右键抬起事件
    this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
      // 发送抬起事件
      self.fire(ViewEventType.mouseUp, SceneViewUtil.getMouseEvent(event, self))
    }, Cesium.ScreenSpaceEventType.RIGHT_UP)

    // 注册鼠标移动事件
    this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
      // 发送鼠标移动事件
      self.fire(
        ViewEventType.mouseMove,
        SceneViewUtil.getMouseMoveEvent(event, self)
      )
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

    // 注册鼠标滚轮事件
    this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
      self._map.layers.forEach(function (layer) {
        switch (layer.type) {
          case LayerType.igsFeature:
          case LayerType.graphics:
            showLayerByScale(self, layer)
            break
          default:
            break
        }
      })
      // 发送鼠标滚轮事件
      self.fire(ViewEventType.wheel, {})
    }, Cesium.ScreenSpaceEventType.WHEEL)

    // 注册监控地图视野改变事件
    this._innerView.camera.changed.addEventListener(function (event) {
      self._mouseMoveHandler()
      self.fire(
        ViewEventType.viewChange,
        SceneViewUtil.getViewChangeEvent(event, self)
      )
    })
  }

  /**
   * <a id='flyTo'></a>
   * @description 视点跳转
   * @param options 跳转参数
   * @param {Array}  [options.center]  相机要跳转的中心点，单位度，[精度，纬度，高程]
   * @param {Number}  [options.duration = 2]  相机飞行到终点时的持续时间，单位秒
   * @param {Extent}  [options.extent]  相机要飞行的某个范围
   * @param {Object}  [options.orientation]  相机飞行到终点时的视角朝向，包含偏航角、俯仰角和翻滚角
   * @param {Function}  [options.complete]  相机飞行到终点时触发的函数
   * @param {Function}  [options.cancel]  相机取消飞行时触发的函数
   * @param {Object}  [options.endTransform]  相机飞行到终点时的矩阵
   * @param {Number}  [options.maximumHeight]  相机飞行的最大高度
   * @param {Number}  [options.pitchAdjustHeight]  如果相机的飞行高度高于该值，则调整飞行过程中的俯仰角使相机视角向下看，并将地球保持在相机视窗中
   * @param {Number}  [options.flyOverLongitude]  强制让相机绕着地球飞行指定经度，直到到达终点位置
   * @param {Number}  [options.flyOverLongitudeWeight]
   * @example <caption><h7>按范围跳转</h7></caption>
   * // ES5引入方式
   * const { Map, SceneView } = Zondy
   * const { IGSMapImageLayer } = Zondy.Layer
   * const { LayerEventType } = Zondy.Enum
   * const { Extent } = Zondy.Geometry
   * // ES6引入方式
   * import { Map, SceneView, IGSMapImageLayer, LayerEventType, Extent } from "@mapgis/webclient-cesium-plugin"
   * // 初始化图层管理容器
   * const map = new Map();
   * // 初始化地图视图对象
   * const sceneView = new SceneView({
   *   // 视图id
   *   viewId: "mapgis-3d-viewer",
   *   // 图层管理容器
   *   map: map
   * });
   * // 添加一个地图图层
   * const igsMapImageLayer = new IGSMapImageLayer({
   *   url: 'http://webclient.smaryun.com:8089/igs/rest/services/Map/Hubei4326/MapServer'
   * });
   * map.add(igsMapImageLayer);
   * // 图层加载完毕
   * igsMapImageLayer.on(LayerEventType.layerViewCreated, function (result) {
   *   console.log("加载完毕:", result.layer)
   *   // 视点跳转
   *   sceneView.flyTo({
   *     extent: new Extent({
   *       xmin: 108.34341,
   *       ymin: 29.01258222765238,
   *       xmax: 116.15093956121316,
   *       ymax: 33.29320177370206
   *     })
   *   })
   * })
   * @example <caption><h7>跳转中心点</h7></caption>
   * // ES5引入方式
   * const { Map, SceneView } = Zondy
   * const { IGSMapImageLayer } = Zondy.Layer
   * const { LayerEventType } = Zondy.Enum
   * // ES6引入方式
   * import { Map, SceneView, IGSMapImageLayer, LayerEventType } from "@mapgis/webclient-cesium-plugin"
   * // 初始化图层管理容器
   * const map = new Map();
   * // 初始化地图视图对象
   * const sceneView = new SceneView({
   *   // 视图id
   *   viewId: "mapgis-3d-viewer",
   *   // 图层管理容器
   *   map: map
   * });
   * // 添加一个地图图层
   * const igsMapImageLayer = new IGSMapImageLayer({
   *   url: 'http://webclient.smaryun.com:8089/igs/rest/services/Map/Hubei4326/MapServer'
   * });
   * map.add(igsMapImageLayer);
   * // 图层加载完毕
   * igsMapImageLayer.on(LayerEventType.layerViewCreated, function (result) {
   *   console.log("加载完毕:", result.layer)
   *   // 视点跳转
   *   sceneView.flyTo({
   *     center: [113, 30, 1000000]
   *   })
   * })
   */
  flyTo(options) {
    options = defaultValue(options, {})
    const duration = defaultValue(options.duration, 2)
    const orientation = defaultValue(options.orientation, undefined)
    const complete = defaultValue(options.complete, undefined)
    const cancel = defaultValue(options.cancel, undefined)
    const endTransform = defaultValue(options.endTransform, undefined)
    const maximumHeight = defaultValue(options.maximumHeight, undefined)
    const flyOverLongitude = defaultValue(options.flyOverLongitude, undefined)
    const flyOverLongitudeWeight = defaultValue(
      options.flyOverLongitudeWeight,
      undefined
    )
    const convert = defaultValue(options.convert, undefined)
    const easingFunction = defaultValue(options.easingFunction, undefined)

    // 获取center
    const center = this._getFlyToCenter(options)

    // 获取extent
    const extent = this._getFlyToExtent(options)

    // 中心点跳转
    if (!isNull(center)) {
      this._innerView.camera.flyTo({
        destination: Cesium.Cartesian3.fromDegrees(
          center.coordinates[0],
          center.coordinates[1],
          center.coordinates[2]
        ),
        duration,
        orientation,
        complete,
        cancel,
        endTransform,
        maximumHeight,
        flyOverLongitude,
        flyOverLongitudeWeight,
        convert,
        easingFunction
      })
    }
    // 范围跳转
    else if (!isNull(extent)) {
      this._innerView.camera.flyTo({
        destination: Cesium.Rectangle.fromDegrees(
          extent.xmin,
          extent.ymin,
          extent.xmax,
          extent.ymax
        ),
        duration,
        orientation,
        complete,
        cancel,
        endTransform,
        maximumHeight,
        flyOverLongitude,
        flyOverLongitudeWeight,
        convert,
        easingFunction
      })
    }
  }

  /**
   * @description 创建图层视图
   * @private
   * @param {Layer} layer 图层
   * @param {LayerEvent} event 添加事件
   * @return {LayerView| null}
   */
  _createLayerView(layer) {
    // 获取原型
    const layerView = getLayerView(this, layer) || null
    return layerView
  }

  /**
   * <a id='toJSON'></a>
   * 导出场景视图的配置文件
   * @return {Object} 导出的配置文件
   * */
  toJSON() {
    return {
      viewId: this._viewId,
      enableAnimation: this.enableAnimation,
      skyBox: this.skyBox,
      skyAtmosphere: this.skyAtmosphere,
      sceneMode: this.sceneMode,
      enableShadows: this.enableShadows,
      terrainShadowMode: this.terrainShadowMode,
      enableGeocoderWidget: this.enableGeocoderWidget,
      enableHomeButtonWidget: this.enableHomeButtonWidget,
      enableSceneModePickerWidget: this.enableSceneModePickerWidget,
      enableNavigationHelpButtonWidget: this.enableNavigationHelpButtonWidget,
      enableAnimationWidget: this.enableAnimationWidget,
      enableTimeLineWidget: this.enableTimeLineWidget,
      enableFullScreenButtonWidget: this.enableFullScreenButtonWidget,
      enableFPSWidget: this.enableFPSWidget,
      map: this._map ? this._map.toJSON() : []
    }
  }

  /**
   * <a id='toMap'></a>
   * 屏幕像素坐标点转地理坐标点
   * @param {Object} screenPoint 屏幕像素坐标点，例如{ x: 900, y: 500 }
   * @return {Point} 地理坐标点
   * @example <caption><h5>屏幕像素坐标点转地理坐标示例</h5></caption>
   * // ES6引入方式
   * import { SceneView } from "@mapgis/webclient-cesium-plugin"
   * import { Map, Point } from "@mapgis/webclient-common"
   * // 初始化图层管理容器
   * const map = new Map();
   * // 初始化地图视图对象
   * const sceneView = new SceneView({
   *  // 视图id
   *  viewId: "mapgis-3d-viewer",
   *  // 图层管理容器
   *  map: map,
   *})
   * const screenPoint = { x: 900, y: 500 }
   * sceneView.toMap(screenPoint)
   * */
  toMap(screenPoint) {
    // 屏幕坐标转为世界坐标
    const cartesian = this._innerView.scene.globe.pick(
      this._innerView.camera.getPickRay(screenPoint),
      this._innerView.scene
    )
    let geoPoint = null
    if (cartesian && !isNull(cartesian)) {
      // 世界坐标转换为弧度
      const ellipsoid = this._innerView.scene.globe.ellipsoid
      const cartographic = ellipsoid.cartesianToCartographic(cartesian)
      // 弧度转换为经纬度
      const longitude = Cesium.Math.toDegrees(cartographic.longitude)
      const latitude = Cesium.Math.toDegrees(cartographic.latitude)
      const height = cartographic.height < 0 ? 0 : cartographic.height
      geoPoint = new Point({ coordinates: [longitude, latitude, height] })
    } else {
      geoPoint = new Point({ coordinates: [0, 0, 0] })
    }
    return geoPoint
  }

  /**
   * <a id='toScreen'></a>
   * 地理坐标点转屏幕像素坐标点
   * @param {Point} point 地理坐标点
   * @return {Object} 屏幕像素坐标点
   * @example <caption><h5>地理坐标点转屏幕像素坐标示例</h5></caption>
   * // ES6引入方式
   * import { MapView } from "@mapgis/webclient-leaflet-plugin"
   * import { Map, Point, Extent } from "@mapgis/webclient-common"
   * // 初始化图层管理容器
   * const map = new Map();
   * // 初始化地图视图对象
   * const mapView = new MapView({
   *   // 视图id
   *   viewId: "mapgis-2d-viewer",
   *   // 图层管理容器
   *   map: map
   * });
   * const geoPoint = new Point({ coordinates: [123, 23, 0] })
   * sceneView.toScreen(geoPoint)
   * */
  toScreen(point) {
    const cartesian3 = Cesium.Cartesian3.fromDegrees(
      point.coordinates[0],
      point.coordinates[1],
      point.coordinates[2]
    )
    const screenPoint = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
      this._innerView.scene,
      cartesian3
    )
    return screenPoint
  }

  /**
   * <a id='getSize'></a>
   * 获取当前视图容器的宽高，单位像素<a id='getSize'></a>
   * @return {Object} 当前视图容器的宽高对象
   * */
  getSize() {
    return {
      x: this._innerView._container.clientWidth,
      y: this._innerView._container.clientHeight
    }
  }

  /**
   * <a id='getCenter'></a>
   * 获取当前视图中心点
   * @return {Object} 当前视图容器的宽高对象
   * */
  getCenter() {
    const position = Cesium.Cartographic.fromCartesian(
      this._innerView.camera.position
    )
    const longitude = Cesium.Math.toDegrees(position.longitude)
    const latitude = Cesium.Math.toDegrees(position.latitude)
    const height = position.height
    const centerPoint = new Point({
      coordinates: [longitude, latitude, height]
    })
    this._center = centerPoint
    return centerPoint
  }

  /**
   * <a id='setCenter'></a>
   * 设置缩视野中心<a id='setCenter'></a>
   * @private
   * @param {Point} value 视图中心
   * */
  setCenter(value) {
    if (!this._innerView || !this._center) return
    let isValid = false
    const altitude = this._center.coordinates[2]
    if (Array.isArray(value) && value.length > 1) {
      this._center = new Point({
        coordinates: [value[0], value[1], altitude]
      })
      isValid = true
    } else if (value instanceof Point) {
      this._center = new Point({
        coordinates: [value.coordinates[0], value.coordinates[1], altitude]
      })
      isValid = true
    }
    if (isValid) {
      this.flyTo({ center: this._center })
    }
  }

  /**
   * <a id='getExtent'></a>
   * 获取当前视图的地理范围<a id='getExtent'></a>
   * @return {Extent}  获取当前视图的地理范围
   * */
  getExtent() {
    if (!this._innerView) return
    const rectangle = this._innerView.camera.computeViewRectangle()
    const extent = new Extent({
      xmin: (rectangle.west / Math.PI) * 180,
      ymin: (rectangle.south / Math.PI) * 180,
      xmax: (rectangle.east / Math.PI) * 180,
      ymax: (rectangle.north / Math.PI) * 180
    })
    this.extent = extent
    return extent
  }

  /**
   * <a id='getInnerLayer'></a>
   * @public
   * 重载基类方法，支持传入IGSSceneLayer或IGSSceneSubLayer，并返回相应的对象
   * @param { IGSSceneLayer | IGSSceneSubLayer} layer 场景图层或场景图的子图层
   * @return { Array<MapGISM3DSet> | MapGISM3DSet | undefined } MapGISM3DSet数组或MapGISM3DSet对象或空对象
   * */
  getInnerLayer(layer) {
    if (layer instanceof IGSSceneLayer) {
      return super.getInnerLayer(layer)
    } else if (layer instanceof IGSSceneSubLayer) {
      const _innerSceneLayer = super.getInnerLayer(layer.layer)
      for (let i = 0; i < _innerSceneLayer.length; i++) {
        if (_innerSceneLayer[i]._layerIndex === layer.layerIndex) {
          return _innerSceneLayer[i]
        }
      }
    }
    return undefined
  }

  /**
   * @description mouse move事件处理器
   * @private
   * */
  _mouseMoveHandler() {
    // 更新地图视野中心点坐标
    this.getCenter()
    // 更新地图视野范围
    // this.getExtent()
    // 更新地图比例尺
    this.getZoom()
    // 更新地图比例尺
    this.getScale()
  }

  /**
   * @description 初始化获取视图尺寸大小
   * @private
   */
  _initSize() {
    const canvas = this._innerView.canvas
    this.width = canvas.width
    this.height = canvas.height
  }

  /**
   * @description 初始化设置地图视图比例尺
   * @private
   */
  _initScale() {
    if (this.scale && this._center) {
      this.zoom = this.getZoomByScale(this.scale)
      const altitude = this._getAltitudeByZoom(this.zoom)
      const lng = this._center.coordinates[0]
      const lat = this._center.coordinates[1]
      this._center = new Point({ coordinates: [lng, lat, altitude] })
      this.flyTo({ center: this._center })
    }
  }

  /**
   * @description 初始化设置地图视图层级
   * @private
   */
  _initZoom() {
    if (!this.scale && this._zoom && this._center) {
      this._zoom = this._getZoomByAltitude(this._center.coordinates[2])
      // 根据zoom计算scale
      this.scale = this.getScaleByZoom(this._zoom)
      const altitude = this._getAltitudeByZoom(this._zoom)
      const lng = this._center.coordinates[0]
      const lat = this._center.coordinates[1]
      this._center = new Point({ coordinates: [lng, lat, altitude] })
      this.flyTo({ center: this._center })
    }
    if (this.maxZoom) {
      const minAltitude = this._getAltitudeByZoom(this.maxZoom)
      this._innerView.scene.screenSpaceCameraController.minimumZoomDistance =
        minAltitude
    }
    if (this.minZoom) {
      const maxAltitude = this._getAltitudeByZoom(this.minZoom)
      this._innerView.scene.screenSpaceCameraController.maximumZoomDistance =
        maxAltitude
    }
  }

  /**
   * <a id='getZoom'></a>
   * @description 获取当前层级
   * @return {Number}  层级
   * */
  getZoom() {
    const zoom = this._getZoomByAltitude(this._center.coordinates[2])
    this._zoom = zoom
  }

  /**
   * <a id='setZoom'></a>
   * 设置缩放级数
   * @private
   * @param {Number} value 视图层级
   * */
  setZoom(value) {
    if (this._innerView && this._zoom && this._center) {
      this._zoom = value
      const altitude = this._getAltitudeByZoom(this._zoom)
      const lng = this._center.coordinates[0]
      const lat = this._center.coordinates[1]
      const center = new Point({ coordinates: [lng, lat, altitude] })
      this.flyTo({ center })
    }
  }

  /**
   * <a id='getScale'></a>
   * @description 获取当前比例尺
   * @return {Number}  比例尺 实际10000米:地图1米
   * */
  getScale() {
    this._scale = this.getScaleByZoom(this._zoom)
  }

  /**
   * <a id='setScale'></a>
   * 设置当前比例尺
   * @private
   * @param {Number} value 比例尺 实际10000米:地图1米
   * */
  setScale(value) {
    if (this._innerView && this._scale && this._center) {
      this._scale = value
      const zoom = this.getZoomByScale(value)
      const altitude = this._getAltitudeByZoom(zoom)
      const lng = this._center.coordinates[0]
      const lat = this._center.coordinates[1]
      const center = new Point({ coordinates: [lng, lat, altitude] })
      this.flyTo({ center })
    }
  }

  /**
   * <a id='getZoomByScale'></a>
   * @description 地图比例尺对应的层级
   * @private
   * @param {Number}  scale 地图比例尺
   * @return {Number}  层级
   */
  getZoomByScale(scale) {
    const ppi = 96
    const initialResolution = (20037508.3427892 * 2) / 256
    const resolution = scale / (ppi / 0.0254)
    const zoom = Math.round(Math.log2(initialResolution / resolution))
    return zoom
  }

  /**
   * <a id='getScaleByZoom'></a>
   * @description 地图层级对应的比例尺
   * @private
   * @param {Number}  zoom 地图层级
   * @return {Number}  比例尺
   */
  getScaleByZoom(zoom) {
    const ppi = 96
    const initialResolution = (20037508.3427892 * 2) / 256
    const resolution = initialResolution / Math.pow(2, zoom)
    // const scale = resolution * ppi * 0.0254
    const scale = (ppi / 0.0254) * resolution
    return scale
  }

  /**
   * @description 根据高度获取当前层级
   * @private
   * @return {Number}  层级
   * */
  _getZoomByAltitude(altitude) {
    const A = 40487.57
    const B = 0.00007096758
    const C = 91610.74
    const D = -40467.74
    const zoom = Math.round(D + (A - D) / (1 + Math.pow(altitude / C, B)))
    return zoom
  }

  /**
   * @description 根据当前层级获取高度
   * @private
   * @return {Number}  高度
   * */
  _getAltitudeByZoom(zoom) {
    const A = 40487.57
    const B = 0.00007096758
    const C = 91610.74
    const D = -40467.74
    const altitude = C * Math.pow((A - D) / (zoom - D) - 1, 1 / B)
    return altitude
  }
}

/**
 * <a id='fromJSON'></a>
 * 通过一个配置生成一个场景视图对象
 * @param {Object} json 场景视图配置
 * @return {SceneView}
 * */
SceneView.fromJSON = function (json) {
  json = defaultValue(json, {})

  return new SceneView(json)
}

Object.defineProperties(SceneView.prototype, {
  enableGeocoderWidget: {
    get() {
      return this._enableGeocoderWidget
    },
    set(value) {
      this._enableGeocoderWidget = value
      document.querySelector('.cesium-viewer-geocoderContainer').style.display =
        value ? 'inline-block' : 'none'
    }
  },
  enableHomeButtonWidget: {
    get() {
      return this._enableHomeButtonWidget
    },
    set(value) {
      this._enableHomeButtonWidget = value
      document.querySelector('.cesium-home-button').style.display = value
        ? 'inline-block'
        : 'none'
    }
  },
  enableSceneModePickerWidget: {
    get() {
      return this._enableSceneModePickerWidget
    },
    set(value) {
      this._enableSceneModePickerWidget = value
      document.querySelector('.cesium-sceneModePicker-wrapper').style.display =
        value ? 'inline-block' : 'none'
    }
  },
  enableBaseLayerPickerWidget: {
    get() {
      return this._enableBaseLayerPickerWidget
    },
    set(value) {
      this._enableBaseLayerPickerWidget = value
      document.querySelector('.cesium-baseLayerPicker-selected').style.display =
        value ? 'inline-block' : 'none'
    }
  },
  enableNavigationHelpButtonWidget: {
    get() {
      return this._enableNavigationHelpButtonWidget
    },
    set(value) {
      this._enableNavigationHelpButtonWidget = value
      document.querySelector(
        '.cesium-navigationHelpButton-wrapper'
      ).style.display = value ? 'inline-block' : 'none'
    }
  },
  enableAnimationWidget: {
    get() {
      return this._enableAnimationWidget
    },
    set(value) {
      this._enableAnimationWidget = value
      document.querySelector(
        '.cesium-viewer-animationContainer'
      ).style.display = value ? 'inline-block' : 'none'
    }
  },
  enableTimeLineWidget: {
    get() {
      return this._enableTimeLineWidget
    },
    set(value) {
      this._enableTimeLineWidget = value
      document.querySelector('.cesium-viewer-timelineContainer').style.display =
        value ? 'inline-block' : 'none'
    }
  },
  enableFullScreenButtonWidget: {
    get() {
      return this._enableFullScreenButtonWidget
    },
    set(value) {
      this._enableFullScreenButtonWidget = value
      document.querySelector(
        '.cesium-viewer-fullscreenContainer'
      ).style.display = value ? 'inline-block' : 'none'
    }
  },
  enableVRButtonWidget: {
    get() {
      return this._enableVRButtonWidget
    },
    set(value) {
      this._enableVRButtonWidget = value
      document.querySelector('.cesium-vrButton').style.display = value
        ? 'inline-block'
        : 'none'
    }
  },
  enableFPSWidget: {
    get() {
      return this._enableFPSWidget
    },
    set(value) {
      this._enableFPSWidget = value
      this._innerView.scene.debugShowFramesPerSecond = value
    }
  },
  scale: {
    get() {
      return this._scale
    },
    set(value) {
      this.setScale(value)
    }
  },
  zoom: {
    get() {
      return this._zoom
    },
    set(value) {
      this.setZoom(value)
    }
  },
  center: {
    get() {
      return this._center
    },
    set(value) {
      this.setCenter(value)
    }
  }
})

Zondy.PluginVersion = '16.5.2'
Zondy.SceneView = SceneView
export default SceneView
