package lux.saxon;

import java.io.IOException;

import lux.XPathQuery;
import lux.api.QueryStats;
import lux.lucene.LuxSearcher;
import net.sf.saxon.om.Item;
import net.sf.saxon.om.SequenceIterator;
import net.sf.saxon.s9api.XdmItem;
import net.sf.saxon.trans.XPathException;

import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.search.Scorer;

@SuppressWarnings("rawtypes")
public class ResultIterator implements SequenceIterator<Item>{
    
    private final DocIdSetIterator docIter;
    private final XPathQuery query;
    private final QueryStats stats;
    private final LuxSearcher searcher;
    private final Saxon saxon;
    private CachingDocReader docCache;
    private Item current = null;
    private int position = 0;
    
    public ResultIterator (Saxon saxon, XPathQuery query) throws IOException {
        this.query = query;
        this.saxon = saxon;
        this.stats = saxon.getQueryStats();
        if (stats != null) {
            stats.query = query.getQuery().toString();
        }
        searcher = saxon.getContext().getSearcher();
        docCache = saxon.getDocReader();
        docIter = searcher.searchOrdered(query);
    }

    public Item next() throws XPathException {
        long t = System.nanoTime();
        try {
            int docID = docIter.nextDoc();
            //System.out.println ("GET " + docID + " " + query.toString());
            if (docID == Scorer.NO_MORE_DOCS) {
                position = -1;
                current = null;
            } else {
                if (stats != null) {
                    if (docCache.isCached(docID)) {
                        stats.cacheHits ++;
                    } else {
                        stats.cacheMisses ++;
                    }
                }
                XdmItem doc = docCache.get(docID);
                current = (Item) doc.getUnderlyingValue();
                ++position;
                stats.retrievalTime += System.nanoTime() - t;
            }
        } catch (IOException e) {
            throw new XPathException(e);
        } finally {
            if (stats != null) {
                if (position >= 0) {
                    stats.docCount = position;
                }
                stats.totalTime += System.nanoTime() - t;
            }
        }
        return current;
    }

    public Item current() {
        return current;
    }

    public int position() {
        return position;
    }

    public void close() {
        // Saxon doesn't call this reliably
    }

    public SequenceIterator<Item> getAnother() throws XPathException {
        try {
            return new ResultIterator (saxon, query);
        } catch (IOException e) {
            throw new XPathException (e);
        }
    }

    public int getProperties() {
        return SequenceIterator.LOOKAHEAD;
    }
    
}
@@ -65,16 +65,45 @@
 hQuery;%0A
+import lux.api.LuxException;%0A
 import l
@@ -290,32 +290,80 @@
 .XPathException;
+%0Aimport net.sf.saxon.tree.tiny.TinyDocumentImpl;
 %0A%0Aimport org.apa
@@ -1917,23 +1917,25 @@
         
-current
+Item item
  = (Item
@@ -1958,24 +1958,313 @@
 ingValue();%0A
+                // assertion for safety%0A                if (current != null && ((TinyDocumentImpl)item).getDocumentNumber() %3C= ((TinyDocumentImpl)current).getDocumentNumber()) %7B%0A                    throw new LuxException (%22out of order%22);%0A                %7D%0A                current = item;%0A
             

assert that results be returned in docID order