/**
 * @Author: Caven
 * @Date: 2019-12-31 17:32:01
 */

import { DomUtil } from '../utils'
import State from '../state/State'
import Widget from './Widget'

const { Cesium } = DC.Namespace

class ContextMenu extends Widget {
  constructor() {
    super()
    this._wrapper = DomUtil.create('div', 'dc-context-menu')
    this._ulEl = undefined
    this._handler = undefined
    this._overlay = undefined
    this._position = undefined
    this._wgs84Position = undefined
    this._surfacePosition = undefined
    this._wgs84SurfacePosition = undefined
    this._windowPosition = undefined
    this._config = {}
    this._defaultMenu = [
      {
        label: '飞到默认位置',
        callback: e => {
          this._viewer.camera.flyHome(1.5)
        },
        context: this
      },
      {
        label: '取消飞行',
        callback: e => {
          this._viewer.camera.cancelFlight()
        },
        context: this
      }
    ]
    this._overlayMenu = []
    this.type = Widget.getWidgetType('contextmenu')
    this._state = State.INITIALIZED
  }

  set DEFAULT_MENU(menus) {
    this._defaultMenu = menus
    return this
  }

  set config(config) {
    this._config = config
    config.customClass && this._setCustomClass()
    return this
  }

  /**
   *
   * @private
   */
  _installHook() {
    Object.defineProperty(this._viewer, 'contextMenu', {
      value: this,
      writable: false
    })
    this._handler = new Cesium.ScreenSpaceEventHandler(this._viewer.canvas)
  }

  /**
   *
   * @private
   */
  _bindEvent() {
    this._handler.setInputAction(movement => {
      this._onRightClick(movement)
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)

    this._handler.setInputAction(movement => {
      this._onClick(movement)
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
  }

  /**
   *
   * @private
   */
  _unbindEvent() {
    this._handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)
    this._handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
  }

  /**
   *
   * @private
   */
  _mountContent() {
    this._ulEl = DomUtil.create('ul', 'menu-list', this._wrapper)
    this._ready = true
  }

  /**
   *
   * @private
   */
  _mountMenu() {
    while (this._ulEl.hasChildNodes()) {
      this._ulEl.removeChild(this._ulEl.firstChild)
    }
    // Add menu item
    if (this._overlayMenu && this._overlayMenu.length) {
      this._overlayMenu.forEach(item => {
        this._addMenuItem(item.label, item.callback, item.context || this)
      })
    }

    if (this._defaultMenu && this._defaultMenu.length) {
      this._defaultMenu.forEach(item => {
        this._addMenuItem(item.label, item.callback, item.context || this)
      })
    }
  }

  /**
   *
   * @param movement
   * @private
   */
  _onRightClick(movement) {
    if (!this._enable) {
      return
    }
    this._overlay = undefined
    let scene = this._viewer.scene
    this._windowPosition = movement.position
    this._updateWindowCoord(movement.position)
    let target = scene.pick(movement.position)
    if (scene.pickPositionSupported) {
      this._position = scene.pickPosition(movement.position)
    }
    if (this._position) {
      let c = Cesium.Ellipsoid.WGS84.cartesianToCartographic(this._position)
      if (c) {
        this._wgs84Position = {
          lng: Cesium.Math.toDegrees(c.longitude),
          lat: Cesium.Math.toDegrees(c.latitude),
          alt: c.height
        }
      }
    }
    if (scene.mode === Cesium.SceneMode.SCENE3D) {
      let ray = scene.camera.getPickRay(movement.position)
      this._surfacePosition = scene.globe.pick(ray, scene)
    } else {
      this._surfacePosition = scene.camera.pickEllipsoid(
        movement.position,
        Cesium.Ellipsoid.WGS84
      )
    }

    if (this._surfacePosition) {
      let c = Cesium.Ellipsoid.WGS84.cartesianToCartographic(
        this._surfacePosition
      )
      if (c) {
        this._wgs84SurfacePosition = {
          lng: Cesium.Math.toDegrees(c.longitude),
          lat: Cesium.Math.toDegrees(c.latitude),
          alt: c.height
        }
      }
    }
    // for Entity
    if (target && target.id && target.id instanceof Cesium.Entity) {
      let layer = this._viewer
        .getLayers()
        .filter(item => item.layerId === target.id.layerId)[0]
      if (layer && layer.getOverlay) {
        this._overlay = layer.getOverlay(target.id.overlayId)
      }
    }
    // for Cesium3DTileFeature
    if (target && target instanceof Cesium.Cesium3DTileFeature) {
      let layer = this._viewer
        .getLayers()
        .filter(item => item.layerId === target.tileset.layerId)[0]
      if (layer && layer.getOverlay) {
        this._overlay = layer.getOverlay(target.tileset.overlayId)
      }
    }
    this._overlayMenu = this._overlay?.contextMenu || []
    this._mountMenu()
  }
  /**
   *
   * @param movement
   * @private
   */
  _onClick(movement) {
    this.hide()
  }

  /**
   *
   * @param windowCoord
   * @private
   */
  _updateWindowCoord(windowCoord) {
    this._wrapper.style.cssText = `
    visibility:visible;
    z-index:1;
    transform:translate3d(${Math.round(windowCoord.x)}px,${Math.round(
      windowCoord.y
    )}px, 0);
    `
  }

  /**
   *
   * @private
   */
  _setCustomClass() {
    DomUtil.setClass(
      this._wrapper,
      `dc-context-menu ${this._config.customClass}`
    )
  }

  /**
   *
   * @param label
   * @param method
   * @param context
   * @returns {ContextMenu}
   * @private
   */
  _addMenuItem(label, method, context) {
    if (!label || !method) {
      return this
    }
    let menu = DomUtil.create('li', 'menu-item', null)
    let a = DomUtil.create('a', '', menu)
    a.innerHTML = label
    a.href = 'javascript:void(0)'
    let self = this
    if (method) {
      a.onclick = () => {
        method.call(context, {
          windowPosition: self._windowPosition,
          position: self._position,
          wgs84Position: self._wgs84Position,
          surfacePosition: self._surfacePosition,
          wgs84SurfacePosition: self._wgs84SurfacePosition,
          overlay: self._overlay
        })
        self.hide()
      }
    }
    this._ulEl.appendChild(menu)
    return this
  }
}

Widget.registerType('contextmenu')

export default ContextMenu
