package com.orci.geoserver.wfs.getnearest;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.geotools.feature.Feature;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.FeatureType;
import org.geotools.feature.GeometryAttributeType;
import org.geotools.feature.IllegalAttributeException;
import org.geotools.feature.collection.AbstractFeatureCollection;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
/**
* A feature collection wrapping a base collection, returning features that do
* conform to the specified type (which has have a subset of the attributes in the
* original schema), and that do use the wrapped features to compute their bounds (so that
* the Feature bounds can be computed even if the visible attributes do not include geometries)
* @author Andrea Aime - TOPP
*
*/
class FeatureBoundsFeatureCollection extends AbstractFeatureCollection {
FeatureCollection wrapped;
/**
* Builds a new BoundsFeatureCollection
* @param wrapped the wrapped feature collection
* @param targetSchema the target schema
*/
public FeatureBoundsFeatureCollection(FeatureCollection wrapped, FeatureType targetSchema) {
super(targetSchema);
this.wrapped = wrapped;
}
protected void closeIterator(Iterator close) {
((BoundsIterator) close).close();
}
protected Iterator openIterator() {
return new BoundsIterator(wrapped.features(), getSchema());
}
public int size() {
return wrapped.size();
}
/**
*
* @author Andrea Aime - TOPP
*
*/
private static class BoundsIterator implements Iterator {
FeatureIterator wrapped;
FeatureType targetSchema;
public BoundsIterator(FeatureIterator wrapped, FeatureType targetSchema) {
this.wrapped = wrapped;
this.targetSchema = targetSchema;
}
public void close() {
wrapped.close();
}
public boolean hasNext() {
return wrapped.hasNext();
}
public Object next() throws NoSuchElementException {
Feature base = wrapped.next();
return new BoundedFeature(base, targetSchema);
}
public void remove() {
throw new UnsupportedOperationException("Removal is not supported");
}
}
/**
* Wraps a Feature shaving off all attributes not included in the original type, but
* delegates bounds computation to the original feature.
* @author Andrea Aime - TOPP
*
*/
private static class BoundedFeature implements Feature {
private Feature wrapped;
private FeatureType type;
public BoundedFeature(Feature wrapped, FeatureType type) {
this.wrapped = wrapped;
this.type = type;
}
public Object getAttribute(int index) {
return wrapped.getAttribute(type.getAttributeType(index).getName());
}
public Object getAttribute(String path) {
if (type.getAttributeType(path) == null)
return null;
return wrapped.getAttribute(path);
}
public Object[] getAttributes(Object[] attributes) {
Object[] retval = attributes != null ? attributes : new Object[type.getAttributeCount()];
for (int i = 0; i < retval.length; i++) {
retval[i] = wrapped.getAttribute(type.getAttributeType(i).getName());
}
return retval;
}
public Envelope getBounds() {
// we may not have the default geometry around in the reduced feature type,
// so let's output a referenced envelope if possible
if(wrapped.getFeatureType().getDefaultGeometry() != null) {
CoordinateReferenceSystem crs = wrapped.getFeatureType().getDefaultGeometry().getCoordinateSystem();
if(crs != null) {
return new ReferencedEnvelope(wrapped.getBounds(), crs);
}
}
return wrapped.getBounds();
}
public Geometry getDefaultGeometry() {
GeometryAttributeType defaultGeometry = type.getDefaultGeometry();
if(defaultGeometry == null)
return null;
return (Geometry) wrapped.getAttribute(defaultGeometry.getName());
}
public FeatureType getFeatureType() {
return type;
}
public String getID() {
return wrapped.getID();
}
public int getNumberOfAttributes() {
return type.getAttributeCount();
}
public void setAttribute(int position, Object val) throws IllegalAttributeException,
ArrayIndexOutOfBoundsException {
throw new UnsupportedOperationException("This feature wrapper is read only");
}
public void setAttribute(String path, Object attribute) throws IllegalAttributeException {
throw new UnsupportedOperationException("This feature wrapper is read only");
}
public void setDefaultGeometry(Geometry geometry) throws IllegalAttributeException {
throw new UnsupportedOperationException("This feature wrapper is read only");
}
public FeatureCollection getParent() {
return wrapped.getParent();
}
public void setParent(FeatureCollection collection) {
wrapped.setParent(collection);
}
}
}