import _regeneratorRuntime from 'babel-runtime/regenerator';
import _asyncToGenerator from 'babel-runtime/helpers/asyncToGenerator';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _createClass from 'babel-runtime/helpers/createClass';
/**
 * @文件说明: Query.WFS - WFS服务
 * @创建人: pjtools@vip.qq.com
 * @创建时间: 2020-03-28 15:53:18
 */

import assign from 'lodash/assign';
import { isEmpty, isBooleanTrue, isNumeric, isBoolean, isArray, isNotEmptyArray } from '../../_util/methods-util';
import hat from 'hat';

export var defaultQueryOptions = {
  // 版本号，可选值：[ 1.0.0 | 1.1.0 ]
  version: '1.0.0',
  // 返回结果模式，可选值：[ result | pagination | count ]，其中：pagination 模式只在GeoGlobe WFS下特有
  mode: 'result',
  // 要素命名空间
  featureNS: null,
  // 要素类型前缀
  featurePrefix: null,
  // 要素几何数据XY是否反转，布尔值，默认根据版本自动设置；
  isReverse: null,
  // Geometry属性名，例如：GeoGlobe：GEOMETRY；Arcgis：SHAPE
  geometryName: null,
  // 格式解析器构造参数
  formatOptions: null,
  // 查询结果是否按图层名分类
  isSeparate: false,
  // 空间参考
  srs: null,
  // 返回要素的最大条目数
  max: 10,
  // 针对多时态矢量数据集，要素版本时间
  time: null,
  // 是否追溯，布尔型
  userecent: null,
  // 排序条件，规则：['name', 'DESC'] 或 [['name', 'ASC'], ['name', 'DESC'], ...]
  sort: null,
  // 分页查询模式，当前页码
  curpage: 1,
  // 分页查询模式，每页条目数
  pagesize: 10,
  // 空间查询时，缓冲范围距离，默认为5
  distance: 5,
  // 空间查询时，缓冲范围的单位，可选项：[ m | degree ]
  units: 'm',
  // 空间查询时，Polygon分析时，是包含还是相交
  contain: false
};

/**
 * 获取GeoGlobe WFS查询实例
 */
export var getWFSQuery = function getWFSQuery(GeoGlobe, url, typeName, options) {
  var opts = {};
  opts.version = !isEmpty(options.version) && ['1.1.0', '1.0.0'].indexOf(options.version) !== -1 ? options.version : defaultQueryOptions.version;
  !isEmpty(options.featureNS) && (opts.featureNS = options.featureNS);
  !isEmpty(options.featurePrefix) && (opts.featurePrefix = options.featurePrefix);
  opts.geometryName = !isEmpty(options.geometryName) ? options.geometryName : 'GEOMETRY';
  var isReverse = isEmpty(options.isReverse) ? options.version === '1.1.0' ? false : true : isBooleanTrue(options.isReverse) ? true : false;
  opts.format = opts.version === '1.1.0' ? new GeoGlobe.Format.GML.v3({ xy: isReverse }) : new GeoGlobe.Format.GML.v2({ xy: isReverse });
  !isEmpty(options.formatOptions) && (opts.formatOptions = options.formatOptions);
  opts.isSeparate = isBooleanTrue(options.isSeparate) ? true : false;
  opts.maxFeatures = isNumeric(options.max) ? parseInt(options.max, 10) : defaultQueryOptions.max;
  opts.srsName = !isEmpty(options.srs) ? options.srs : null;
  !isEmpty(options.time) && (opts.time = options.time);
  isBoolean(options.userecent) && (opts.userecent = options.userecent);
  // 排序
  var sortBy = null;
  if (isArray(options.sort)) {
    sortBy = [];
    // 判断是否为多字段排序
    if (isArray(options.sort[0])) {
      options.sort.map(function (item) {
        sortBy.push({ property: item[0], order: item[1] && ['ASC', 'DESC'].indexOf(item[1].toUpperCase()) !== -1 ? item[1].toUpperCase() : 'ASC' });
      });
    } else {
      sortBy.push({
        property: options.sort[0],
        order: options.sort[1] && ['ASC', 'DESC'].indexOf(options.sort[1].toUpperCase()) !== -1 ? options.sort[1].toUpperCase() : 'ASC'
      });
    }
  }
  sortBy && (opts.sortBy = sortBy);
  !isEmpty(options.groupBy) && (opts.groupBy = options.groupBy);

  return new GeoGlobe.Query.WFSQuery(url, typeName, opts);
};

/**
 * 查询过滤条件进行数据转换
 */
