// a Unit Capacity Data Link using simjava
// (c) 1997 by Felix Gaertner <theedge@rbg.informatik.th-darmstadt.de>
// DO NOT EDIT - look at UCDL.nw instead

import java.util.*;

import eduni.simjava.*;
import eduni.simanim.*;

public class UCDL extends Anim_applet {

  public static Random speed = new Random();
  public static final int threshold = 10;     // maximum delay of messages
  public static final int timeout_threshold = 10*threshold;

  public void anim_layout() {
    finished = false;
    // build simulation: create processes, link ports etc.
    // add entities:
    Sim_system.add(new Sender("Sender", "sender", 50, 20, Anim_port.RIGHT));
    Sim_system.add(new Receiver("Receiver", "receiver", 250, 20, Anim_port.LEFT));
    // add ports:
    Sim_system.link_ports("Sender", "out", "Receiver", "in");
    Sim_system.link_ports("Receiver", "out", "Sender", "in");
  }

  private static boolean finished = false;

  public static boolean finished() {
    return finished;
  }
  public static void finish() {
    finished = true;
  }
}
class Sender extends Sim_entity {
  // data to send
  private char data[] = { 'h', 'a', 'l', 'l', 'o', '!' };
  // number to send
  private int ns = 1;
  // timeout counter
  private int timeout = UCDL.timeout_threshold;
  private Sim_port in;
  private Sim_port out;
  public Sender(String name, String image_name, int x, int y, int side) {
    super(name, image_name, x, y);
    out = new Sim_port("out", "out-port", side, 5);
    add_port(out);
    in =  new Sim_port("in", "in-port", side, 15);
    add_port(in);
    add_param(new Anim_param("ns", Anim_param.NAME_VALUE, ""+ns, -45, 10));
    add_param(new Anim_param("to", Anim_param.NAME_VALUE, ""+timeout, -45, 20));
  }
  public void body() {
    Sim_event ev = new Sim_event();

    while (!UCDL.finished()) {
      int choice = (int)(UCDL.speed.nextDouble() * 3) + 1;
      System.out.println("sender taking choice " + choice);

      switch (choice) {
        case 1:
          if (timeout <= 0) {
            System.out.println("sender timed out");
            sim_schedule(out, UCDL.threshold*UCDL.speed.nextDouble(), ns,
                new Character(data[ns-1]));
            timeout=UCDL.timeout_threshold; // reset timeout
            sim_trace(1, "S out <" + ns + "," + data[ns-1] + ">");
          }
          break;
        case 2:
          if (sim_waiting(new Sim_type_p(ns)) >= 1) {
            sim_select(new Sim_type_p(ns), ev);
            ns++;
            sim_schedule(out, UCDL.threshold*UCDL.speed.nextDouble(), ns,
                new Character(data[ns-1]));
            timeout=UCDL.timeout_threshold; // reset timeout
            sim_trace(1, "S out <" + ns + "," + data[ns-1] + ">");
          }
          break;
        case 3:
          if (sim_waiting(new Sim_not_type_p(ns)) >= 1) {
            sim_select(new Sim_not_type_p(ns), ev);
            // purge event
            timeout=UCDL.timeout_threshold; // reset timeout
          }
          break;
        }

      // check for end:
      if (ns==data.length) UCDL.finish();

      timeout--;
      sim_trace(1, "P " + ns + " " + timeout);
      sim_hold(1);
    }
  }
}
class Receiver extends Sim_entity {
  // last acknowledged item
  private int na = 0;
  // received data
  private char d;
  // already delivered data (used to display value of `delivered' parameter
  String delivered = "";
  // local ports
  private Sim_port in;
  private Sim_port out;
  public Receiver(String name, String image_name, int x, int y, int side) {
    super(name, image_name, x, y);
    out = new Sim_port("out", "out-port", side, 15);
    add_port(out);
    in =  new Sim_port("in", "in-port", side, 5);
    add_port(in);
    // add parameters
    add_param(new Anim_param("delivered", Anim_param.NAME_VALUE, "", 30, 10));
  }
  public void body() {
    Sim_event ev = new Sim_event();

    while (!UCDL.finished()) {
      int choice = (int)(UCDL.speed.nextDouble() * 2) + 1;
      System.out.println("receiver taking choice " + choice);

      switch (choice) {
        case 1:
          if (sim_waiting(new Sim_not_type_p(na)) >= 1) {
            sim_select(new Sim_not_type_p(na), ev);
            na=ev.get_tag();
            System.out.println("deliver data=" + (Character)ev.get_data());
            delivered = delivered + (Character)ev.get_data();
            sim_trace(1, "P " + delivered);
            sim_schedule(out, UCDL.threshold*UCDL.speed.nextDouble(), na);
            sim_trace(1, "S out <" + na + ">");
          }
          break;
        case 2:
          if (sim_waiting(new Sim_type_p(na)) >= 1) {
            sim_select(new Sim_type_p(na), ev);
            sim_schedule(out, UCDL.threshold*UCDL.speed.nextDouble(), na);
            sim_trace(1, "S out <" + na + ">");
          }
          break;
        }

      sim_hold(1);
    }
  }
}
class Sim_not_type_p extends Sim_predicate {
  int not_tag = 0;

  public Sim_not_type_p(int tag) {
    not_tag = tag;
  }

  public boolean match(Sim_event event) {
    return (event.get_tag() != not_tag);
  }
}

