    import { TileLayer } from '../baseLayer'
    import { Zondy } from '../../../base'
    import { defaultValue, Log, toJSON } from '../../../util'
    import { LayerType, LoadStatus } from '../../../base/enum'
    import { TileServer } from '../../../service'
    import {
      Extent,
      Geometry,
      SpatialReference,
      Point
    } from '../../../base/geometry'
    import TileInfoUtil from '../support/TileInfoUtil'

    /**
     * IGS瓦片图层，<br>
     * 支持IGS1.0和2.0两个服务版本，支持自定义坐标系，当IGS版本是1.0时，需要手动设置图层坐标系，当IGS版本是2.0时，会自动读取元信息上的坐标系，不需要用户指定，
     * <br><br>[ES5引入方式]：<br/>
     * Zondy.Layer.IGSTileLayer() <br/>
     * [ES6引入方式]：<br/>
     * import { IGSTileLayer } from "@mapgis/webclient-common" <br/>
     * <br/>
     * 针对图层的操作请在图层加载完毕事件中进行<br/>
     * Layer.on('layerview-created', function (result) {<br/>
     *   console.log("加载完毕:", result.layer)<br/>
     * });<br/>
     * 如果不想在该事件中放入业务代码，则请确认图层资源已加载完毕后再进行操作<br/>
     * if(layer.loadStatus === 'loaded') {<br/>
     *   // 你的业务逻辑<br/>
     * }
     * @class IGSTileLayer
     * @moduleEX LayerModule
     * @extends Layer
     * @fires Layer#图层加载完毕事件
     * @fires Layer#图层销毁完毕事件
     * @fires Layer#图层更新完毕事件
     * @fires Layer#图层显隐更新完毕事件
     * @fires Layer#图层透明度更新完毕事件
     * @fires Layer#图层顺序更新完毕事件
     * @fires Layer#图层刷新完毕事件
     * @param {Object} options 构造参数
     * @param {String} [options.url] 服务基地址，<br/>
     * IGS1.0的服务为：http://{ip}:{port}/igs/rest/mrms/tile/{serviceName}，暂时无法从元信息中获取坐标系，请自行指定图层坐标系，参考示例：<a href='#igs-1'>[IGS1.0的瓦片图层示例]</a><br/>
     * IGS2.0的服务为：http://{ip}:{port}/igs/rest/services/{folder}/{serviceName}/TileServer，参考示例：<a href='#igs-2'>[IGS2.0的瓦片图层示例]</a><br/>
     * 删除图层方法：<a href='#remove-layer'>[删除图层]</a>
     * @param {String} [options.id] 图层id，不给则给一个随机的id
     * @param {Number} [options.opacity = 1] 图层透明度，0到1之间的值，0为完全透明，1为不透明，参考示例：<a href='#opacity'>[设置图层透明度]</a>
     * @param {Boolean} [options.visible = true] 图层显示或隐藏，true则显示，false则隐藏，参考示例：<a href='#visible'>[设置图层显示或隐藏]</a>
     * @param {SpatialReference} [options.spatialReference] 图层坐标系，默认从服务元信息上读取，当为igs1.0服务时，需要用户指定坐标系，
     * 参考示例：<a href='#igs-1'>[设置图层坐标系(IGS1.0)]</a>
     * @param {Number} [options.minScale = null] 最小比例尺，只有当地图视图的比例尺大于最小比例尺时显示瓦片图层
     * @param {Number} [options.maxScale = null] 最大比例尺，只有当地图视图的比例尺小于最大比例尺时显示瓦片图层
     * @param {String} [options.tokenKey = 'token'] token名
     * @param {String} [options.tokenValue] token值，只有当tokenValue存在时，才会绑定token
     * @param {Polygon|Extent|Circle|null} [options.clippingArea = null] 图层空间裁剪范围，仅支持多边形裁剪、矩形裁剪、圆形裁剪
     *
     * @summary <h5>支持如下方法：</h5>
     * <a href='#load'>[1、加载图层资源]</a><br/>
     * <a href='#getTileUrl'>[2、根据级数以及行列号获取瓦片的url]</a><br/>
     * <a href='#toJSON'>[3、将图层转为json对象]</a><br/>
     * <a href='#fromJSON'>[4、通过传入的json构造并返回一个新的几何对象]</a><br/>
     * [5、导出为json对象]{@link OGCLayer#toJSON}<br/>
     * [6、克隆几何对象]{@link OGCLayer#clone}
     *
     * @example <caption><h7 id='igs-1'>IGS1.0的瓦片图层示例</h7></caption>
     * // ES5引入方式
     * const { Map ,MapView,SpatialReference} = Zondy
     * const { IGSTileLayer} = Zondy.Layer
     * // ES6引入方式
     * import { Map ,MapView,IGSTileLayer } from "@mapgis/webclient-common"
     * // 初始化图层管理容器
     * const map = new Map();
     * // 初始化地图视图对象
     * const mapView = new MapView({
     *   // 视图id
     *   viewId: "viewer-id",
     *   // 图层管理容器
     *   map: map
     * });
     * const igsTileLayer = new IGSTileLayer({
     *   // 服务基地址
     *   url: 'http://{ip}:{port}/igs/rest/mrms/tile/{serviceName}',
     *   // IGS1.0服务，暂时无法从元信息中获取坐标系，请自行指定图层坐标系
     *   spatialReference: new SpatialReference({
     *     wkid: 4326
     *   })
     * });
     * map.add(igsTileLayer);
     *
     * @example <caption><h7 id='igs-2'>IGS2.0的瓦片图层示例</h7></caption>
     * // ES5引入方式
     * const { Map ,MapView,SpatialReference} = Zondy
     * const { IGSTileLayer} = Zondy.Layer
     * // ES6引入方式
     * import { Map ,MapView,IGSTileLayer } from "@mapgis/webclient-common"
     * // 初始化图层管理容器
     * const map = new Map();
     * // 初始化地图视图对象
     * const mapView = new MapView({
     *   // 视图id
     *   viewId: "viewer-id",
     *   // 图层管理容器
     *   map: map
     * });
     * const igsTileLayer = new IGSTileLayer({
     *   // 服务基地址
     *   url: 'http://{ip}:{port}/igs/rest/services/Tile/{serviceName}/TileServer'
     * });
     * map.add(igsTileLayer);
     *
     * @example <caption><h7 id='opacity'>设置图层透明度</h7></caption>
     * // ES5引入方式
     * const { IGSTileLayer} = Zondy.Layer
     * // ES6引入方式
     * import { IGSTileLayer } from "@mapgis/webclient-common"
     * // 初始化时设置
     * const igsTileLayer = new IGSTileLayer({
     *   // 服务基地址
     *   url: 'http://{ip}:{port}/igs/rest/services/Tile/{serviceName}/TileServer',
     *   // 设置图层透明度
     *   opacity: 1.0
     * });
     * map.add(igsTileLayer);
     * // 加载完成后设置
     * arcgisTileLayer.on('layerview-created', function (result) {
     *   console.log("加载完毕:", result.layer)
     * igsTileLayer.opacity = 0.5
     * })
     *
     * @example <caption><h7 id='visible'>设置图层显示或隐藏</h7></caption>
     * * // ES5引入方式
     * const { IGSTileLayer} = Zondy.Layer
     * // ES6引入方式
     * import { IGSTileLayer } from "@mapgis/webclient-common"
     * // 初始化时设置
     * const igsTileLayer = new IGSTileLayer({
     *   // 服务基地址
     *   url: 'http://{ip}:{port}/igs/rest/services/Tile/{serviceName}/TileServer',
     *   // 设置图层显示或隐藏
     *   visible: true
     * });
     * map.add(igsTileLayer);
     *
     * // 加载完成后设置
     * arcgisTileLayer.on('layerview-created', function (result) {
     *   console.log("加载完毕:", result.layer)
     *   // 设置图层显示或隐藏
     *   igsTileLayer.visible = !igsTileLayer.visible
     * })
     *
     * @example <caption><h7>ArcGIS的瓦片图层示例</h7></caption>
     *  // ES5引入方式
     * const { Map ,SceneView } = Zondy
     * const { IGSTileLayer} = Zondy.Layer
     * // ES6引入方式
     * import { Map ,MapView,IGSTileLayer } from "@mapgis/webclient-common"
     * //初始化图层管理容器
     * const map = new Map();
     * //初始化地图视图对象
     * const sceneView = new SceneView({
     *   //视图id
     *   viewId: "mapgis-3d-viewer",
     *   //图层管理容器
     *   map: map
     * });
     * const arcgisTileLayer = new IGSTileLayer({
     *   url: 'https://services.arcgisonline.com/arcgis/rest/services/World_Terrain_Base/MapServer'
     * });
     * map.add(arcgisTileLayer);
     * // 视点跳转
     * arcgisTileLayer.on('layerview-created', function (result) {
     *   console.log("加载完毕:", result.layer)
     *   sceneView.flyTo({
     *     extent: result.layer.extent
     *   })
     * })
     *
     * @example <caption><h7 id='remove-layer'>删除图层</h7></caption>
     * map.remove(igsTileLayer)
     *
     * @example <caption><h7 id='index'>图层顺序</h7></caption>
     * // 加载完毕后，更改图层顺序
     * map.reorder(igsTileLayer, '要移动到的index');
     * */
    class IGSTileLayer extends TileLayer {
      constructor(options) {
        super(options)
        options = defaultValue(options, {})

        this.type = LayerType.igsTile
        this.description = 'IGS瓦片图层'
        /**
         * 服务基地址
         * @member {String} IGSTileLayer.prototype.url
         */
        this.url = defaultValue(options.url, '')
        /**
         * 服务名称
         * @member {String} IGSTileLayer.prototype.mapName
         */
        this.mapName = defaultValue(options.mapName, '')
        // 空间裁剪范围
        this._clippingArea = defaultValue(options.clippingArea, null)
        // IGS服务版本号
        this._igsVersion = '2.0'
        if (this.url.indexOf('/igs/rest/mrms/tile/') > -1) {
          this._igsVersion = '1.0'
        }
        // 瓦片服务
        this._tileServer = new TileServer({
          url: this.url
        })
      }

      /**
       * 加载图层资源
       * @example <caption><h7 id='load'>不加载图层，仅获取图层信息</h7></caption>
       * // 初始化图层
       * const igsTileLayer = new Zondy.Layer.IGSTileLayer({
       *   // 服务基地址
       *   url: 'http://{ip}:{port}/igs/rest/services/Tile/{serviceName}/TileServer'
       * });
       * igsTileLayer.load().then((result) => {
       *   // 获取完图层信息
       *   console.log(wmsLayer)
       * })
       * */
      load() {
        return super.load()
      }

      /**
       * 子类请求服务资源的方法
       * @private
       * */
      _load() {
        const self = this
        return this._tileServer
          .queryServerInfo()
          .then((result) => {
            Log.info('TileServer信息查询成功:', result)
            const data = result.data
            // igs1.0服务
            if (self._igsVersion === '1.0') {
              // 获取瓦片大小
              self.tileSize = data.tileWidth
              // 获取图层信息
              self.tileInfo = TileInfoUtil.parseTileInfo1(data)
              self.tileInfo.origin.spatialReference = self._spatialReference
              self.tileInfo.spatialReference = self._spatialReference
              if (!self._spatialReference) {
                Log.error('IGS1.0服务必须设置参考系')
              }
              // 获取图层范围
              self.extent = new Extent({
                xmin: data.xMin,
                ymin: data.yMin,
                xmax: data.xMax,
                ymax: data.yMax,
                spatialReference: SpatialReference.fromJSON(self._spatialReference)
              })
            }
            // igs2.0服务
            else {
              // 获取图层名称
              self.mapName = data.mapName
              // 获取瓦片大小
              self.tileSize = data.tileInfo.cols
              // 获取图层信息
              self.tileInfo = TileInfoUtil.parseTileInfo2(data.tileInfo)
              // 获取图层坐标系
              self.spatialReference = new SpatialReference(
                self.tileInfo.spatialReference
              )
              // 获取图层范围
              self.extent = new Extent({
                xmin: data.extent.xmin,
                ymin: data.extent.ymin,
                xmax: data.extent.xmax,
                ymax: data.extent.ymax,
                spatialReference: SpatialReference.fromJSON(self.spatialReference)
              })
            }

            return new Promise((resolve) => {
              self.loadStatus = LoadStatus.loaded
              self.loaded = true
              resolve(self)
            })
          })
          .catch((result) => {
            Log.error('TileServer信息查询失败:', result)
          })
      }

      /**
       * 根据级数以及行列号获取瓦片的url
       * @param {Number} level 瓦片级数
       * @param {Number} row 行号
       * @param {Number} col 列号
       * @example <caption><h7 id='getTileUrl'>根据级数以及行列号获取瓦片的url</h7></caption>
       * const url = igsTileLayer.getTileUrl(0, 1, 2)
       * */
      getTileUrl(level, row, col) {
        return `${this.url}/tileImage/${level}/${row}/${col}?f=image`
      }

      /**
       * 通过传入的json构造并返回一个新的几何对象<a id='fromJSON'></a>
       * @param {Object} [json] JSON对象
       * @example <caption><h7>通过传入的json构造并返回一个新的几何对象</h7></caption>
       * const json = {
       *   // 服务基地址
       *   url: 'http://{ip}:{port}/igs/rest/services/Tile/{serviceName}/TileServer'
       * }
       * const igsTileLayer = new Zondy.Layer.IGSTileLayer.fromJSON(json)
       */
      static fromJSON(json) {
        json = defaultValue(json, {})
        const _layer = new IGSTileLayer(json)
        _layer._isFromJSON = true
        _layer.tileSize = json.tileSize
        _layer.tileInfo = {
          dpi: json.tileInfo.dpi,
          format: json.tileInfo.format,
          size: json.tileInfo.size,
          spatialReference: SpatialReference.fromJSON(
            json.tileInfo.spatialReference
          ),
          lods: json.tileInfo.lods,
          origin: Geometry.fromJSON(json.tileInfo.origin)
        }
        _layer.spatialReference = SpatialReference.fromJSON(json.spatialReference)
        _layer.extent = Geometry.fromJSON(json.extent)

        return _layer
      }

      /**
       * @description 转换为json对象
       * @return {Object} json对象
       */
      toJSON() {
        const json = super.toJSON()
        json.description = this.description
        json.url = this.url
        json.mapName = this.mapName
        json.tileSize = this.tileSize
        const _tileInfo = {
          size: this.tileInfo.size,
          dpi: this.tileInfo.dpi,
          format: this.tileInfo.format,
          spatialReference: toJSON(
            this.tileInfo.spatialReference,
            SpatialReference
          ),
          origin: toJSON(this.tileInfo.origin, Point),
          lods: this.tileInfo.lods
        }
        json.tileInfo = _tileInfo

        return json
      }
    }

    Object.defineProperties(IGSTileLayer.prototype, {
      /**
       * 空间裁剪范围
       * @member IGSTileLayer.prototype.clippingArea
       * @type {Polygon|Extent|Circle|null}
       */
      clippingArea: {
        get() {
          return this._clippingArea
        },
        set(value) {
          this._clippingArea = value
          this._fireUpdateEvent('空间裁剪区域', [
            {
              name: 'clippingArea',
              params: [this._clippingArea],
              dataChanged: true,
              operationType: 'property'
            }
          ])
        }
      }
    })

    Zondy.Layer.IGSTileLayer = IGSTileLayer
    export default IGSTileLayer