export var getQueryFilters = function getQueryFilters(GeoGlobe, options, wfsQuery) {
  if (isNotEmptyArray(options.filters)) {
    var toQueryFilters = function toQueryFilters(filters) {
      // 获取条件项的关键词
      var logical = filters[0] && filters[0].toUpperCase();
      // 判断过滤条件是否为复合逻辑条件
      if (logical && ['AND', 'OR', 'NOT'].indexOf(logical) !== -1) {
        var condition = [];
        for (var i = 1, len = filters.length; i < len; i++) {
          if (isNotEmptyArray(filters[i])) {
            condition.push(toQueryFilters(filters[i]));
          }
        }
        return new GeoGlobe.Filter.Logical({
          type: GeoGlobe.Filter.Logical[logical],
          filters: condition
        });
      } else {
        // 判断过滤条件是否为一般逻辑条件
        if (logical && ['==', '!=', '<', '>', '<=', '>=', '..', 'BETWEEN', '~', 'LIKE', 'NULL'].indexOf(logical) !== -1) {
          var comparison = {};
          comparison.property = filters[1];
          comparison.matchCase = true;
          // 根据类型设置属性
          switch (logical) {
            case '==':
              comparison.type = GeoGlobe.Filter.Comparison.EQUAL_TO;
              comparison.value = filters[2];
              break;
            case '!=':
              comparison.type = GeoGlobe.Filter.Comparison.NOT_EQUAL_TO;
              comparison.value = filters[2];
              break;
            case '<':
              comparison.type = GeoGlobe.Filter.Comparison.LESS_THAN;
              comparison.value = filters[2];
              break;
            case '>':
              comparison.type = GeoGlobe.Filter.Comparison.GREATER_THAN;
              comparison.value = filters[2];
              break;
            case '<=':
              comparison.type = GeoGlobe.Filter.Comparison.LESS_THAN_OR_EQUAL_TO;
              comparison.value = filters[2];
              break;
            case '>=':
              comparison.type = GeoGlobe.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO;
              comparison.value = filters[2];
              break;
            case '..':
            case 'BETWEEN':
              comparison.type = GeoGlobe.Filter.Comparison.BETWEEN;
              comparison.lowerBoundary = filters[2];
              comparison.upperBoundary = filters[3];
              break;
            case '~':
            case 'LIKE':
              comparison.type = GeoGlobe.Filter.Comparison.LIKE;
              comparison.value = filters[2].indexOf('*') !== -1 ? filters[2] : '*' + filters[2] + '*';
              break;
            case 'NULL':
              comparison.type = GeoGlobe.Filter.Comparison.IS_NULL;
              break;
          }
          return new GeoGlobe.Filter.Comparison(comparison);
        } else if (logical && ['BBOX', 'POINT', 'LINE', 'PATH', 'POLYGON'].indexOf(logical) !== -1) {
          var spatial = {};
          spatial.property = wfsQuery.geometryName;
          spatial.value = filters[1];
          // 判断WFS服务是否为1.1.0版本，则空间几何数据需要反转
          if (wfsQuery.version === '1.1.0') {
            var xReverseFun = function xReverseFun(coords) {
              for (var _i = 0, _len = coords.length; _i < _len; _i++) {
                // 判断是否还有坐标嵌套层级
                if (isArray(coords[_i]) && coords[_i][0] && isArray(coords[_i][0])) {
                  coords[_i] = xReverseFun(coords[_i]);
                } else {
                  coords[_i] = [coords[_i][1], coords[_i][0]];
                }
              }
              return coords;
            };
            spatial.value = logical === 'POINT' ? [spatial.value[1], spatial.value[0]] : isArray(spatial.value) && xReverseFun(spatial.value);
          }
          // 根据类型设置空间属性
          var points = null;
          var polygon = null;
          switch (logical) {
            case 'BBOX':
              spatial.type = GeoGlobe.Filter.Spatial.BBOX;
              spatial.value = new GeoGlobe.LngLatBounds(spatial.value[0], spatial.value[1]);
              break;
            case 'POINT':
              spatial.type = isBooleanTrue(options.contain) ? GeoGlobe.Filter.Spatial.DWITHIN : GeoGlobe.Filter.Spatial.INTERSECTS;
              spatial.distance = options.distance || defaultQueryOptions.distance;
              spatial.distanceUnits = options.units && ['degree', 'm'].indexOf(options.units) !== -1 ? options.units : defaultQueryOptions.units;
              spatial.value = new GeoGlobe.Geometry.Point(spatial.value[0], spatial.value[1]);
              break;
            case 'LINE':
            case 'PATH':
              spatial.type = isBooleanTrue(options.contain) ? GeoGlobe.Filter.Spatial.DWITHIN : GeoGlobe.Filter.Spatial.INTERSECTS;
              spatial.distance = options.distance || defaultQueryOptions.distance;
              spatial.distanceUnits = options.units && ['degree', 'm'].indexOf(options.units) !== -1 ? options.units : defaultQueryOptions.units;
              points = [];
              spatial.value.map(function (coord) {
                points.push(new GeoGlobe.Geometry.Point(coord[0], coord[1]));
              });
              spatial.value = new GeoGlobe.Geometry.LineString(points);
              break;
            case 'POLYGON':
              spatial.type = isBooleanTrue(options.contain) ? GeoGlobe.Filter.Spatial.CONTAINS : GeoGlobe.Filter.Spatial.INTERSECTS;
              polygon = [];
              spatial.value.map(function (coords) {
                points = [];
                coords.map(function (coord) {
                  points.push(new GeoGlobe.Geometry.Point(coord[0], coord[1]));
                });
                polygon.push(new GeoGlobe.Geometry.LinearRing(points));
              });
              spatial.value = new GeoGlobe.Geometry.Polygon(polygon);
              break;
          }
          return new GeoGlobe.Filter.Spatial(spatial);
        }
      }
      return null;
    };
    return toQueryFilters(options.filters);
  }
  return null;
};

