package org.basex.query.item;
import java.util.Arrays;
import org.basex.query.iter.NodeCache;
import org.basex.query.iter.AxisIter;
import org.basex.query.iter.AxisMoreIter;
import org.basex.util.Token;
import org.basex.util.TokenBuilder;
/**
* Node type.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
public abstract class FNode extends ANode {
/**
* Constructor.
* @param t data type
*/
FNode(final NodeType t) {
super(t);
}
@Override
public byte[] string() {
if(val == null) val = Token.EMPTY;
return val;
}
@Override
public QNm update(final QNm nm) {
return qname();
}
@Override
public ANode deepCopy() {
return copy();
}
@Override
public final boolean is(final ANode node) {
return id == node.id;
}
@Override
public final int diff(final ANode node) {
if(id != node.id) {
ANode n = this;
while(n != null) {
final ANode p = n.parent();
if(p == node) return 1;
n = p;
}
n = node;
while(n != null) {
final ANode p = n.parent();
if(p == this) return -1;
n = p;
}
}
return id - node.id;
}
@Override
public final ANode parent() {
return par;
}
@Override
public final AxisIter ancestor() {
return new AxisIter() {
/** Temporary node. */
private ANode node = FNode.this;
@Override
public ANode next() {
node = node.parent();
return node;
}
};
}
@Override
public final AxisIter ancestorOrSelf() {
return new AxisIter() {
/** Temporary node. */
private ANode node = FNode.this;
@Override
public ANode next() {
if(node == null) return null;
final ANode n = node;
node = n.parent();
return n;
}
};
}
@Override
public AxisMoreIter attributes() {
return AxisMoreIter.EMPTY;
}
@Override
public AxisMoreIter children() {
return AxisMoreIter.EMPTY;
}
@Override
public final FNode parent(final ANode p) {
par = p;
return this;
}
@Override
public boolean hasChildren() {
return false;
}
@Override
public final AxisIter descendant() {
return desc(false);
}
@Override
public final AxisIter descendantOrSelf() {
return desc(true);
}
/**
* Iterates all nodes of the specified iterator.
* @param iter iterator
* @return node iterator
*/
static final AxisMoreIter iter(final NodeCache iter) {
return new AxisMoreIter() {
/** Child counter. */ int c;
@Override
public boolean more() { return iter != null && c != iter.size(); }
@Override
public ANode next() { return more() ? iter.get(c++) : null; }
@Override
public ANode get(final long i) { return iter.get(i); }
@Override
public long size() { return iter.size(); }
@Override
public boolean reset() { c = 0; return true; }
@Override
public Value value() { return iter.value(); }
};
}
/**
* Returns the string value for the specified nodes.
* @param iter iterator
* @return node iterator
*/
final byte[] string(final NodeCache iter) {
if(val == null) {
final TokenBuilder tb = new TokenBuilder();
for(int c = 0; c < iter.size(); ++c) {
final ANode nc = iter.get(c);
if(nc.type == NodeType.ELM || nc.type == NodeType.TXT)
tb.add(nc.string());
}
val = tb.finish();
}
return val;
}
/**
* Returns an iterator for all descendant nodes.
* @param self include self node
* @return node iterator
*/
private AxisIter desc(final boolean self) {
return new AxisIter() {
/** Iterator. */
private AxisMoreIter[] nm = new AxisMoreIter[1];
/** Iterator Level. */
private int l;
@Override
public ANode next() {
if(nm[0] == null) nm[0] = self ? self() : children();
if(l < 0) return null;
final ANode node = nm[l].next();
if(node != null) {
final AxisMoreIter ch = node.children();
if(ch.more()) {
if(l + 1 == nm.length) nm = Arrays.copyOf(nm, l + 1 << 1);
nm[++l] = ch;
} else {
while(!nm[l].more()) if(l-- <= 0) break;
}
}
return node;
}
};
}
@Override
public final AxisIter parentIter() {
return new AxisIter() {
/** First call. */
private boolean more;
@Override
public ANode next() {
return (more ^= true) ? par : null;
}
};
}
@Override
public final AxisIter followingSibling() {
return new AxisIter() {
/** Iterator. */
private AxisIter ai;
@Override
public ANode next() {
if(ai == null) {
final ANode r = parent();
if(r == null) return null;
ai = r.children();
for(ANode n; (n = ai.next()) != null && !n.is(FNode.this););
}
return ai.next();
}
};
}
@Override
public final AxisIter following() {
return new AxisIter() {
/** Iterator. */
private NodeCache nc;
@Override
public ANode next() {
if(nc == null) {
nc = new NodeCache();
ANode n = FNode.this;
ANode p = n.parent();
while(p != null) {
final AxisIter i = p.children();
for(ANode c; n.type != NodeType.ATT &&
(c = i.next()) != null && !c.is(n););
for(ANode c; (c = i.next()) != null;) {
nc.add(c.finish());
addDesc(c.children(), nc);
}
n = p;
p = p.parent();
}
}
return nc.next();
}
};
}
}