    import {defaultValue, isNull, Log, toJSON} from '../../../util'
    import {Collection, Zondy} from '../../../base'
    import { WMSServer } from '../../../service'
    import { LoadStatus, LayerType } from '../../../base/enum'
    import {Extent, Geometry, SpatialReference} from '../../../base/geometry'
    import WMSSubLayer from './WMSSubLayer'
    import { setSublayer } from '../Utils'
    import OGCLayer from './OGCLayer'
    import {jsonClone} from '../../../util/Utils';

    /**
     * WMS图层，<br/>
     * 目前二维上支持4326(包括4490，4214以及4610)，3857以及EPSG支持的自定义坐标系，三维上仅支持4326(包括4490，4214以及4610)以及3857坐标系，会自动读取元信息上的坐标系，不需要用户指定，同时所有的WMS服务都支持动态投影，用户也可指定任意该服务支持的坐标系<br/>
     * <br>[ES5引入方式]：<br/>
     * Zondy.Layer.WMSLayer() <br/>
     * [ES6引入方式]：<br/>
     * import { WMSLayer } 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 WMSLayer
     * @moduleEX LayerModule
     * @extends OGCLayer
     * @fires Layer#图层加载完毕事件
     * @fires Layer#图层销毁完毕事件
     * @fires Layer#图层更新完毕事件
     * @fires Layer#图层显隐更新完毕事件
     * @fires Layer#图层透明度更新完毕事件
     * @fires Layer#图层顺序更新完毕事件
     * @fires Layer#图层刷新完毕事件
     * @fires WMSLayer#子图层显隐更新完毕事件
     * @param {Object} options 构造参数
     * @param {String} [options.url] 服务基地址，支持的服务如下：<br/>
     * 1、支持MapGIS的WMS服务，格式为：http://{ip}:{port}/igs/rest/services/{ServiceName}/WMSServer，参考示例：<a href='#MapIGS'>[加载MapGIS的WMS服务]</a><br/>
     * 2、支持ArcGIS的WMS服务，格式为：http://{ip}:{port}/arcgis/rest/services/{ServiceName}/WMSServer，参考示例：<a href='#ArcGIS'>[加载ArcGIS的WMS服务]</a>
     * @param {String} [options.title] 图层名称
     * @param {SpatialReference} [options.spatialReference] 图层坐标系，支持4326、3857以及EPSG上的自定义坐标系，坐标系默认从元信息中获取，也可指定坐标系，
     * 参考示例：<a href='#spatialReference'>[设置图层坐标系]</a>
     * @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 {Number} [options.imageWidth = 256] 图片宽度，单位px
     * @param {Number} [options.imageHeight = 256] 图片高度，单位px
     * @param {Number} [options.minScale = 0] 最小缩放级数，仅会请求级数小于等于maxScale的图片
     * @param {Number} [options.maxScale = 19] 最大缩放级数，仅会请求级数小于等于maxScale的图片
     * @param {Boolean} [options.imageTransparency = true] 图片中没有数据的地方是否透明，默认为true，即透明
     * @param {Polygon|Extent|Circle|null} [options.clippingArea = null] 图层空间裁剪范围，仅支持多边形裁剪、矩形裁剪、圆形裁剪
     * @param {Array} [options.sublayers = []] 指定子图层参数，可设置子图层是否显示，若不填则显示所有子图层，若有值则只显示visible为true的子图层，<br/>
     * 参考示例：<br/>
     * <a href='#SubLayers'>[1、初始化时，设置子图层显隐]</a><br/>
     * <a href='#SubLayers-Method'>[2、通过方法，设置子图层显隐]</a><br/>
     * <a href='#SubLayers-Property'>[3、通过修改子图参数，设置子图层显隐]</a>
     * @param {String} [options.tokenKey = 'token'] token名
     * @param {String} [options.tokenValue] token值，只有当tokenValue存在时，才会绑定token
     *
     * @summary <h5>支持如下方法：</h5>
     * <a href='#load'>[1、加载图层资源]</a><br/>
     * <a href='#setSubLayer'>[2、设置子图层参数]</a><br/>
     * <a href='#findSublayerById'>[3、根据子图层id查询图层]</a><br/>
     * <a href='#fromJSON'>[4、通过传入的json构造并返回一个新的几何对象]</a><br/>
     * [5、导出为json对象]{@link OGCLayer#toJSON}<br/>
     * [6、克隆几何对象]{@link OGCLayer#clone}
     *
     * @example <caption><h7 id='MapIGS'>添加WMS图层示例</h7></caption>
     * // ES5引入方式
     * const { Map, MapView } = Zondy
     * const { WMSLayer } = Zondy.Layer
     * // ES6引入方式
     * import { Map, MapView, WMSLayer } from "@mapgis/webclient-common"
     * // 初始化图层管理容器
     * const map = new Map();
     * // 初始化二维地图视图对象
     * const mapView = new MapView({
     *   // 视图id
     *   viewId: "viewer-id",
     *   // 图层管理容器
     *   map: map
     * });
     * // 初始化wms图层
     * const wmsLayer = new WMSLayer({
     *   // 服务基地址
     *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMSServer'
     * });
     * // 将图层加入容器中
     * map.add(wmsLayer);
     *
     * // 图层加载完毕
     * wmsLayer.on('layerview-created', function (result) {
     *   console.log("加载完毕:", result.layer)
     *   // 视点跳转
     *   mapView.flyTo({
     *     extent: result.layer.extent
     *   })
     * })
     *
     * @example <caption><h7 id='opacity'>设置图层透明度</h7></caption>
     * // ES5引入方式
     * const { WMSLayer } = Zondy.Layer
     * // ES6引入方式
     * import { WMSLayer } from "@mapgis/webclient-common"
     * // 初始化时设置
     * const wmsLayer = new WMSLayer({
     *   // 服务基地址
     *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMSServer',
     *  // 设置透明度
     *   opacity: 1.0
     * });
     * // 将图层加入容器中
     * map.add(wmsLayer);
     *
     * // 加载完成后设置
     * wmsLayer.on('layerview-created', function (result) {
     *   console.log("加载完毕:", result.layer)
     *   // 设置透明度
     *   wmsLayer.opacity = 0.5
     * })
     *
     * @example <caption><h7 id='visible'>显示或隐藏图层</h7></caption>
     * // ES5引入方式
     * const { WMSLayer } = Zondy.Layer
     * // ES6引入方式
     * import { WMSLayer } from "@mapgis/webclient-common"
     * // 初始化时设置
     * const wmsLayer = new WMSLayer({
     *   // 服务基地址
     *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMSServer',
     *   // 显示或隐藏图层
     *   visible: true
     * });
     * // 将图层加入容器中
     * map.add(wmsLayer);
     *
     * // 加载完成后设置
     * wmsLayer.on('layerview-created', function (result) {
     *   console.log("加载完毕:", result.layer)
     *   // 显示或隐藏图层
     *   wmsLayer.visible = !wmsLayer.visible
     * })
     *
     * @example <caption><h7 id='spatialReference'>设置图层坐标系</h7></caption>
     * // ES5引入方式
     * const { WMSLayer } = Zondy.Layer
     * const { SpatialReference } = Zondy
     * // ES6引入方式
     * import { WMSLayer, SpatialReference } from "@mapgis/webclient-common"
     * // 初始化wms图层
     * const wmsLayer = new WMSLayer({
     *   // 服务基地址
     *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMSServer',
     *   // 指定图层坐标系
     *   spatialReference: new SpatialReference({
     *     // 坐标系的wkid，可在https://epsg.io/网站查询
     *     wkid: 4326
     *   })
     * });
     * // 将图层加入容器中
     * map.add(wmsLayer);
     *
     * @example <caption><h7>删除图层</h7></caption>
     * map.remove(wmsLayer)
     *
     * @example <caption><h7 id='ArcGIS'>添加ArcGIS的WMS图层示例</h7></caption>
     * // ES5引入方式
     * const { Map, MapView } = Zondy
     * const { WMSLayer } = Zondy.Layer
     * // ES6引入方式
     * import { Map, MapView, WMSLayer } from "@mapgis/webclient-common"
     * // 初始化图层管理容器
     * const map = new Map();
     * // 初始化二维地图视图对象
     * const mapView = new MapView({
     *   // 视图id
     *   viewId: "viewer-id",
     *   // 图层管理容器
     *   map: map
     * });
     * // 初始化WMS图层
     * const wmsLayer = new WMSLayer({
     *   url: 'http://219.142.81.85/arcgis/rest/services/10wanZH/MapServer/WMSServer',
     *   // 注意一个WMS图层可能支持多个坐标系，这里指定3857坐标系
     *   spatialReference: new Zondy.SpatialReference({
     *     wkid: 3857
     *   })
     * });
     * // 将图层加入容器中
     * map.add(wmsLayer);
     * // 图层加载完毕
     * wmsLayer.on('layerview-created', function (result) {
     *   console.log("加载完毕:", result.layer)
     *   // 视点跳转
     *   mapView.flyTo({
     *     extent: result.layer.extent
     *   })
     * })
     *
     * @example <caption><h7 id='SubLayers'>初始化时，设置子图层显隐</h7></caption>
     * // ES5引入方式
     * const { Map, MapView } = Zondy
     * const { WMSLayer } = Zondy.Layer
     * // ES6引入方式
     * import { Map, MapView, WMSLayer } from "@mapgis/webclient-common"
     * // 初始化图层管理容器
     * const map = new Map();
     * // 初始化地图视图对象
     * const mapView = new MapView({
     *   // 视图id
     *   viewId: "mapgis-3d-viewer",
     *   // 图层管理容器
     *   map: map
     * });
     * // 初始化WMS图层
     * const wmsLayer = new WMSLayer({
     *   // 服务基地址
     *   url: 'http://{ip}:{port}/igs/rest/services/{ServiceName}/WMSServer',
     *   // 要显示的子图层，若不填，则默显示所有子图层
     *   sublayers: [{
     *     id: 0,
     *     visible: true
     *   }, {
     *     id: 1,
     *     visible: true
     *   }]
     * });
     * map.add(wmsLayer);
     * // 图层加载完毕
     * wmsLayer.on('layerview-created', function (result) {
     *   console.log("加载完毕:", result.layer)
     *   // 视点跳转
     *   mapView.flyTo({
     *     extent: result.layer.extent
     *   })
     * })
     * @example <caption><h7 id='SubLayers-Method'>通过方法，设置子图层显隐</h7></caption>
     * // ES5引入方式
     * const { WMSLayer } = Zondy.Layer
     * // ES6引入方式
     * import { WMSLayer } from "@mapgis/webclient-common"
     * // 初始化WMS图层
     * const wmsLayer = new WMSLayer({
     *   // 服务基地址
     *   url: 'http://{ip}:{port}/igs/rest/services/{ServiceName}/WMSServer'
     * });
     * // 添加到容器中
     * map.add(wmsLayer);
     *
     * // 通过图层id来设置显隐
     * wmsLayer.setSubLayer({
     *   id: 0,
     *   visible: false
     * })
     * // 或者通过图层名称设置显隐
     * wmsLayer.setSubLayer({
     *   name: "Map_Hubei4326:t1",
     *   visible: true
     * })
     * @example <caption><h7 id='SubLayers-Property'>通过修改子图参数，设置子图层显隐</h7></caption>
     * // ES5引入方式
     * const { WMSLayer } = Zondy.Layer
     * // ES6引入方式
     * import { WMSLayer } from "@mapgis/webclient-common"
     * // 初始化WMS图层
     * const wmsLayer = new WMSLayer({
     *   // 服务基地址
     *   url: 'http://{ip}:{port}/igs/rest/services/{ServiceName}/WMSServer'
     * });
     * // 添加到容器中
     * map.add(wmsLayer);
     *
     * // 根据id获取子图层
     * const wmsSubLayer = wmsLayer.findSublayerById(0)
     * // 设置子图层显隐
     * wmsSubLayer.visible = false
     * */

    /**
     * 子图层显隐更新完毕事件，请注意该事件是图层更新事件(layerview-update)的子事件
     * @event WMSLayer#子图层显隐更新完毕事件
     * @property {Object} event 事件对象
     * @property {String} [event.type = 'layerview-update'] 图层更新完毕事件
     * @property {String} [event.message = null] 更新描述
     * @property {Array<UpdateContent>} [event.updateContent = null] 更新详情对象
     * @property {Layer} [event.layer = null] 地图图层对象
     * @property {MapView} [event.layerView = null] 图层的视图对象
     * @property {Layer} [event.sourceTarget = null] 事件发起对象
     * @property {Map} [event.target = null] 事件接收对象
     * @example <caption><h5>子图层显隐更新完毕事件</h5></caption>
     * Layer.on('layerview-update', function (event) {
     *   // 获取更新事件对象
     *   console.log("更新完毕:", event)
     *   // 获取更新详情数组
     *   const updateContent = event.updateContent
     *   // 循环数组，根据事件名进行后续操作
     *   for (let i = 0; i < updateContent.length; i++) {
     *     // 子图层显隐更新完毕事件
     *     if(updateContent[i].name === 'sublayerVisible'){
     *       console.log("子图层显隐更新完毕事件:", event);
     *     }
     *   }
     * });
     */
    class WMSLayer extends OGCLayer {
      constructor(options) {
        super(options)
        options = defaultValue(options, {})
        this._sublayers = defaultValue(options.sublayers, [])
        /**
         * 服务基地址
         * @readonly
         * @member {String} WMSLayer.prototype.url
         */
        this.url = defaultValue(options.url, '')
        /**
         * 用户自定义的子图层参数
         * @member {Array} WMSLayer.prototype.sublayers
         */
        this.sublayers = defaultValue(options.sublayers, [])
        /**
         * 图片宽度，单位px
         * @member {Number} WMSLayer.prototype.imageWidth
         */
        this.imageWidth = defaultValue(options.imageWidth, 256)
        /**
         * 图片高度，单位px
         * @member {Number} WMSLayer.prototype.imageHeight
         */
        this.imageHeight = defaultValue(options.imageHeight, 256)

        /**
         * 所有子图层对象信息
         * @member {Array} WMSLayer.prototype.allSublayers
         */
        this.allSublayers = []
        /**
         * WMS服务要加载的图层id，多个id以逗号分割
         * @readonly
         * @member {String} WMSLayer.prototype.layers
         */
        this.layers = defaultValue(options.layers, undefined)
        /**
         * 图片格式
         * @member {String} WMSLayer.prototype.imageFormat
         */
        this.imageFormat = defaultValue(options.imageFormat, 'image/png')
        /**
         * 图片格式数组，表示服务支持的所有图片格式
         * @readonly
         * @member {Array} WMSLayer.prototype.imageFormats
         */
        this.imageFormats = ['image/png']
        /**
         * 图层中的非数据部分是否透明
         * @member {Boolean} WMSLayer.prototype.imageTransparency
         */
        this.imageTransparency = defaultValue(options.imageTransparency, true)
        /**
         * WMS服务版本号
         * @readonly
         * @member {String} WMSLayer.prototype.version
         */
        this.version = defaultValue(options.version, '1.1.1')
        /**
         * 图层类型
         * @readonly
         * @member {String} WMSLayer.prototype.type
         */
        this.type = LayerType.wms

        /**
         * 图层支持的所有坐标系
         * @member {Array<SpatialReference>} WMSLayer.prototype.spatialReferences
         */
        this.spatialReferences = defaultValue(options.spatialReferences, [])
        // 空间裁剪范围
        this._clippingArea = defaultValue(options.clippingArea, null)

        // 图层在不同坐标系上的全图范围
        this._extentList = []

        // WMSServer对象
        this._WMSServer = new WMSServer({
          url: this.url,
          version: '1.3.0'
        })
      }

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

        const _extentList = []
        for (let i = 0; i < json.extentList.length; i++) {
          _extentList.push(Geometry.fromJSON(json.extentList[i]))
        }
        _layer._extentList = _extentList

        function formatSublayer(sublayer) {
          sublayer.extent = Geometry.fromJSON(sublayer.extent)
          sublayer.spatialReference = SpatialReference.fromJSON(
            sublayer.spatialReference
          )
          for (let j = 0; j < sublayer.spatialReferences.length; j++) {
            sublayer.spatialReferences[j] = SpatialReference.fromJSON(
              sublayer.spatialReferences[j]
            )
          }
        }
        const _sublayers = json.sublayers
        if (_sublayers && _sublayers instanceof Array) {
          _layer._sublayers = new Collection()
          for (let i = 0; i < _sublayers.length; i++) {
            formatSublayer(_sublayers[i])
            _layer._sublayers.add(new WMSSubLayer(_sublayers[i]))
          }
        }

        const _allSublayers = json.allSublayers
        if (_allSublayers && _allSublayers instanceof Array) {
          _layer.allSublayers = new Collection()
          for (let i = 0; i < _allSublayers.length; i++) {
            formatSublayer(_allSublayers[i])
            _layer.allSublayers.add(new WMSSubLayer(_allSublayers[i]))
          }
        }

        return _layer
      }

      /**
       * 加载图层资源<a id='load'></a>
       * @example <caption><h7>不加载图层，仅获取图层信息</h7></caption>
       * // ES5引入方式
       * const { WMSLayer } = Zondy.Layer
       * // ES6引入方式
       * import { WMSLayer } from "@mapgis/webclient-common"
       * // 初始化图层
       * const wmsLayer = new WMSLayer({
       *   // 服务基地址
       *   url: 'http://{ip}:{port}/igs/rest/services/{serviceName}/WMSServer'
       * });
       * wmsLayer.load().then((result) => {
       *   // 获取完图层信息
       *   console.log(wmsLayer)
       * })
       * */
      load() {
        return super.load()
      }

      /**
       * 子类加载服务器端资源的方法
       * @private
       * */
      _load() {
        const self = this
        return this._WMSServer
          .getCapabitities()
          .then((result) => {
            Log.info('WMS信息查询成功:', result)

            // 1.清空之前缓存的元数据信息
            self.spatialReferences = []
            self._extentList = []

            // 2.解析请求回来的元数据
            const data = result.data
            // 2.1获取图层名称
            self.title = data.title

            // 2.2解析图层支持的参考系列表、图层范围列表
            for (let i = 0; i < data.crs.length; i++) {
              for (let j = 0; j < data.boundingBox.length; j++) {
                if (data.crs[i] === data.boundingBox[j].crs) {
                  const spatialReference = new SpatialReference(data.crs[i])
                  const boundingBox = data.boundingBox[j]
                  const extent = new Extent({
                    xmin: Number(boundingBox.minx),
                    ymin: Number(boundingBox.miny),
                    ymax: Number(boundingBox.maxy),
                    xmax: Number(boundingBox.maxx),
                    spatialReference
                  })

                  self.spatialReferences.push(spatialReference)
                  self._extentList.push(extent)
                  break
                }
              }
            }

            // 2.3设置图层的默认空间参考系、全图范围
            // 如果用户没有主动设置就用第一个
            if (isNull(self.spatialReference)) {
              self._spatialReference = self.spatialReferences[0]
            }

            self._extentSrc = self._getExtentBySP(self._spatialReference)

            // 清空子图层
            self.allSublayers = []

            // 2.4获取所有子图层信息
            for (let i = 0; i < data.layer.length; i++) {
              data.layer[i].id = String(i)
              data.layer[i].visible = true
              data.layer[i].spatialReference = self.spatialReference
              data.layer[i].spatialReferences = []
              const _crs = data.layer[i].crs
              for (let j = 0; j < _crs.length; j++) {
                data.layer[i].spatialReferences.push(
                  SpatialReference.fromJSON(_crs[i])
                )
              }
              const _boundingBox = data.layer[i].boundingBox
              for (let j = 0; j < _boundingBox.length; j++) {
                if (`EPSG:${self.spatialReference.wkid}` === _boundingBox[j].crs) {
                  data.layer[i].extent = new Extent({
                    xmin: Number(_boundingBox[j].minx),
                    ymin: Number(_boundingBox[j].miny),
                    xmax: Number(_boundingBox[j].maxx),
                    ymax: Number(_boundingBox[j].maxy)
                  })
                }
              }
              self.allSublayers.push(
                new WMSSubLayer(
                  Object.assign(data.layer[i], {
                    layer: this
                  })
                )
              )
            }

            // 2.5获取所有要显示子图层名
            if (self._sublayers.length > 0) {
              // 生成子图层对象
              for (let i = 0; i < data.layer.length; i++) {
                for (let j = 0; j < self._sublayers.length; j++) {
                  if (
                    String(self._sublayers[j].id) === String(data.layer[i].id) ||
                    String(self._sublayers[j].name) === String(data.layer[i].name)
                  ) {
                    self._sublayers[j] = new WMSSubLayer(
                      Object.assign(data.layer[i], self._sublayers[j], {
                        layer: this
                      })
                    )
                    break
                  }
                }
              }
              self._getLayersFromSubLayers()
            } else {
              // 没有则全部显示
              self._getLayersFromAllSubLayers()
            }
            return new Promise((resolve) => {
              // 图层加载完毕
              self.loadStatus = LoadStatus.loaded
              self.loaded = true
              resolve(self)
            })
          })
          .catch((result) => {
            self.loadStatus = Log.error('WMS信息查询失败:', result)
          })
      }

      /**
       * 通过图层名称或id来设置子图层，若找到相同图层仅会覆盖相同名称的参数，若没有则在最后新增一个<a id='setSubLayer'></a>
       * @param {WMSSubLayer | Object} wmsSublayer 子图层对象
       * @example <caption><h7>设置子图层参数</h7></caption>
       * // ES5引入方式
       * const { WMSLayer } = Zondy.Layer
       * // ES6引入方式
       * import { WMSLayer } from "@mapgis/webclient-common"
       * // 初始化WMS图层
       * const wmsLayer = new WMSLayer({
       *   // 服务基地址
       *   url: 'http://{ip}:{port}/igs/rest/services/{ServiceName}/WMSServer'
       * });
       * map.add(wmsLayer);
       * // 通过setSubLayer方法设置子图层显隐
       * // 通过图层id来设置显隐
       * wmsLayer.setSubLayer({
       *   id: 0,
       *   visible: false
       * })
       * // 或者通过图层名称设置显隐
       * wmsLayer.setSubLayer({
       *   name: "Map_Hubei4326:t1",
       *   visible: true
       * })
       * */
      setSubLayer(wmsSublayer) {
        // 更新子图层
        setSublayer(this, wmsSublayer, WMSSubLayer)
        // 更新layers信息
        this._getLayersFromAllSubLayers()
        // 发送更新事件
        this._fireUpdateEvent('更新子图层', [
          {
            name: 'sublayerVisible',
            params: [this],
            dataChanged: true,
            operationType: 'method'
          }
        ])
      }

      /**
       * 从sublayers中获取layers字符串
       * @private
       * @return {String} layers字符串
       * */
      _getLayersFromSubLayers() {
        let layers = ''

        // 获取要显示的子图层
        for (let i = 0; i < this._sublayers.length; i++) {
          if (this._sublayers[i].visible && this._sublayers[i].name) {
            layers += `${this._sublayers[i].name},`
          }
        }

        // 删除最后一个逗号
        layers = layers.substring(0, layers.length - 1)
        this.layers = layers

        return layers
      }

      /**
       * 从allSublayers中获取layers字符串
       * @private
       * @return {String} layers字符串
       * */
      _getLayersFromAllSubLayers() {
        let layers = ''

        for (let i = 0; i < this.allSublayers.length; i++) {
          if (this.allSublayers[i].visible && this.allSublayers[i].name) {
            layers += `${this.allSublayers[i].name},`
          }
        }
        layers = layers.substring(0, layers.length - 1)
        this.layers = layers

        return layers
      }

      /**
       * 获取指定空间参照系对应的范围
       * @private
       * @param {SpatialReference} sp 空间参照系，必须是该图层支持的空间参照系
       * @return {Extent} 图层在指定空间参照系的全图范围
       * */
      _getExtentBySP(sp) {
        let extent = null

        if (!isNull(sp)) {
          for (let i = 0; i < this._extentList.length; i++) {
            if (this._extentList[i].spatialReference.equals(sp)) {
              extent = this._extentList[i]

              break
            }
          }
        }

        return extent
      }

      /**
       * 根据子图层id查询图层<a id='findSublayerById'></a>
       * @param {String} sublayerID 图层ID
       * @return {IGSVectorTileSubLayer} 子图层
       * @example <caption><h7>根据子图层id查询图层</h7></caption>
       * // ES5引入方式
       * const { WMSLayer } = Zondy.Layer
       * // ES6引入方式
       * import { WMSLayer } from "@mapgis/webclient-common"
       * // 初始化WMS图层
       * const wmsLayer = new WMSLayer({
       *   // 服务基地址
       *   url: 'http://{ip}:{port}/igs/rest/services/{ServiceName}/WMSServer'
       * });
       * map.add(wmsLayer);
       * // 根据id获取子图层
       * const wmsSubLayer = wmsLayer.findSublayerById(0)
       */
      findSublayerById(sublayerID) {
        for (let i = 0; i < this.allSublayers.length; i++) {
          if (this.allSublayers[i].id === sublayerID) {
            return this.allSublayers[i]
          }
        }
        return null
      }

      toJSON() {
        const _json = super.toJSON()
        _json.url = this.url
        _json.imageWidth = this.imageWidth
        _json.imageHeight = this.imageHeight
        _json.imageFormat = this.imageFormat
        _json.imageFormats = this.imageFormats
        _json.imageTransparency = this.imageTransparency
        _json.version = this.version
        _json.type = this.type
        _json.layers = this.layers
        const _extentList = []
        for (let i = 0; i < this._extentList.length; i++) {
          _extentList.push(toJSON(this._extentList[i], Extent))
        }
        _json.extentList = _extentList
        const _sublayers = []
        this.sublayers.forEach(function (sublayer) {
          _sublayers.push(toJSON(sublayer, WMSSubLayer))
        })
        _json.sublayers = _sublayers
        const _allSublayers = []
        this.allSublayers.forEach(function (sublayer) {
          _allSublayers.push(toJSON(sublayer, WMSSubLayer))
        })
        _json.allSublayers = _allSublayers

        return _json
      }
    }

    Object.defineProperties(WMSLayer.prototype, {
      /**
       * 子图层对象
       * @member WMSLayer.prototype.sublayers
       * @type {Array}
       */
      sublayers: {
        get() {
          return this._sublayers
        },
        set(value) {
          this._sublayers = value
        }
      },
      /**
       * 图层坐标系对象
       * @member Layer.prototype.spatialReference
       * @type {SpatialReference}
       */
      spatialReference: {
        set(newSpatialReference) {
          let i = 0
          if (
            newSpatialReference &&
            this.spatialReferences &&
            this.spatialReferences instanceof Array
          ) {
            for (; i < this.spatialReferences.length; i++) {
              if (this.spatialReferences[i].equals(newSpatialReference)) {
                this._spatialReference = newSpatialReference
                this._fireUpdateEvent('修改图层坐标系', [
                  {
                    name: 'spatialReference',
                    params: [this._spatialReference],
                    dataChanged: true,
                    operationType: 'property'
                  }
                ])
                break
              }
            }

            if (i === this.spatialReferences.length) {
              throw new Error('该图层不支持所指定的空间参考系,设置失败！')
            }
          }
        },
        get() {
          return this._spatialReference
        }
      },
      /**
       * 图层范围，从服务中读取，仅会请求在该范围内的瓦片
       * @readonly
       * @member {String} MapImageLayer.prototype.extent
       */
      extent: {
        get() {
          return this._getExtentBySP(this.spatialReference)
        }
      }
    })

    /**
     * 通过url创建图层对象
     * @param {String} url 服务基地址
     * @return {WMSLayer} 新的图层对象
     * */
    WMSLayer.fromServerUrl = function (url) {
      return new WMSLayer({
        url
      })
    }

    Object.defineProperties(WMSLayer.prototype, {
      /**
       * 空间裁剪范围
       * @member WMSLayer.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.WMSLayer = WMSLayer
    export default WMSLayer