// BOOTPReceiver.java	(C) K. A. Whyte, K. J. Turner	08/03/06

package protocol;				// protocol package

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

public class BOOTPReceiver			// protocol receiver (server)
 implements ProtocolEntity {			// protocol entity

  // simulator variables

  private ProtocolEntity peer;			// peer entity (client)
  private Medium medium;			// communications medium
  private String name;				// entity name

  // protocol variables

  private String ipAddress = "net.";		// IP address root
  private String bootFile = "boot";		// boot file name
  private String bootPath = "\\path\\";		// boot file root
  private PDU pduSent;				// PDU sent
  private PDU pduReceived;			// PDU received
  private Vector<ProtocolEvent> entityEvents;	// events from entity

  // protocol messages

  final static String request = "REQUEST";	// boot request message
  final static String reply = "REPLY";		// boot reply message

  public BOOTPReceiver(Medium m, String name) { // construct receiver instance
    this.name = name;				// set protocol entity name
    medium = m;					// set underlying medium
    initialise();				// initialise protocol
  }

  public String getName() {			// get protocol entity name
    return((name));				// return protocol entity name
  }

  public void initialise() {			// initialise protocol
    pduReceived = null;				// initialise no PDU received
    pduSent = null;				// initialise no PDU sent
    entityEvents = new Vector<ProtocolEvent>();	// empty medium events
  }

  public Vector<String> getServices() {
    Vector<String> events =			// initialise events list
      new Vector<String>();
    String pduType;				// received PDU type
    String pduData;				// PDU data
    String pduTrans;				// transaction identifier
    int hwPos, ipPos, bootPos;			// hw/ip/boot file positions
    int trans;					// transaction identifier
    String hw, ip;				// hardware/IP addr address
    String boot;				// boot file name

    if (pduReceived != null) {			// PDU received?
      pduType = pduReceived.type;		// get received PDU type
      pduData = pduReceived.sdu;		// get received PDU data
      if (pduType.equals(request)) {		// boot request?
	hwPos = pduData.indexOf(',');		// get hardware position
	trans =					// get transaction identifier
	  Integer.parseInt(pduData.substring(0, hwPos));
	ipPos = pduData.indexOf(',', hwPos + 1); // get IP address position
	if (ipPos == -1) {			// no IP address parameter
	  hw = pduData.substring(hwPos + 1);	// get hardware address
	  ip =					// random IP address 10..99
	    ipAddress + (10 + (int) (BOOTPMedium.random() * 99));
	  boot = bootPath + bootFile;		// set full boot file name
	}
	else {					// IP address parameter
	  hw =					// get hardware address
	    pduData.substring(hwPos + 1, ipPos);
	  bootPos =				// get boot file position
	    pduData.indexOf(',', ipPos + 1);
	  if (bootPos == -1) {			// no boot file parameter
	    ip = pduData.substring(ipPos + 1); // get IP address
	    boot = bootPath + bootFile;		// set full boot file name
	  }
	  else {				// boot file parameter
	    ip =				// get IP address
	      pduData.substring(ipPos + 1, bootPos);
	    boot =				// get boot file name
	      pduData.substring(bootPos + 1);
	    boot = bootPath + boot;		// prefix with boot file path
	  }
	}
	events.addElement(			// send reply
	  reply + "(" + trans +
	    "," + hw + "," + ip + "," + boot +
	      ") - reply with IP address and boot file path");
      }
    }
    return(events);
  }

  public Vector<ProtocolEvent> performService(String s) {
    Vector<ProtocolEvent> events = 		// initialise events list
      new Vector<ProtocolEvent>();
    int start, middle, end;			// start/middle/end positions
    String pduData;				// PDU data

    if (s.startsWith(reply)) {			// reply?
      start = s.indexOf('(') + 1;		// get contents start
      end = s.indexOf(')');			// get contents end
      pduData = s.substring(start, end);	// get data contents
      transmitPDU(				// send reply
	new PDU(reply, pduData), peer);
      events.addElement(			// transmit PDU
	new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
    }
    for (Enumeration e = entityEvents.elements(); // go through medium events
	 e.hasMoreElements(); )
      events.addElement(			// add medium event
	(ProtocolEvent) e.nextElement());
    return(events);
  }

  public Vector<ProtocolEvent> receivePDU(PDU pdu) { // handle received PDU
    pduReceived = pdu;				// store PDU
    return((new Vector<ProtocolEvent>()));	// return no events
  }

  public void setPeer(ProtocolEntity peer) {	// set protocol peer
    this.peer = peer;				// set this entity's peer
  }

  public void transmitPDU(			// transmit PDU
   PDU pdu, ProtocolEntity dest) {		// for given PDU, destination
    pdu.setSource(this);			// source is this entity
    pdu.setDestination(dest);			// destination is as given
    pduSent = pdu;				// copy PDU sent
    entityEvents = medium.receivePDU(pdu);	// medium receives PDU
    pduReceived = null;				// note no PDU in response
  }

}
