package modules.hashtable;

import simulator.*;
import modules.neighborset.*;
import modules.hierarchy.*;
import utils.*;
import java.util.*;

// Failures should produce "quarantine zones" --- regions
// containing all suspect behavior.
// There are three portions to a QZ:
// 1. failure edges: nodes with a physical failed neighbor
// 2. failure zone: region connecting the edges of a failure
// 3. quarantine zone: per-node artifact for region touched by a 
//    storage node from a failure zone

public class FailureDetector implements ProcessorModule {
  PortedProcessor pp;
  public Symbol getName() { return Symbol.GetSymbol("FailureDetector"); }
  public void link(PortedProcessor p) {
    pp = p;
    pp.addClockListener(this);
    pp.openNetworkPort(this,port);
    nh = (PNHierarchy)pp.getModule("Hierarchy");
  }
  PNHierarchy nh; NeighborSet ns;
  static final Symbol port = Symbol.GetSymbol("FailPort");

  public void init() {};

  Hashtable nbrs = new Hashtable();
  static final int timeout = 0; // transmit every round
  static final int threshold = 5; // 5 rounds to kill a neighbor
  int lastTime = 0;

  public boolean signalEvent(Symbol name, Object data) {
    boolean changed = false;
    if(name==PortedProcessor.kClock) {
      // transmit periodically
      int t = ((Integer)data).intValue();
      if(t-lastTime > timeout) { 
        lastTime=t; pp.sendMessage(port,new Double(pp.getUID()));
      }
      
      // if a neighbor hasn't been heard from, prune and call a foul
      Iterator i = nbrs.keySet().iterator();
      while(i.hasNext()) {
        Counter c = (Counter)nbrs.get(i.next());
        c.tick(); 
        if(c.expired()) { i.remove(); edge=true; }
      }

      // to build the failure zone, climb the hierarchy until reaching
      // a level where the set of neighbors is stable
    } else if(name==port) {
      Counter c = (Counter)nbrs.get(data);
      if(c==null) { c=new Counter(threshold); nbrs.put(data,c); }
      else c.reset();
    }
    return changed;
  }
  public String toString() { 
    String s = "FailureDetector: "+edge;
    return s;
  }

  public boolean isEdge() { return edge; }
  public boolean isFailZone() { return failzone; }
  // public boolean isQuarantined()

  boolean edge = false;
  boolean failzone = false;
}
