package org.geotools.caching.grid.featurecache.readers;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Stack;
import org.geotools.caching.grid.spatialindex.GridData;
import org.geotools.caching.grid.spatialindex.GridNode;
import org.geotools.caching.grid.spatialindex.GridRootNode;
import org.geotools.caching.grid.spatialindex.GridSpatialIndex;
import org.geotools.caching.spatialindex.NodeIdentifier;
import org.geotools.data.FeatureReader;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
/**
* Feature Reader that reads features from a cache.
*
* <p>
*
* </p>
* @author Emily
* @since 1.2.0
*
* @source $URL$
*/
public class GridCacheFeatureReader implements FeatureReader<SimpleFeatureType, SimpleFeature> {
private Stack<NodeIdentifier> tovisit = new Stack<NodeIdentifier>(); //nodes to visit
private Iterator<GridData> currentNodeIterator = null; //current node data iterator
private GridSpatialIndex grid; //grid cache
private SimpleFeature next; //next feature in the collection
private HashSet<String> collectedFeatureIds; //need this for now because the "grid" may store the same feature multiple times per node; we only want to get each feature once
/**
* Creates a feature reader which reads features from a collection
* of nodes.
*
* @param nodeids
* @param g
*/
public GridCacheFeatureReader(Collection<NodeIdentifier> nodeids, GridSpatialIndex g){
this.grid = g;
collectedFeatureIds = new HashSet<String>();
GridRootNode gn = g.getRootNode();
tovisit.add(gn.getIdentifier());
if (nodeids != null) {
for( Iterator<NodeIdentifier> iterator = nodeids.iterator(); iterator.hasNext(); ) {
NodeIdentifier id = (NodeIdentifier) iterator.next();
if (id.isValid()) {
tovisit.add(id);
}
}
init();
}
}
/**
* Closes the feature reader
*/
public void close() throws IOException {
tovisit.clear();
tovisit =null;
currentNodeIterator = null;
next = null;
grid = null;
}
/**
* @returns the type of features that the feature reader returns
*/
public SimpleFeatureType getFeatureType() {
if (grid.getStorage().getFeatureTypes().size() == 0){
return null;
}else{
return (SimpleFeatureType)grid.getStorage().getFeatureTypes().iterator().next();
}
}
/**
* @returns true if more features to be read; false if all features read
*/
public boolean hasNext() throws IOException {
return next != null;
}
/**
* Finds the first element in the collection (or null if no elements).
*/
private void init(){
//find first
currentNodeIterator = null;
next = findNext();
}
/**
* Finds the next element to read.
*
* @return next element or null if no more elements
*/
private SimpleFeature findNext(){
SimpleFeature sf = null;
while(true){
if (currentNodeIterator != null && currentNodeIterator.hasNext()){
sf = (SimpleFeature)((GridData)currentNodeIterator.next()).getData();
if (!collectedFeatureIds.contains(sf.getID())){
//we want to return sf
break;
}
}
if (currentNodeIterator == null || !currentNodeIterator.hasNext()){
if (tovisit.size() == 0){
//nothing found; no other things to look at
return null;
}
NodeIdentifier nodeid = tovisit.pop();
GridNode currentNode = (GridNode)grid.readNode(nodeid);
currentNodeIterator = currentNode.getData().iterator();
}
}
if (sf != null){
collectedFeatureIds.add(sf.getID());
}
return sf;
}
/**
* Returns the next element in the collection
*/
public SimpleFeature next() throws IOException, IllegalArgumentException,
NoSuchElementException {
SimpleFeature current = next;
next = findNext();
if (current == null){
throw new NoSuchElementException("Invalid call; no more feature here.");
}
return current;
}
}