package simpledb;
import java.util.*;

/**
 * HashScan is an implementation of a index access method that reads
 * each tuple of a table that hits the key. 
 * tuples with the same index key value is returned in no particular order 
 * (e.g., as they are laid out on disk).
 */
public class HashScan implements IndexDbIterator {
    private TransactionId tid;
    private int tableid;
    private IndexPredicate ipred;
    private ExHashFile hashFile;
    private TupleDesc tupleDesc;
    private DbFileIterator iter;
    
    /** 
     * Constructor.
     * Creates a index access method over the specified table as a part of the
     * specified transaction.
     *
     * @param tid The transaction this scan is running as a part of.
     * @param tableid the table to scan.
     * @param ipred the key field it wants to match
     */
    public HashScan(TransactionId tid, int tableid, IndexPredicate ipred) {
        this.tid = tid;
        this.tableid = tableid;
        this.ipred = ipred;

        if ((ipred != null) && (ipred.getOp() != Predicate.Op.EQUALS)) {
            throw new RuntimeException("HashScans require an equality predicate");
        }
    }

    /**
     * Opens this hash scan.
     * Needs to be called before getNext().
     */
    public void open() 
	throws DbException, TransactionAbortedException {
        hashFile = (ExHashFile) Database.getCatalog().getDbFile(tableid);
        tupleDesc = Database.getCatalog().getTupleDesc(tableid);

        if (ipred != null) {
            iter = hashFile.indexIterator(tid, ipred.getField());
            iter.open();
        }
    }

    public void open(IndexPredicate ipred) 
	throws DbException, TransactionAbortedException {
        this.ipred = ipred;
        if (ipred.getOp() != Predicate.Op.EQUALS) {
            throw new DbException("HashScans require an equality predicate");
        }

        open();
    }
    
    /**
     * Implementation of DbIterator.getTupleDesc method.
     */
    public TupleDesc getTupleDesc() {
        return tupleDesc;
    }

    /**
     * Implementation of DbIterator.getNext method.
     * Return the next tuple in the scan.
     *
     * @throws NoSuchElementException if the scan is complete. 
     */
    public Tuple getNext() 
	throws NoSuchElementException, TransactionAbortedException, DbException {
        return iter.getNext();
    }

    /**
     * Closes the sequential scan.
     */
    public void close() {
        if (iter != null) {
            iter.close();
            iter = null;
        }
    }

    /**
     * Rewinds the sequential back to the first record.
     */
    public void rewind()
	throws DbException, NoSuchElementException, TransactionAbortedException {
        iter = hashFile.indexIterator(tid, ipred.getField());
        iter.open();
    }

    public void rewind(IndexPredicate ipred)
	throws DbException, NoSuchElementException, TransactionAbortedException {
        this.ipred = ipred;
        if (ipred.getOp() != Predicate.Op.EQUALS) {
            throw new DbException("HashScans require an equality predicate");
        }
        rewind();
    }
}
