package modules.gradient;

import utils.*;
import simulator.*;
import java.util.*;

public class Gradient {
  public Object gid;
  public Symbol type;
  public Object data;
  public PropagationTest limit;
  int hopcount = 0;
  boolean dead = false;
  boolean finaldead = false;
  boolean delete = false;
  int age = 0;
  boolean edge = true;
  int edgeage = 0;

  public String toString() {
    return "("+gid+", "+type+", "+hopcount+", "+dead+", "+
      finaldead+", "+age+", "+data+")";
  }
  public int getHopcount() { return hopcount; }
  public boolean isFinalDead() { return finaldead; }
  public boolean isDead() { return dead; }
  public int getAge() { return age; }
  public boolean isEdge() { return edge; }

  public Gradient(Object gid, Symbol type, Object data) {
    this.gid=gid; this.type=type; this.data=data;
  }
  public Gradient(Object gid, Symbol type, Object data, 
                  PropagationTest limit) {
    this.gid=gid; this.type=type; this.data=data; this.limit=limit;
  }
  public Gradient(Object gid, Symbol type, Object data, 
                  PropagationTest limit, int hop) {
    this.gid=gid; this.type=type; this.data=data; this.limit=limit;
    this.hopcount=hop;
  }

  public Object clone() {
    Gradient c = new Gradient(gid,type,data,limit,hopcount);
    c.dead=dead; c.finaldead=finaldead; c.delete=delete; c.age=age; 
    return c;
  }

  // function for copying gradients in from a neighbors
  public static Gradient copyFromNeighbor(Gradient nbr) {
    Gradient g = (Gradient)nbr.clone();
    g.hopcount=nbr.hopcount+1;
    g.resetLife();
    return g;
  }

  void resetLife() {
    dead = false;
    finaldead = false;
    delete = false;
    age = 0;
  }
  // Integrate data from a neighbor.
  // if both are live & neighbor has a smaller hopcount:
  //   copy nbr data and reset age, life and hopcount
  // if both are merely dead & neighbor has a larger hopcount
  //   reset age
  boolean flagreset;
  void integrate(Gradient nbr) {
    flagreset=false;
    if(!nbr.dead && hopcount > nbr.hopcount) {
      hopcount = nbr.hopcount+1;
      data = nbr.data;
      flagreset=true;
    } else if(!nbr.dead && hopcount < nbr.hopcount) {
      edge = false;
      edgeage = 0;
    } else if(nbr.dead && dead && !nbr.finaldead && hopcount < nbr.hopcount) {
      finaldead = false;
      age = 0;
    }
  }
  void allowResets() { if(flagreset) resetLife(); }

  public static int kDecayBase = 3;//5;
  // increments the age of the gradient and possibly kills it off
  void decay() {
    age++;
    if(delete) return;
    else if(finaldead) {
      if(age > kDecayBase) delete = true;
    } else if(dead) {
      if(age > 2*kDecayBase) { finaldead = true; age = 0; }
    } else {
      if(age > kDecayBase) { dead = true; age = 0; }
    }
    if(edgeage > kDecayBase) {
      edge = true;
    }
  }
}
