    ﻿import { defaultValue, isNull, Log } from '../util'
    import FetchRequest from './FetchRequest'
    import RequestInterceptor from './RequestInterceptor'
    import ResponseInterceptor from './ResponseInterceptor'
    import { TokenAttachType } from '../base/enum'
    import {
      getWMSInfoFromXML,
      getDoc,
      getWMTSInfoFromXML,
      getWFSInfoFromXML,
      fromQueryResult,
      getWFSFeature,
      ServiceConfigToken,
      ServiceConfigRequestInterceptors, ServiceConfigResponseInterceptors
    } from './Utils'
    import { FeatureSet } from '../base'
    import { SpatialReference } from '../base/geometry'
    import Config from './Config'

    /**
     * @private
     * @class FetchServer
     * @classdesc 对接各种服务的Service的基类。
     * @param url - {string} 服务地址。
     * @param options - {Object} 可选参数。如：
     * @param {String} [options.url = 无] 基地址，必填
     * @param {Object} [options.headers = 无] 自定义请求头参数
     * @param {Function} [options.requestInterceptor = 无] 所有请求发送前会触发的函数
     * @param {Function} [options.responseInterceptor = 无] 所有请求发送后会触发的函数
     * @param {Number} [options.requestTimeout = 45000] 请求超时时间，默认45000ms，即45s
     * @param {String} [options.tokenKey = 'token'] token名
     * @param {String} [options.tokenValue = 无] token值
     * @param {TokenAttachType} [options.tokenAttachType = TokenAttachType.url] 指定token附加到何处
     */
    class FetchServer {
      constructor(url, options) {
        options = defaultValue(options, {})
        /**
         * 服务基地址
         * @member {String} FetchServer.prototype.url
         * */
        this.url = url
        /**
         * 所有请求发送前会触发的函数
         * @member {Function} FetchServer.prototype.requestInterceptor
         * */
        this.requestInterceptor = defaultValue(
          options.requestInterceptor,
          new RequestInterceptor()
        )
        /**
         * 所有请求发送后会触发的函数
         * @member {Function} FetchServer.prototype.responseInterceptor
         * */
        this.responseInterceptor = defaultValue(
          options.responseInterceptor,
          new ResponseInterceptor()
        )
        /**
         * 请求超时时间，默认45000ms，即45s
         * @member {Function} FetchServer.prototype.requestTimeout
         * */
        this.requestTimeout = defaultValue(options.requestTimeout, 45000)
        /**
         * 请求头参数
         * @member {Function} FetchServer.prototype.headers
         * */
        this.headers = defaultValue(options.headers, {})
        /**
         * token名
         * @member {Function} FetchServer.prototype.tokenKey
         * */
        this.tokenKey = defaultValue(options.tokenKey, 'token')
        /**
         * token值
         * @member {Function} FetchServer.prototype.tokenValue
         * */
        this.tokenValue = defaultValue(options.tokenValue, undefined)
        /**
         * 指定token附加到何处
         * @member {Function} FetchServer.prototype.tokenAttachType
         * */
        this.tokenAttachType = defaultValue(
          options.tokenAttachType,
          TokenAttachType.url
        )
      }

      /**
       * 销毁对象方法
       * */
      destroy() {
        this.url = null
        this.options = null
      }

      /**
       * @function  FetchServer.prototype.request
       * @description: 该方法用于向服务发送请求。
       * @param options - {Object} 参数。
       * @param {string} [options.method] 请求方式，包括"GET"，"POST"，"PUT"，"DELETE"。
       * @param {string} [options.url] 发送请求的地址。<br>
       * @param {String} [options.data] 发送到服务器的数据，适用于"POST"。
       * @param {Function} [options.success] 成功回调函数。
       * @param {Function} [options.failure] 失败回调函数。
       * @param {Boolean} [options.withCredentials = false] 是否携带cookie。
       */
      request(options) {
        options = defaultValue(options, {})

        // url正确性检查
        if (isNull(options.url)) {
          Log.error('url不存在！')
          return
        }

        // 执行所有请求发送前会触发的函数
        if (
          !isNull(this.requestInterceptor) &&
          !isNull(this.requestInterceptor.before) &&
          this.requestInterceptor.before instanceof Function
        ) {
          options = this.requestInterceptor.before(options)
        }

        if (!isNull(options)) {
          return this._commit(options)
        }
      }

      _commit(options) {
        const self = this
        if (options.url.indexOf('?') > -1) {
          options.url += `&${ServiceConfigToken(Config)}`
        } else {
          options.url += `?${ServiceConfigToken(Config)}`
        }
        options.url = ServiceConfigRequestInterceptors(Config, options.url)
        options.headers = defaultValue(options.headers, {})
        let _headers = Object.assign(options.headers, this.headers)
        _headers = Object.assign(_headers, Config.headers)
        return FetchRequest.commit(options.method, options.url, options.data, {
          headers: _headers,
          withCredentials: options.withCredentials,
          requestTimeout: this.requestTimeout,
          proxy: options.proxy,
          tokenKey: this.tokenKey,
          tokenValue: this.tokenValue,
          tokenAttachType: this.tokenAttachType
        })
          .then(function (response) {
            let check
            if (response.text) {
              check = () => response.text()
            } else {
              check = () => response.json()
            }
            if (response.status === 200) {
              return new Promise(
                (resolve) => {
                  check().then(function (text) {
                    let result
                    // 如果返回信息不存在
                    if (isNull(text)) {
                      result = {
                        succeed: true,
                        msg: '服务器没有返回信息',
                        data: undefined
                      }
                    } else {
                      let data
                      // 有返回信息，将text转为对象
                      if (typeof text === 'string') {
                        // 是xml，则解析
                        if (text.indexOf('<?xml') > -1) {
                          // 是WMS的元数据信息
                          if (
                            text.indexOf('OGC:WMS') > -1 ||
                            text.indexOf('WMS_Capabilities') > -1
                          ) {
                            // 确认服务版本号
                            let version = '1.1.1'
                            if (text.indexOf('1.3.0') > -1) {
                              version = '1.3.0'
                            }
                            // xml转dom元素
                            const xmlDoc = getDoc(text)
                            // 从dom中获取信息
                            data = getWMSInfoFromXML(xmlDoc, version)
                          } else if (
                            text.indexOf('WMTS') > -1 ||
                            text.indexOf('wmts/1.0') > -1
                          ) {
                            // 是WMTS的元数据信息
                            // xml转dom元素
                            const xmlDoc = getDoc(text)
                            // 从dom中获取信息
                            data = getWMTSInfoFromXML(xmlDoc)
                          }
                          // 取服务元信息
                          else if (text.indexOf('wfs:WFS_Capabilities') > -1) {
                            // 是WFS的元数据信息
                            // xml转dom元素
                            const xmlDoc = getDoc(text)
                            // 从dom中获取信息
                            data = getWFSInfoFromXML(xmlDoc)
                          }
                          // WFS要素查询
                          else if (text.indexOf('wfs:FeatureCollection') > -1) {
                            // 是WFS的元数据信息
                            // xml转dom元素
                            const xmlDoc = getDoc(text)
                            // 从dom中获取信息
                            data = getWFSFeature(xmlDoc)
                          } else if (text.indexOf('<svg') > -1) {
                            // 是svg，则直接返回
                            data = text
                          }
                        } else if (text.indexOf('html>') > -1) {
                          if (
                            !isNull(self.responseInterceptor) &&
                            !isNull(self.responseInterceptor.failure) &&
                            self.responseInterceptor.failure instanceof Function
                          ) {
                            self.responseInterceptor.failure({
                              succeed: false,
                              msg: `服务器不支持${options.method}请求或其他错误`,
                              data: undefined,
                              errorType: 'unKnownError'
                            })
                          }
                          if (
                            !isNull(options.failure) &&
                            options.failure instanceof Function
                          ) {
                            options.failure({
                              succeed: false,
                              msg: `服务器不支持${options.method}请求或其他错误`,
                              data: undefined,
                              errorType: 'unKnownError'
                            })
                          }
                          return Promise.reject({
                            succeed: false,
                            msg: `服务器不支持${options.method}请求或其他错误`,
                            data: undefined,
                            errorType: 'unKnownError'
                          })
                        } else {
                          data = JSON.parse(text)
                          // 基于矢量图层的要素查询，报数据转为feature
                          if (
                            data instanceof Object &&
                            (options.url.indexOf('/igs/rest/mrfs/layer/query') >
                              -1 ||
                              options.url.indexOf('/igs/rest/mrfs/docs/') > -1)
                          ) {
                            // 可以进行多GDBP的要素查询，因此返回要素集合数组
                            const featureSets = fromQueryResult(data)

                            delete data.SFEleArray
                            data.featureSets = featureSets
                            // 返回要素信息数组
                            const featureInfos = []
                            if (featureSets.length > 1) {
                              for (let i = 0; i < featureSets.length; i++) {
                                featureInfos.push(data[String(i)])
                                delete data[String(i)]
                              }
                            } else {
                              data.AttStruct.TotalCount = data.TotalCount
                              featureInfos.push(data.AttStruct)
                              delete data.AttStruct
                              delete data.TotalCount
                            }
                            data.featureInfos = featureInfos
                            if (
                              options.url.indexOf('/igs/rest/mrfs/docs/') > -1 ||
                              options.url.indexOf('/igs/rest/mrfs/layer/') > -1
                            ) {
                              if (featureSets.length > 0) {
                                data.featureSet = featureSets[0]
                              } else {
                                data.featureSet = new FeatureSet()
                              }
                            }
                          }
                        }
                      }
                      // 如果不是对象，直接返回信息
                      if (!(data instanceof Object)) {
                        result = {
                          succeed: true,
                          msg: data,
                          data
                        }
                      } else {
                        // 数据里面有features属性且为数组，且里面的是一个要素
                        if (
                          data.hasOwnProperty('features') &&
                          data.features instanceof Array
                        ) {
                          // 解析服务内坐标信息
                          let spatialReference = new SpatialReference('EPSG:4326')
                          if (data.spatialReference) {
                            spatialReference = new SpatialReference({
                              wkid: data.spatialReference.wkid,
                              wkt: data.spatialReference.name
                            })
                          }

                          const reg = /(igs)\/rest\/services\/.*\/WFSServer/
                          let reverse = false
                          // 是否对数据反转
                          if (
                            reg.test(options.url) &&
                            spatialReference.wkid === 4326
                          ) {
                            reverse = true
                          }
                          // 转成要素基本对象
                          data.featureSet = FeatureSet.fromArray(
                            data.features,
                            new FeatureSet({
                              spatialReference
                            }),
                            {
                              reverse
                            }
                          )
                        } else if (
                          options.url.indexOf('/MapServer/query') > -1 ||
                          options.url.indexOf('/SceneServer/query') > -1
                        ) {
                          if (data.layers && data.layers instanceof Array) {
                            // 解析服务内坐标信息
                            let spatialReference = new SpatialReference('EPSG:4326')
                            if (data.spatialReference) {
                              spatialReference = new SpatialReference({
                                wkid: data.spatialReference.wkid,
                                wkt: data.spatialReference.name
                              })
                            }
                            const layers = data.layers
                            for (let i = 0; i < layers.length; i++) {
                              if (layers[i].features) {
                                layers[i].featureSet = FeatureSet.fromArray(
                                  layers[i].features,
                                  new FeatureSet({ spatialReference })
                                )
                                delete layers[i].features
                              }
                            }
                          }
                        }
                        result = {
                          succeed: true,
                          msg: '请求成功',
                          data
                        }
                      }
                    }

                    // 执行config的after方法
                    result = ServiceConfigResponseInterceptors(
                      Config,
                      options.url,
                      result
                    )

                    // 执行请求响应，接口调用成功时会执行的回调
                    if (
                      !isNull(self.responseInterceptor) &&
                      !isNull(self.responseInterceptor.success) &&
                      self.responseInterceptor.success instanceof Function
                    ) {
                      result = self.responseInterceptor.success(result)
                    }

                    // 有成功回调函数，则执行
                    if (
                      !isNull(result) &&
                      !isNull(options.success) &&
                      options.success instanceof Function
                    ) {
                      options.success(result)
                    }
                    resolve(result)
                  })
                },
                (reject) => {
                  console.log('Fetch返回异常', reject)
                }
              )
            } else {
              return new Promise(
                (resolve) => {
                  check().then(function (text) {
                    let result
                    // 如果返回信息不存在，则返回请求失败
                    if (isNull(text)) {
                      result = {
                        succeed: false,
                        msg: '请求失败，服务器没有返回信息',
                        data: undefined
                      }
                    } else {
                      // 有返回信息，将text转为对象
                      const data = JSON.parse(text)
                      // 如果不是对象，直接返回信息
                      if (!(data instanceof Object)) {
                        result = {
                          succeed: false,
                          msg: data,
                          data: undefined
                        }
                      } else {
                        result = {
                          succeed: false,
                          msg: '请求失败',
                          data
                        }
                      }
                    }

                    // 请求响应成功，接口调用失败时会执行的函数
                    if (
                      !isNull(self.responseInterceptor) &&
                      !isNull(self.responseInterceptor.failure) &&
                      self.responseInterceptor.failure instanceof Function
                    ) {
                      result = self.responseInterceptor.failure(result)
                    }

                    // 当failure回调存在，则运行failure
                    if (
                      !isNull(result) &&
                      !isNull(options.failure) &&
                      options.failure instanceof Function
                    ) {
                      options.failure(result)
                    }
                    resolve(result)
                  })
                },
                (reject) => {
                  console.error('Fetch返回异常', reject)
                }
              )
            }
          })
          .catch(function (error) {
            // 执行所有请求发送失败后触发的函数
            if (
              !isNull(self.requestInterceptor) &&
              !isNull(self.requestInterceptor.failure) &&
              self.requestInterceptor.failure instanceof Function
            ) {
              self.requestInterceptor.failure(error)
            }
          })
      }
    }

    export default FetchServer