    import * as T from '@turf/turf'
    import Geometry from './Geometry'
    import { defaultValue, isNumber } from '../../util'
    import Zondy from '../Zondy'
    import { GeometryType, IGSGeometryType } from '../enum'
    import Point from './Point'
    import Extent from './Extent'

    /**
     * 多线段几何
     * <br><br>[ES5引入方式]：<br/>
     * Zondy.Geometry.MultiLineString() <br/>
     * [ES6引入方式]：<br/>
     * import { MultiLineString } from "@mapgis/webclient-common" <br/>
     * <br/>
     * @class MultiLineString
     * @moduleEX BaseModule
     * @extends Geometry
     * @param {Object} options 构造参数
     * @param {Array} [options.coordinates = []] 几何点的坐标数组，支持任意单位，参考示例：<a href='#LineString'>[多线段几何对象]</a>
     * @param {SpatialReference} [options.spatialReference = new Zondy.SpatialReference('EPSG:4326')] 几何点的空间参考系，默认4326，当不是4326时请指定坐标系，方便进行投影转换，参考示例：<a href='#SpatialReference'>[指定坐标系]</a>
     * @summary <h5>支持如下方法：</h5>
     * <a href='#addPath'>[1、添加线段]</a><br/>
     * <a href='#removePath'>[2、移除线段]</a><br/>
     * <a href='#getPoint'>[3、获取指定线段上的点]</a><br/>
     * <a href='#insertPoint'>[4、插入点到指定线段上]</a><br/>
     * <a href='#removePoint'>[5、删除指定线段上的点]</a><br/>
     * <a href='#setPoint'>[6、修改指定线段上的点]</a><br/>
     * <a href='#toString'>[7、返回字符串]</a><br/>
     * <a href='#toXMl'>[8、导出为OGC服务要求的xml字符串]</a><br/>
     * <a href='#getIGSType'>[9、返回IGS所对应的GeometryModule型]</a><br/>
     * <a href='#toOldIGSGeometry'>[10、返回igs1.0的几何对象]</a>
     * <a href='#fromJSON'>[11、通过传入的json构造并返回一个新的几何对象]</a><br/>
     * <a href='#toJSON'>[12、导出为json对象]</a><br/>
     * [13、克隆几何对象]{@link Geometry#clone}
     *
     * @example <caption><h7 id='MultiLineString'>创建几何对象</h7></caption>
     * // ES5引入方式
     * const { MultiLineString } = Zondy.Geometry
     * // ES6引入方式
     * import { MultiLineString } from "@mapgis/webclient-common"
     * new MultiLineString({
     *   coordinates: [
     *     // 第一个线几何
     *     [
     *       [100.0, 0.0],[101.0, 1.0]
     *     ],
     *     // 第二个线几何
     *     [
     *       [102.0, 2.0],[103.0, 3.0]
     *     ]
     *   ]
     * })
     *
     * @example <caption><h7 id='SpatialReference'>指定坐标系</h7></caption>
     * // ES5引入方式
     * const { MultiLineString } = Zondy.Geometry
     * const { SpatialReference } = Zondy
     * // ES6引入方式
     * import { MultiLineString, SpatialReference } from "@mapgis/webclient-common"
     * new MultiLineString({
     *   // 3857坐标系的点
     *   coordinates: [
     *     // 第一个线几何
     *     [
     *       [12929863.44711455, 3934286.575385226],
     *       [12060733.232006868, 3377247.5680546067]
     *     ],
     *     // 第二个线几何
     *     [
     *       [12929863.44711455, 3934286.575385226],
     *       [12060733.232006868, 3377247.5680546067]
     *     ]
     *   ],
     *   // 当不是4326时请指定坐标系，方便进行投影转换
     *   spatialReference: new SpatialReference('EPSG:3857')
     * })
     */
    class MultiLineString extends Geometry {
      constructor(options) {
        super(options)
        options = defaultValue(options, {})
        /**
         * 几何点的坐标
         * @member {Array} MultiLineString.prototype.coordinates
         */
        this.coordinates = defaultValue(options.coordinates, [])
        /**
         * 几何类型
         * @member {GeometryType} MultiLineString.prototype.type
         */
        this.type = GeometryType.multiLineString
        if (!Array.isArray(this.coordinates)) {
          throw new Error('坐标必须为数组')
        }
        for (const path of this.coordinates) {
          if (path.length < 2) {
            throw new Error('坐标必须是两个或多个位置的数组')
          }
        }

        if (this.coordinates[0][0].length === 3) {
          this.hasZ = true
        }
      }

      /**
       * 添加线段
       * @param {Array<Point>} points 控制点组
       * @return {MultiLineString} 更新后的几何对象
       * @example <caption><h7 id='addPath'>添加线段</h7></caption>
       * // ES5引入方式
       * const { MultiLineString, Point } = Zondy.Geometry
       * // ES6引入方式
       * import { MultiLineString, Point } from "@mapgis/webclient-common"
       * const multiLineString = new MultiLineString({
       *   coordinates: [
       *     // 第一个线几何
       *     [
       *       [100.0, 0.0],[101.0, 1.0]
       *     ],
       *     // 第二个线几何
       *     [
       *       [102.0, 2.0],[103.0, 3.0]
       *     ]
       *   ]
       * })
       * const path = [
       *   new Point({
       *     coordinates: [100.0, 0.0]
       *   }),
       *   new Point({
       *     coordinates: [101.0, 1.0]
       *   }),
       *   new Point({
       *     coordinates: [102.0, 2.0]
       *   })
       * ]
       * multiLineString.addPath(path)
       */
      addPath(points) {
        if (!Array.isArray(points)) throw new Error('传入参数错误')
        const pnts = []
        points.forEach((point) => {
          pnts.push(Point.toCoordinates(point))
        })
        this.coordinates.push(pnts)
        return this
      }

      /**
       * 移除线段
       * @param {Number} pathIndex 路径下标
       * @return {Array<Point>|null} 删除的线段点
       * @example <caption><h7 id='removePath'>移除线段</h7></caption>
       * // ES5引入方式
       * const { MultiLineString } = Zondy.Geometry
       * // ES6引入方式
       * import { MultiLineString } from "@mapgis/webclient-common"
       * const multiLineString = new MultiLineString({
       *   coordinates: [
       *     // 第一个线几何
       *     [
       *       [100.0, 0.0],[101.0, 1.0]
       *     ],
       *     // 第二个线几何
       *     [
       *       [102.0, 2.0],[103.0, 3.0]
       *     ]
       *   ]
       * })
       * multiLineString.removePath(0)
       */
      removePath(pathIndex) {
        if (!this._isValidate(pathIndex, 0)) return null
        const coords = JSON.parse(
          JSON.stringify(this._cloneCoordinates()[pathIndex])
        )
        this.coordinates.splice(pathIndex, 1)
        return coords.map((coord) => {
          return new Point({
            coordinates: coord
          })
        })
      }

      /**
       * 克隆几何对象
       * @param {MultiLineString} multiLineString 被克隆的几何对象
       * @return {MultiLineString} 克隆后的几何对象
       * @example <caption><h7 id='clone'>克隆几何对象</h7></caption>
       * // ES5引入方式
       * const { MultiLineString } = Zondy.Geometry
       * // ES6引入方式
       * import { MultiLineString } from "@mapgis/webclient-common"
       * const multiLineString = new MultiLineString({
       *   coordinates: [
       *     // 第一个线几何
       *     [
       *       [100.0, 0.0],[101.0, 1.0]
       *     ],
       *     // 第二个线几何
       *     [
       *       [102.0, 2.0],[103.0, 3.0]
       *     ]
       *   ]
       * })
       * const newMultiLineString = MultiLineString.clone(multiLineString)
       */
      static clone(multiLineString) {
        return new MultiLineString(multiLineString.toJSON())
      }

      /**
       * 通过传入的json构造并返回一个新的几何对象
       * @param {Object} [json] JSON对象
       * @example <caption><h7 id='fromJSON'>通过传入的json构造并返回一个新的几何对象</h7></caption>
       * // ES5引入方式
       * const { MultiLineString } = Zondy.Geometry
       * // ES6引入方式
       * import { MultiLineString } from "@mapgis/webclient-common"
       * const json = {
       *   coordinates: [
       *     // 第一个线几何
       *     [
       *       [100.0, 0.0],[101.0, 1.0]
       *     ],
       *     // 第二个线几何
       *     [
       *       [102.0, 2.0],[103.0, 3.0]
       *     ]
       *   ]
       * }
       * const newMultiLineString = MultiLineString.fromJSON(json)
       */
      static fromJSON(json) {
        json = defaultValue(json, {})
        return new MultiLineString(json)
      }

      /**
       * <a id='toJSON'></a>
       * 导出为json对象
       * @return {Object} json对象
       */
      toJSON() {
        const json = super.toJSON()
        json.coordinates = JSON.parse(JSON.stringify(this.coordinates))
        json.extent = this.extent.toJSON()

        return json
      }

      /**
       * 获取指定线段上的点
       * @param {Number} pathIndex 路径下标
       * @param {Number} pointIndex 数组下标
       * @return {Point | null} 点
       * @example <caption><h7 id='getPoint'>获取指定线段上的点</h7></caption>
       * // ES5引入方式
       * const { MultiLineString } = Zondy.Geometry
       * // ES6引入方式
       * import { MultiLineString } from "@mapgis/webclient-common"
       * const multiLineString = new MultiLineString({
       *   coordinates: [
       *     // 第一个线几何
       *     [
       *       [100.0, 0.0],[101.0, 1.0]
       *     ],
       *     // 第二个线几何
       *     [
       *       [102.0, 2.0],[103.0, 3.0]
       *     ]
       *   ]
       * })
       * const point = multiLineString.getPoint(0, 1)
       */
      getPoint(pathIndex, pointIndex) {
        if (!this._isValidate(pathIndex, pointIndex)) return null
        const path = this._cloneCoordinates()[pathIndex]
        return new Point({
          coordinates: path[pointIndex]
        })
      }

      /**
       * 插入点到指定线段上
       * @param {Number} pathIndex 路径下标
       * @param {Number} pointIndex 数组下标
       * @param {Point} point 点
       * @return {MultiLineString | null} 插入点后的线对象
       * @example <caption><h7 id='insertPoint'>插入点到指定线段上</h7></caption>
       * // ES5引入方式
       * const { MultiLineString, Point } = Zondy.Geometry
       * // ES6引入方式
       * import { MultiLineString, Point } from "@mapgis/webclient-common"
       * const multiLineString = new MultiLineString({
       *   coordinates: [
       *     // 第一个线几何
       *     [
       *       [100.0, 0.0],[101.0, 1.0]
       *     ],
       *     // 第二个线几何
       *     [
       *       [102.0, 2.0],[103.0, 3.0]
       *     ]
       *   ]
       * })
       * const point = new Point({
       *   coordinates: [102.0, 2.0]
       * })
       * multiLineString.insertPoint(0, 1, point)
       */
      insertPoint(pathIndex, pointIndex, point) {
        if (!this._isValidate(pathIndex, pointIndex)) return null
        const path = this.coordinates[pathIndex]
        if (Array.isArray(path)) {
          path.splice(pointIndex, 0, Point.toCoordinates(point))
        }
        this.coordinates[pathIndex] = path
        return this
      }

      /**
       * 删除指定线段上的点
       * @param {Number} pathIndex 路径下标
       * @param {Number} pointIndex 数组下标
       * @return {MultiLineString} 删除点后的线对象
       * @example <caption><h7 id='removePoint'>删除指定线段上的点</h7></caption>
       * // ES5引入方式
       * const { MultiLineString } = Zondy.Geometry
       * // ES6引入方式
       * import { MultiLineString } from "@mapgis/webclient-common"
       * const multiLineString = new MultiLineString({
       *   coordinates: [
       *     // 第一个线几何
       *     [
       *       [100.0, 0.0],[101.0, 1.0]
       *     ],
       *     // 第二个线几何
       *     [
       *       [102.0, 2.0],[103.0, 3.0]
       *     ]
       *   ]
       * })
       * multiLineString.removePoint(0, 1)
       */
      removePoint(pathIndex, pointIndex) {
        if (!this._isValidate(pathIndex, pointIndex)) return null
        const path = this.coordinates[pathIndex]
        if (Array.isArray(path)) {
          path.splice(pointIndex, 1)
        }
        this.coordinates = path
        return this
      }

      /**
       * 修改指定线段上的点
       * @param {Number} pathIndex 路径下标
       * @param {Number} pointIndex 数组下标
       * @param {Point} point 要更新的点
       * @return {MultiLineString} 修改后的线对象
       * @example <caption><h7 id='setPoint'>修改指定线段上的点</h7></caption>
       * // ES5引入方式
       * const { MultiLineString, Point } = Zondy.Geometry
       * // ES6引入方式
       * import { MultiLineString, Point } from "@mapgis/webclient-common"
       * const multiLineString = new MultiLineString({
       *   coordinates: [
       *     // 第一个线几何
       *     [
       *       [100.0, 0.0],[101.0, 1.0]
       *     ],
       *     // 第二个线几何
       *     [
       *       [102.0, 2.0],[103.0, 3.0]
       *     ]
       *   ]
       * })
       * const point = new Point({
       *   coordinates: [102.0, 2.0]
       * })
       * multiLineString.setPoint(0, 1, point)
       */
      setPoint(pathIndex, pointIndex, point) {
        if (!this._isValidate(pathIndex, pointIndex)) return this
        const path = this.coordinates[pathIndex]
        if (Array.isArray(path)) {
          path.splice(pointIndex, 1, Point.toCoordinates(point))
        }
        this.coordinates[pathIndex] = path
        return this
      }

      /**
       * 返回如下格式的字符串："x0,y0,x1,y1,x2,y2"<a id='toString'></a>
       * @returns string
       */
      toString() {
        return ''
      }

      /**
       * 导出为OGC服务要求的xml字符串<a id='toXMl'></a>
       * @return {String} 字符串
       */
      toXMl() {
        return ''
      }

      /**
       * 返回IGS所对应的GeometryModule型<a id='getIGSType'></a>
       * @returns string GeometryModule型
       */
      getIGSType() {
        return IGSGeometryType.multiLineString
      }

      /**
       * 返回igs1.0的几何对象<a id='toOldIGSGeometry'></a>
       * @returns Object igs1.0的几何对象
       */
      toOldIGSGeometry() {
        const LinGeom = []
        for (let i = 0; i < this.coordinates.length; i++) {
          const Dots = []
          for (let j = 0; j < this.coordinates[i].length; j++) {
            Dots.push({
              x: this.coordinates[i][j][0],
              y: this.coordinates[i][j][1]
            })
          }
          LinGeom.push({
            Line: {
              // 弧段信息
              Arcs: [
                {
                  // 弧段包含的坐标信息
                  Dots,
                  ArcID: 0
                }
              ]
            },
            GID: i
          })
        }
        return {
          // 线要素的空间几何对象，线由弧段构成，弧段由点构成
          LinGeom
        }
      }

      /**
       * @function MultiLineString.prototype._isValidate
       * @private
       * @description 判断输入是否合法
       * @param {Number} pathIndex 路径下标
       * @param {Number} pointIndex 数组下标
       * @returns {Boolean} 输入是否合法
       */
      _isValidate(pathIndex, pointIndex) {
        const len = this.coordinates.length
        if (!isNumber(pathIndex) || pathIndex < 0 || pathIndex >= len) return false
        const path = this.coordinates[pathIndex]
        const pathLen = path.length
        if (!isNumber(pointIndex) || pointIndex < 0 || pointIndex >= pathLen) {
          return false
        }
        return true
      }

      /**
       * @function MultiLineString.prototype._cloneCoordinates
       * @private
       * @description 拷贝几何信息
       * @returns {Array}
       */
      _cloneCoordinates() {
        return JSON.parse(JSON.stringify(this.coordinates))
      }

      /**
       * @function MultiLineString.prototype._calcExtent
       * @private
       * @description 计算外包盒
       * @param {Array} coordinates 坐标点
       * @param {Boolean} hasZ 是否是三维
       * @returns {Extent}
       */
      _calcExtent(coordinates, hasZ) {
        const line = T.multiLineString(coordinates)
        const bbox = T.bbox(line)

        if (!hasZ) {
          return new Extent({
            xmin: bbox[0],
            ymin: bbox[1],
            xmax: bbox[2],
            ymax: bbox[3]
          })
        }
        return new Extent({
          xmin: bbox[0],
          ymin: bbox[1],
          zmin: bbox[2],
          xmax: bbox[3],
          ymax: bbox[4],
          zmax: bbox[5]
        })
      }

      /**
       * 克隆几何对象
       * @return {Geometry} 克隆后的几何对象
       */
      clone() {
        return new MultiLineString(this.toJSON())
      }
    }
    Object.defineProperties(MultiLineString.prototype, {
      /**
       * 外包盒
       * @member {Number} MultiLineString.prototype.extent
       * */
      extent: {
        configurable: false,
        get() {
          return this._calcExtent(this.coordinates, this.hasZ)
        }
      }
    })

    Zondy.Geometry.MultiLineString = MultiLineString
    export default MultiLineString