/*
 * Section4.java
 *
 * Code template for Berkeley DB practice.
 *
 * Harvard Extension School
 * CSCI E-66
 */

import com.sleepycat.je.*;                // for Database, Environment, etc.
import java.io.*;

public class Section4 {
  
  private static final int FIELD1_LENGTH = 7;     // length of instructorID
  private static final int KEY_LENGTH = 7;        // length of record keys
  
  public static void main(String[] args) {
    
    Environment env = null; 
    Database db = null;
    
    // 1. creating and opening a BDB environment
    env = problemOne();
    
    // 2. creating and opening and new b-tree database
    db = problemTwo(env);
    
    // 3. storing a new record
    problemThree(db);
    
    // 4. looking up the new record
    problemFour(db);

    // 5. iterating over all records in the database
    problemFive(db);
    
    
    /*
     * Always close your database and environment before exiting!
     */
    
    try { 
      if (db != null)
        db.close(); 
      
      if (env != null)
        env.close(); 
      
    } catch (DatabaseException de) { 
      /*
       * Any necessary exception handling would
       * go here.
       */
    }
  }
  
  
  private static Environment problemOne() {
    /*
     * Creates a new directory in the current working directory
     * that will contain the environment and later, the database
     * file.
     */
    File envHome = new File("db_dir");
    envHome.mkdir();
    
    // create a new EnvironmentConfig object
    EnvironmentConfig envConfig = new EnvironmentConfig();
    
    /*
     * Allows BDB to create environment files, if necessary.
     */
    envConfig.setAllowCreate(true);
    
    // create and return a new Environment object
    Environment e = null;
    try {
      e = new Environment(envHome, envConfig);
    } catch (DatabaseException de) {
      System.err.println("an error occurred creating environment");
    }
    
    return e;
  }
  
  
  private static Database problemTwo(Environment env) {
    String dbFileName = new String("courses.db"); 
    
    // create a new DatabaseConfig object
    DatabaseConfig dbConfig = new DatabaseConfig();
    
    /*
     * Allows BDB to create environment files, if necessary.
     */
    dbConfig.setAllowCreate(true);
    
    // create and return a new Database object
    Database db = null;
    try {
      db = env.openDatabase(null, dbFileName, dbConfig);
    } catch (DatabaseException de) {
      System.err.println("an error occurred opening database");
    } 
    
    return db;
  }
  
  
  private static void problemThree(Database db) {
    String keyStr = "CSCIE66"; 
    String instructorID = "1234567";
    int enrollment = 35;
    
    // create RowOutput objects for the key and value
    RowOutput keyOutput = new RowOutput();
    RowOutput valueOutput = new RowOutput();
    
    // write bytes to the RowOutput buffers
    try{
      keyOutput.writeBytes(keyStr);
      valueOutput.writeBytes(instructorID);
      valueOutput.writeInt(enrollment);
    } catch (Exception e) {
      System.out.println(e);
    }
    // create new DatabaseEntry objects for key and value
    DatabaseEntry keyEntry = new DatabaseEntry(keyOutput.getBufferBytes());
    DatabaseEntry valueEntry = new DatabaseEntry(valueOutput.getBufferBytes());
    
    // use database's put() method to store the record
    try {
      OperationStatus op = db.put(null, keyEntry, valueEntry);   
    } catch (OperationFailureException de) {
      System.out.println("Error putting value in db: " + de);
    }
  }
  
  
  private static void problemFour(Database db) {
    String keyStr = "CSCIE66";
    
    // create RowOutput object for the key
    RowOutput keyOutput = new RowOutput();
    
    // write bytes to the RowOutput object
    try{
      keyOutput.writeBytes(keyStr);
    } catch (Exception e) {
      System.out.println(e);
    }
    // create new DatabaseEntry objects for the key and value
    DatabaseEntry keyEntry = new DatabaseEntry(keyOutput.getBufferBytes());
    DatabaseEntry valueEntry = new DatabaseEntry();
    
    // use the database's get() method
    OperationStatus op = null;
    try {
      op = db.get(null, keyEntry, valueEntry, null);
    } catch (DatabaseException de) {
      System.out.println("Unable to access entry: " + de);
      return;
    }
    
    // if the operation was a success, print the record
    if(op == OperationStatus.SUCCESS) {
      RowInput valueInput = new RowInput(valueEntry.getData());
      String instructorID = valueInput.readNextBytes(FIELD1_LENGTH);
      int enrollment = valueInput.readNextInt();
      
      String dataStr = instructorID + ", " + enrollment;
      System.out.println("key: " + keyStr + ", data: " + dataStr); 
    } else {
      System.out.println("Error looking up key:" + op);
    }
  }
  
 /* From and older version of this assignment-- looks up a key/value pair that doesn't exist in the DB.
  private static void problemFive(Database db) {
    String keyStr = "CSCIE22";
    
    // create RowOutput object for the key
    RowOutput keyOutput = new RowOutput();
    
    // write bytes to the RowOutput object
    try{
      keyOutput.writeBytes(keyStr);
    } catch (Exception e) {
      System.out.println(e);
    }
    // create new DatabaseEntry objects for the key and value
    DatabaseEntry keyEntry = new DatabaseEntry(keyOutput.getBufferBytes());
    DatabaseEntry valueEntry = new DatabaseEntry();
    
    // use the database's get() method
    OperationStatus op = null;
    try {
      op = db.get(null, keyEntry, valueEntry, null);
    } catch (DatabaseException de) {
      System.out.println("Error occured: " + de);
    }
    
    // if the key was not found, print to the standard out
    if(op == OperationStatus.SUCCESS) {
      RowInput valueInput = new RowInput(valueEntry.getData());

      String strValue = valueInput.readNextBytes(FIELD1_LENGTH);
      int enrollment = valueInput.readNextInt();
      
      System.out.println(strValue + " " + enrollment);
    } else {
      System.out.println("Failure: " + op);
    }
  }
*/
  
  
  private static void problemFive(Database db) {
    // create Cursor object
    Cursor c = null;
    try {
      c = db.openCursor(null, null);
    } catch (Exception e) {
      System.out.println("Failed to open cursor: " + e);
      return;
    }
    
    // create DatabaseEntry objects for keys and values
    DatabaseEntry key = new DatabaseEntry();
    DatabaseEntry value = new DatabaseEntry();
    
    // use Cursor's getNext method
    try{
      while(c.getNext(key, value, null) == OperationStatus.SUCCESS){
        // unmarshall each record and print it
        RowInput keyIn = new RowInput(key.getData());
        RowInput valIn = new RowInput(value.getData());
        
        String keyStr = keyIn.readNextBytes(KEY_LENGTH);
        String instructorID = valIn.readNextBytes(FIELD1_LENGTH);
        int enrollment = valIn.readNextInt();
        
        String dataStr = instructorID + ", " + enrollment;
        System.out.println("key: " + keyStr + ", data: " + dataStr); 
      }
    } catch (DatabaseException de) {
      System.out.println("Error iterating over Database: " + de);
    }
    
    try {
      c.close();
    } catch (DatabaseException de) {
      System.err.println("error occurred while closing cursor: " + de);
    }
  }
  
}
