import java.util.Vector;

class Packet
{
  public int data;

  Packet() {}
  Packet(int d)
  {
    data=d;
  }
}

class Frame
{
  final static int data_frame=0;
  final static int ack_frame=1;
  final static int nak_frame=2;

  int kind;  
  int seq;
  int ack;
  Packet info;
}

//////////////////////////////////////////////////////////////////////////////////

class SendingNetworkLayer
{
  Vector contents;

  SendingNetworkLayer()
  {
    contents=new Vector();
  }

  public synchronized Packet Read()
  {
	while (contents.size()==0)
	  try
	  {
	    wait();
	  } catch (InterruptedException e) {}
    Packet packet=(Packet)contents.elementAt(0);
	contents.removeElementAt(0);
	return packet;
  }
  public synchronized void Write(Packet p)
  {
    contents.addElement(p);
	notify();
  }
}

class UtopiaSendingDataLinkLayer extends Thread
{
  private SendingNetworkLayer network_layer;
  private SendingPhysicalLayer physical_layer;

  public UtopiaSendingDataLinkLayer(SendingNetworkLayer nwd,SendingPhysicalLayer ph)
  {
    network_layer=nwd;
    physical_layer=ph;
  }

  public void run()
  {
    while (true)
    {
      try
      {
		Packet packet=network_layer.Read();
		Frame frame=new Frame();
		frame.info=packet;
		physical_layer.Write(frame);
		sleep(10);  
      } catch (InterruptedException e) {}
    }
  }
};

class SendingPhysicalLayer
{
  Network network;

  public SendingPhysicalLayer(Network nw)
  {
    network=nw;
  }

  public synchronized void Write(Frame f)
  {
	network.Write(f);
  }

  public synchronized Frame Read()
  {
    return network.BackwardRead();
  }
};

//////////////////////////////////////////////////////////////////////////////////

class Network
{
  Vector forward,backward;

  Network()
  {
    forward=new Vector();
    backward=new Vector();
  }

  public synchronized Frame Read()
  {
	while (forward.size()==0)
	  try
	  {
	    wait();
	  } catch (InterruptedException e) {}
    Frame frame=(Frame)forward.elementAt(0);
	forward.removeElementAt(0);
	return frame;
  }
  public synchronized void Write(Frame f)
  {
    forward.addElement(f);
	notify();
  }

  public synchronized Frame BackwardRead()
  {
	while (backward.size()==0)
	{
	  try
	  {
	    wait();
	  } catch (InterruptedException e) {}
	}
    Frame frame=(Frame)backward.elementAt(0);
	backward.removeElementAt(0);
	return frame;
  }
  public synchronized void BackwardWrite(Frame f)
  {
    backward.addElement(f);
	notify();
  }
}

//////////////////////////////////////////////////////////////////////////////////

class ReceivingPhysicalLayer
{
  Network network_layer;
  ReceivingPhysicalLayer(Network nw)
  {
    network_layer=nw;
  }
  public Frame Read() {return network_layer.Read();}

  public synchronized void Write(Frame f)
  {
	network_layer.BackwardWrite(f);
  }

};

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
///////////////////DOOR CURSISTEN TE IMPLEMENTEREN////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////

class UtopiaReceivingDataLinkLayer extends Thread
{
  private ReceivingNetworkLayer network_layer;
  private ReceivingPhysicalLayer physical_layer;

  public UtopiaReceivingDataLinkLayer(ReceivingPhysicalLayer ph,ReceivingNetworkLayer nw)
  {
    network_layer=nw;
    physical_layer=ph;
  }

  public void run()
  {
    while (true)
    {
      try
      {
//		System.out.println("next iteration in ReceivingDataLinkLayer::run");
		Frame frame=physical_layer.Read();
		network_layer.Write(frame.info);
		Frame ack=new Frame();
		physical_layer.Write(ack);
		sleep(10);  
      } catch (InterruptedException e) {}
    }
  }
};

class ReceivingNetworkLayer
{
  Vector contents;

  ReceivingNetworkLayer()
  {
    contents=new Vector();
  }

  public synchronized Packet Read()
  {
//    System.out.println("ReceivingNetworkLayer::Read");
	while (contents.size()==0)
	  try
	  {
	    wait();
	  } catch (InterruptedException e) {}
    Packet packet=(Packet)contents.elementAt(0);
	contents.removeElementAt(0);
	return packet;
  }
  public synchronized void Write(Packet p)
  {
//    System.out.println("ReceivingNetworkLayer::Write");
    contents.addElement(p);
	notify();
  }
}

class Main
{
  static SendingNetworkLayer sending_network;
  static UtopiaSendingDataLinkLayer sending_data_link;
  static SendingPhysicalLayer sending_physical;

  static Network network;

  static ReceivingNetworkLayer receiving_network;
  static UtopiaReceivingDataLinkLayer receiving_data_link;
  static ReceivingPhysicalLayer receiving_physical;

  public static void main(String[] args)
  {
    sending_network=new SendingNetworkLayer();
    network=new Network();
	sending_physical=new SendingPhysicalLayer(network);
    sending_data_link=new UtopiaSendingDataLinkLayer(sending_network,sending_physical);

	receiving_physical=new ReceivingPhysicalLayer(network);
	receiving_network=new ReceivingNetworkLayer();
	receiving_data_link=new UtopiaReceivingDataLinkLayer(receiving_physical,receiving_network);

	sending_data_link.start();
	receiving_data_link.start();

	for (int i=0; i<10; i++)
	{
	  System.out.println("sending "+i);
	  sending_network.Write(new Packet(i));
	}
   System.out.println();

	for (int i=0; i<10; i++)
	{
	  Packet packet=receiving_network.Read();
	  System.out.println(packet.data);
	}

	System.out.println("Ready.");
	sending_data_link.stop();
	receiving_data_link.stop();
  }
}