    import {
      Extent,
      Geometry,
      Polygon,
      SpatialReference,
      LineString,
      MultiLineString,
      Point,
      Circle,
      MultiPolygon,
      MultiPoint
    } from '../base/geometry'
    import Log from '../util/Log'
    import {defaultValue, isBoolean, isNull, isNumber, isString} from '../util'
    import {Color, Feature, FeatureSet} from '../base'
    import Config from './Config';

    /**
     * @private
     * @description 获取查询参数字符串
     * @param fields 字段名数组
     * @param options 查询参数
     * @param checkOptions 检测规则
     * @return String GUID
     */
    function getParameters(fields, options, checkOptions) {
      let url = ''
      for (let i = 0; i < fields.length; i++) {
        // 获取查询条件
        const _filter = defaultValue(
          options[fields[i]],
          checkOptions[fields[i]].default
        )
        // 必须不为空
        if (_filter !== undefined) {
          let str = ''
          // 没有process参数，走类型判断
          if (isNull(checkOptions[fields[i]].process)) {
            // 根据类型进行数据处理
            switch (checkOptions[fields[i]].type) {
              case 'String':
              case 'Number':
              case 'Boolean':
                url += `&${checkOptions[fields[i]].alias || fields[i]}=${_filter}`
                break
              case 'Geometry':
              case 'Point':
              case 'MultiPoint':
              case 'Extent':
              case 'Circle':
              case 'LineString':
              case 'MultiLineString':
              case 'Polygon':
              case 'MultiPolygon':
                url += `&${
                  fields[i]
                }=${_filter.toString()}&geometryType=${_filter.getIGSType()}`
                break
              case 'layerDefs':
                str = '['
                for (let i = 0; i < _filter.length; i++) {
                  if (
                    _filter[i] instanceof Object &&
                    !(_filter[i] instanceof Array)
                  ) {
                    str += '{'
                    Object.keys(_filter[i]).forEach((key) => {
                      if (_filter[i].hasOwnProperty(key)) {
                        str += `"${key}":"${_filter[i][key]}",`
                      }
                    })
                    str = str.substring(0, str.length - 1)
                    str += '},'
                  }
                }
                if (_filter.length > 0) {
                  str = str.substring(0, str.length - 1)
                }
                str += ']'

                if (str !== '[]') {
                  url += `&${fields[i]}=${str}`
                }
                break
              case 'OutStatistics':
                str += '['
                for (let i = 0; i < _filter.length; i++) {
                  if (
                    _filter[i] instanceof Object &&
                    !(_filter[i] instanceof Array)
                  ) {
                    str += '{'
                    Object.keys(_filter[i]).forEach((key) => {
                      if (_filter[i].hasOwnProperty(key)) {
                        if (
                          key === 'statisticType' ||
                          key === 'onStatisticField' ||
                          key === 'outStatisticFieldName'
                        ) {
                          str += `"${key}":"${_filter[i][key]}",`
                        }
                      }
                    })
                    str = str.substring(0, str.length - 1)
                    str += '},'
                  }
                }
                if (_filter.length > 0) {
                  str = str.substring(0, str.length - 1)
                }
                str += ']'

                if (str !== '[]') {
                  url += `&${fields[i]}=${str}`
                }
                break
              case 'FeatureSet':
                str = `&${fields[i]}=${JSON.stringify(
                  options[fields[i]].toGeoJSON()
                )}`
                url += str
                break
              case 'FeatureCollection':
                url += `&${fields[i]}=${JSON.stringify(options[fields[i]])}`
                break
              default:
                url += `&${fields[i]}=${_filter}`
            }
          } else if (typeof checkOptions[fields[i]].process === 'string') {
            // 有定义好的处理类型
            switch (checkOptions[fields[i]].process) {
              case 'igsGeometryServer':
                url += `&${fields[i]}=${JSON.stringify(_filter.toGeoJSON())}&srs=`
                // 确保spatialReference存在
                if (_filter.spatialReference) {
                  // 是SpatialReference对象
                  if (_filter.spatialReference instanceof SpatialReference) {
                    url += _filter.spatialReference.toString()
                  } else if (
                    _filter.spatialReference instanceof Object &&
                    !(_filter.spatialReference instanceof Array)
                  ) {
                    // 外部传入一个对象
                    url += _filter.spatialReference.wkt
                      ? _filter.spatialReference.wkt
                      : 'EPSG:4326'
                  } else if (typeof _filter.spatialReference === 'string') {
                    // 传入字符串
                    url += _filter.spatialReference
                  }
                } else {
                  // spatialReference不存在，默认EPSG:4326
                  url += 'EPSG:4326'
                }
                break
              case 'igsGeometryServerNoSRS':
                url += `&${fields[i]}=${JSON.stringify(_filter.toGeoJSON())}`
                break
              case 'igsRange$':
                url += `&${
                  checkOptions[fields[i]].alias || fields[i]
                }=${_filter.toIGSOldString()}`
                break
              case 'igsGeometryOld':
                if (_filter.type === 'Point' || _filter.type === 'LineString') {
                  if (_filter.type === 'Point' && _filter.hasZ === true) {
                    url += `&${fields[i]}=${_filter.toString()},${
                      options['distance'] || checkOptions['distance'].default
                    }&geometryType=${_filter.getIGSType()}`
                  } else {
                    url += `&${fields[i]}=${_filter.toString()};${
                      options['distance'] || checkOptions['distance'].default
                    }&geometryType=${_filter.getIGSType()}`
                  }
                } else {
                  url += `&${
                    fields[i]
                  }=${_filter.toString()}&geometryType=${_filter.getIGSType()}`
                }
                break
              default:
                url += `&${
                  fields[i]
                }=${_filter.toString()}&geometryType=${_filter.getIGSType()}`
            }
          } else if (checkOptions[fields[i]].process instanceof Function) {
            // 方法类型
            url += checkOptions[fields[i]].process(
              options[fields[i]],
              checkOptions[fields[i]].default
            )
          }
        }
      }

      return url
    }

    function getParametersObject(fields, options, checkOptions) {
      const data = {}
      for (let i = 0; i < fields.length; i++) {
        // 获取查询条件
        const _filter = defaultValue(
          options[fields[i]],
          checkOptions[fields[i]].default
        )
        // 必须不为空
        if (_filter !== undefined) {
          // 没有process参数，走类型判断
          if (isNull(checkOptions[fields[i]].process)) {
            // 根据类型进行数据处理
            switch (checkOptions[fields[i]].type) {
              case 'String':
              case 'Number':
              case 'Boolean':
              default:
                data[checkOptions[fields[i]].alias || fields[i]] = _filter
                break
              case 'Geometry':
              case 'Point':
              case 'MultiPoint':
              case 'Extent':
              case 'Circle':
              case 'LineString':
              case 'MultiLineString':
              case 'Polygon':
              case 'MultiPolygon':
                data[
                checkOptions[fields[i]].alias || fields[i]
                  ] = `${_filter.toString()}&geometryType=${_filter.getIGSType()}`
                break
            }
          } else if (typeof checkOptions[fields[i]].process === 'string') {
            // 有定义好的处理类型
            switch (checkOptions[fields[i]].process) {
              case 'igsDots':
                data[checkOptions[fields[i]].alias || 'Dots'] = _filter.toDots()
                break
              case 'toOldIGSGeometry':
                switch (_filter.type) {
                  case 'Point':
                    data[checkOptions[fields[i]].alias || 'Pnt'] =
                      _filter.toOldIGSGeometry().PntGeom[0]
                    break
                  case 'LineString':
                    data[checkOptions[fields[i]].alias || 'Line'] =
                      _filter.toOldIGSGeometry().LinGeom[0]
                    break
                  case 'Polygon':
                    data[checkOptions[fields[i]].alias || 'Reg'] =
                      _filter.toOldIGSGeometry().RegGeom[0]
                    break
                  default:
                }
                break
              default:
                data[checkOptions[fields[i]].alias || fields[i]] = _filter
            }
          } else if (checkOptions[fields[i]].process instanceof Function) {
            // 方法类型
            data[fields[i]] = checkOptions[fields[i]].process(
              options[fields[i]],
              checkOptions[fields[i]].default
            )
          }
        }
      }

      return JSON.stringify(data)
    }

    /**
     * 检测输入参数类型是否是OutStatistics
     * @private
     * @param {OutStatistics} param 输入参数
     * @return {Boolean} 是否是正确的类型
     * */
    function isOutStatistics(param) {
      // 首先必须是数组
      if (!(param instanceof Array)) {
        return false
      }

      // 循环所有子元素
      for (let i = 0; i < param.length; i++) {
        // 子元素一定是对象
        if (!(param[i] instanceof Object)) {
          return false
        }

        // 子元素不可以是数组
        if (param[i] instanceof Object && param[i] instanceof Array) {
          return false
        }

        // 子元素必须包含statisticType、onStatisticField以及outStatisticFieldName
        if (
          !param[i].hasOwnProperty('statisticType') ||
          !param[i].hasOwnProperty('onStatisticField') ||
          !param[i].hasOwnProperty('outStatisticFieldName')
        ) {
          return false
        }

        // 子元素的statisticType、onStatisticField以及outStatisticFieldName必须不为空
        if (
          isNull(param[i]['statisticType']) ||
          isNull(param[i]['onStatisticField']) ||
          isNull(param[i]['outStatisticFieldName'])
        ) {
          return false
        }

        // 子元素的statisticType、onStatisticField以及outStatisticFieldName必须为String类型
        if (
          !isString(param[i]['statisticType']) ||
          !isString(param[i]['onStatisticField']) ||
          !isString(param[i]['outStatisticFieldName'])
        ) {
          return false
        }
      }

      return true
    }

    /**
     * 检测输入参数类型是否正确
     * @private
     * @param {String} type 输入参数类型
     * @param {Any} param 输入参数
     * @return {Boolean} 是否是正确的类型
     * */
    function checkType(type, param) {
      if (typeof type === 'function') {
        return type(param)
      }
      let flag
      switch (type) {
        case 'String':
          flag = isString(param)
          break
        case 'Number':
          flag = isNumber(param)
          break
        case 'Boolean':
          flag = isBoolean(param)
          break
        case 'Extent':
          flag = param instanceof Extent
          break
        case 'Geometry':
          flag = param instanceof Geometry
          break
        case 'Point':
          flag = param instanceof Point
          break
        case 'Polygon':
          flag = param instanceof Polygon
          break
        case 'MultiPolygon':
          flag = param instanceof MultiPolygon
          break
        case 'Circle':
          flag = param instanceof Circle
          break
        case 'LineString':
          flag = param instanceof LineString
          break
        case 'MultiLineString':
          flag = param instanceof MultiLineString
          break
        case 'LineString | MultiLineString':
          flag = param instanceof LineString || param instanceof MultiLineString
          break
        case 'Polygon | Extent':
          flag = param instanceof Polygon || param instanceof Extent
          break
        case 'Array':
          flag = param instanceof Array
          break
        case 'Object':
          flag = param instanceof Object
          break
        case 'OutStatistics':
          flag = isOutStatistics(param)
          break
        case 'FeatureSet':
          flag = param instanceof FeatureSet
          break
        case 'FeatureCollection':
          flag =
            param instanceof Object &&
            !(param instanceof Array) &&
            param.hasOwnProperty('features') &&
            param.type === 'FeatureCollection'
          break
        case 'Color':
          flag = param instanceof Color
          break
        default:
          flag = isString(param)
      }

      return flag
    }

    /**
     * 检测输入参数正确性
     * @private
     * @param {Object} options 输入参数
     * @param {Object} checkOptions 检测规则
     * */
    function checkParam(options, checkOptions) {
      // 是否检测通过
      let isChecked = true
      // 错误信息
      let errorMessage = ''
      // 错误类型
      let errorType = ''
      // 错误变量名
      let wrongKey
      // 请求参数
      let queryString = ''

      // 不通过检测不走下面的逻辑
      try {
        // 检测类型
        let flag = true
        Object.keys(checkOptions).forEach(function (key) {
          if (
            (options.hasOwnProperty(key) && checkOptions.hasOwnProperty(key)) ||
            (checkOptions.hasOwnProperty(key) && checkOptions[key].required)
          ) {
            // 检测空输入
            if (checkOptions[key].required) {
              // 不是多选一
              if (isNull(checkOptions[key].oneOf)) {
                if (isNull(options[key])) {
                  wrongKey = key
                  throw new Error('isNull')
                }
              } // 是多选一，如果都为空，才报错
              else {
                // 是否都为空
                let allIsNull = false

                // 确定本身是否为空
                if (isNull(options[key])) {
                  allIsNull = true
                }

                // 确定其他的可选参数是否为空
                for (let i = 0; i < checkOptions[key].oneOf.length; i++) {
                  if (!isNull(options[checkOptions[key].oneOf[i]])) {
                    allIsNull = false
                    break
                  }
                }

                // 如果都为空，报错
                if (allIsNull) {
                  wrongKey = `${key},${checkOptions[key].oneOf.toString()}`
                  throw new Error('isNull')
                }
              }
            }

            // 由于上面做了多选一的判断，这里进行下非空判断
            if (!isNull(options[key])) {
              flag = checkType(checkOptions[key].type, options[key])
            }

            if (!flag) {
              wrongKey = key
              throw new Error('wrongType')
            }
          }
        })

        if (flag) {
          const fields = []
          Object.keys(checkOptions).forEach((key) => {
            if (checkOptions.hasOwnProperty(key)) {
              fields.push(key)
            }
          })
          if (options.useObject) {
            queryString = getParametersObject(fields, options, checkOptions)
          } else {
            queryString = getParameters(fields, options, checkOptions)
          }
        }
      } catch (e) {
        isChecked = false
        switch (e.message) {
          case 'isNull':
            errorMessage = `${wrongKey}值不能为空！`
            errorType = 'isNull'
            Log.error(errorMessage)
            break
          case 'wrongType':
            errorMessage = `${wrongKey}类型错误！`
            errorType = 'isWrongType'
            Log.error(errorMessage)
            break
          default:
            errorMessage = `${wrongKey}值不能为空！`
            errorType = 'isNull'
            Log.error(errorMessage)
        }
      }

      return {
        isChecked,
        errorMessage,
        errorType,
        queryString
      }
    }

    /**
     * 验证所有PathParameter参数的正确性，PathParameter里的参数都是必填参数，必须验证正确性
     * @private
     * @param {Object} checkOptions 验证对象
     * @param {Object} options 请求参数对象
     * @return {Object} 是否验证通过对象
     * */
    function checkPathParameters(checkOptions, options) {
      let errorType = ''
      let errorMessage = ''
      let isChecked = true

      // try&catch是为了跳出forEach的循环
      try {
        Object.keys(checkOptions).forEach((key) => {
          // 要检测某个参数
          if (checkOptions.hasOwnProperty(key)) {
            // 有这个参数的值
            if (options.hasOwnProperty(key)) {
              const param = options[key]

              // 非空判断
              if (isNull(param)) {
                errorType = 'isNull'
                isChecked = false
                throw new Error(`${key}不能为空！`)
              }

              // 类型判断
              if (!checkType(checkOptions[key].type, options[key])) {
                errorType = 'isWrongType'
                isChecked = false
                throw new Error(`${key}类型错误！`)
              }
            } else {
              // 没有这个参数的值
              errorType = 'isNull'
              isChecked = false
              throw new Error(`${key}不能为空！`)
            }
          }
        })
      } catch (e) {
        Log.error(e)
        errorMessage = e
        return {
          isChecked,
          errorMessage,
          errorType
        }
      }

      return {
        isChecked,
        errorMessage,
        errorType
      }
    }

    /**
     * 获取XML的DOM对象
     * @param xml xml字符串对象
     * @return string
     */
    function getDoc(xml) {
      let xmlDoc = null
      if (window.DOMParser) {
        const parser = new DOMParser()
        xmlDoc = parser.parseFromString(xml, 'text/xml')
      } else {
        // IE
        // eslint-disable-next-line no-undef
        xmlDoc = new ActiveXObject('Microsoft.XMLDOM')
        xmlDoc.async = 'false'
        xmlDoc.loadXML(xml)
      }

      return xmlDoc
    }

    /**
     * 从DOM元素中获取信息
     * @param dom dom元素
     * @param WMSInfo WMS信息对象
     */
    function getWMSInfoFromDOM(dom, WMSInfo) {
      // 取得整个图层的Title信息
      if (dom.nodeName === 'Name') {
        WMSInfo.name = dom.innerHTML
      } else if (dom.nodeName === 'Abstract') {
        // WMS的1.1.1版本信息
        WMSInfo.abstract = dom.innerHTML
      } else if (dom.nodeName === 'Title') {
        let title = dom.innerHTML
        // 注意排除文件夹名
        if (title.indexOf(':') > -1) {
          title = title.split(':')[1]
        }
        WMSInfo.title = title
      } else if (dom.nodeName === 'SRS') {
        // 取得整个图层的SRS信息
        WMSInfo.srs.push(dom.innerHTML)
      } else if (dom.nodeName === 'CRS') {
        // 取得整个图层的CRS信息
        WMSInfo.crs.push(dom.innerHTML)
      } else if (dom.nodeName === 'BoundingBox') {
        // 取得整个图层的BoundingBox信息
        let boundingBox = {}
        // WMS 1.1.1版本是SRS
        if (dom.attributes.SRS) {
          boundingBox = {
            minx: dom.attributes.minx.value,
            miny: dom.attributes.miny.value,
            maxx: dom.attributes.maxx.value,
            maxy: dom.attributes.maxy.value
          }
          boundingBox.srs = dom.attributes.SRS.value
        } else if (dom.attributes.CRS) {
          const EPSG = dom.attributes.CRS.value
          const epsgNo = Number(EPSG.split(':')[1])
          // 高斯坐标系，xy反转
          if (
            (epsgNo >= 2327 && epsgNo <= 2442) ||
            (epsgNo >= 4491 && epsgNo <= 4554) ||
            (epsgNo >= 21413 && epsgNo <= 21423) ||
            (epsgNo >= 21473 && epsgNo <= 21483)
          ) {
            boundingBox = {
              minx: dom.attributes.miny.value,
              miny: dom.attributes.minx.value,
              maxx: dom.attributes.maxy.value,
              maxy: dom.attributes.maxx.value
            }
          }
          // 经纬度，xy反转
          else if (
            epsgNo === 4326 ||
            epsgNo === 4214 ||
            epsgNo === 4490 ||
            epsgNo === 4610
          ) {
            boundingBox = {
              minx: dom.attributes.miny.value,
              miny: dom.attributes.minx.value,
              maxx: dom.attributes.maxy.value,
              maxy: dom.attributes.maxx.value
            }
          }
          // 其他xy正常
          else {
            boundingBox = {
              minx: dom.attributes.minx.value,
              miny: dom.attributes.miny.value,
              maxx: dom.attributes.maxx.value,
              maxy: dom.attributes.maxy.value
            }
          }
          // WMS 1.3.0版本是CRS
          boundingBox.crs = dom.attributes.CRS.value
        }
        WMSInfo.boundingBox.push(boundingBox)
      } else if (dom.nodeName === 'LatLonBoundingBox') {
        // WMS的1.1.1版本信息
        WMSInfo.latLonBoundingBox = {
          minx: dom.attributes.miny.value,
          miny: dom.attributes.minx.value,
          maxx: dom.attributes.maxy.value,
          maxy: dom.attributes.maxx.value
        }
      } else if (dom.nodeName === 'EX_GeographicBoundingBox') {
        // WMS的1.3.0版本信息
        WMSInfo.geographicBoundingBox = {
          westBoundLongitude: dom.childNodes[0].innerHTML,
          eastBoundLongitude: dom.childNodes[1].innerHTML,
          southBoundLatitude: dom.childNodes[2].innerHTML,
          northBoundLatitude: dom.childNodes[3].innerHTML
        }
      }
    }

    /**
     * 将XML的Document对象转换为JSON字符串
     * @param xmlDoc xml的Document对象
     * @param version WMS版本
     * @return {Object} WMS的元数据信息
     */
    function getWMSInfoFromXML(xmlDoc, version) {
      const WMSInfo = {
        boundingBox: [],
        layer: []
      }

      if (version === '1.3.0') {
        WMSInfo.crs = []
      } else {
        WMSInfo.srs = []
      }

      // 获取xml文档的所有子节点
      const nodeList = xmlDoc.childNodes

      for (let i = 0; i < nodeList.length; i++) {
        // 取得localName为WMT_MS_Capabilities的子元素，注意一定是localName
        if (
          nodeList[i].nodeName === 'WMT_MS_Capabilities' ||
          nodeList[i].nodeName === 'WMS_Capabilities'
        ) {
          const childNodes = nodeList[i].childNodes
          for (let j = 0; j < childNodes.length; j++) {
            // 只取nodeName为Capability的子元素
            if (childNodes[j].nodeName === 'Capability') {
              const cbChildren = childNodes[j].childNodes
              for (let k = 0; k < cbChildren.length; k++) {
                // 取Capability里面名字为Layer的子元素
                if (cbChildren[k].nodeName === 'Layer') {
                  const layerChildren = cbChildren[k].childNodes
                  // 取得整个图层的WMS信息
                  for (let m = 0; m < layerChildren.length; m++) {
                    // 取得所有Layer信息
                    if (layerChildren[m].nodeName === 'Layer') {
                      const layerInfos = layerChildren[m].childNodes
                      const layerInfo = {
                        boundingBox: []
                      }
                      if (version === '1.3.0') {
                        layerInfo.crs = []
                      } else {
                        layerInfo.srs = []
                      }
                      for (let n = 0; n < layerInfos.length; n++) {
                        // 取得单个图层的WMS信息
                        getWMSInfoFromDOM(layerInfos[n], layerInfo)
                      }
                      WMSInfo.layer.push(layerInfo)
                    } else {
                      // 取得其他信息
                      getWMSInfoFromDOM(layerChildren[m], WMSInfo)
                    }
                  }
                  break
                }
              }
              break
            }
          }
          break
        }
      }

      return WMSInfo
    }

    /**
     * 将XML的Document对象转换为JSON字符串
     * @param xmlDoc xml的Document对象
     * @return {Object} WMTS的元数据信息
     */
    function getWMTSInfoFromXML(xmlDoc) {
      const rootChildren = xmlDoc.childNodes
      const WMTSInfo = {
        layer: {
          infoFormat: [],
          tileMatrixSetLink: []
        },
        tileMatrixSet: []
      }

      for (let i = 0; i < rootChildren.length; i++) {
        // 仅取Capabilities上的信息
        if (rootChildren[i].nodeName === 'Capabilities') {
          const cbChildren = rootChildren[i].childNodes
          for (let j = 0; j < cbChildren.length; j++) {
            // 仅取Contents上的信息
            if (cbChildren[j].nodeName === 'Contents') {
              const ctChildren = cbChildren[j].childNodes
              for (let k = 0; k < ctChildren.length; k++) {
                // 获取Layer上的信息
                if (ctChildren[k].nodeName === 'Layer') {
                  const layerInfos = ctChildren[k].childNodes
                  for (let x = 0; x < layerInfos.length; x++) {
                    if (layerInfos[x].nodeName === 'ows:Title') {
                      WMTSInfo.layer.title = layerInfos[x].innerHTML
                    } else if (layerInfos[x].nodeName === 'ows:Identifier') {
                      WMTSInfo.layer.identifier = layerInfos[x].innerHTML
                    } else if (layerInfos[x].nodeName === 'ows:BoundingBox') {
                      const boundingBox = {}
                      for (let l = 0; l < layerInfos[x].childNodes.length; l++) {
                        if (
                          layerInfos[x].childNodes[l].nodeName === 'ows:LowerCorner'
                        ) {
                          boundingBox.lowerCorner =
                            layerInfos[x].childNodes[l].innerHTML
                        }
                        if (
                          layerInfos[x].childNodes[l].nodeName === 'ows:UpperCorner'
                        ) {
                          boundingBox.upperCorner =
                            layerInfos[x].childNodes[l].innerHTML
                        }
                      }
                      WMTSInfo.layer.boundingBox = boundingBox
                    } else if (layerInfos[x].nodeName === 'ows:WGS84BoundingBox') {
                      WMTSInfo.layer.WGS84BoundingBox = {
                        lowerCorner: layerInfos[x].childNodes[0].innerHTML,
                        upperCorner: layerInfos[x].childNodes[1].innerHTML
                      }
                    } else if (layerInfos[x].nodeName === 'Style') {
                      const Style = {}
                      for (let l = 0; l < layerInfos[x].childNodes.length; l++) {
                        if (
                          layerInfos[x].childNodes[l].nodeName === 'ows:Identifier'
                        ) {
                          Style.identifier = layerInfos[x].childNodes[l].innerHTML
                        }
                        if (layerInfos[x].childNodes[l].nodeName === 'ows:Title') {
                          Style.title = layerInfos[x].childNodes[l].innerHTML
                        }
                      }
                      WMTSInfo.layer.Style = Style
                    } else if (layerInfos[x].nodeName === 'Format') {
                      WMTSInfo.layer.format = layerInfos[x].innerHTML
                    } else if (layerInfos[x].nodeName === 'InfoFormat') {
                      WMTSInfo.layer.infoFormat.push(layerInfos[x].innerHTML)
                    } else if (layerInfos[x].nodeName === 'TileMatrixSetLink') {
                      const links = layerInfos[x].childNodes
                      const TileMatrixSetLink = {
                        tileMatrixSetLimits: []
                      }

                      for (let w = 0; w < links.length; w++) {
                        if (links[w].nodeName === 'TileMatrixSet') {
                          TileMatrixSetLink.tileMatrixSet = links[w].innerHTML
                        } else if (links[w].nodeName === 'TileMatrixSetLimits') {
                          const limits = links[w].childNodes

                          for (let y = 0; y < limits.length; y++) {
                            const tls = limits[y].childNodes
                            const TileMatrixLimits = {}

                            for (let z = 0; z < tls.length; z++) {
                              if (tls[z].nodeName === 'TileMatrix') {
                                TileMatrixLimits.tileMatrix = tls[z].innerHTML
                              } else if (tls[z].nodeName === 'MinTileRow') {
                                TileMatrixLimits.minTileRow = tls[z].innerHTML
                              } else if (tls[z].nodeName === 'MaxTileRow') {
                                TileMatrixLimits.maxTileRow = tls[z].innerHTML
                              } else if (tls[z].nodeName === 'MinTileCol') {
                                TileMatrixLimits.minTileCol = tls[z].innerHTML
                              } else if (tls[z].nodeName === 'MaxTileCol') {
                                TileMatrixLimits.maxTileCol = tls[z].innerHTML
                              }
                            }

                            TileMatrixSetLink.tileMatrixSetLimits.push(
                              TileMatrixLimits
                            )
                          }
                        }
                      }

                      WMTSInfo.layer.tileMatrixSetLink.push(TileMatrixSetLink)
                    }
                  }
                } else if (ctChildren[k].nodeName === 'TileMatrixSet') {
                  // 获取TileMatrixSet上的信息
                  const TileMatrixSet = ctChildren[k].childNodes
                  const tileMatrixSet = {
                    tileMatrix: []
                  }

                  for (let m = 0; m < TileMatrixSet.length; m++) {
                    if (TileMatrixSet[m].nodeName === 'ows:Title') {
                      tileMatrixSet.title = TileMatrixSet[m].innerHTML
                    } else if (TileMatrixSet[m].nodeName === 'ows:Abstract') {
                      tileMatrixSet.abstract = TileMatrixSet[m].innerHTML
                    } else if (TileMatrixSet[m].nodeName === 'ows:Identifier') {
                      tileMatrixSet.identifier = TileMatrixSet[m].innerHTML
                    } else if (TileMatrixSet[m].nodeName === 'ows:SupportedCRS') {
                      tileMatrixSet.supportedCRS = TileMatrixSet[m].innerHTML
                    } else if (TileMatrixSet[m].nodeName === 'TileMatrix') {
                      const TileMatrix = TileMatrixSet[m].childNodes
                      const tileMatrix = {}

                      for (let n = 0; n < TileMatrix.length; n++) {
                        if (TileMatrix[n].nodeName === 'ows:Identifier') {
                          tileMatrix.identifier = TileMatrix[n].innerHTML
                        } else if (TileMatrix[n].nodeName === 'ScaleDenominator') {
                          tileMatrix.scaleDenominator = TileMatrix[n].innerHTML
                        } else if (TileMatrix[n].nodeName === 'TopLeftCorner') {
                          tileMatrix.topLeftCorner = TileMatrix[n].innerHTML
                        } else if (TileMatrix[n].nodeName === 'TileWidth') {
                          tileMatrix.tileWidth = TileMatrix[n].innerHTML
                        } else if (TileMatrix[n].nodeName === 'TileHeight') {
                          tileMatrix.tileHeight = TileMatrix[n].innerHTML
                        } else if (TileMatrix[n].nodeName === 'MatrixWidth') {
                          tileMatrix.matrixWidth = TileMatrix[n].innerHTML
                        } else if (TileMatrix[n].nodeName === 'MatrixHeight') {
                          tileMatrix.matrixHeight = TileMatrix[n].innerHTML
                        }
                      }

                      tileMatrixSet.tileMatrix.push(tileMatrix)
                    }
                  }

                  WMTSInfo.tileMatrixSet.push(tileMatrixSet)
                }
              }
              break
            }
          }
          break
        }
      }

      return WMTSInfo
    }

    /**
     * 将XML的Document对象转换为JSON字符串
     * @param xmlDoc xml的Document对象
     * @return {Object} WFS的元数据信息
     */
    function getWFSInfoFromXML(xmlDoc) {
      const rootChildren = xmlDoc.childNodes
      const WFSInfo = {
        featureTypeList: []
      }

      // 循环子元素
      for (let i = 0; i < rootChildren.length; i++) {
        if (rootChildren[i].nodeName === 'wfs:WFS_Capabilities') {
          const cpChildren = rootChildren[i].childNodes
          for (let m = 0; m < cpChildren.length; m++) {
            // 只拿FeatureTypeList里的数据
            if (cpChildren[m].nodeName === 'FeatureTypeList') {
              const ftList = cpChildren[m].childNodes
              for (let j = 0; j < ftList.length; j++) {
                // 只拿FeatureType里的数据
                if (ftList[j].nodeName === 'FeatureType') {
                  const featureType = {}
                  const ftChildren = ftList[j].childNodes
                  for (let k = 0; k < ftChildren.length; k++) {
                    if (ftChildren[k].nodeName.toLowerCase() === 'name') {
                      featureType.name = ftChildren[k].innerHTML
                    } else if (ftChildren[k].nodeName.toLowerCase() === 'title') {
                      featureType.title = ftChildren[k].innerHTML
                    } else if (
                      ftChildren[k].nodeName.toLowerCase() === 'abstract'
                    ) {
                      featureType.abstract = ftChildren[k].innerHTML
                    } else if (
                      ftChildren[k].nodeName.toLowerCase() === 'defaultSRS'
                    ) {
                      featureType.defaultSRS = ftChildren[k].innerHTML
                    } else if (
                      ftChildren[k].nodeName.toLowerCase() ===
                      'ows:wgs84boundingbox'
                    ) {
                      featureType.WGS84BoundingBox = {
                        lowerCorner: ftChildren[k].childNodes[0].innerHTML,
                        UpperCorner: ftChildren[k].childNodes[1].innerHTML
                      }
                    }
                  }
                  WFSInfo.featureTypeList.push(featureType)
                }
              }
              break
            }
          }
        }
      }

      return WFSInfo
    }

    function parseWFSElementForSpatialReference(element) {
      let srsName = 'EPSG:4326'
      if (!element) {
        return srsName
      }
      const _srsName = element.getAttribute('srsName')
      if (!_srsName) return srsName
      const res = _srsName.match(/EPSG::\d+/)
      if (res[0]) {
        srsName = `EPSG:${res[0].replace('EPSG::', '')}`
      }
      return srsName
    }

    function getWFSFeature(xmlDoc) {
      const rootChildren = xmlDoc.childNodes
      const WFSFeatureDom = rootChildren[0].childNodes
      const WFSFeature = new FeatureSet()
      let geometry = undefined

      for (let i = 0; i < WFSFeatureDom.length; i++) {
        const WFSSubLayer = WFSFeatureDom[i].childNodes[0]
        const WFSSubLayerChildren = WFSSubLayer.childNodes
        const attributes = {}
        for (let j = 0; j < WFSSubLayerChildren.length; j++) {
          // 多边形几何，确保节点名称包含:the_geom
          if (WFSSubLayerChildren[j].nodeName.indexOf(':the_geom') > -1) {
            // 遍历子节点，最后找到节点名包含exterior的节点，里面的就是多边形的点坐标
            const WFSGeometry = WFSSubLayerChildren[j]
            // 解析空间参考系
            const srsName = parseWFSElementForSpatialReference(
              WFSGeometry.childNodes[0]
            )
            WFSFeature.spatialReference = new SpatialReference(srsName)
            if (WFSGeometry.childNodes[0].nodeName.indexOf('MultiSurface') > -1) {
              const WFSMultiSurface = WFSGeometry.childNodes[0]
              const WFSSurfaceMembers = WFSMultiSurface.childNodes
              if (WFSSurfaceMembers.length === 1) {
                const WFSPolygon = WFSSurfaceMembers[0].childNodes[0]
                const WFSPolygonChildNodes = WFSPolygon.childNodes
                for (let k = 0; k < WFSPolygonChildNodes.length; k++) {
                  if (WFSPolygonChildNodes[k].nodeName.indexOf('exterior') > -1) {
                    const WFSPolygonExterior = WFSPolygonChildNodes[k]
                    const WFSPolygonExteriorPoints =
                      WFSPolygonExterior.childNodes[0].childNodes[0].innerHTML.split(
                        ' '
                      )
                    const exteriorPoints = []
                    for (let l = 0; l < WFSPolygonExteriorPoints.length; l += 2) {
                      exteriorPoints.push([
                        Number(WFSPolygonExteriorPoints[l]),
                        Number(WFSPolygonExteriorPoints[l + 1])
                      ])
                    }
                    geometry = new Polygon({
                      coordinates: [exteriorPoints]
                    })
                  }
                }
              } else if (WFSSurfaceMembers.length > 1) {
                // 未测试该情况，要向igs了解
              }
            }
            // 线几何，确保节点名称包含MultiCurve
            else if (
              WFSGeometry.childNodes[0].nodeName.indexOf('MultiCurve') > -1
            ) {
              // 遍历子节点，最后找到节点名包含posList的节点，里面的就是线的点坐标
              const WFSMultiSurface = WFSGeometry.childNodes[0]
              const WFSSurfaceMembers = WFSMultiSurface.childNodes
              if (WFSSurfaceMembers.length === 1) {
                const WFSLine = WFSSurfaceMembers[0].childNodes[0]
                const WFSLineChildNodes = WFSLine.childNodes
                for (let k = 0; k < WFSLineChildNodes.length; k++) {
                  if (WFSLineChildNodes[k].nodeName.indexOf('posList') > -1) {
                    const WFSLineString = WFSLineChildNodes[k]
                    const WFSLineStringPoints = WFSLineString.innerHTML.split(' ')
                    const lineStringPoints = []
                    for (let l = 0; l < WFSLineStringPoints.length; l += 2) {
                      lineStringPoints.push([
                        Number(WFSLineStringPoints[l]),
                        Number(WFSLineStringPoints[l + 1])
                      ])
                    }
                    geometry = new LineString({
                      coordinates: lineStringPoints
                    })
                  }
                }
              } else if (WFSSurfaceMembers.length > 1) {
                // 未测试该情况，要向igs了解
              }
            }
            // 点几何，确保节点名称包含MultiCurve
            else if (
              WFSGeometry.childNodes[0].nodeName.indexOf('MultiPoint') > -1
            ) {
              // 遍历子节点，最后找到节点名包含posList的节点，里面的就是线的点坐标
              const WFSMultiPoint = WFSGeometry.childNodes[0]
              const WFSPointMembers = WFSMultiPoint.childNodes
              if (WFSPointMembers.length === 1) {
                const WFSPoint = WFSPointMembers[0].childNodes[0]
                const WFSPointPos = WFSPoint.childNodes[0].innerHTML.split(' ')
                geometry = new Point({
                  coordinates: [Number(WFSPointPos[0]), Number(WFSPointPos[1])]
                })
              } else if (WFSPointMembers.length > 1) {
                // 未测试该情况，要向igs了解
              }
            }
          }
          // 属性信息
          else {
            let key = WFSSubLayerChildren[j].nodeName
            key = key.split(':')[1]
            attributes[key] = WFSSubLayerChildren[j].innerHTML
          }
          const feature = new Feature({
            geometry,
            attributes
          })
          WFSFeature.features.push(feature)
        }
      }

      return WFSFeature
    }

    function fromQueryResult(result) {
      function _fromQueryResult(result) {
        if (
          !result.hasOwnProperty('SFEleArray') ||
          !result.hasOwnProperty('AttStruct') ||
          (result.hasOwnProperty('SFEleArray') && !result.SFEleArray) ||
          (result.hasOwnProperty('AttStruct') && !result.AttStruct)
        ) {
          return []
        }
        const SFEleArray = result.SFEleArray
        const AttStruct = result.AttStruct
        const featureSet = new FeatureSet({
          spatialReference: new SpatialReference('EPSG:0000')
        })
        let feature
        let geometry
        let coordinates
        for (let i = 0; i < SFEleArray.length; i++) {
          const attributes = {}
          for (let j = 0; j < SFEleArray[i].AttValue.length; j++) {
            if (SFEleArray[i].AttValue[j] !== '') {
              attributes[AttStruct.FldName[j]] = SFEleArray[i].AttValue[j]
            }
          }
          if (SFEleArray[i].fGeom) {
            switch (SFEleArray[i].ftype) {
              case 1:
                // 多个点
                const PntGeom = SFEleArray[i].fGeom.PntGeom
                // 获取所有点的点坐标
                coordinates = []
                for (let k = 0; k < PntGeom.length; k++) {
                  // 处理数据
                  const dot = PntGeom[k].Dot
                  coordinates.push([dot.x, dot.y])
                }
                geometry = new MultiPoint({
                  coordinates
                })
                break
              case 2:
                // 多个线
                const LinGeom = SFEleArray[i].fGeom.LinGeom
                // 获取所有线的点坐标
                coordinates = []
                for (let k = 0; k < LinGeom.length; k++) {
                  // 处理下数据
                  const dots = LinGeom[k].Line.Arcs[0].Dots
                  const lineCos = []
                  for (let i = 0; i < dots.length; i++) {
                    lineCos.push([dots[i].x, dots[i].y])
                  }
                  coordinates.push(lineCos)
                }
                geometry = new MultiLineString({
                  coordinates
                })
                break
              case 3:
              default:
                // 多个多边形
                const RegGeom = SFEleArray[i].fGeom.RegGeom
                // 获取所有多边形的点坐标
                coordinates = []
                for (let k = 0; k < RegGeom.length; k++) {
                  // 这个是多边形的外圈
                  const outerDots = RegGeom[k].Rings[0].Arcs[0].Dots
                  // 处理下数据
                  const outerCos = []
                  for (let i = 0; i < outerDots.length; i++) {
                    outerCos.push([outerDots[i].x, outerDots[i].y])
                  }
                  const singleCoordinates = [outerCos]
                  for (let m = 1; m < RegGeom[k].Rings.length; m++) {
                    // 这个是多边形的内圈
                    // 处理数据
                    const innerDots = RegGeom[k].Rings[m].Arcs[0].Dots
                    const innerCos = []
                    for (let i = 0; i < innerDots.length; i++) {
                      innerCos.push([innerDots[i].x, innerDots[i].y])
                    }
                    singleCoordinates.push(innerCos)
                  }
                  coordinates.push(singleCoordinates)
                }
                geometry = new MultiPolygon({
                  coordinates
                })
                break
            }
          }
          let symbol
          if (SFEleArray[i].GraphicInfo) {
            const GraphicInfo = SFEleArray[i].GraphicInfo
            switch (GraphicInfo.InfoType) {
              case 1:
                symbol = GraphicInfo.PntInfo
                break
              case 2:
                symbol = GraphicInfo.LinInfo
                break
              case 3:
              default:
                symbol = GraphicInfo.RegInfo
                break
            }
          }

          feature = new Feature({
            id: SFEleArray[i].FID,
            attributes,
            geometry,
            symbol
          })
          featureSet.features.push(feature)
        }
        return featureSet
      }

      if (result instanceof Array) {
        const featureSets = []
        for (let i = 0; i < result.length; i++) {
          featureSets.push(_fromQueryResult(result[i]))
        }
        return featureSets
      } else {
        return [_fromQueryResult(result)]
      }
    }

    function formatBaseUrl(url) {
      const _index = url.indexOf('?')
      if (_index < 0) {
        return {
          baseUrl: url,
          params: {}
        }
      }
      const _baseUrl = url.substring(0, _index)
      const _paramStr = url.substring(_index + 1, url.length)
      return {
        baseUrl: _baseUrl,
        paramString: _paramStr ? `&${_paramStr}` : ''
      }
    }

    function ServiceConfigToken(Config) {
      let tokenStr = ''
      if (Config) {
        if (Config.tokenKey && Config.tokenValue) {
          tokenStr = `${Config.tokenKey}=${Config.tokenValue}`
        }
      }
      return tokenStr
    }

    function ServiceConfigRequestInterceptors(Config, url) {
      url = defaultValue(url, '')
      const requestInterceptors = Config.request.interceptors
      const _urlOrigin = decodeURI(url)
      if (requestInterceptors && requestInterceptors instanceof Array) {
        let _beforeUrl = ''
        for (let i = 0; i < requestInterceptors.length; i++) {
          const urls = requestInterceptors[i].urls
          const before = requestInterceptors[i].before
          // 不存在urls，则应用到全部url上
          if (!urls) {
            if (before && before instanceof Function) {
              const _before = before(url)
              if (_before) {
                _beforeUrl += _before
              }
            }
          }
          // urls是字符串
          else if (typeof urls === 'string') {
            const _url = decodeURI(urls)
            if (_urlOrigin.indexOf(_url) > -1) {
              if (before && before instanceof Function) {
                const _before = before(url)
                if (_before) {
                  _beforeUrl += _before
                }
              }
            }
          }
          // urls是数组
          else if (urls instanceof Array) {
            for (let j = 0; j < urls.length; j++) {
              const _url = decodeURI(urls[j])
              if (_urlOrigin.indexOf(_url) > -1) {
                if (before && before instanceof Function) {
                  const _before = before(url)
                  if (_before) {
                    _beforeUrl += _before
                  }
                }
              }
            }
          }
          if (_beforeUrl) {
            url = _beforeUrl
          }
        }
      }
      return url
    }

    function ServiceConfigResponseInterceptors(Config, url, response) {
      url = defaultValue(url, '')
      const requestInterceptors = Config.request.interceptors
      const _urlOrigin = decodeURI(url)
      if (requestInterceptors && requestInterceptors instanceof Array) {
        for (let i = 0; i < requestInterceptors.length; i++) {
          const urls = requestInterceptors[i].urls
          const after = requestInterceptors[i].after
          // 不存在urls，则应用到全部url上
          if (!urls || (urls instanceof Array && urls.length === 0)) {
            if (after && after instanceof Function) {
              const _after = after(response)
              if (_after) {
                return _after
              }
            }
          }
          // urls是字符串
          else if (typeof urls === 'string') {
            const _url = decodeURI(urls)
            if (_urlOrigin.indexOf(_url) > -1) {
              if (after && after instanceof Function) {
                const _after = after(response)
                if (_after) {
                  return _after
                }
              }
            }
          }
          // urls是数组
          else if (urls instanceof Array) {
            for (let j = 0; j < urls.length; j++) {
              const _url = decodeURI(urls[j])
              if (_urlOrigin.indexOf(_url) > -1) {
                if (after && after instanceof Function) {
                  const _after = after(response)
                  if (_after) {
                    return _after
                  }
                }
              }
            }
          }
        }
      }
      return response
    }

    export {
      fromQueryResult,
      checkParam,
      getParameters,
      checkPathParameters,
      getWMSInfoFromXML,
      getDoc,
      getWMTSInfoFromXML,
      getWFSInfoFromXML,
      getParametersObject,
      getWFSFeature,
      formatBaseUrl,
      ServiceConfigToken,
      ServiceConfigRequestInterceptors,
      ServiceConfigResponseInterceptors
    }