/**
 * 指定图层名查询要素的统计总数
 */
export var fetchTotalTask = function fetchTotalTask(GeoGlobe, wfsQuery) {
  return new Promise(function (resolve, reject) {
    GeoGlobe.Request.GET({
      url: wfsQuery.url + '?VERSION=' + wfsQuery.version + '&REQUEST=GetFeature&SERVICE=WFS&TYPENAME=' + wfsQuery.featureType + '&RESULTTYPE=hits',
      success: function success(data) {
        data = !data.responseXML || !data.responseXML.documentElement ? data.responseText : data.responseXML;
        if (data && data.querySelector('FeatureCollection')) {
          var total = parseInt(data.querySelector('FeatureCollection').getAttribute('numberOfFeatures'), 10);
          resolve(total || 0);
        } else {
          reject();
        }
      },
      failure: function failure() {
        reject();
      }
    });
  });
};

var WFS = function () {
  function WFS(GeoGlobe) {
    _classCallCheck(this, WFS);

    this.GeoGlobe = GeoGlobe;
  }

  /**
   * 发送WFS服务任务，获取指定过滤条件的GeoJSON要素数据集合
   * @param {String} url 服务地址
   * @param {String} typeName 要素图层标识名
   * @param {Object} options 解析服务的参数选项
   */


  _createClass(WFS, [{
    key: 'queryTask',
    value: function () {
      var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(url) {
        var _this = this;

        var typeName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
        var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
        var opts;
        return _regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                opts = assign({}, defaultQueryOptions, options);
                return _context.abrupt('return', new Promise(function (resolve, reject) {
                  // 获取查询服务实例
                  var wfsQuery = getWFSQuery(_this.GeoGlobe, url, typeName, opts);
                  // 获取查询过滤条件
                  var filters = getQueryFilters(_this.GeoGlobe, opts, wfsQuery);
                  // 发送查询请求任务
                  var errorMsg = 'WFS\u67E5\u8BE2\u670D\u52A1[ ' + url + ' ]\u8981\u7D20\u6570\u636E\u89E3\u6790\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5[filters]\u8FC7\u6EE4\u6761\u4EF6\u6216\u5C5E\u6027\u4FE1\u606F\u7B49\u662F\u5426\u6709\u8BEF.';
                  var failFun = function failFun() {
                    console.error(errorMsg);
                    reject();
                  };
                  var successFun = function successFun(data) {
                    if (opts.mode !== 'count') {
                      var geojson = data && data.features && data.features.length > 0 ? data.geojson : { type: 'FeatureCollection', features: [] };
                      geojson.features.map(function (f) {
                        f.id = opts.idField ? f.properties[opts.idField].toString() : hat();
                      });
                      resolve(geojson);
                    } else {
                      resolve(data);
                    }
                  };
                  if (wfsQuery) {
                    switch (opts.mode) {
                      case 'count':
                        {
                          fetchTotalTask(GeoGlobe, wfsQuery).then(successFun)['catch'](failFun);
                          break;
                        }
                      case 'pagination':
                        {
                          wfsQuery.queryPage(filters, successFun, failFun, {
                            pageNumber: parseInt(opts.curpage, 10),
                            perPageNumber: parseInt(opts.pagesize, 10)
                          });
                          break;
                        }
                      default:
                        {
                          wfsQuery.query(filters, successFun, failFun);
                          break;
                        }
                    }
                  } else {
                    failFun();
                  }
                }));

              case 2:
              case 'end':
                return _context.stop();
            }
          }
        }, _callee, this);
      }));

      function queryTask(_x3) {
        return _ref.apply(this, arguments);
      }

      return queryTask;
    }()
  }]);

  return WFS;
}();

export default WFS;