// ABPReceiver.java	(C) I. A. Robin, K. J. Turner	08/03/06

package protocol;

import java.util.Enumeration;			// enumeration
import java.util.Vector;			// vector (list)
import support.*;				// protocol entity support

public class ABPReceiver implements ProtocolEntity {

  private int seqExpected;
  private PDU pduReceived;
  private PDU ackPDU;
  private ProtocolEntity peer;
  private Medium medium;
  private String name;
  private Vector<ProtocolEvent> entityEvents;		// events from entity

  public ABPReceiver(Medium m, String name) {
    this.name = name;
    medium = m;
    initialise();
  }

  public String getName() {
    return(name);
  }

  public Vector<String> getServices() {
    Vector<String> list = new Vector<String>();
    if (pduReceived != null && pduReceived.type.equals("DATA")) {
      if (pduReceived.seq == seqExpected) seqExpected = inc(seqExpected);
      list.addElement(
	"Send ACK(" + seqExpected +
	  ") - with sequence number of next message");
    }
    return(list);
  }

  /** Increment PDU sequence number (0 or 1 only in ABP protocol) */

  private int inc(int seq) {
    return(1 - seq);
  }

  public void initialise() {
    seqExpected = 0;
    pduReceived = null;
    entityEvents = new Vector<ProtocolEvent>();		// empty entity events
  }

  public Vector<ProtocolEvent> performService(String s) {
    Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
    if (s.startsWith("Send ACK")) {
      int startIndex = s.indexOf( '(' ) + 1;
      int endIndex = s.indexOf( ')' );
      int seq = Integer.parseInt(s.substring(startIndex, endIndex));
      transmitPDU(new PDU("ACK", seq), peer);
      events.addElement(
	new ProtocolEvent(ProtocolEvent.TRANSMIT, ackPDU));
    }
    for (Enumeration e = entityEvents.elements();	// get medium events
	 e.hasMoreElements(); )
      events.addElement(				// add medium event
	(ProtocolEvent) e.nextElement());
    return(events);
  }

  public Vector<ProtocolEvent> receivePDU(PDU pdu) {
    pduReceived = pdu;
    return(new Vector<ProtocolEvent>());
  }

  public void setPeer(ProtocolEntity peer) {
    this.peer = peer;
  }

  public void transmitPDU(PDU pdu, ProtocolEntity dest) {
    pdu.setSource(this);
    pdu.setDestination(dest);
    ackPDU = pdu;
    entityEvents = medium.receivePDU(pdu);
    pduReceived = null;
  }

}
