// 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: EventTableManager.java
// Path: eventbase/event
// Description: Manage table recorded collection of event.
//              Entry sorted chronologically.

package eventbase.event;
import java.util.*;

public class EventTableManager {

  final String OBJECT_NAME = "EventTable";
  private EventList table;
  private ListIterator retrievalIterator;

  public EventTableManager() {
    // Empty List of <initSize> elements, extended <extendedSize> elements
    table = new EventList();
  }

  // perform Insertion Sort order by time
  public void InsertEventToTable (EventTableEntry entry) {
    EventTableEntry firstEvent = null;
    // try begining
    if (table.size() > 0)
      firstEvent = (EventTableEntry) table.getFirst();
    if (table.size() == 0 || entry.occursEarlier(firstEvent)) {
      table.addFirst(entry);
      return;
    }

    // try end
    EventTableEntry lastEvent = (EventTableEntry) table.getLast();
    if (entry.occursLater(lastEvent)) {
      table.addLast(entry);
      return;
    }

    // insert somewhere in the middle
    table.resetListIterator(EventType.SEARCH);
    EventTableEntry prevEvent;
    EventTableEntry curEvent = table.getNextEntry(EventType.SEARCH);

    while (table.hasNextEntry(EventType.SEARCH)) {
      prevEvent = curEvent;
      curEvent = table.getNextEntry(EventType.SEARCH);
      if (entry.occursLater(prevEvent) && entry.occursEarlier(curEvent)) {
        // rewind and add entry
        table.getPrevEntry(EventType.SEARCH);
        table.insertAtIteratorLocation(EventType.SEARCH, entry);
        return;
      }
    }
  }

  public void getNextEventInit(double time) {

    table.resetListIterator(EventType.DISPLAY);

    EventTableEntry prevEvent;
    EventTableEntry curEvent = table.getNextEntry(EventType.DISPLAY);

    if (time <= curEvent.getTime()) {// start from the first event
      table.getPrevEntry(EventType.DISPLAY);
      return;
    }
    while (table.hasNextEntry(EventType.DISPLAY)) {
      prevEvent = curEvent;
      curEvent = table.getNextEntry(EventType.DISPLAY);
      if (prevEvent.getTime() < time && curEvent.getTime() >= time) {
        table.getPrevEntry(EventType.DISPLAY);
        return;
      }
    }
  }

  public EventTableEntry getNextEvent() {
    if (table.hasNextEntry(EventType.DISPLAY))
      return table.getNextEntry(EventType.DISPLAY);
    else
      return null;
  }

  // This function can only be called after all the log files has been parsed
  public double getTimeOfFirstEvent() {
    if (table.getFirst() != null)
      return table.getFirst().getTime();
    else
      return -1;
  }

  public double getTimeOfLastEvent() {
    if (table.getLast() != null)
      return table.getLast().getTime();
    else
      return -1;
  }

  public void printTable() {

    System.out.println();
    System.out.println("================ EventTableStart ===================" );

    EventTableEntry entry;
    table.resetListIterator(EventType.SEARCH);
    while (table.hasNextEntry(EventType.SEARCH)){
      entry = table.getNextEntry(EventType.SEARCH);
      entry.print();
    }

    System.out.println("================ EventTableEnd ===================" );
    System.out.println();
  }

  public int getMemorySize() {
    int retVal = 0;
    table.resetListIterator(EventType.SEARCH);
    while (table.hasNextEntry(EventType.SEARCH))
      retVal += table.getNextEntry(EventType.SEARCH).getMemorySize();
    return retVal;
  }

}