package org.wikibrain.spatial.dao.postgis;
import com.google.common.collect.Lists;
import com.typesafe.config.Config;
import com.vividsolutions.jts.geom.Geometry;
import gnu.trove.set.TIntSet;
import gnu.trove.set.hash.TIntHashSet;
import org.geotools.data.FeatureSource;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.opengis.feature.Feature;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.PropertyName;
import org.wikibrain.conf.Configuration;
import org.wikibrain.conf.ConfigurationException;
import org.wikibrain.conf.Configurator;
import org.wikibrain.core.dao.DaoException;
import org.wikibrain.spatial.dao.SpatialContainmentDao;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Created by bjhecht on 4/7/14.
*/
public class PostGISSpatialContainmentDao implements SpatialContainmentDao {
private final PostGISDB db;
public PostGISSpatialContainmentDao(PostGISDB db){
this.db = db;
}
@Override
public TIntSet getContainedItemIds(Integer itemId, String layerName, String refSysName, Set<String> subLayers, ContainmentOperationType opType) throws DaoException {
Geometry g = db.getGeometry(itemId, layerName, refSysName);
if (g == null){
throw new DaoException(String.format("Could not find item %d in layer %s (%s)", itemId, layerName, refSysName));
}
return getContainedItemIds(g, refSysName, subLayers, opType);
}
@Override
public TIntSet getContainedItemIds(Geometry g, String refSysName, Set<String> subLayers, ContainmentOperationType opType) throws DaoException {
if (subLayers.size() == 0) throw new DaoException("Cannot get containment without any layers");
// *** BUILD SOMEWHAT COMPLEX QUERY ***
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
PropertyName geomProperty = ff.property(db.getGeometryAttributeName());
//build ref sys clause
PropertyName refSysProperty = ff.property(db.getRefSysAttributeName());
Filter refSysFilter = ff.equals(refSysProperty, ff.literal(refSysName));
// build layer-related clause
PropertyName layerProperty = ff.property(db.getLayerAttributeName());
List<Filter> layerFilters = Lists.newArrayList();
for (String subLayer : subLayers){
Filter curLayerFilter = ff.equals(layerProperty, ff.literal(subLayer));
layerFilters.add(curLayerFilter);
}
Filter layerFilter = ff.and(layerFilters);
Filter geomFilter = null;
switch(opType){
case CONTAINMENT:
geomFilter = ff.contains(ff.literal(g), geomProperty);
break;
case INTERSECTION:
geomFilter = ff.intersects(ff.literal(g), geomProperty);
break;
default:
throw new DaoException("Illegal containment operation type (not supported): " + opType);
}
List<Filter> filters = Lists.newArrayList();
filters.add(refSysFilter);
filters.add(layerFilter);
filters.add(geomFilter);
Filter finalFilter = ff.and(filters);
// *** EXECUTE QUERY ***
FeatureSource featureSource;
FeatureCollection containedFeatures;
try {
featureSource = db.getFeatureSource();
containedFeatures = featureSource.getFeatures(finalFilter);
}
catch (IOException e){
throw new DaoException();
}
FeatureIterator featureIterator = containedFeatures.features();
TIntSet rVal = new TIntHashSet();
while (featureIterator.hasNext()){
Feature f = featureIterator.next();
Integer itemId = (Integer)f.getProperty(db.getItemIdAttributeName()).getValue();
rVal.add(itemId);
}
featureIterator.close();
return rVal;
}
public static class Provider extends org.wikibrain.conf.Provider<PostGISSpatialContainmentDao> {
public Provider(Configurator configurator, Configuration config) throws ConfigurationException {
super(configurator, config);
}
@Override
public Class getType() {
return SpatialContainmentDao.class;
}
@Override
public String getPath() {
return "spatial.dao.spatialContainment";
}
@Override
public PostGISSpatialContainmentDao get(String name, Config config, Map<String, String> runtimeParams) throws ConfigurationException {
return new PostGISSpatialContainmentDao( getConfigurator().get(PostGISDB.class, config.getString("dataSource")));
}
}
}