import MapvBaseLayer from './MapvBaseLayer'

let idIndex = 0

/**
 * @author 基础平台/创新中心 潘卓然 ParnDeedlit
 * @class  module:客户端可视化.MapVLayer
 * @classdesc  Mapv图表图层
 * @description CesiumZondy.Overlayer.MapVLayer 基于新建立的Html Element嵌入mapv
 * @param map - {Object} 传入的cesium的地图对象Viewer
 * @param dataset - {MapvDataSet} 传入的mapv的属性
 * @param mapVOptions - {MapvOption} 可选参数。https://github.com/huiyan-fe/mapv/blob/master/API.md
 * @param {Object} [mapVOptions.cesium] cesium的渲染模式
 * @param {Boolean} [mapVOptions.cesium.postRender=false] 是否实时渲染
 * @param {Boolean} [mapVOptionscesium.cesium.postRenderFrame=30] 每间隔多少帧渲染一次
 * @param container - {Element} 外部传入的div;外接的方式使用mapv
 * @example
 *  // 构建对应的dataset
 var dataSet = new mapv.DataSet(data);

 // 设置对应的参数
 // https://github.com/huiyan-fe/mapv/blob/master/API.md
 var options = {
    context: '2d',    //cesium必须设置画布为2d
    postRender: false,
    postRenderFrame: 5,
    //fillStyle: 'rgba(255, 250, 50, 0.7)',
    label: {
        show: true,
        fillStyle: 'white',
        shadowColor: 'yellow',
        font: '15px Arial',
        shadowBlur: 10
    },
    size: 30,
    gradient: {
        0: "rgba(49, 54, 149, 0)",
        0.2: "rgba(69,117,180, 0.7)",
        0.3: "rgba(116,173,209, 0.7)",
        0.4: "rgba(171,217,233, 0.7)",
        0.5: "rgba(224,243,248, 0.7)",
        0.6: "rgba(254,224,144,0.7)",
        0.7: "rgba(253,174,97,0.7)",
        0.8: "rgba(244,109,67,0.8)",
        0.9: "rgba(215,48,39,0.8)",
        0.95: "rgba(165, 0, 38,0.8)"
    },
    max: 100,
    draw: 'honeycomb'   // 绘制蜂窝图
    }
 // 声明cesium的mapv图层并将其显示到三维球上
 var mapvLayer = new CesiumZondy.Overlayer.MapvLayer(map, dataSet, options);
 */
export default class MapvLayer {
  constructor(map, dataSet, mapVOptions, container) {
    this.map = map
    this.scene = map.scene

    this.mapvBaseLayer = new MapvBaseLayer(map, dataSet, mapVOptions, this)
    this.mapVOptions = mapVOptions

    this.initDevicePixelRatio()

    this.canvas = this._creteWidgetCanvas() // this._createCanvas();

    this.render = this.render.bind(this)
    this.handler = undefined
    this.postRenderTime = 0

    const cesiumOpt = mapVOptions.cesium
    if (cesiumOpt) {
      this.postRender = cesiumOpt.postRender || false
      this.postRenderFrame = cesiumOpt.postRenderFrame || 30
    }

    if (container != undefined) {
      this.container = container
      container.appendChild(this.canvas)
    } else {
      const parents = document.getElementsByClassName('cesium-widget')
      const parent = parents.length > 0 ? parents[0] : map.container
      this.container = parent
      this.addInnerContainer()
    }

    this.bindEvent()

    this._reset()
  }

  initDevicePixelRatio() {
    // 经测试这里不取屏幕像素比，直接设置为1即可
    this.devicePixelRatio = 1
  }

  addInnerContainer() {
    // var container = document.createElement('div');
    this.container.appendChild(this.canvas)
    // container.appendChild(this.canvas);
    // return container;
  }

