package org.basex.api.xqj;
import static org.basex.api.xqj.BXQText.*;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.net.URI;
import java.util.Properties;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Result;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xquery.XQConnection;
import javax.xml.xquery.XQConstants;
import javax.xml.xquery.XQException;
import javax.xml.xquery.XQItem;
import javax.xml.xquery.XQItemType;
import javax.xml.xquery.XQResultSequence;
import org.basex.io.out.ArrayOutput;
import org.basex.io.serial.SAXSerializer;
import org.basex.io.serial.Serializer;
import org.basex.query.QueryException;
import org.basex.query.item.Item;
import org.basex.query.iter.ItemCache;
import org.basex.query.iter.Iter;
import org.basex.util.Util;
import org.w3c.dom.Node;
import org.xml.sax.ContentHandler;
/**
* Java XQuery API - Result Sequence.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
final class BXQSequence extends BXQAbstract implements XQResultSequence {
/** Result iterator. */
final Iter result;
/** Current result. */
private BXQItem it;
/** Iterator position. */
private int pos;
/** BXQConnection. */
private final BXQConnection conn;
/** Next flag. */
private boolean next;
/** Forward flag. */
private final boolean scrollable;
/**
* Constructor.
* @param item result item
* @param c closer
* @throws XQException xquery exception
*/
BXQSequence(final Iter item, final BXQDataFactory c) throws XQException {
this(item, c, null);
}
/**
* Constructor.
* @param item result item
* @param c closer
* @param cn connection
* @throws XQException xquery exception
*/
BXQSequence(final Iter item, final BXQAbstract c,
final BXQConnection cn) throws XQException {
super(c);
result = item;
conn = cn;
scrollable = cn == null || cn.getStaticContext().
getScrollability() == XQConstants.SCROLLTYPE_SCROLLABLE;
}
@Override
public XQConnection getConnection() throws XQException {
opened();
return conn;
}
@Override
public boolean absolute(final int p) throws XQException {
final ItemCache ic = sequence();
cursor(ic, p >= 0 ? p - 1 : (int) ic.size() + p);
return pos > 0;
}
@Override
public void afterLast() throws XQException {
cursor(sequence(), Integer.MAX_VALUE);
}
@Override
public void beforeFirst() throws XQException {
cursor(sequence(), -1);
}
@Override
public int count() throws XQException {
return (int) sequence().size();
}
@Override
public boolean first() throws XQException {
return cursor(sequence(), 0);
}
@Override
public String getAtomicValue() throws XQException {
return item().getAtomicValue();
}
@Override
public boolean getBoolean() throws XQException {
return item().getBoolean();
}
@Override
public byte getByte() throws XQException {
return item().getByte();
}
@Override
public double getDouble() throws XQException {
return item().getDouble();
}
@Override
public float getFloat() throws XQException {
return item().getFloat();
}
@Override
public int getInt() throws XQException {
return item().getInt();
}
@Override
public XQItem getItem() throws XQException {
return item();
}
@Override
public XMLStreamReader getItemAsStream() throws XQException {
opened();
return item().getItemAsStream();
}
@Override
public String getItemAsString(final Properties p) throws XQException {
return item().getItemAsString(p);
}
@Override
public XQItemType getItemType() throws XQException {
pos();
return it.getItemType();
}
@Override
public long getLong() throws XQException {
return item().getLong();
}
@Override
public Node getNode() throws XQException {
return item().getNode();
}
@Override
public URI getNodeUri() throws XQException {
pos();
return it.getNodeUri();
}
@Override
public Object getObject() throws XQException {
return item().getObject();
}
@Override
public int getPosition() throws XQException {
final ItemCache ic = sequence();
return pos != -1 ? pos : (int) ic.size() + 1;
}
@Override
public XMLStreamReader getSequenceAsStream() throws XQException {
opened();
if(it != null && !next) throw new BXQException(TWICE);
return new IterStreamReader(result);
}
@Override
public String getSequenceAsString(final Properties p) throws XQException {
opened();
if(it != null && !next) throw new BXQException(TWICE);
if(!next && !next()) return "";
final ArrayOutput ao = new ArrayOutput();
try {
final Serializer ser = Serializer.get(ao);
do {
final BXQItem item = item();
item.serialize(item.it, ser);
} while(next());
ser.close();
} catch(final IOException ex) {
throw new BXQException(ex);
}
return ao.toString();
}
@Override
public short getShort() throws XQException {
return item().getShort();
}
@Override
public boolean instanceOf(final XQItemType type) throws XQException {
pos();
return it.instanceOf(type);
}
@Override
public boolean isAfterLast() throws XQException {
sequence();
return pos == -1;
}
@Override
public boolean isBeforeFirst() throws XQException {
sequence();
return pos == 0 && pos < sequence().size();
}
@Override
public boolean isFirst() throws XQException {
sequence();
return pos == 1;
}
@Override
public boolean isLast() throws XQException {
return pos == sequence().size();
}
@Override
public boolean isOnItem() throws XQException {
opened();
return pos > 0;
}
@Override
public boolean isScrollable() throws XQException {
opened();
return scrollable;
}
@Override
public boolean last() throws XQException {
final ItemCache ic = sequence();
return cursor(ic, (int) ic.size() - 1);
}
@Override
public boolean next() throws XQException {
opened();
if(pos < 0) return false;
try {
final Item i = result.next();
next = i != null;
++pos;
it = new BXQItem(i, this, conn);
if(!next) pos = -1;
return next;
} catch(final QueryException ex) {
throw new BXQException(ex);
}
}
@Override
public boolean previous() throws XQException {
return relative(-1);
}
@Override
public boolean relative(final int p) throws XQException {
return cursor(sequence(), getPosition() + p - 1);
}
@Override
public void writeItem(final OutputStream os, final Properties p)
throws XQException {
item().writeItem(os, p);
}
@Override
public void writeItem(final Writer ow, final Properties p)
throws XQException {
item().writeItem(ow, p);
}
@Override
public void writeItemToResult(final Result r) throws XQException {
item().writeItemToResult(r);
}
@Override
public void writeItemToSAX(final ContentHandler sax) throws XQException {
item().writeItemToSAX(sax);
}
@Override
public void writeSequence(final OutputStream os, final Properties p)
throws XQException {
if(it != null && !next) throw new BXQException(TWICE);
while(next()) item().writeItem(os, p);
}
@Override
public void writeSequence(final Writer ow, final Properties p)
throws XQException {
if(it != null && !next) throw new BXQException(TWICE);
while(next()) item().writeItem(ow, p);
}
@Override
public void writeSequenceToResult(final Result res) throws XQException {
valid(res, Result.class);
if(it != null && !next) throw new BXQException(TWICE);
// evaluate different result types...
if(res instanceof StreamResult) {
// StreamResult.. directly write result as string
final StreamResult sr = (StreamResult) res;
if(sr.getWriter() != null) writeSequence(sr.getWriter(), null);
else writeSequence(sr.getOutputStream(), null);
} else if(res instanceof SAXResult) {
// SAXResult.. serialize result to underlying parser
final SAXSerializer ser = new SAXSerializer(null);
final SAXResult sax = (SAXResult) res;
ser.setContentHandler(sax.getHandler());
ser.setLexicalHandler(sax.getLexicalHandler());
while(next()) serialize(item().it, ser);
} else {
Util.notimplemented();
}
}
@Override
public void writeSequenceToSAX(final ContentHandler sax) throws XQException {
valid(sax, ContentHandler.class);
writeSequenceToResult(new SAXResult(sax));
}
/**
* Checks the specified cursor position.
* @return item
* @throws XQException xquery exception
*/
private BXQItem item() throws XQException {
pos();
if(!next) throw new BXQException(TWICE);
next = scrollable;
return it;
}
/**
* Checks the specified cursor position.
* @throws XQException xquery exception
*/
private void pos() throws XQException {
if(!isOnItem()) throw new BXQException(CURSOR);
}
/**
* Checks the forward flag and returns the result.
* @return sequence iterator
* @throws XQException xquery exception
*/
private ItemCache sequence() throws XQException {
opened();
if(!scrollable) throw new BXQException(FORWARD);
return (ItemCache) result;
}
/**
* Sets the cursor to the specified position.
* @param seq iterator sequence
* @param p cursor position
* @return result of check
* @throws XQException xquery exception
*/
private boolean cursor(final ItemCache seq, final int p) throws XQException {
pos = p < 0 ? 0 : p >= seq.size() ? -1 : p;
seq.pos(pos - 1);
return p >= 0 && next();
}
}