package jp.aonir.fuzzyxml.xpath;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import jp.aonir.fuzzyxml.FuzzyXMLDocument;
import jp.aonir.fuzzyxml.FuzzyXMLElement;
import jp.aonir.fuzzyxml.FuzzyXMLNode;
import org.apache.commons.jxpath.ri.compiler.NodeTest;
import org.apache.commons.jxpath.ri.model.NodeIterator;
import org.apache.commons.jxpath.ri.model.NodePointer;
public class FuzzyXMLNodeIterator implements NodeIterator {
private NodePointer _parent;
private NodeTest _nodeTest;
private boolean _reverse;
private int _position = 0;
private int _index = 0;
private List<FuzzyXMLNode> _children;
private Object _child;
/**
*
*/
public FuzzyXMLNodeIterator(NodePointer parent, NodeTest nodeTest, boolean reverse, NodePointer startWith) {
this._parent = parent;
if (startWith != null) {
this._child = startWith.getNode();
}
// TBD: optimize me for different node tests
Object node = parent.getNode();
if (node instanceof FuzzyXMLDocument) {
this._children = Arrays.asList(new FuzzyXMLNode[] { ((FuzzyXMLDocument) node).getDocumentElement() });
}
else if (node instanceof FuzzyXMLElement) {
this._children = Arrays.asList(((FuzzyXMLElement) node).getChildren());
}
else {
this._children = new ArrayList<FuzzyXMLNode>();
}
this._nodeTest = nodeTest;
this._reverse = reverse;
}
public int getPosition() {
return _position;
}
public boolean setPosition(int position) {
while (this._position < position) {
if (!next()) {
return false;
}
}
while (this._position > position) {
if (!previous()) {
return false;
}
}
return true;
}
public NodePointer getNodePointer() {
if (_child == null) {
if (!setPosition(1)) {
return null;
}
_position = 0;
}
return new FuzzyXMLNodePointer(_parent, _child);
}
/**
* This is actually never invoked during the normal evaluation
* of xpaths - an iterator is always going forward, never backwards.
* So, this is implemented only for completeness and perhaps for
* those who use these iterators outside of XPath evaluation.
*/
private boolean previous() {
_position--;
if (!_reverse) {
while (--_index >= 0) {
_child = _children.get(_index);
if (testChild()) {
return true;
}
}
}
else {
for (; _index < _children.size(); _index++) {
_child = _children.get(_index);
if (testChild()) {
return true;
}
}
}
return false;
}
private boolean next() {
_position++;
if (!_reverse) {
if (_position == 1) {
_index = 0;
if (_child != null) {
_index = _children.indexOf(_child) + 1;
}
}
else {
_index++;
}
for (; _index < _children.size(); _index++) {
_child = _children.get(_index);
if (testChild()) {
return true;
}
}
return false;
}
if (_position == 1) {
_index = _children.size() - 1;
if (_child != null) {
_index = _children.indexOf(_child) - 1;
}
}
else {
_index--;
}
for (; _index >= 0; _index--) {
_child = _children.get(_index);
if (testChild()) {
return true;
}
}
return false;
}
private boolean testChild() {
return FuzzyXMLNodePointer.testNode(_parent, _child, _nodeTest);
}
}