package simpledb;

import java.io.*;
import java.util.*;

import simpledb.unittest.Utility;

/**
 * ExHashFileEncoder reads a comma delimited text file and converts it to 
 * pages of binary data in the appropriate format for simpledb extendible hash
 * pages.
 */

public class ExHashFileEncoder {

    /**
     * Encode the file using the ExHashFile's Insert method.
     */
    public static void convert(File inFile, File hFile, File hashFile, 
			       int keyfield, int numFields)			       
	throws IOException {
	// TupleDesc
	Type ta[] = new Type[numFields];
	for(int i=0; i<numFields; i++)
	    ta[i] = Type.INT_TYPE;
	TupleDesc t = new TupleDesc(ta);

	// convert the inFile to HeapFile first.
	HeapFileEncoder.convert(inFile, hFile, BufferPool.PAGE_SIZE, numFields);
	HeapFile heapf = new HeapFile(hFile);
	Database.getCatalog().addTable(heapf, t);

	// create a new empty hash file
	if( hashFile.exists() )
	    hashFile.delete();
	hashFile.createNewFile();

	// add the heap file to the hash file
	ExHashFile hashf = new ExHashFile(hashFile, keyfield);
	Database.getCatalog().addTable(hashf, t);  // now the table been existed in the catalog
	hashf.init();    // initialization of your file, like you want other meta files

	TransactionId tid = new TransactionId();
	SeqScan ss = new SeqScan(tid, heapf.id());

	Insert insOp = null;
	try {
	    insOp = new Insert(tid, ss, hashf.id());
	} catch (DbException dbe) {
	    dbe.printStackTrace();
	    System.exit(-1);
	}

	Type typeAr[] = new Type[1];
	typeAr[0] = Type.INT_TYPE;
	TupleDesc returnTD = new TupleDesc(typeAr);

	Query q = new Query(insOp, tid);

	try {
	    q.start();
	    try {
		while(true) {
		    Tuple tup = q.getNext();
		    if(!tup.getTupleDesc().equals(returnTD))
			throw new DbException("wrong return type");		   
		}
	    } catch(NoSuchElementException e) {
		insOp.close();
	    }
	} catch(TransactionAbortedException te){
	    te.printStackTrace();
	    return;
	} catch(DbException e) {
	    e.printStackTrace();
	    return;
	} catch(IOException e) {
	    e.printStackTrace();
	    return;
	}

	// dump contents before we flush
	//try {
	//    dump(tid, hashf);
	//} catch(TransactionAbortedException te) {
	//    te.printStackTrace();
	//    return;
	//}

	try {
	    Database.getBufferPool().flushAllPages();
	} catch(Exception e) {
	    e.printStackTrace();
	}

    }

    public static void dump(TransactionId tid, DbIterator dbi) 
	throws TransactionAbortedException {
	try {
	    dbi.open();
	} catch (DbException e) {
	}
	
	try {
	    while (true) {
		Tuple tup = dbi.getNext();
		tup.print();
	    }
	} catch(DbException e) {
	    System.out.println("unexpected DbException");
	    dbi.close();
	} catch(NoSuchElementException e) {
	    dbi.close();
	}
    }
    
    public static void dump(TransactionId tid, DbFile file) throws TransactionAbortedException {
	SeqScan ss = new SeqScan(tid, file.id());
	dump(tid, ss);
    }
}
