/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/
package org.geomajas.widget.searchandfilter.client.util;
import com.google.gwt.core.client.GWT;
import org.geomajas.global.GeomajasConstant;
import org.geomajas.gwt.client.command.AbstractCommandCallback;
import org.geomajas.gwt.client.command.GwtCommand;
import org.geomajas.gwt.client.command.GwtCommandDispatcher;
import org.geomajas.gwt.client.map.MapModel;
import org.geomajas.gwt.client.map.feature.Feature;
import org.geomajas.gwt.client.map.layer.VectorLayer;
import org.geomajas.gwt.client.spatial.geometry.Geometry;
import org.geomajas.gwt.client.util.GeometryConverter;
import org.geomajas.gwt.client.widget.MapWidget;
import org.geomajas.widget.searchandfilter.command.dto.FeatureSearchRequest;
import org.geomajas.widget.searchandfilter.command.dto.FeatureSearchResponse;
import org.geomajas.widget.searchandfilter.command.dto.GeometryUtilsRequest;
import org.geomajas.widget.searchandfilter.command.dto.GeometryUtilsResponse;
import org.geomajas.widget.searchandfilter.search.dto.Criterion;
import org.geomajas.widget.searchandfilter.search.dto.GeometryCriterion;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* Convenience class with helper methods for commands.
*
* @author Kristof Heirwegh
*/
public final class SearchCommService {
// CHECKSTYLE VISIBILITY MODIFIER: OFF
/** Search result size limitation. */
public static int searchResultSize = FeatureSearchRequest.MAX_UNLIMITED;
// CHECKSTYLE VISIBILITY MODIFIER: ON
// CHECKSTYLE VISIBILITY MODIFIER: OFF
/** Feature includes for searches. */
public static int featureIncludes = GeomajasConstant.FEATURE_INCLUDE_ATTRIBUTES |
GeomajasConstant.FEATURE_INCLUDE_LABEL | GeomajasConstant.FEATURE_INCLUDE_GEOMETRY;
// CHECKSTYLE VISIBILITY MODIFIER: ON
/**
* Utility class, hide constructor.
*/
private SearchCommService() {
}
/**
* The returned result will contain a merged-only and a merged and buffered result.
*
* @param geometries geometries
* @param buffer buffer size
* @param onFinished
* callback contains two geometries, one just merged, one buffered
*/
public static void mergeAndBufferGeometries(List<Geometry> geometries, double buffer,
final DataCallback<Geometry[]> onFinished) {
GeometryUtilsRequest request = new GeometryUtilsRequest();
request.setActionFlags(GeometryUtilsRequest.ACTION_BUFFER | GeometryUtilsRequest.ACTION_MERGE);
request.setIntermediateResults(true);
request.setBuffer(buffer);
request.setGeometries(toDtoGeometries(geometries));
GwtCommand command = new GwtCommand(GeometryUtilsRequest.COMMAND);
command.setCommandRequest(request);
GwtCommandDispatcher.getInstance().execute(command, new AbstractCommandCallback<GeometryUtilsResponse>() {
public void execute(GeometryUtilsResponse response) {
if (onFinished != null) {
Geometry[] geoms = new Geometry[2];
geoms[0] = GeometryConverter.toGwt(response.getGeometries()[0]);
geoms[1] = GeometryConverter.toGwt(response.getGeometries()[1]);
onFinished.execute(geoms);
}
}
});
}
/**
* @param geometries geometries
* @param onFinished callback returns one geometry
*/
public static void mergeGeometries(List<Geometry> geometries, final DataCallback<Geometry> onFinished) {
GeometryUtilsRequest request = new GeometryUtilsRequest();
request.setActionFlags(GeometryUtilsRequest.ACTION_MERGE);
request.setGeometries(toDtoGeometries(geometries));
GwtCommand command = new GwtCommand(GeometryUtilsRequest.COMMAND);
command.setCommandRequest(request);
GwtCommandDispatcher.getInstance().execute(command, new AbstractCommandCallback<GeometryUtilsResponse>() {
public void execute(GeometryUtilsResponse response) {
if (onFinished != null) {
onFinished.execute(GeometryConverter.toGwt(response.getGeometries()[0]));
}
}
});
}
public static void bufferGeometry(Geometry geometry, double buffer, final DataCallback<Geometry> onFinished) {
List<Geometry> geometries = new ArrayList<Geometry>();
geometries.add(geometry);
bufferGeometries(geometries, buffer, new DataCallback<Geometry[]>() {
public void execute(Geometry[] result) {
if (result != null && result.length > 0) {
onFinished.execute(result[0]);
} else {
onFinished.execute(null);
}
}
});
}
/**
* @param geometries geometries
* @param buffer buffer size
* @param onFinished
* callback returns buffered geometries
*/
public static void bufferGeometries(List<Geometry> geometries, double buffer,
final DataCallback<Geometry[]> onFinished) {
GeometryUtilsRequest request = new GeometryUtilsRequest();
request.setActionFlags(GeometryUtilsRequest.ACTION_BUFFER);
request.setGeometries(toDtoGeometries(geometries));
request.setBuffer(buffer);
GwtCommand command = new GwtCommand(GeometryUtilsRequest.COMMAND);
command.setCommandRequest(request);
GwtCommandDispatcher.getInstance().execute(command, new AbstractCommandCallback<GeometryUtilsResponse>() {
public void execute(GeometryUtilsResponse response) {
if (onFinished != null) {
Geometry[] geometriesArray = new Geometry[response.getGeometries().length];
for (int i = 0; i < geometriesArray.length; i++) {
geometriesArray[i] = GeometryConverter.toGwt(response.getGeometries()[i]);
}
onFinished.execute(geometriesArray);
}
}
});
}
public static org.geomajas.geometry.Geometry[] toDtoGeometries(List<Geometry> geometries) {
org.geomajas.geometry.Geometry[] dtoGeometries = new org.geomajas.geometry.Geometry[geometries.size()];
for (int i = 0; i < geometries.size(); i++) {
dtoGeometries[i] = GeometryConverter.toDto(geometries.get(i));
}
return dtoGeometries;
}
/**
* Build {@link GeometryCriterion} for the map widget, geometry and optional layer.
*
* @param geometry geometry
* @param mapWidget map widget
* @param layer layer
* @return geometry criterion
*/
public static GeometryCriterion buildGeometryCriterion(final Geometry geometry, final MapWidget mapWidget,
VectorLayer layer) {
List<String> layers;
if (null == layer) {
layers = getVisibleServerLayerIds(mapWidget.getMapModel());
} else {
layers = new ArrayList<String>();
layers.add(layer.getServerLayerId());
}
return new GeometryCriterion(layers, GeometryConverter.toDto(geometry));
}
/**
* Execute a search by criterion command.
*
* @param criterion criterion
* @param mapWidget map widget
* @param onFinished callback
* @param onError
* callback to execute in case of error, optional use null if you
* don't need it
*/
public static void searchByCriterion(final Criterion criterion, final MapWidget mapWidget,
final DataCallback<Map<VectorLayer, List<Feature>>> onFinished, final Runnable onError) {
FeatureSearchRequest request = new FeatureSearchRequest();
request.setMapCrs(mapWidget.getMapModel().getCrs());
request.setCriterion(criterion);
request.setLayerFilters(getLayerFiltersForCriterion(criterion, mapWidget.getMapModel()));
request.setFeatureIncludes(featureIncludes);
request.setMax(searchResultSize);
GwtCommand commandRequest = new GwtCommand(FeatureSearchRequest.COMMAND);
commandRequest.setCommandRequest(request);
GwtCommandDispatcher.getInstance().execute(commandRequest,
new AbstractCommandCallback<FeatureSearchResponse>() {
public void execute(FeatureSearchResponse response) {
onFinished.execute(convertFromDto(response.getFeatureMap(), mapWidget.getMapModel()));
}
@Override
public void onCommunicationException(Throwable error) {
if (null != onError) {
onError.run();
} else {
super.onCommunicationException(error);
}
}
});
}
/**
* Builds a map with the filters for all layers that are used in the given criterion.
*
* @param critter criterion
* @param mapModel map model
* @return filters for all layers
*/
public static Map<String, String> getLayerFiltersForCriterion(Criterion critter, MapModel mapModel) {
Map<String, String> filters = new HashMap<String, String>();
Set<String> serverLayerIds = new HashSet<String>();
critter.serverLayerIdVisitor(serverLayerIds);
for (VectorLayer vectorLayer : mapModel.getVectorLayers()) {
if (serverLayerIds.contains(vectorLayer.getServerLayerId())) {
if (vectorLayer.getFilter() != null && !"".equals(vectorLayer.getFilter())) {
filters.put(vectorLayer.getServerLayerId(), vectorLayer.getFilter());
}
}
}
return filters;
}
// ----------------------------------------------------------
/**
* This also adds the features to their respective layers, so no need to do
* that anymore.
*
* @param dtoFeatures DTOPs for features
* @param model map model
* @return client features
*/
private static Map<VectorLayer, List<Feature>> convertFromDto(
Map<String, List<org.geomajas.layer.feature.Feature>> dtoFeatures, MapModel model) {
Map<VectorLayer, List<Feature>> result = new LinkedHashMap<VectorLayer, List<Feature>>();
for (Entry<String, List<org.geomajas.layer.feature.Feature>> entry : dtoFeatures.entrySet()) {
if (!entry.getValue().isEmpty()) {
List<Feature> convertedFeatures = new ArrayList<Feature>();
VectorLayer layer = convertFromDto(entry.getKey(), entry.getValue(), convertedFeatures, model);
if (layer != null) {
result.put(layer, convertedFeatures);
} else {
// TODO couldn't find layer client-side ?? maybe should throw an error here
GWT.log("Couldn't find layer client-side ?? " + entry.getKey());
}
}
}
return result;
}
private static VectorLayer convertFromDto(String serverLayerId,
List<org.geomajas.layer.feature.Feature> dtoFeatures, List<Feature> convertedFeatures, MapModel model) {
List<VectorLayer> layers = model.getVectorLayersByServerId(serverLayerId);
for (VectorLayer vectorLayer : layers) {
for (org.geomajas.layer.feature.Feature dtoFeature : dtoFeatures) {
org.geomajas.gwt.client.map.feature.Feature feature = new org.geomajas.gwt.client.map.feature.Feature(
dtoFeature, vectorLayer);
vectorLayer.getFeatureStore().addFeature(feature);
convertedFeatures.add(feature);
}
return vectorLayer;
}
return null;
}
/**
* Get a list of all visible layers on the given {@link MapModel}.
*
* @param mapModel map model
* @return a list of all visible layers.
*/
public static List<String> getVisibleServerLayerIds(MapModel mapModel) {
List<String> layerIds = new ArrayList<String>();
for (VectorLayer layer : mapModel.getVectorLayers()) {
if (layer.isShowing()) {
layerIds.add(layer.getServerLayerId());
}
}
return layerIds;
}
}