
// Carnegie Mellon University
//   Information Networking Institute and
//   School of Computer Science
//
// Master Thesis: A Monitoring Tool for Overlay Network
// By: TungFai Chan and Annie Cheng
//
// File: EventBaseAget.java
// Path: eventabase
// Description: Provide static functions.  Manage both B+ tree and Virtul Memory
//              help Database to do content insertion and retrieval

package eventbase;
import eventbase.virtualMemory.*;
import eventbase.btree.*;

public class MemoryManager {

  private VirtualMemory vm;
  private static long BITMASK = 0xFF;

  public MemoryManager() {
    vm = new VirtualMemory();
  }

  public int getMemorySize() {
    return vm.getMemorySize();
  }

  public int getDiskSize() {
    return vm.getDiskSize();
  }

  // insert the bytes as record
  public void insertRecord(BTree btree, double key, byte[] bytes) {
    Record r = new Record (vm.getAvailableRID(), bytes);
    int pgid = vm.InsertRecord(r);
    int recid = r.getRecordID();
    IntermediateNodeRecord interNode = new IntermediateNodeRecord();
    LeafNodeRecord leaf = new LeafNodeRecord(key, pgid, recid);
    btree.Insert(btree.getRoot(), leaf, interNode);
  }

  public void setIterationPointer (BTree btree, double key) {
    btree.setIterationPointer(key);
  }

  public byte[] getPrevRecord(BTree btree) {
    LeafNodeRecord leafRecord = btree.getPrevRID();
    Record record = null;
    if (leafRecord != null)
      record = vm.RetrieveRecord(leafRecord.getPageNumber(), leafRecord.getRecordID());
    if (record != null)
      return record.getBytes();
    return null;
  }

  public byte[] getNextRecord(BTree btree) {
    LeafNodeRecord leafRecord = btree.getNextRID();
    Record record = null;
    if (leafRecord != null)
      record = vm.RetrieveRecord(leafRecord.getPageNumber(), leafRecord.getRecordID());
    if (record != null)
      return record.getBytes();
    return null;
  }


  // utility functions
  public static double bytesToDouble(byte[] buf, int startPos) {
    long value = 0;
    for (int i = 0; i < 8; i++)
      value = ((((long)(buf[i + startPos])) & 0xFF) << (56 - i * 8)) | value;
    return Double.longBitsToDouble(value);
  }

  public static int bytesToInteger(byte[] buf, int startPos) {
    int value = 0;
    for (int i = 0; i < 4; i++)
      value = ((((int)(buf[i + startPos])) & 0xFF) << (24 - i * 8)) | value;
    return value;
  }

  private static byte[] integerToBytes(int value) {
    byte[] buf = new byte[4];
    buf[0] = (new Integer((value & 0xFF000000) >>> 24)).byteValue();
    buf[1] = (new Integer((value & 0x00FF0000) >>> 16)).byteValue();
    buf[2] = (new Integer((value & 0x0000FF00) >>> 8)).byteValue();
    buf[3] = (new Integer((value & 0x000000FF))).byteValue();
    return buf;
  }

  private static byte[] doubleToBytes(double value) {
    byte[] buf = new byte[8];
    long longVal = Double.doubleToLongBits(value);
    buf[0] = (new Long((longVal & (BITMASK << 56)) >>> 56)).byteValue();
    buf[1] = (new Long((longVal & (BITMASK << 48)) >>> 48)).byteValue();
    buf[2] = (new Long((longVal & (BITMASK << 40)) >>> 40)).byteValue();
    buf[3] = (new Long((longVal & (BITMASK << 32)) >>> 32)).byteValue();
    buf[4] = (new Long((longVal & (long)0x00000000FF000000) >>> 24)).byteValue();
    buf[5] = (new Long((longVal & (long)0x0000000000FF0000) >>> 16)).byteValue();
    buf[6] = (new Long((longVal & (long)0x000000000000FF00) >>>  8)).byteValue();
    buf[7] = (new Long((longVal & (long)0x00000000000000FF))).byteValue();
    return buf;
  }

  public static void insertDouble(byte[] buffer, int startPos, double val) {
    byte[] insertVal = doubleToBytes(val);
    for (int i =0; i< 8; i++)
      buffer[startPos+i] = insertVal[i];
  }

  public static void insertInteger (byte[] buffer, int startPos, int val) {
    byte[] insertVal = integerToBytes(val);
    for (int i = 0; i < 4; i++)
      buffer[startPos+i] = insertVal[i];
  }

  public void printVM() {
    vm.printMemoryBuffer();
    vm.printReferenceBitMap();
  }

  public static int getBytesPerRecord() {
    return VirtualMemory.BYTESPERREC;
  }
}