import java.util.*;

/** Hyphos allows Java applications to talk to a Hyphos network.  It
 * generates all the low level Hyphos headers, but requires the
 * application to generate the full Hyphos payload.
 * @version 0.1
 * @author Matthew Gray <mkgray@mit.edu>
 */

public class Hyphos {
  Bridge bridge;

  /**
   * Create a Hyphos network interface.
   * @param b The bridge it should talk to.
   */
  Hyphos(Bridge b) {
    bridge = b;
    VirtualAmulet.bridge = b;
  }

  /** The Hyphos class can operate in simulated mode or real mode.  In
   * simulated mode, unreliable amulets are implemented in software. 
   * @param s true if simulated mode, false if real
   */

  public void setSimulated(boolean s){
    VirtualAmulet.simulate = s;
  }

  /** A fraction between 0 and 1 representing the
   * <strong>two-way</strong> probability that a packet is
   * successfully transmitted.
   * @param r Probability of successful packet round trip
   */

  public void setReliability(double r){
    VirtualAmulet.reliability = r;
    if(!VirtualAmulet.simulate)
      System.out.println("Warning: Not in simulation mode when setting simulation parameters.\n");
  }

  /** A fraction between 0 and 1 representing the
   * probability that a packet will be unintentionally
   * repeated on the return trip.
   * @param r Probability of an unintentional repeat.
   */

  public void setRepeatProbability(double r){
    VirtualAmulet.repeatProbability = r;
    if(!VirtualAmulet.simulate)
      System.out.println("Warning: Not in simulation mode when setting simulation parameters.\n");
  }

  /** A time in milliseconds for the average round trip latency.
   * @param a The average latency in milliseconds
   */

  public void setAverageLatency(double a){
    VirtualAmulet.averageLatency = a;
    if(!VirtualAmulet.simulate)
      System.out.println("Warning: Not in simulation mode when setting simulation parameters.\n");
  }
  /** The range of variation in the latency.  The actual latency will
   * be a vlue between the average minus half <tt>l</tt> and the
   * average plust half <tt>l</tt>.
   * <p>
   * If the minimum latency is below zero, it is considered to be zero.
   * @param l The total variation of the latency
   */
  public void setLatencyRange(double l){
    VirtualAmulet.latencyRange = l;
    if(!VirtualAmulet.simulate)
      System.out.println("Warning: Not in simulation mode when setting simulation parameters.\n");
  }

  /**
   * Transmit a packet over the Hyphos network.
   * @param a The address of the target node
   * @param msg The Hyphos packet payload
   * @param len The length of msg */
  public void transmit(byte a[], byte msg[], int len, byte uniqid){
    (VirtualAmulet.find(new AmuletAddress(a))).send(msg, len, uniqid);
  }

}

class AmuletAddress {
  byte addr[] = new byte[4];
  AmuletAddress(byte a, byte b, byte c, byte d){
    addr[0] = a;
    addr[1] = b;
    addr[2] = c;
    addr[3] = d;
  }
  AmuletAddress(byte a[]){
    this(a[0], a[1], a[2], a[3]);
  }
  public int hashCode(){
    return (int) (addr[0]+addr[1]+addr[2]+addr[3]);
  }
  public boolean equals(Object o){
    if(o instanceof AmuletAddress){
      if(((AmuletAddress) o).addr[0] == addr[0] &&
	 ((AmuletAddress) o).addr[1] == addr[1] &&
	 ((AmuletAddress) o).addr[2] == addr[2] &&
	 ((AmuletAddress) o).addr[3] == addr[3])
	return true;
      else
	return false;
    }
    return false;
  }

}

class VirtualAmulet {
  AmuletAddress address;
  static boolean simulate;
  static double reliability;
  static double repeatProbability;
  static double averageLatency;
  static double latencyRange;
  static Bridge bridge;
  static Hashtable lookup = new Hashtable();
  
  VirtualAmulet(AmuletAddress ad){
    address = ad;
    lookup.put(address, this);
  }
  
  public static VirtualAmulet find(AmuletAddress a){
    VirtualAmulet va;
    va =  (VirtualAmulet) lookup.get(a);
    if(va == null)
      va = new VirtualAmulet(a);
    return va;
  }
  
  public void send(byte d[], int l, byte uid){
    if(simulate){
      (new ResponseSimulation(address, d, uid, bridge)).start();
    }
    else{
      System.out.println("Real Hyphos transmission is not currently");
      System.out.println("supported.  You must run in simulation mode.");
    }
  }
}

// This thread handles simulating an amulets response to an individual
// query.  Randomly drops, repeats, or delays a response.
class ResponseSimulation extends Thread {
  Bridge bridge;
  AmuletAddress am;
  byte type, uniqid;
  byte to[] = new byte[4];
  byte ack[] = {TSConstants.ACK};

  ResponseSimulation(AmuletAddress a, byte p[], byte id, Bridge b){
    am = a;
    bridge = b;
    type = p[0];
    uniqid = id;
  }

  public void run() {
    switch(type){
    case TSConstants.AMULET_QUERY:

      break;
    case TSConstants.ROUTE_QUERY:

      break;
    case TSConstants.CHIRP:
    case TSConstants.PLAY_AUDIO:
    case TSConstants.SET_LED_STATE:
    case TSConstants.SET_AUDIO_STREAMING:
      // Just acknowledge it
      bridge.fromAmulet(am.addr, uniqid, ack);
      break;
    }
  }
  
}
