package tlc2.tool.fp;

import java.util.NoSuchElementException;

import tlc2.output.EC;
import util.Assert;


public class TLCIterator {

	private final long[][] buff;
	private int firstIdx = 0;
	private int secondIdx = 0;
	private long previous = -1l;
	/**
	 * Number of elements read with next()
	 */
	private long readElements = 0l;

	public TLCIterator(long[][] buff) {
		this.buff = buff;
	}

    /**
     * Returns <tt>true</tt> if the iteration has more elements. (In other
     * words, returns <tt>true</tt> if <tt>next</tt> would return an element
     * rather than throwing an exception.)
     *
     * @return <tt>true</tt> if the iterator has more elements.
     */
	public boolean hasNext() {
		// has next does not move the indices at all!
		
		if (firstIdx <= buff.length - 1) {
			long[] bucket = buff[firstIdx];
			if (secondIdx <= bucket.length - 1 && bucket[secondIdx] > 0) {
				return true;
			} else if (firstIdx + 1 <= buff.length -1) {
				bucket = buff[firstIdx + 1];
				return bucket[0] > 0;
			}
		}
		return false;
	}

    /**
     * Returns the next element in the iteration.
     *
     * @return the next element in the iteration.
     * @exception NoSuchElementException iteration has no more elements.
     */
	public long next() {
		long result = -1l;
		
		// at least one more element in current bucket
		if (firstIdx <= buff.length - 1) {
			long[] bucket = buff[firstIdx];
			if (secondIdx < bucket.length && bucket[secondIdx] > 0) {
				result = bucket[secondIdx];
				bucket[secondIdx] |= 0x8000000000000000L;
				secondIdx++;
			} else {
				firstIdx++;
				secondIdx = 0;
				result = buff[firstIdx][secondIdx];
				buff[firstIdx][secondIdx] |= 0x8000000000000000L;
				secondIdx++;
			}
		}
		
		Assert.check(previous  < result, EC.GENERAL);
		previous = result;
		
		readElements++;
		
		return result;
	}

	public long getLast() {
		long[] bucket = buff[buff.length - 1];
		for (int i = bucket.length - 1; i >= 0 ;i--) {
			if (bucket[i] > 0) {
				return bucket[i];
			}
		}
		throw new NoSuchElementException();
	}
	
	public long reads() {
		return readElements;
	}
}

@@ -102,17 +102,41 @@
 ssert;%0A%0A
+//TODO skip null buckets
 %0A
-
 public c
@@ -354,16 +354,90 @@
  = 0l;%0A%0A
+%09/**%0A%09 * @param buff an %5B%5D%5B%5D with null elements on the second level.%0A%09 */%0A
 %09public 
@@ -1088,32 +1088,50 @@
 + 1%5D;%0A%09%09%09%09return
+ bucket != null &&
  bucket%5B0%5D %3E 0;%0A
@@ -1993,46 +1993,304 @@
 %7B%0A%09%09
-long%5B%5D bucket = buff%5Bbuff.length - 1%5D;
+int len = buff.length - 1;%0A%09%09long%5B%5D bucket = buff%5Blen%5D;%0A%0A%09%09// find last bucket containing elements, buff elements might be null if%0A%09%09// no fingerprint for such an index has been added to the DiskFPSet%0A%09%09while (bucket == null) %7B%0A%09%09%09bucket = buff%5B--len%5D;%0A%09%09%7D%0A%09%09%0A%09%09// find last element %3E 0 in bucket
 %0A%09%09f

Handle null values in buff