package org.basex.query.path;
import static org.basex.query.util.Err.*;
import org.basex.query.QueryContext;
import org.basex.query.QueryException;
import org.basex.query.expr.Expr;
import org.basex.query.item.Item;
import org.basex.query.item.ANode;
import org.basex.query.item.SeqType;
import org.basex.query.item.Value;
import org.basex.query.iter.Iter;
import org.basex.query.iter.NodeIter;
import org.basex.util.InputInfo;
/**
* Iterative path expression for location paths which return sorted and
* duplicate-free results.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
final class IterPath extends AxisPath {
/**
* Constructor.
* @param ii input info
* @param r root expression
* @param s axis steps
* @param t return type
* @param c cardinality
*/
IterPath(final InputInfo ii, final Expr r, final Expr[] s, final SeqType t,
final long c) {
super(ii, r, s);
type = t;
size = c;
}
@Override
public NodeIter iter(final QueryContext ctx) {
return new NodeIter() {
Expr[] expr;
Iter[] iter;
ANode node;
int p;
@Override
public ANode next() throws QueryException {
if(iter == null) {
if(expr == null) {
expr = steps;
if(root != null) {
// add root as first expression
expr = new Expr[steps.length + 1];
expr[0] = root;
System.arraycopy(steps, 0, expr, 1, steps.length);
}
}
// create iterator array
iter = new Iter[expr.length];
iter[0] = ctx.iter(expr[0]);
}
final Value cv = ctx.value;
final long cp = ctx.pos;
final long cs = ctx.size;
try {
while(true) {
final Item item = iter[p].next();
if(item == null) {
if(--p == -1) {
node = null;
break;
}
} else if(p < iter.length - 1) {
++p;
ctx.value = item;
if(iter[p] == null || !iter[p].reset())
iter[p] = ctx.iter(expr[p]);
} else {
// not expected to happen, as steps will always yield nodes
if(!item.type.isNode()) NODESPATH.thrw(input, this, item.type);
final ANode n = (ANode) item;
if(node == null || !node.is(n)) {
node = n;
break;
}
}
}
return node;
} finally {
// reset context and return result
ctx.value = cv;
ctx.pos = cp;
ctx.size = cs;
}
}
@Override
public boolean reset() {
iter = null;
node = null;
p = 0;
return true;
}
};
}
}