// 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: EventList.java
// Path: eventbase/event
// Description: used as a link list for events.  functions are limited for
//              this application

package eventbase.event;

public class EventList {
  EventNode head;
  EventNode tail;
  EventNode searchIterator; // use to insert new event
  EventNode displayIterator; // for dispaly purpose, can not modify list
  int elementCount;

  public EventList() {
    head = tail = searchIterator = displayIterator = null;
    elementCount = 0;
  }

  public int size() {
    return elementCount;
  }

  public EventTableEntry getFirst() {
    if (head != null)
      return head.getEvent();
    return null;
  }

  public EventTableEntry getLast() {
    if (tail != null)
      return tail.getEvent();
    return null;
  }

  public void addFirst(EventTableEntry e) {
    EventNode temp = new EventNode(e);
    if (head == null)
      head = tail = temp;
    else {
      temp.setNext(head);
      head.setPrev(temp);
      head = temp;
    }
    elementCount++;
  }

  public void addLast (EventTableEntry e) {
    EventNode temp = new EventNode(e);
    if (tail == null)
      head = tail = temp;
    else {
      tail.setNext(temp);
      temp.setPrev(tail);
      tail = temp;
    }
    elementCount++;
  }

  // TODO: may need to fix dummy
  // now it will work in real time as long as we have a queue gap between
  // UI and database
  public void resetListIterator(int type) {
    EventNode dummy = new EventNode(null);
    dummy.setNext(head);
    head.setPrev(dummy);
    if (type == EventType.SEARCH)
      this.searchIterator = dummy;
    else
      this.displayIterator = dummy;
  }

  // for traversing purpose
  public EventTableEntry getNextEntry(int type) {
    if (type == EventType.SEARCH)  {
      if (this.searchIterator.getNext() != null) {
        this.searchIterator = this.searchIterator.getNext();
        return this.searchIterator.getEvent();
      }
    } else {
      if (this.displayIterator.getNext() != null) {
        this.displayIterator = this.displayIterator.getNext();
        return this.displayIterator.getEvent();
      }
    }
    System.err.println("Error:EventList:getNextEntry");
    return null;
  }

  // for traversing purpose
  public EventTableEntry getPrevEntry(int type) {
    EventTableEntry e;
    if (type == EventType.SEARCH)  {
      if (this.searchIterator.getPrev() != null) {
        this.searchIterator = this.searchIterator.getPrev();
        return this.searchIterator.getEvent();
      }
    } else {
      if (this.displayIterator.getPrev() != null){
        this.displayIterator = this.displayIterator.getPrev();
        return this.displayIterator.getEvent();
      }
    }
    System.err.println("Error:EventList:getPrevEntry");
    return null;
  }

  // Node: only for searchIterator
  public void insertAtIteratorLocation(int type, EventTableEntry e) {
    if (type == EventType.DISPLAY)
      return;
    EventNode temp = new EventNode(e);
    EventNode next = this.searchIterator.getNext();
    temp.setNext(next);
    temp.setPrev(this.searchIterator);
    this.searchIterator.setNext(temp);
    if (next != null)
      next.setPrev(temp);
    elementCount++;
  }

  public boolean hasNextEntry(int type) {
    if ((type == EventType.DISPLAY) && (this.displayIterator != null) &&
        (this.displayIterator.getNext() != null))
      return true;
    if ((type == EventType.SEARCH) && (this.searchIterator != null) &&
        (this.searchIterator.getNext() != null))
      return true;
    return false;
  }

}


class EventNode {
  protected EventNode prev;
  protected EventNode next;
  protected EventTableEntry obj;

  EventNode(EventTableEntry entry) {
    this.prev = null;
    this.next = null;
    obj = entry;
  }

  EventTableEntry getEvent() {
    return obj;
  }

  EventNode getPrev() {
    return this.prev;
  }

  EventNode getNext() {
    return this.next;
  }

  void setNext(EventNode n) {
    this.next = n;
  }

  void setPrev(EventNode p) {
    this.prev = p;
  }

}