import util from './libs/util'
import diff from './libs/diff'
import Event from './libs/event'
import Painter from './painter'
import Style from './style'
import events from './constants/event_list'
import { Scene, Mapbox } from '@cgcs2000/l7'

class VMap extends Event {
  /**
   * 构造函数，传入配置文件和容器id
   * @style 地图样式文件
   * @options 选项，包含容器id
   */
  constructor(options) {
    super()
    this._options = options
    this._layers = {}
    this.basemap = null
    this.scene = null
    this.loaded = false
    this.painter = new Painter(this) // 组件绘制工具
    let { style, container } = this._options
    if (!container) {
      throw new Error(`Can't get the contaniner of vmap`)
    }
    this.setStyle(style) // 根据配置文件绘制大屏
  }

  initMap(style) {
    let { center, zoom, pitch, bearing } = this._options
    let { basemap } = style
    center = center || style.center
    zoom = zoom || style.zoom
    pitch = pitch || style.pitch
    bearing = bearing || style.bearing
    let options = Object.assign({}, basemap)
    if (center) {
      options.center = center
    }
    if (zoom !== undefined) {
      options.zoom = zoom
    }
    if (pitch !== undefined) {
      options.pitch = pitch
    }
    if (bearing !== undefined) {
      options.bearing = bearing
    }
    this.scene = new Scene({
      id: this._options.container,
      map: new Mapbox(options),
      logoVisible: false
    })
    this.basemap = this.scene.map
    this.scene.on('loaded', () => {
      this.loaded = true
    })
    // 托管场景的事件
    events.forEach(eventName => {
      this.scene.on(eventName, e => this.fire(eventName, e))
    })
  }

  /**
   * 绘制画布，更新画布大小，然后根据配置文件绘制各组件图层
   */
  setStyle(style) {
    if (typeof style === 'string') {
      fetch(style)
        .then(res => res.json())
        .then(data => {
          this._setStyle(data)
        })
    } else {
      this._setStyle(style)
    }
  }

  _setStyle(style) {
    let newStyle = JSON.parse(JSON.stringify(style))
    let oldStyle = this.style ? this.style.getStyle() : {}
    let cmds = diff(oldStyle, newStyle)
    if (cmds.length === 1 && cmds[0].command === 'setStyle') {
      this.destroy()
      this.style = new Style(newStyle)
      this.initMap(newStyle)
      newStyle.layers.forEach(layer => {
        this.addLayer(layer)
      })
      return
    }
    for (let i = 0; i < cmds.length; i++) {
      if (this[cmds[i].command]) {
        this[cmds[i].command](...cmds[i].args)
      }
    }
    //this._resetIndex()
  }

  /**
   * 添加新的图表
   * @component {Object} 图表的配置项，应包含图表的id
   * @beforeId  {String}  图表插入的位置，将目标图表移动到该图表的前面（上面）
   */
  addLayer(layerConfig, beforeId) {
    if (!layerConfig.id) {
      throw new Error('Add layer faild, layer id is not provided!')
    }
    let layers = this.style.getStyle().layers
    if (util.isIdExist(layerConfig.id, layers)) {
      throw new Error(
        `Error in layer "${layerConfig.name}(${layerConfig.id})": Layer id has already exist!`
      )
    }
    let zIndex = layers.length
    let layerInstance = this.painter.draw(layerConfig, zIndex)
    if (layerInstance) {
      this.style.addLayer(layerConfig, beforeId)
      this._layers[layerInstance.id] = layerInstance
    }
  }

  /**
   * 移除图表
   * @id {String} 需要删除的图表id
   */
  removeLayer(id) {
    let layerInstance = this.getLayerInstance(id)
    if (!layerInstance) {
      return
    }
    layerInstance.remove()
    this.style.removeLayer(id)
    delete this._layers[id]
  }

  _resetIndex() {
    let layers = this.style.getStyle().layers
    layers.forEach((lyr, index) => {
      this.setLayerIndex(lyr.id, index)
    })
  }

