    import Zondy from '../Zondy'
    import { getGUID, defaultValue } from '../../util'
    import Feature from './Feature'
    import {
      Geometry,
      LineString,
      MultiLineString,
      MultiPoint,
      MultiPolygon,
      Point,
      Polygon,
      SpatialReference
    } from '../geometry'
    import { GeometryType } from '../enum'
    import Projection from '../Projection'

    function transformToWGS84(spatialReference, geo) {
      if (!geo) return geo
      if (spatialReference && spatialReference.wkid !== '4326') {
        geo.spatialReference = spatialReference
        return Projection.project(geo, new SpatialReference('EPSG:4326'))
      }
      return geo
    }

    function coordsToLatLng(coords) {
      if (coords.length > 2) {
        return [coords[1], coords[0], coords[2]]
      }
      return [coords[1], coords[0]]
    }

    function coordsToLatLngs(coords, levelsDeep, _coordsToLatLng) {
      const latlngs = []

      for (let i = 0, len = coords.length, latlng; i < len; i++) {
        latlng = levelsDeep
          ? coordsToLatLngs(coords[i], levelsDeep - 1, _coordsToLatLng)
          : (_coordsToLatLng || coordsToLatLng)(coords[i])

        latlngs.push(latlng)
      }

      return latlngs
    }

    /**
     * 要素集合类，示例如下：<a id='add-FeatureSet'>[初始化要素集合对象]</a>
     * <br><br>[ES5引入方式]：<br/>
     * Zondy.FeatureSet() <br/>
     * [ES6引入方式]：<br/>
     * import { FeatureSet } from "@mapgis/webclient-common" <br/>
     * <br/>
     * @class FeatureSet
     * @moduleEX FeatureModule
     * @param {Object} options 构造参数
     * @param {String} [options.id] 要素集合的id，不给则给一个随机的默认id
     * @param {Array} [options.features = []] 要素数组
     * @param {SpatialReference} [options.spatialReference = new Zondy.SpatialReference('EPSG:4326')] 要素集合的参考系，
     * 默认为4326，当要素的几何对象上制定了参考系时，用要素上的；当要素的集合对象上没有指定参考系时，则使用该参考系
     *
     * @summary <h5>支持如下方法：</h5>
     * <a href='#findFeatureById'>[1、通过ID寻找要素]</a><br/>
     * <a href='#fromGeoJSON'>[3、从geoJSON对象中导入数据]</a><br/>
     * <a href='#toGeoJSON'>[4、导出为GeoJSON数据]</a><br/>
     * <a href='#fromArray'>[5、将一个要素数组对象转为要素集合]</a><br/>
     * <a href='#toJSON'>[6、导出一个JSON对像]</a><br/>
     * <a href='#clone'>[7、克隆并返回新的要素集合]</a><br/>
     * <a href='#static fromJSON'>[8、通过传入的json构造并返回一个新的几何对象]</a><br/>
     *
     * @example <caption><h7 id='add-FeatureSet'>初始化要素集合对象</h7></caption>
     * // ES5引入方式
     * const { FeatureSet } = Zondy
     * // ES6引入方式
     * import { FeatureSet } from "@mapgis/webclient-common"
     * //创建要素集合
     * let featureSet = new FeatureSet({
     *   //不填则创建一个随机的guid
     *   id: "你的id",
     *   //要素集合
     *   features: []
     * })
     */
    class FeatureSet {
      constructor(options) {
        options = defaultValue(options, {})
        /**
         * 要素集合的id
         * default 随机id
         * @member {String} FeatureSet.prototype.id
         */
        this.id = defaultValue(options.id, getGUID())
        /**
         * 要素数组
         * default []
         * @member {Array} FeatureSet.prototype.features
         */
        this.features = defaultValue(options.features, [])
        /**
         * 要素集合的参考系
         * default new Zondy.SpatialReference('EPSG:4326')
         * @member {SpatialReference} FeatureSet.prototype.spatialReference
         */
        this.spatialReference = defaultValue(
          options.spatialReference,
          new SpatialReference('EPSG:4326')
        )
        /**
         * 该类的类型
         * default FeatureCollection
         * @readonly
         * @member {String} FeatureSet.prototype.type
         */
        this.type = 'FeatureCollection'
      }

      /**
       * 通过ID寻找要素，若没有id，则在要素的attributes中查找<a id='findFeatureById'></a>
       * @param id 要素ID
       * @return Feature 要素对象
       * @example <caption><h7 id='findFeatureById'>通过ID寻找要素</h7></caption>
       * let feature = featureSet.findFeatureById("要素id");
       */
      findFeatureById(id) {
        let feature = undefined
        for (let i = 0; i < this.features.length; i++) {
          if (this.features[i].id === id || this.features[i].attributes.id === id) {
            feature = this.features[i]
            break
          }
        }

        return feature
      }

      /**
       * 导出一个JSON对像<a id='toJSON'></a>
       * @return {Object} JSON对像
       */
      toJSON() {
        const json = {}
        json.id = this.id
        json.features = this.features.map((feature) => feature.toJSON())
        json.spatialReference = this.spatialReference.toJSON()
        json.type = this.type
        return json
      }

      /**
       * 克隆并返回新的要素集合<a id='clone'></a>
       * @return {FeatureSet} 克隆后的新要素集合
       * @example <caption><h7>克隆并返回新的要素集合</h7></caption>
       * let newFeatureSet = featureSet.clone();
       */
      clone() {
        const newFeatureSet = new FeatureSet()
        for (let i = 0; i < this.features.length; i++) {
          newFeatureSet.features.push(this.features[i].clone())
        }
        return newFeatureSet
      }

      /**
       * 通过传入的json构造并返回一个新的几何对象<a id='fromJSON'></a>
       * @param {Object} json JSON对象
       * @example <caption><h7 id='fromJSON'>通过传入的json构造并返回一个新的几何对象</h7></caption>
       * // ES5引入方式
       * const { FeatureSet } = Zondy
       * // ES6引入方式
       * import { FeatureSet } from "@mapgis/webclient-common"
       * const json = {
       *   //不填则创建一个随机的guid
       *   id: "你的id",
       *   //要素集合
       *   features: []
       * }
       * const featureSet = new FeatureSet.fromJSON(json)
       */
      static fromJSON(json) {
        json = defaultValue(json, {})
        return new FeatureSet(json)
      }

      /**
       * 从geoJSON对象中导入数据，若要素id相同，则会覆盖当前要素的值<a id='fromGeoJSON'></a>
       * @param geoJSON geoJSON数据
       * @example <caption><h7>从geoJSON对象中导入数据</h7></caption>
       * //数据格式参考https://geojson.org/
       * FeatureSet.fromGeoJSON({
       *   //类型必须为FeatureCollection
       *   type: "FeatureCollection",
       *   //要素集合
       *   features: []
       * })
       */
      static fromGeoJSON(geoJSON) {
        geoJSON = defaultValue(geoJSON, {})
        const { type } = geoJSON
        const features = []
        let spatialReference = new SpatialReference('EPSG:4326')
        // 获取要素集空间参考系
        if (geoJSON.crs && geoJSON.crs.properties && geoJSON.crs.properties.name) {
          spatialReference = new SpatialReference({
            wkt: geoJSON.crs.properties.name
          })
        }
        // 是一个要素collection
        if (type === 'FeatureCollection') {
          // 从features导入数据
          const geoFeatures = defaultValue(geoJSON.features, [])
          for (let i = 0; i < geoFeatures.length; i++) {
            // 确保有属性
            geoFeatures[i].properties = defaultValue(geoFeatures[i].properties, {})
            // 获取要素id
            const id = geoFeatures[i].id || geoFeatures[i].properties.id
            // 在当前要素集合中查找要素
            const feature = new Feature({
              id,
              attributes: JSON.parse(JSON.stringify(geoFeatures[i].properties)),
              geometry: Geometry.fromGeoJSON(geoFeatures[i].geometry)
            })
            feature.geometry.spatialReference = spatialReference.clone()
            features.push(feature)
          }
        }
        // 还需要考虑GeometryCollection情况，时间不够，先留着
        return new FeatureSet({
          spatialReference,
          features
        })
      }

      /**
       * 导出为GeoJSON数据<a id='toGeoJSON'></a>
       * @return {Object} geoJSON数据
       * @example <caption><h7>导出为GeoJSON数据</h7></caption>
       * let geojson = featureSet.toGeoJSON();
       */
      toGeoJSON() {
        const featureSet = {
          type: 'FeatureCollection',
          features: []
        }
        for (let i = 0; i < this.features.length; i++) {
          const feature = this.features[i].clone()
          if (feature.geometry) {
            const geometryJSON = transformToWGS84(
              feature.geometry.spatialReference,
              feature.geometry
            )
            feature.geometry = Geometry.fromGeoJSON(geometryJSON)
          }
          featureSet.features.push(feature.toGeoJSON())
        }
        return featureSet
      }

      /**
       * 将一个要素数组对象转为要素集合<a id='fromArray'></a>
       * @param {Array<Object>|FeatureSet} features
       * @param {FeatureSet} featureSet
       * @return FeatureSet 新的featureSet对象
       * @example <caption><h7>将一个要素数组对象转为要素集合</h7></caption>
       * // ES5引入方式
       * const { FeatureSet } = Zondy
       * // ES6引入方式
       * import { FeatureSet } from "@mapgis/webclient-common"
       * featureSet = FeatureSet.fromArray(
       *   [
       *   {
       *     "attributes": {
       *       "FID": 650,
       *       "CODE": "420000",
       *       "CAPNAME": "武汉市",
       *       "mpPerimeter": "38.93733309514808",
       *       "mpArea": "17.556751278282672",
       *       "mpLayer": "18",
       *       "NAME": "湖北省"
       *     },
       *     "geometry": {
       *       "type": "Polygon",
       *       "coordinates": [[]]
       *     },
       *     "symbol": null
       *   }
       * ],
       *   new FeatureSet()
       * )
       */
      static fromArray(features, featureSet, options) {
        options = defaultValue(options, {})
        const reverse = options.reverse
        let featureArr = defaultValue(features, [])
        if (features instanceof FeatureSet) {
          featureArr = defaultValue(features.features, [])
        }
        featureSet = defaultValue(featureSet, new FeatureSet())
        for (let i = 0; i < featureArr.length; i++) {
          // 确保是对象
          if (featureArr[i] && featureArr[i] instanceof Object) {
            let geometry
            // 确保有这些属性
            if (
              featureArr[i].geometry &&
              featureArr[i].geometry instanceof Object &&
              featureArr[i].geometry.type &&
              featureArr[i].geometry.coordinates
            ) {
              switch (featureArr[i].geometry.type) {
                case GeometryType.point: {
                  let coordinates = featureArr[i].geometry.coordinates
                  if (reverse) {
                    coordinates = coordsToLatLng(coordinates)
                  }
                  geometry = new Point({
                    coordinates
                  })
                  break
                }
                case GeometryType.multiPoint: {
                  let coordinates = featureArr[i].geometry.coordinates
                  if (reverse) {
                    coordinates = coordsToLatLngs(coordinates, 0, coordsToLatLng)
                  }
                  geometry = new MultiPoint({
                    coordinates
                  })
                  break
                }
                case GeometryType.lineString: {
                  let coordinates = featureArr[i].geometry.coordinates
                  if (reverse) {
                    coordinates = coordsToLatLngs(coordinates, 0, coordsToLatLng)
                  }
                  geometry = new LineString({
                    coordinates
                  })
                  break
                }
                case GeometryType.multiLineString: {
                  let coordinates = featureArr[i].geometry.coordinates
                  if (reverse) {
                    coordinates = coordsToLatLngs(coordinates, 1, coordsToLatLng)
                  }
                  geometry = new MultiLineString({
                    coordinates
                  })
                  break
                }
                case GeometryType.polygon: {
                  let coordinates = featureArr[i].geometry.coordinates
                  if (reverse) {
                    coordinates = coordsToLatLngs(coordinates, 1, coordsToLatLng)
                  }
                  geometry = new Polygon({
                    coordinates
                  })
                  break
                }
                case GeometryType.multiPolygon: {
                  let coordinates = featureArr[i].geometry.coordinates
                  if (reverse) {
                    coordinates = coordsToLatLngs(coordinates, 2, coordsToLatLng)
                  }
                  geometry = new MultiPolygon({
                    coordinates
                  })
                  break
                }
                default:
                  geometry = {}
              }
            }
            // 创建要素
            const feature = new Feature({
              attributes: features[i].attributes,
              geometry,
              symbol: features[i].symbol,
              additional: features[i].additional
            })
            feature.geometry.spatialReference = featureSet.spatialReference.clone()

            featureSet.features.push(feature)
          }
        }

        return featureSet
      }
    }

    Zondy.FeatureSet = FeatureSet
    export default FeatureSet