    import { Zondy, Collection, WMTSStyle } from '../../../base'
    import { LayerType, LoadStatus } from '../../../base/enum'
    import { defaultValue, Log } from '../../../util'
    import { WMTSServer } from '../../../service'
    import WMTSSubLayer from './WMTSSubLayer'
    import TileMatrixSet from '../../../base/TileMatrixSet'
    import { Extent, Point, SpatialReference } from '../../../base/geometry'
    import {
      getEPSGCodeFromOGCSupportedCRSString,
      getEPSGFromTileMatrixSetId,
      getTileResolution,
      initCorporationType
    } from '../support/Utils'
    import OGCLayer from './OGCLayer'
    import TileInfo from '../support/TileInfo'
    import LOD from '../support/LOD'

    /**
     * WMTS图层，<br>
     * 目前二维上支持4326(包括4490，4214以及4610)，3857以及EPSG支持的自定义坐标系，三维上仅支持4326(包括4490，4214以及4610)以及3857坐标系，WMTS服务会自动读取元信息上的坐标系，不需要用户指定
     * <br><br>[ES5引入方式]：<br/>
     * Zondy.Layer.WMTSLayer() <br/>
     * [ES6引入方式]：<br/>
     * import { WMTSLayer } 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 WMTSLayer
     * @moduleEX LayerManagerModule
     * @extends OGCLayer
     * @fires Layer#图层加载完毕事件
     * @fires Layer#图层销毁完毕事件
     * @fires Layer#图层更新完毕事件
     * @fires Layer#图层显隐更新完毕事件
     * @fires Layer#图层透明度更新完毕事件
     * @fires Layer#图层顺序更新完毕事件
     * @fires Layer#图层刷新完毕事件
     * @param {Object} options 构造参数
     * @param {String} [options.url] 服务基地址，支持如下服务：<br/>
     * 1、支持MapGIS的WMTS服务，格式为：http://{ip}:{port}/igs/rest/services/{ServiceName}/WMTSServer，请注意，当在IGS中发布自定义坐标系的WMTS服务时，可能会有部分地图无法正确的进行预览，
     * 并且该服务中的范围参数是错误的，请自行指定跳转范围，或从该服务对应的瓦片服务中获取，参考示例：<a href='#MapIGS'>[加载MapGIS的WMTS服务]</a><br/>
     * 2、支持ArcGIS的WMTS服务，格式为：http://{ip}:{port}/arcgis/rest/services/{ServiceName}/MapServer/WMTS，参考示例：<a href='#ArcGIS'>[加载ArcGIS的WMTS服务]</a><br/>
     * 3、支持天地图的WMTS服务：格式为：http://t{0~6的随机数}.tianditu.gov.cn/{图层类型}_{坐标系}/wmts，<br/>
     * 其中天地图层类型如下：<br/>
     * vec：矢量底图、img：卫星影像底图、cva: 矢量注记图层（中文）、eva: 矢量注记图层（英文）、cia: 注记图层（中文）、eia: 注记图层（英文）、ter: 地形晕渲底图、cta: 注记（中文）、ibo: 全球国界<br/>
     * 坐标系如下：<br/>
     * w：墨卡托坐标系(3857)、c：经纬度坐标系(4326)<br/>
     * 参考示例：<a href='#tdt'>[加载天地图的WMTS服务]</a><br/>
     * @param {Number} [options.opacity = 1] 图层透明度，0到1之间的值，0为完全透明，1为不透明，参考示例：<a href='#opacity'>[修改图层透明度]
     * @param {Boolean} [options.visible = true] 图层显示或隐藏，true则显示，false则隐藏，参考示例：<a href='#visible'>[设置图层显隐]
     * @param {Number} [options.minScale = 0] 最小缩放级数，仅会请求级数大于等于minScale的图片
     * @param {Number} [options.maxScale = 19] 最大缩放级数，仅会请求级数小于等于maxScale的图片
     * @param {String} [options.tokenKey = 'token'] token名
     * @param {String} [options.tokenValue] token值，只有当tokenValue存在时，才会绑定token
     *
     * @summary <h5>支持如下方法：</h5>
     * <a href='#load'>[1、加载图层资源]</a><br/>
     * <a href='#findSublayerById'>[2、根据子图层id查询图层]</a><br/>
     * <a href='#fromServerUrl'>[3、通过url创建图层对象]</a><br/>
     * <a href='#fromJSON'>[4、通过传入的json构造并返回一个新的几何对象]</a><br/>
     * [5、导出为json对象]{@link OGCLayer#toJSON}<br/>
     * [6、克隆几何对象]{@link OGCLayer#clone}
     *
     * @example <caption><h7 id='MapIGS'>加载WMTS图层</h7></caption>
     * // ES5引入方式
     * const { Map, MapView, SceneView } = Zondy
     * const { WMTSLayer } = Zondy.Layer
     * // ES6引入方式
     * import { Map, MapView, SceneView, WMTSLayer } from "@mapgis/webclient-common"
     * // 初始化图层管理容器
     * const map = new Map();
     * // 初始化二维地图视图对象
     * const mapView = new MapView({
     *   // 视图id
     *   viewId: "viewer-id",
     *   // 图层管理容器
     *   map: map
     * });
     * // 初始化三维地图视图对象
     * const mapView = new SceneView({
     *   // 视图id
     *   viewId: "viewer-id",
     *   // 图层管理容器
     *   map: map
     * });
     * // 初始化WMTS图层
     * const wmtsLayer = new WMTSLayer({
     *   // 服务基地址
     *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMTSServer'
     * });
     * // 将图层加入容器中
     * map.add(wmtsLayer);
     * // 图层加载完毕
     * wmsLayer.on('layerview-created', function (result) {
     *   console.log("加载完毕:", result.layer)
     *   // 视点跳转
     *   sceneView.flyTo({
     *     extent: result.layer.extent
     *   })
     * });
     *
     * @example <caption><h7 id='ArcGIS'>添加ArcGIS的WMTS图层示例</h7></caption>
     * // ES5引入方式
     * const { Map, MapView, SceneView } = Zondy
     * const { WMTSLayer } = Zondy.Layer
     * // ES6引入方式
     * import { Map, MapView, SceneView, WMTSLayer } from "@mapgis/webclient-common"
     * // 初始化图层管理容器
     * const map = new Map();
     * // 初始化二维地图视图对象
     * const mapView = new MapView({
     *   // 视图id
     *   viewId: "viewer-id",
     *   // 图层管理容器
     *   map: map
     * });
     * // 初始化三维地图视图对象
     * const mapView = new SceneView({
     *   // 视图id
     *   viewId: "viewer-id",
     *   // 图层管理容器
     *   map: map
     * });
     * // 初始化WMTS图层
     * const wmtsLayer = new WMTSLayer({
     *   url: 'http://{ip}:{port}/arcgis/rest/services/{serviceName}/MapServer/WMTS'
     * });
     * // 将图层加入容器中
     * map.add(wmtsLayer);
     * // 图层加载完毕
     * wmsLayer.on('layerview-created', function (result) {
     *   console.log("加载完毕:", result.layer)
     *   // 视点跳转
     *   sceneView.flyTo({
     *     extent: result.layer.extent
     *   })
     * });
     *
     * @example <caption><h7 id='tdt'>加载天地图的WMTS服务</h7></caption>
     * // ES5引入方式
     * const { Map, MapView, SceneView } = Zondy
     * const { WMTSLayer } = Zondy.Layer
     * // ES6引入方式
     * import { Map, MapView, SceneView, WMTSLayer } from "@mapgis/webclient-common"
     * // 初始化图层管理容器
     * const map = new Map();
     * // 初始化二维地图视图对象
     * const mapView = new MapView({
     *   // 视图id
     *   viewId: "viewer-id",
     *   // 图层管理容器
     *   map: map
     * });
     * // 初始化三维地图视图对象
     * const mapView = new SceneView({
     *   // 视图id
     *   viewId: "viewer-id",
     *   // 图层管理容器
     *   map: map
     * });
     * 初始化WMTS图层
     * const wmtsLayer = new WMTSLayer({
     *   // 加载经纬度的影像地图
     *   url: 'http://t6.tianditu.gov.cn/img_c/wmts',
     *   // 天地图必须加token，且token名为tk
     *   tokenKey: 'tk',
     *   // token请在天地图官网申请
     *   tokenValue: '天地图token'
     * });
     * // 将图层加入容器中
     * map.add(wmtsLayer);
     * // 图层加载完毕
     * wmsLayer.on('layerview-created', function (result) {
     *   console.log("加载完毕:", result.layer)
     *   // 视点跳转
     *   sceneView.flyTo({
     *     extent: result.layer.extent
     *   })
     * });
     *
     * @example <caption><h7 id='opacity'>修改图层透明度</h7></caption>
     * // ES5引入方式
     * const { WMTSLayer } = Zondy.Layer
     * // ES6引入方式
     * import { WMTSLayer } from "@mapgis/webclient-common"
     * // 初始化时设置
     * const wmtsLayer = new WMTSLayer({
     *   // 服务基地址
     *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMTSServer',
     *   // 设置透明度
     *   opacity: 1.0
     * });
     * // 将图层加入容器中
     * map.add(wmtsLayer);
     *
     * // 加载完成后设置
     * wmsLayer.on('layerview-created', function (result) {
     *   console.log("加载完毕:", result.layer)
     *   // 设置透明度
     *   wmtsLayer.opacity = 0.5
     * })
     *
     * @example <caption><h7 id='visible'>设置图层显隐</h7></caption>
     * // ES5引入方式
     * const { WMTSLayer } = Zondy.Layer
     * // ES6引入方式
     * import { WMTSLayer } from "@mapgis/webclient-common"
     * // 初始化时设置
     * const wmtsLayer = new WMTSLayer({
     *   // 服务基地址
     *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMTSServer',
     *   // 设置图层显隐
     *   visible: true
     * });
     * // 将图层加入容器中
     * map.add(wmtsLayer);
     *
     * // 加载完成后设置
     * wmsLayer.on('layerview-created', function (result) {
     *   console.log("加载完毕:", result.layer)
     *   // 设置图层显隐
     *   wmtsLayer.visible = !wmtsLayer.visible
     * })
     *
     * @example <caption><h7>删除图层</h7></caption>
     * map.remove(wmtsLayer)
     */
    class WMTSLayer extends OGCLayer {
      constructor(options) {
        super(options)
        options = defaultValue(options, {})

        /**
         * 图层类型
         * @readonly
         * @member {type} WMTSLayer.prototype.type
         */
        this.type = LayerType.wmts

        /**
         * 当前处于活动状态的子图层
         * @member {WMTSSubLayer} WMTSLayer.prototype.activeLayer
         */
        this.activeLayer = defaultValue(options.activeLayer, new WMTSSubLayer())
        /**
         * WMTSSublayer 子图层对象的集合
         * @readonly
         * @member {Array<WMTSSubLayer>} WMTSLayer.prototype.sublayers
         */
        this.sublayers = defaultValue(options.sublayers, new Collection())
        /**
         * 服务基地址
         * @readonly
         * @member {String} WMTSLayer.prototype.url
         */
        this.url = defaultValue(options.url, undefined)
        /**
         * 空间参考
         * @readonly
         * @member {SpatialReference} WMTSLayer.prototype.spatialReference
         */
        this.spatialReference = SpatialReference.fromJSON(options.spatialReference)
        /**
         * 图块矩阵集的集合
         * @readonly
         * @member {Array<TileMatrixSet>} WMTSLayer.prototype.tileMatrixSets
         */
        this.tileMatrixSets = defaultValue(options.tileMatrixSets, [])
        /**
         * WMTS 公司代码
         * @readonly
         * @member {String} WMTSLayer.prototype.corporationType
         */
        this.corporationType = initCorporationType(this.url)
        /**
         * 最小缩放级别
         * @member {Number} WMTSLayer.prototype.minScale
         */
        this.minScale = defaultValue(options.minScale, 0)
        /**
         * 最大缩放级别
         * @member {Number} WMTSLayer.prototype.maxScale
         */
        this.maxScale = defaultValue(options.maxScale, 19)
        /**
         * 图片宽度
         * @readonly
         * @member {Number} WMTSLayer.prototype.imageWidth
         */
        this.imageWidth = 256
        /**
         * 图片高度
         * @readonly
         * @member {Number} WMTSLayer.prototype.imageHeight
         */
        this.imageHeight = 256

        // 地图服务对象
        this._mapServer = new WMTSServer({
          url: this.url
        })
      }

      /**
       * 通过传入的json构造并返回一个新的几何对象<a id='fromJSON'></a>
       * @param {Object} [json] JSON对象
       * @example <caption><h7>通过传入的json构造并返回一个新的几何对象</h7></caption>
       * // ES5引入方式
       * const { WMTSLayer } = Zondy.Layer
       * // ES6引入方式
       * import { WMTSLayer } from "@mapgis/webclient-common"
       * const json = {
       *   // 服务基地址
       *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMTSServer'
       * }
       * const wmtsLayer = new WMTSLayer.fromJSON(json)
       */
      static fromJSON(json) {
        json = defaultValue(json, {})
        return new WMTSLayer(json)
      }

      /**
       * @description 转换为json对象
       * @return {Object} json对象
       */
      toJSON() {
        const json = super.toJSON()
        json.type = this.type
        json.activeLayer = this.activeLayer.toJSON()
        json.url = this.url
        json.spatialReference = this.spatialReference.toJSON()
        json.corporationType = this.corporationType
        json.minScale = this.minScale
        json.maxScale = this.maxScale
        json.imageWidth = this.imageWidth
        json.imageHeight = this.imageHeight

        const _sublayers = []
        this.sublayers.forEach(function (sublayer) {
          _sublayers.push(sublayer.toJSON())
        })
        json.sublayers = _sublayers

        const _tileMatrixSets = []
        for (let i = 0; i < this.tileMatrixSets.length; i++) {
          _tileMatrixSets.push(this.tileMatrixSets[i].toJSON())
        }
        json.tileMatrixSets = _tileMatrixSets

        return json
      }

      /**
       * 加载图层资源<a id='load'></a>
       * @example <caption><h7>不加载图层，仅获取图层信息</h7></caption>
       * // ES5引入方式
       * const { WMTSLayer } = Zondy.Layer
       * // ES6引入方式
       * import { WMTSLayer } from "@mapgis/webclient-common"
       * // 初始化图层
       * const wmtsLayer = new WMTSLayer({
       *   // 服务基地址
       *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMTSServer'
       * });
       * wmtsLayer.load().then((result) => {
       *   // 获取完图层信息
       *   console.log(wmtsLayer)
       * })
       */
      load() {
        const self = this
        return this._mapServer.getCapabitities().then((result) => {
          Log.info('MapServer信息查询成功:', result)
          const data = result.data

          // IGS2.0服务
          if (
            self.url.indexOf('/igs/rest/services/') > -1 ||
            self.url.indexOf('/arcgis/rest/services/') > -1 ||
            self.url.indexOf('.tianditu.gov.cn/') > -1
          ) {
            // 获取tileMatrixSets
            data.tileMatrixSet.forEach((tileMatrixSet) => {
              const _epsgCode = getEPSGCodeFromOGCSupportedCRSString(
                tileMatrixSet.supportedCRS
              )
              const _spatialReference = new SpatialReference({
                wkid: _epsgCode
              })
              const _topLeftCorner =
                tileMatrixSet.tileMatrix[0].topLeftCorner.split(' ')
              const _lods = []
              tileMatrixSet.tileMatrix.forEach(function (tileMatrix, index) {
                const _lod = new LOD()
                _lod.level = index
                _lod.scale = Number(tileMatrix.scaleDenominator)
                if (tileMatrix.identifier) {
                  // 存在两种情况，其一是参照系:级数,其二是只为级数
                  const _pos = tileMatrix.identifier.lastIndexOf(':')
                  if (_pos >= 0) {
                    _lod.levelValue = parseInt(
                      tileMatrix.identifier.substring(_pos + 1)
                    )
                  } else {
                    _lod.levelValue = parseInt(tileMatrix.identifier)
                  }
                }
                _lod.resolution = getTileResolution(
                  tileMatrix.identifier,
                  self.corporationType,
                  _lod.scale,
                  _spatialReference
                )
                _lods.push(_lod)
              })
              const _tileInfo = new TileInfo({
                origin: new Point({
                  coordinates: [
                    Number(_topLeftCorner[1]),
                    Number(_topLeftCorner[0])
                  ],
                  spatialReference: _spatialReference
                }),
                size: [
                  Number(tileMatrixSet.tileMatrix[0].tileWidth),
                  Number(tileMatrixSet.tileMatrix[0].tileHeight)
                ],
                lods: _lods,
                spatialReference: _spatialReference
              })
              self.tileMatrixSets.push(
                new TileMatrixSet({
                  extent: '',
                  id: tileMatrixSet.identifier,
                  tileInfo: _tileInfo,
                  layer: self,
                  tileMatrix: tileMatrixSet.tileMatrix,
                  identifier: tileMatrixSet.identifier,
                  supportedCRS: tileMatrixSet.supportedCRS
                })
              )
            })
            // 设置activeLayer以及坐标系
            if (Array.isArray(data.layer)) {
              data.layer.forEach((layer, index) => {
                if (index === 0) {
                  self.activeLayer = self._createWMTSSubLayer(layer, data)
                  self.spatialReference = new SpatialReference(
                    getEPSGFromTileMatrixSetId(layer.tileMatrixSetId)
                  )
                }
                self.sublayers.add(self._createWMTSSubLayer(layer, data))
              })
            }
            // 地图文档中只有一个图层的情况
            else {
              // 指定激活图层
              self.activeLayer = self._createWMTSSubLayer(
                data.layer,
                self.tileMatrixSets
              )
              // 新增子图层
              self.sublayers.add(
                self._createWMTSSubLayer(data.layer, self.tileMatrixSets)
              )
              // 遍历所有的tileMatrixSets，找到identifier包含028mm_GB的子元素
              // 暂时这样做，没找到更好的处理方法
              for (let i = 0; i < self.tileMatrixSets.length; i++) {
                if (
                  self.tileMatrixSets[i].identifier.indexOf('028mm_GB') > -1 ||
                  self.tileMatrixSets[i].identifier === 'default' ||
                  self.tileMatrixSets[i].identifier === 'default028mm' ||
                  self.tileMatrixSets[i].identifier === 'w' ||
                  self.tileMatrixSets[i].identifier === 'c'
                ) {
                  // 设置地图范围
                  if (typeof data.layer.boundingBox.lowerCorner === 'string') {
                    data.layer.boundingBox.lowerCorner =
                      data.layer.boundingBox.lowerCorner.split(' ')
                  }
                  if (typeof data.layer.boundingBox.upperCorner === 'string') {
                    data.layer.boundingBox.upperCorner =
                      data.layer.boundingBox.upperCorner.split(' ')
                  }
                  self.extent = new Extent({
                    xmin: Number(data.layer.boundingBox.lowerCorner[1]),
                    ymin: Number(data.layer.boundingBox.lowerCorner[0]),
                    xmax: Number(data.layer.boundingBox.upperCorner[1]),
                    ymax: Number(data.layer.boundingBox.upperCorner[0])
                  })
                  // 获取坐标系wkid
                  const supportedCRS =
                    self.tileMatrixSets[i].supportedCRS.split(':')
                  const wkid = Number(supportedCRS[supportedCRS.length - 1])
                  // 初始化坐标系
                  const spatialReference = new SpatialReference({
                    wkid
                  })
                  // 获取瓦片大小
                  self.imageWidth = defaultValue(
                    Number(self.tileMatrixSets[i].tileMatrix[0].tileWidth),
                    256
                  )
                  self.imageHeight = defaultValue(
                    Number(self.tileMatrixSets[i].tileMatrix[0].tileHeight),
                    256
                  )
                  self._spatialReference = spatialReference
                }
              }
            }
            return new Promise((resolve) => {
              self.loadStatus = LoadStatus.loaded
              self.loaded = true
              resolve(self)
            })
          }
        })
      }

      /**
       * @description 根据id查询子图层<a id='findSublayerById'></a>
       * @param {Object} id 子图层的id
       * @return {WMTSSubLayer} 找到的子图层对象
       */
      findSublayerById(id) {
        return this.sublayers.items[id]
      }

      _createWMTSSubLayer(layerJson, tileMatrixSets) {
        return new WMTSSubLayer({
          identifier: layerJson.identifier,
          title: layerJson.title,
          description: 'WMTS子图层',
          imageFormat: layerJson.format,
          imageFormats: [layerJson.format],
          styleId: Array.isArray(layerJson.Style)
            ? layerJson.Style[0].identifier
            : layerJson.Style.identifier,
          styles: [
            new WMTSStyle({
              id: layerJson.Style.identifier,
              title: layerJson.Style.title
            })
          ],
          tileMatrixSets,
          tileMatrixSetId: tileMatrixSets[0].identifier,
          extent: new Extent({
            xmin: Number(layerJson.boundingBox.lowerCorner.split(' ')[1]),
            ymin: Number(layerJson.boundingBox.lowerCorner.split(' ')[0]),
            xmax: Number(layerJson.boundingBox.upperCorner.split(' ')[1]),
            ymax: Number(layerJson.boundingBox.upperCorner.split(' ')[0])
          }),
          resourceURLTemplates: []
        })
      }
    }

    /**
     * 通过url创建图层对象<a id='fromServerUrl'></a>
     * @param {String} url 服务基地址
     * @return {WMTSLayer} 新的图层对象
     * @example <caption><h7>通过url创建图层对象</h7></caption>
     * // ES5引入方式
     * const { WMTSLayer } = Zondy.Layer
     * // ES6引入方式
     * import { WMTSLayer } from "@mapgis/webclient-common"
     * // 初始化图层
     * const url = 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMTSServer';
     * const wmtsLayer = new WMTSLayer.fromServerUrl(url);
     * */
    WMTSLayer.fromServerUrl = function (url) {
      return new WMTSLayer({
        url
      })
    }

    Zondy.Layer.WMTSLayer = WMTSLayer
    export default WMTSLayer