  /**
   * 获取指定id的图表组件
   */
  getLayerInstance(id) {
    return this._layers[id]
  }

  /**
   * 获取大屏中的所有图表组件
   */
  getLayerInstances() {
    return this._layers
  }

  /**
   * 获取大屏的配置文件
   */
  getStyle() {
    return this.style.getStyle()
  }

  setBaseMap(basemap) {
    this.style.setMapStyle(basemap.style)
    this.scene.setMapStyle(basemap.style)
  }

  setLayerSource(id, source) {
    let layerInstance = this.getLayerInstance(id)
    if (!layerInstance) {
      throw new Error(`Layer Not Found: Layer id "${id}" is not exist!`)
    }
    this.style.updateLayerProperty(id, 'source', source)
    layerInstance.setSource()
  }

  setLayerScale(id, scale) {
    let layerInstance = this.getLayerInstance(id)
    if (!layerInstance) {
      throw new Error(`Layer Not Found: Layer id "${id}" is not exist!`)
    }
    this.style.updateLayerProperty(id, 'scale', scale)
    layerInstance.setScale()
    this.scene.render()
  }

  setLayerAction(id, action) {
    let layerInstance = this.getLayerInstance(id)
    if (!layerInstance) {
      throw new Error(`Layer Not Found: Layer id "${id}" is not exist!`)
    }
    this.style.updateLayerProperty(id, 'action', action)
    layerInstance.setAction()
    this.scene.render()
  }

  setLayerShape(id, shape) {
    let layerInstance = this.getLayerInstance(id)
    if (!layerInstance) {
      throw new Error(`Layer Not Found: Layer id "${id}" is not exist!`)
    }
    this.style.updateLayerProperty(id, 'shape', shape)
    layerInstance.setShape()
    this.scene.render()
  }

  setLayerStyle(id, style) {
    let layerInstance = this.getLayerInstance(id)
    if (!layerInstance) {
      throw new Error(`Layer Not Found: Layer id "${id}" is not exist!`)
    }
    this.style.updateLayerProperty(id, 'style', style)
    layerInstance.setStyle()
    this.scene.render()
  }

  setLayerVisibility(id, visible) {
    let layerInstance = this.getLayerInstance(id)
    if (!layerInstance) {
      throw new Error(`Layer Not Found: Layer id "${id}" is not exist!`)
    }
    this.style.updateLayerProperty(id, 'visible', !!visible)
    if (visible) {
      layerInstance.show()
    } else {
      layerInstance.hide()
    }
  }

  setLayerIndex(id, index) {
    let layerInstance = this.getLayerInstance(id)
    if (!layerInstance) {
      throw new Error(`Layer Not Found: Layer id "${id}" is not exist!`)
    }
    try {
      layerInstance.setIndex(+index)
    } catch (e) {
      // 线图层和面图层会报错，暂不清楚原因
    }
  }

  zoomToExtent(id) {
    let layerInstance = this.getLayerInstance(id)
    if (!layerInstance) {
      throw new Error(`Layer Not Found: Layer id "${id}" is not exist!`)
    }
    layerInstance.fitBounds()
  }

  getZoom() {
    return this.scene.getZoom()
  }

  getCenter() {
    return this.scene.getCenter()
  }

  getPitch() {
    return this.scene.getPitch()
  }

  getBearing() {
    return this.scene.getRotation()
  }

  setZoom(zoom) {
    this.scene.setZoom(zoom)
  }

  setCenter(center) {
    this.scene.setCenter(center)
  }

  setPitch(pitch) {
    this.scene.setPitch(pitch)
  }

  setBearing(bearing) {
    this.scene.setRotation(bearing)
  }
  /**
   * 销毁地图，移除所有图层
   */
  destroy() {
    let layers = this._layers
    for (let id in layers) {
      this.removeLayer(id)
    }
  }
}

export default VMap
