Source: filter/filtermodule.js

goog.provide('M.filter.spatial');

goog.require('M.filter.Spatial');


/**
 * @namespace M.filter.spatial
 */
(function() {
  /**
   * This function creates a spatial filter to know which features contain another feature or layer
   *
   * @function
   * @param {M.layer.Vector|object} param - Layer or geometry on which the query is performed
   * @return {M.filter.Spatial} Space filter
   * @api stable
   */
  M.filter.spatial.CONTAIN = function(param) {
    let geometries = M.filter.spatial.parseParamToGeometries(param);
    return new M.filter.Spatial(function(geometryToFilter, index) {
      let geojsonParser = new jsts.io.GeoJSONReader();
      let jtsGeomToFilter = geojsonParser.read(geometryToFilter);
      return geometries.some(geom => {
        let jtsGeom = geojsonParser.read(geom);
        return jtsGeomToFilter.contains(jtsGeom);
      });
    }, {
      cqlFilter: M.filter.spatial.toCQLFilter_("CONTAINS", geometries)
    });
  };

  /**
   * This function creates a spatial filter to know which features disjoint another feature or layer
   *
   * @function
   * @param {M.layer.Vector|object} param - Layer or geometry on which the query is performed
   * @return {M.filter.Spatial} Space filter
   * @api stable
   */
  M.filter.spatial.DISJOINT = function(param) {
    let geometries = M.filter.spatial.parseParamToGeometries(param);
    return new M.filter.Spatial(function(geometryToFilter, index) {
      let geojsonParser = new jsts.io.GeoJSONReader();
      let jtsGeomToFilter = geojsonParser.read(geometryToFilter);
      return geometries.some(geom => {
        let jtsGeom = geojsonParser.read(geom);
        return jtsGeomToFilter.disjoint(jtsGeom);
      });
    }, {
      cqlFilter: M.filter.spatial.toCQLFilter_("DISJOINT", geometries)
    });
  };

  /**
   * This function creates a spatial filter to know which features within another feature or layer
   *
   * @function
   * @param {M.layer.Vector|object} param - Layer or geometry on which the query is performed
   * @return {M.filter.Spatial} Space filter
   * @api stable
   */
  M.filter.spatial.WITHIN = function(param) {
    let geometries = M.filter.spatial.parseParamToGeometries(param);
    return new M.filter.Spatial(function(geometryToFilter, index) {
      let geojsonParser = new jsts.io.GeoJSONReader();
      let jtsGeomToFilter = geojsonParser.read(geometryToFilter);
      return geometries.some(geom => {
        let jtsGeom = geojsonParser.read(geom);
        return jtsGeomToFilter.within(jtsGeom);
      });
    }, {
      cqlFilter: M.filter.spatial.toCQLFilter_("WITHIN", geometries)
    });
  };

  /**
   * This function creates a spatial filter to know which features intersects another feature or layer
   *
   * @function
   * @param {M.layer.Vector|M.Feature|object|Array<M.Feature|object>} param - Layer or geometry on which the query is performed
   * @return {M.filter.Spatial} Space filter
   * @api stable
   */
  M.filter.spatial.INTERSECT = function(param) {
    let geometries = M.filter.spatial.parseParamToGeometries(param);
    return new M.filter.Spatial(function(geometryToFilter, index) {
      let geojsonParser = new jsts.io.GeoJSONReader();
      let jtsGeomToFilter = geojsonParser.read(geometryToFilter);
      return geometries.some(geom => {
        let jtsGeom = geojsonParser.read(geom);
        return jtsGeomToFilter.intersects(jtsGeom);
      });
    }, {
      cqlFilter: M.filter.spatial.toCQLFilter_("INTERSECTS", geometries)
    });
  };

  /**
   * TODO
   *
   * @function
   * @param {M.layer.Vector|M.Feature|object|Array<M.Feature|object>} param - Layer or geometry on which the query is performed
   * @return {M.filter.Spatial} Space filter
   * @api stable
   */
  M.filter.spatial.parseParamToGeometries = function(param) {
    let geometries = [];
    if (param instanceof M.layer.Vector) {
      geometries = [...param.getFeatures().map(feature => feature.getGeometry())];
    }
    else {
      if (!M.utils.isArray(param)) {
        param = [param];
      }
      geometries = param.map(p => {
        let geom;
        if (p instanceof M.Feature) {
          geom = p.getGeometry();
        }
        else if (M.utils.isObject(p)) {
          geom = p;
        }
        return geom;
      });
    }

    return geometries;
  };

  /**
   * TODO
   *
   * @private
   * @function
   * @param {M.layer.Vector|M.Feature|object|Array<M.Feature|object>} param - Layer or geometry on which the query is performed
   * @return {M.filter.Spatial} Space filter
   */
  M.filter.spatial.toCQLFilter_ = function(operation, geometries) {
    let cqlFilter = "";
    let wktFormat = new M.format.WKT();
    for (let i = 0; i < geometries.length; i++) {
      if (i !== 0) {
        // es un OR porque se hace una interseccion completa con todas
        // las geometries
        cqlFilter += " OR ";
      }
      let geometry = geometries[i];
      if (geometry.type.toLowerCase() === "point") {
        geometry.coordinates.length = 2;
      }
      cqlFilter += operation + "({{geometryName}}, " + wktFormat.write(geometry) + ")";
    }
    return cqlFilter;
  };
})();