  bindEvent() {
    const self = this
    const map = this.map
    // 下面几个是cesium专属事件,clickEvent和mousemoveEvent是mapv内部自带的方法不放出来
    this.innerMoveStart = this.moveStartEvent.bind(this)
    this.innerMoveEnd = this.moveEndEvent.bind(this)

    this.innnerZoomStart = this.zoomStartEvent.bind(this)
    this.innnerZoomEnd = this.zoomEndEvent.bind(this)

    this.postEventHandle = this.postEvent.bind(this)
    this.postStartEvent = this.postStartEvent.bind(this)
    this.postEndEvent = this.postEndEvent.bind(this)

    // handler.setInputAction(this.innerMoveEnd, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    if (this.postRender) {
      // this.scene.postRender.addEventListener(this.postEventHandle);
      this.scene.camera.moveStart.addEventListener(this.postStartEvent, this)
      this.scene.camera.moveEnd.addEventListener(this.postEndEvent, this)
    } else {
      const handler = new Cesium.ScreenSpaceEventHandler(this.scene.canvas)

      handler.setInputAction(
        this.innerMoveEnd,
        Cesium.ScreenSpaceEventType.WHEEL
      )
      handler.setInputAction(
        this.innerMoveStart,
        Cesium.ScreenSpaceEventType.LEFT_DOWN
      )
      handler.setInputAction(
        this.innerMoveEnd,
        Cesium.ScreenSpaceEventType.LEFT_UP
      )
      handler.setInputAction(
        this.innerMoveStart,
        Cesium.ScreenSpaceEventType.RIGHT_DOWN
      )
      handler.setInputAction(
        this.innerMoveEnd,
        Cesium.ScreenSpaceEventType.RIGHT_UP
      )

      map.scene.camera.moveEnd.addEventListener(this.innerMoveEnd(), this)

      this.handler = handler
    }
  }

  unbindEvent() {
    const map = this.map
    if (this.postRender) {
      this.scene.camera.moveStart.removeEventListener(this.postStartEvent, this)
      this.scene.camera.moveEnd.removeEventListener(this.postEndEvent, this)
    } else {
      const handler = this.handler
      if (handler) {
        handler.removeInputAction(
          this.innerMoveEnd,
          Cesium.ScreenSpaceEventType.WHEEL
        )
        handler.removeInputAction(
          this.innerMoveStart,
          Cesium.ScreenSpaceEventType.LEFT_DOWN
        )
        handler.removeInputAction(
          this.innerMoveEnd,
          Cesium.ScreenSpaceEventType.LEFT_UP
        )
        handler.removeInputAction(
          this.innerMoveStart,
          Cesium.ScreenSpaceEventType.RIGHT_DOWN
        )
        handler.removeInputAction(
          this.innerMoveEnd,
          Cesium.ScreenSpaceEventType.RIGHT_UP
        )
        handler.destroy()
      }
      map.scene.camera.moveEnd.removeEventListener(this.innerMoveEnd(), this)
    }
  }

  postStartEvent() {
    if (this.mapvBaseLayer) {
      this.mapvBaseLayer.animatorMovestartEvent()
      this.scene.postRender.addEventListener(this._reset, this)
    }
    this._visiable()
  }

  postEndEvent() {
    if (this.mapvBaseLayer) {
      this.mapvBaseLayer.animatorMoveendEvent()
      this.scene.postRender.removeEventListener(this._reset, this)
    }
    this._reset()
    this._visiable()
  }

  moveStartEvent() {
    if (this.mapvBaseLayer) {
      this.mapvBaseLayer.animatorMovestartEvent()
    }
    this._unvisiable()
  }

  moveEndEvent() {
    if (this.mapvBaseLayer) {
      this.mapvBaseLayer.animatorMoveendEvent()
    }
    this._reset()
    this._visiable()
  }

  zoomStartEvent() {
    this._unvisiable()
  }

  zoomEndEvent() {
    this._unvisiable()
  }

  postEvent() {
    this.postRenderTime++
    if (this.postRenderTime % this.postRenderFrame === 0) this.moveEndEvent()
  }

  // -----------------------------------Start Data Operation---------------------------------

  /**
   * 增加数据
   * @function module:客户端可视化.MapVLayer.prototype.addData
   *
   * @param data - {Array} 数据.
   * @param options - {Object} 只做额外增加的字段作用
   * @see https://github.com/huiyan-fe/mapv/blob/master/API.md
   */
  addData(data, options) {
    if (this.mapvBaseLayer == undefined) return
    this.mapvBaseLayer.addData(data, options)
  }

  /**
   * 更新数据
   * @function module:客户端可视化.MapVLayer.prototype.updateData
   *
   * @param data - {Array} 数据.
   * @param options - {Object} 只做额外增加的字段作用
   * @see https://github.com/huiyan-fe/mapv/blob/master/API.md
   */
  updateData(data, options) {
    if (this.mapvBaseLayer == undefined) return
    this.mapvBaseLayer.updateData(data, options)
  }

  /**
   * 获取数据
   * @function module:客户端可视化.MapVLayer.prototype.getData
   *
   * @param data - {Array} 数据.
   * @param options - {Object} 只做额外增加的字段作用
   * @see https://github.com/huiyan-fe/mapv/blob/master/API.md
   */
  getData() {
    if (this.mapvBaseLayer) {
      this.dataSet = this.mapvBaseLayer.getData()
    }
    return this.dataSet
  }

  removeData(filter) {
    if (this.mapvBaseLayer == undefined) return
    this.mapvBaseLayer && this.mapvBaseLayer.removeData(filter)
  }

  /**
   * 删除数据
   * @function module:客户端可视化.MapVLayer.prototype.removeAllData
   */
  removeAllData() {
    if (this.mapvBaseLayer == undefined) return
    this.mapvBaseLayer.clearData()
  }

  // -----------------------------------End Data Operation---------------------------------
  _visiable() {
    this.canvas.style.display = 'block'
    return this
  }

  _unvisiable() {
    this.canvas.style.display = 'none'
    return this
  }

  setOpacity(Opacity) {
    this.canvas.style.opacity = Opacity
    return this
  }

  _createCanvas() {
    const canvas = document.createElement('canvas')
    canvas.id = this.mapVOptions.layerid || `mapv${idIndex++}`
    canvas.style.position = 'absolute'
    canvas.style.top = '0px'
    canvas.style.left = '0px'

    canvas.style.pointerEvents = 'none'
    canvas.style.zIndex = this.mapVOptions.zIndex || 100

    // canvas.width = parseInt(this.map.canvas.width);
    // canvas.height = parseInt(this.map.canvas.height);
    // canvas.style.width = this.map.canvas.style.width;
    // canvas.style.height = this.map.canvas.style.height;
    canvas.width =
      parseInt(this.map.canvas.width) ||
      parseInt(this.map.container.offsetWidth)
    canvas.height =
      parseInt(this.map.canvas.height) ||
      parseInt(this.map.container.offsetHeight)
    canvas.style.width = `${parseInt(this.map.container.offsetWidth)}px`
    canvas.style.height = `${parseInt(this.map.container.offsetHeight)}px`

    const devicePixelRatio = this.devicePixelRatio
    if (this.mapVOptions.context == '2d') {
      canvas
        .getContext(this.mapVOptions.context)
        .scale(devicePixelRatio, devicePixelRatio)
    }
    return canvas
  }

  _creteWidgetCanvas() {
    const canvas = document.createElement('canvas')

    canvas.id = this.mapVOptions.layerid || `mapv${idIndex++}`
    canvas.style.position = 'absolute'
    canvas.style.top = '0px'
    canvas.style.left = '0px'

    canvas.style.pointerEvents = 'none'
    canvas.style.zIndex = this.mapVOptions.zIndex || 100

    // canvas.width = parseInt(this.map.canvas.width);
    // canvas.height = parseInt(this.map.canvas.height);
    // canvas.style.width = this.map.canvas.style.width;
    // canvas.style.height = this.map.canvas.style.height;
    canvas.width =
      parseInt(this.map.canvas.width) ||
      parseInt(this.map.container.offsetWidth)
    canvas.height =
      parseInt(this.map.canvas.height) ||
      parseInt(this.map.container.offsetHeight)
    canvas.style.width = `${parseInt(this.map.container.offsetWidth)}px`
    canvas.style.height = `${parseInt(this.map.container.offsetHeight)}px`
    const devicePixelRatio = this.devicePixelRatio
    if (this.mapVOptions.context == '2d') {
      canvas.getContext('2d').scale(devicePixelRatio, devicePixelRatio)
    }

    return canvas
  }

  _reset() {
    this.resizeCanvas()
    this.fixPosition()
    this.onResize()
    this.render()
  }

  /**
   * 强制重回图层
   * @function module:客户端可视化.MapVLayer.prototype.draw
   */
  draw() {
    this._reset()
  }

  /**
   * 显示图层
   * @function module:客户端可视化.MapVLayer.prototype.show
   */
  show() {
    this._visiable()
  }

  /**
   * 隐藏图层
   * @function module:客户端可视化.MapVLayer.prototype.hide
   */
  hide() {
    this._unvisiable()
  }

  /**
   * 销毁图层-实际调用remove，为了接口保持一致
   * @function module:客户端可视化.MapVLayer.prototype.destroy
   */
  destroy() {
    this.remove()
  }

  /**
   * 销毁图层
   * @function module:客户端可视化.MapVLayer.prototype.remove
   */
  remove() {
    if (this.mapvBaseLayer == undefined) return
    this.unbindEvent()
    this.removeAllData()
    this.mapvBaseLayer.clear(this.mapvBaseLayer.getContext())
    this.mapvBaseLayer = undefined
    const parent = this.canvas.parentElement
    parent.removeChild(this.canvas)
  }

  /**
   * 更新图层
   * @function module:客户端可视化.MapVLayer.prototype.update
   */
  update(opt) {
    if (opt == undefined) {
      return
    }
    this.updateData(opt.data, opt.options)
  }

  resizeCanvas() {
    // this.mapContainer.style.perspective = this.map.transform.cameraToCenterDistance + 'px';
    if (this.canvas == undefined || this.canvas == null) return
    const canvas = this.canvas
    canvas.style.position = 'absolute'
    canvas.style.top = '0px'
    canvas.style.left = '0px'
    // canvas.width = parseInt(this.map.canvas.width);
    // canvas.height = parseInt(this.map.canvas.height);
    // canvas.style.width = this.map.canvas.style.width;
    // canvas.style.height = this.map.canvas.style.height;
    canvas.width =
      parseInt(this.map.canvas.width) ||
      parseInt(this.map.container.offsetWidth) * this.devicePixelRatio
    canvas.height =
      parseInt(this.map.canvas.height) ||
      parseInt(this.map.container.offsetHeight) * this.devicePixelRatio
    canvas.style.width = `${parseInt(this.map.container.offsetWidth)}px`
    canvas.style.height = `${parseInt(this.map.container.offsetHeight)}px`
    const devicePixelRatio = this.devicePixelRatio
    if (this.mapVOptions.context == '2d') {
      canvas.getContext('2d').scale(devicePixelRatio, devicePixelRatio)
    }
  }

  fixPosition() {}

  onResize() {}

  render() {
    if (this.mapvBaseLayer == undefined) return
    this.mapvBaseLayer._canvasUpdate()
  }
}
