package org.exist.xquery;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.dom.persistent.NodeSet;
import org.exist.xquery.value.AbstractSequence;
import org.exist.xquery.value.IntegerValue;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.MemoryNodeSet;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceIterator;
import org.exist.xquery.value.Type;
public class RangeSequence extends AbstractSequence {
private final static Logger LOG = LogManager.getLogger(AbstractSequence.class);
private IntegerValue start;
private IntegerValue end;
public RangeSequence(IntegerValue start, IntegerValue end) {
this.start = start;
this.end = end;
}
public void add(Item item) throws XPathException {
throw new XPathException("Internal error: adding to an immutable sequence");
}
public void addAll(Sequence other) throws XPathException {
throw new XPathException("Internal error: adding to an immutable sequence");
}
public int getItemType() {
return Type.INTEGER;
}
@Override
public SequenceIterator iterate() throws XPathException {
return new RangeSequenceIterator(start.getLong(), end.getLong());
}
@Override
public SequenceIterator unorderedIterator() throws XPathException {
return new RangeSequenceIterator(start.getLong(), end.getLong());
}
public SequenceIterator iterateInReverse() throws XPathException {
return new ReverseRangeSequenceIterator(start.getLong(), end.getLong());
}
private static class RangeSequenceIterator implements SequenceIterator {
private long current;
private final long end;
public RangeSequenceIterator(final long start, final long end) {
this.current = start;
this.end = end;
}
public Item nextItem() {
if (current <= end) {
return new IntegerValue(current++);
} else {
return null;
}
}
public boolean hasNext() {
return current <= end;
}
}
private static class ReverseRangeSequenceIterator implements SequenceIterator {
private final long start;
private long current;
public ReverseRangeSequenceIterator(final long start, final long end) {
this.start = start;
this.current = end;
}
public Item nextItem() {
if (current >= start) {
return new IntegerValue(current--);
} else {
return null;
}
}
public boolean hasNext() {
return current >= start;
}
}
public int getItemCount() {
if (start.compareTo(end) > 0)
{return 0;}
try {
return ((IntegerValue) end.minus(start)).getInt() + 1;
} catch (final XPathException e) {
LOG.warn("Unexpected exception when processing result of range expression: " + e.getMessage(), e);
return 0;
}
}
public boolean isEmpty() {
return getItemCount() == 0;
}
public boolean hasOne() {
return getItemCount() == 1;
}
public boolean hasMany() {
return getItemCount() > 1;
}
public Item itemAt(int pos) {
if (pos <= getItemCount())
try {
return new IntegerValue(start.getLong() + pos);
} catch (final XPathException e) {
LOG.warn("Unexpected exception when processing result of range expression: " + e.getMessage(), e);
}
return null;
}
public NodeSet toNodeSet() throws XPathException {
throw new XPathException("Type error: the sequence cannot be converted into" +
" a node set. Item type is xs:integer");
}
public MemoryNodeSet toMemNodeSet() throws XPathException {
throw new XPathException("Type error: the sequence cannot be converted into" +
" a node set. Item type is xs:integer");
}
public void removeDuplicates() {
}
}