// 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: NeighborTableEntry.java
// Path: eventbase/neighbor
// Description: defines neighbor table entry

package eventbase.neighbor;
import java.util.*;
import eventbase.*;

public class NeighborTableEntry {

  final String OBJECT_NAME = "NeighborTableEntry";
  private OverlayHost neighbor;
  // vector of JoinLeavePair elements
  private Vector joinLeaveList;

  // Neighbor can only join or leave multiple times
  public NeighborTableEntry(OverlayHost node, double timeStamp) {
    neighbor = node;
    joinLeaveList = new Vector();
    JoinLeavePair listElement = new JoinLeavePair(timeStamp);
    joinLeaveList.addElement(listElement);
  }

  public int getMemorySize() {
    return OverlayHost.getMemorySize() +
      joinLeaveList.size() * JoinLeavePair.getMemoroySize();
  }

  public OverlayHost getNeighbor() {
    return neighbor;
  }

  public JoinLeavePair getJoinLeavePair (double t) {
    JoinLeavePair jlpair;
    for (Enumeration e = joinLeaveList.elements(); e.hasMoreElements();) {
      jlpair = (JoinLeavePair) e.nextElement();
      if (t >= jlpair.getTimeSinceNeighbor())
        return jlpair;
    }
    return null;
  }

  public void addTimeCeaseNeighbor(double t, int reason) {
    // should just add the neighbor to the last element of vector
    ((JoinLeavePair) joinLeaveList.lastElement()).setTimeCeaseNeighbor(t, reason);
  }

  // WARNING: this function can only be called after
  public void addTimeJoinNeighbor(double t) {
    // assure that all elements in joinLeaveList are complete.
    // meaning each elements has both join and leave value filled
    for (Enumeration e = joinLeaveList.elements(); e.hasMoreElements();) {
      if (!((JoinLeavePair)e.nextElement()).isComplete()) {
        System.err.println("WARNING: " + OBJECT_NAME + ":addTimeJoinNeighbor()");
        System.err.println("       Neighbor Join without Leaving");
        return;
      }
    }
    JoinLeavePair listElement = new JoinLeavePair(t);
    joinLeaveList.addElement(listElement);
  }

  public void print() {
    System.out.print(neighbor.getName());
    for (Enumeration e = joinLeaveList.elements(); e.hasMoreElements();) {
      ((JoinLeavePair)e.nextElement()).print();
    }
    System.out.println();
  }

    /* TODO: NOT USED, CAN BE DELETED AT THE END
  // at time t, whether this neighbor is alive
  public boolean isAlive (double t) {
    JoinLeavePair jlpair;
    for (Enumeration e = joinLeaveList.elements(); e.hasMoreElements();) {
      jlpair = (JoinLeavePair) e.nextElement();
      // if time cease neighbor is -1, means nodes never leaves the group
      if (t >= jlpair.getTimeSinceNeighbor() &&
         ((jlpair.getTimeCeaseNeighbor() == -1) || t < jlpair.getTimeCeaseNeighbor()))
        return true;
    }
    return false;
  }

  // get time since neighbor at time t
  public double getTimeSinceNeighbor(double t) {
    JoinLeavePair jlpair;
    for (Enumeration e = joinLeaveList.elements(); e.hasMoreElements();) {
      jlpair = (JoinLeavePair) e.nextElement();
      if (t >= jlpair.getTimeSinceNeighbor() &&
         ((jlpair.getTimeCeaseNeighbor() == -1) || t < jlpair.getTimeCeaseNeighbor()))
        return jlpair.getTimeSinceNeighbor();
    }
      return -1;
  }
*/



}
