// HTTPSender.java

package protocol;				// protocol package

import java.util.*;				// import Java utility classes

import support.*;				// import Jasper support classes

/**
  This is the main class for simulation of an HTTP sender (i.e. client).

  @author	Kenneth J. Turner, Kenneth A. Whyte
  @version	1.4 (9th March 2006, KJT/KAW): initial version
  <br/>		1.5 (19th July 2010, KJT): minor tidying
*/

public class HTTPSender implements ProtocolEntity {

  // Protocol state constants
  private static final int IDLE      = 0;	// ready to send
  private static final int GET_SENT  = 1;	// waiting GET resp.
  private static final int HEAD_SENT = 2;	// waiting HEAD resp.
  private static final int POST_SENT = 3;	// waiting POST resp.
  private static final int PUT_SENT  = 4;	// waiting PUT resp.

  private int state;

  private PDU pduSent;
  private PDU pduReceived;
  private ProtocolEntity peer;
  private Medium medium;
  private String name;

  private int index;				// data/URL index

  public HTTPSender(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>();
    String pduType, pduData;

    if (pduReceived != null) {
      pduType = pduReceived.type;
      pduData = pduReceived.sdu;
    }
    else {
      pduType = "";
      pduData = "";
    }
    switch (state) {
      case GET_SENT:
	if (pduType.startsWith("200") || pduType.startsWith("400"))
	      state = IDLE;
	else if (pduType.startsWith("301"))
	  list.addElement(pduSent.type + "(" + pduData + ") - get data for new URL");
	break;
      case HEAD_SENT:
	if (pduType.startsWith("200") || pduType.startsWith("400"))
	      state = IDLE;
	else if (pduType.startsWith("301"))
	  list.addElement(pduSent.type + "(" + pduData + ") - get header for new URL");
	break;
      case POST_SENT:
      case PUT_SENT:
	if (pduType.startsWith("200") || pduType.startsWith("400"))
	      state = IDLE;
	break;
    }
    if (state == IDLE) {
      list.addElement("GET(URL" + index + ") - get data for URL");
      list.addElement("HEAD(URL" + index + ") - get header for URL");
      list.addElement("POST(URL" + index + ",DATA" +
	index + ") - append data to URL");
      list.addElement("PUT(URL" + index + ",DATA" +
	index + ") - send data to URL");
    }
    return(list);
  }

  public void initialise() {
    state = IDLE;
    index = 1;
    pduSent = null;
    pduReceived = null;
  }

  public Vector<ProtocolEvent> performService (String s) {
    Vector<ProtocolEvent> events = new Vector<ProtocolEvent>();
    int startIndex, midIndex, endIndex;		// start/mid/end subscripts
    String url = "";				// current URL
    String data;				// URL data

    pduSent = null;
    startIndex = s.indexOf ('(') + 1;		// get URL start
    endIndex = s.indexOf (')');			// get URL end
    if (s.startsWith ("GET")) {			// GET?
      url = s.substring(startIndex, endIndex);	// get URL
      transmitPDU(new PDU("GET", url), peer);
      state = GET_SENT;				// GET now sent
    }
    else if (s.startsWith ("HEAD")) {		// HEAD?
      url = s.substring(startIndex, endIndex);	// get URL
      transmitPDU(new PDU("HEAD", url), peer);
      state = HEAD_SENT;			// HEAD now sent
    }
    else if (s.startsWith ("POST")) {		// POST?
      midIndex = s.indexOf (',');		// get URL end
      url = s.substring(startIndex, midIndex);	// get URL
      data = s.substring(midIndex + 1, endIndex); // get URL data
      transmitPDU(new PDU("POST", url + "," + data), peer);
      state = POST_SENT;			// POST now sent
    }
    else if (s.startsWith ("PUT")) {		// PUT?
      midIndex = s.indexOf (',');		// get URL end
      url = s.substring(startIndex, midIndex);	// get URL
      data = s.substring(midIndex + 1, endIndex); // get URL data
      transmitPDU(new PDU("PUT", url + "," + data), peer);
      state = PUT_SENT;				// PUT now sent
    }
    if (pduSent != null) {
      startIndex = url.indexOf ("URL");		// get URL start
      index =					// extract/increment index
	Integer.parseInt(url.substring(startIndex + 3)) + 1;
      events.addElement(new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
      events.addElement( new ProtocolEvent(ProtocolEvent.RECEIVE, pduSent));
    }
    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);
    pduSent = pdu;
    peer.receivePDU(pdu);
    pduReceived = null;
  }

}
