package modules.hierarchy;

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

public class Level {
  int timeout; // countdown to leader-election
  double nextID=Double.NaN;
  double ID;
  int level;
  
  // required routines
  public static double w_0 = 5;
  public static double w_m = 2;
  public Level(double id, int l) {
    ID=id; level=l;
    timeout = (int)(w_0*Math.pow(w_m,level));
  }
  public String toString() {
    return "("+ID+", "+nextID+", "+timeout+")";
  }
  public Object clone() {
    Level l = new Level(ID,level);
    l.timeout=timeout; l.nextID=nextID;
    return l;
  }

  public static final int NID_PENDING=0;
  public static final int NID_SELF=1;
  public static final int NID_NBR=2;
  public int getStatus() { 
    if(Double.isNaN(nextID)) return NID_PENDING;
    else if(nextID==ID) return NID_SELF;
    else return NID_NBR;
  }
  public void setStatus(int status) { setStatus(status,Double.NaN); }
  public void setStatus(int status, double nbrID) {
    if(status==NID_PENDING) nextID=Double.NaN;
    else if(status==NID_SELF) nextID=ID;
    else nextID=nbrID;
  }

  //********** Algorithm Routines ***********
  /*
    Three states: nextID==NIL, ID==nextID!=NIL, ID!=nextID!=NIL
    nextID==NIL: no neighbors, or is nbr with NID_PENDING and ID>my ID
    nextID==ID: all neighbors have <ID, or NID_NBR
    nextID!=ID: some nbr has ID>myID and NID_SELF
  **/
  void calculateNextID(Set nbrs) {
    if(nbrs.isEmpty()) { setStatus(NID_PENDING); }
    else {
      boolean self=true; double best=Double.NaN;
      Iterator i = nbrs.iterator();
      while(i.hasNext()) {
        Level nd = (Level)i.next();
        switch(nd.getStatus()) {
        case NID_PENDING: 
          if(nd.ID>ID) self=false;
          break;
        case NID_SELF:
          if(nd.ID>ID && (Double.isNaN(best) || best<nd.ID)) 
            { best=nd.ID; self=false; }
          break;
        case NID_NBR: 
          break; // do nothing
        }
      }
      if(self) setStatus(NID_SELF);
      else if(!Double.isNaN(best)) setStatus(NID_NBR,best);
      else setStatus(NID_PENDING);
    }
  }
}
