package simpledb;
import java.util.*;
import java.io.*;

/**
 * Inserts tuples read from the child operator into
 * the tableid specified in the constructor
 */
public class Insert implements DbIterator {
    private TransactionId tid;
    private DbIterator child;
    private int tableid;
    private TupleDesc td;
    private DbFile dbFile;
    private int insertCount;
    private boolean opened;
    private boolean resultRead;
    
    /**
     * Constructor.
     * @param t The transaction running the insert.
     * @param child The child operator to read tuples to be inserted from.
     * @param tableid The table to insert tuples into.
     */
    public Insert(TransactionId t, DbIterator child, int tableid) 
	throws DbException {
        this.tid = t;
        this.child = child;
        this.tableid = tableid;

        Type[] types = new Type[1];
        types[0] = Type.INT_TYPE;
        td = new TupleDesc(types);

        opened = false;
        resultRead = false;
    }

    public TupleDesc getTupleDesc() {
        return td;
    }
    
    public void open() throws DbException, TransactionAbortedException {
        dbFile = Database.getCatalog().getDbFile(tableid);
        child.open();
        insertCount = 0;

        while (true) {
            try {
                Tuple t = child.getNext();
                try {
                    dbFile.addTuple(tid, t);
                } catch (IOException e) {
                    throw new DbException("I/O exception on insert");
                }
                insertCount++;
            } catch (NoSuchElementException e) {
                break;
            }
        }

        child.close();
        opened = true;
        resultRead = false;
    }
    
    public void close() {
        opened = false;
        resultRead = false;
    }
    
    public void rewind() throws DbException, TransactionAbortedException {
        resultRead = false;
    }

    /**
     * DbIterator getNext method.
     * Inserts tuples read from child into the tableid specified by the
     * constructor.  Inserts should be passed through BufferPool.  
     * An instances of BufferPool is available via Database.getBufferPool().  
     * Note that insert
     * DOES NOT need check to see if a particular tuple is a duplicate before
     * inserting it.
     *
     * @return A 1-field tuple containing the number of inserted records.
     * @see Database#getBufferPool
     * @see BufferPool#insertTuple
     * @throws NoSuchElementException When the child iterator has no more 
     * tuples.
     */
    public Tuple getNext() 
	throws NoSuchElementException, TransactionAbortedException,
               DbException {
        if (!opened) {
            throw new DbException("Iterator is not open");
        }

        if (resultRead) {
            throw new NoSuchElementException();
        }

        Tuple t = new Tuple(td);
        t.setField(0, new IntField(insertCount));
        resultRead = true;
        return t;
    }
    
}
