/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2009-2012, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.index.tree;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.ArraysExt;
import org.geotoolkit.internal.tree.TreeAccess;
import static org.geotoolkit.internal.tree.TreeUtilities.*;
/**
* An Iterator which travel all search result one by one, from Tree architecture stored in a {@link TreeAccess } object.
*
* @author Remi Marechal (Geomatys).
*/
class TreeIntegerIdentifierIterator implements TreeIdentifierIterator {
/**
* {@link TreeAccess} which contain all saved {@link Tree} {@link Node}.
*/
private final TreeAccess tAF;
/**
* Area of search.
*/
private final double[] regionSearch;
/**
* List which contain all Node search stack path.
*/
private final List<Node> path;
/**
* Current data Node identifier.
*/
private int dataID;
/**
* Current tree identifier.
*/
private int dataValue;
/**
* Create an Iterator to travel all treeIdentifier from search results one by one.
*
* @param tAF TreeAccess which contain all saved Node.
* @param regionSearch area of search
* @throws StoreIndexException if problem during iterator initialize.(TreeAccess should not read tree root Node).
*/
TreeIntegerIdentifierIterator(final TreeAccess tAF, final double[] regionSearch) throws StoreIndexException {
ArgumentChecks.ensureNonNull("TreeAccess tAF", tAF);
ArgumentChecks.ensureNonNull("regionSearch", regionSearch);
if (ArraysExt.hasNaN(regionSearch))
throw new StoreIndexException("regionSearch parameter should not contain NaN value. region search : "+Arrays.toString(regionSearch));
this.tAF = tAF;
this.regionSearch = regionSearch;
this.path = new ArrayList<Node>();
try {
final Node root = tAF.readNode(1);
if (root != null && !root.isEmpty()) {
this.path.add(root);
// initialization
getNextData(0);
} else {
dataValue = 0;
}
} catch (IOException ex) {
throw new StoreIndexException("problem during first data search file reading.", ex);
}
}
/**
* Remove all Nodes from i index position to end of list.
*
* @param i index position of first Node which will be delete.
*/
private void removeNodes(final int i) {
for (int idL = path.size()-1; idL >= i; idL--) {
path.remove(idL);
}
}
/**
* Find recursively, next data in tree.
*
* @param pathID Node index position in path list.
* @throws IOException if problem during Node reading from TreeAccess.
*/
private void getNextData(final int pathID) throws IOException {
final Node currentNode = path.get(pathID);
if ((!currentNode.isEmpty()) && intersects(currentNode.getBoundary(), regionSearch, true)) {
if (currentNode.isData()) {
if (dataID == currentNode.getNodeId()) {
/**
* Go to next sibling.
*/
if (currentNode.getSiblingId() != 0) {
path.remove(pathID);
path.add(tAF.readNode(currentNode.getSiblingId()));
getNextData(pathID);
} else {
/**
* end of current Node chained list.
*/
getNextData(pathID-1);
}
} else {
dataID = currentNode.getNodeId();
dataValue = -currentNode.getChildId();
}
} else {
// if path + 1 == path.size there isn't child in list. add first child.
if (pathID + 1 == path.size()) {//pas d'enfant
path.add(tAF.readNode(currentNode.getChildId()));
getNextData(pathID+1);
} else if (currentNode.getSiblingId() != 0) {// there is a child in list which mean we are in travel up recurency
/**
* There is a child in list which mean we are in travel up recurency and the current Node has already be red.<br/>
* We follow its sibling Node.
*/
removeNodes(pathID);
path.add(tAF.readNode(currentNode.getSiblingId()));
getNextData(pathID);
} else if (currentNode.getParentId() != 0) {
/**
* We are at the end of chained Node List we travel up to current Node parent.
*/
getNextData(pathID-1);
} else {
dataValue = 0;
}
}
} else {
if (currentNode.getSiblingId() != 0) {
/**
* There is a child in list which mean we are in travel up recurency and the current Node has already be red.<br/>
* We follow its sibling Node.
*/
// remove currentNode.
removeNodes(pathID);
// add sibling current Node.
path.add(tAF.readNode(currentNode.getSiblingId()));
getNextData(pathID);
} else if (currentNode.getParentId() != 0) {
/**
* We are at the end of chained Node List we travel up to current Node parent.
*/
getNextData(pathID-1);
} else {
// finish
dataValue = 0;
}
}
}
/**
* {@inheritDoc }.
*/
@Override
public int nextInt() throws IOException {
final int nextInt = dataValue;
getNextData(path.size() - 1);
return nextInt;
}
/**
* {@inheritDoc }
*/
@Override
public boolean hasNext() {
return dataValue != 0;
}
/**
* {@inheritDoc }.
*/
@Override
public Integer next() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
/**
*
*/
@Override
public void remove() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}