// STACKApplication.java

package protocol;				// protocol package

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

import support.*;				// import Jasper support classes

/**
  This is the class that supports the application layer of a protocol stack.

  @author	Kenneth J. Turner
  @version	1.0 (20th July 2010, KJT): initial version
*/
public class STACKApplication implements ProtocolEntity {

  /** Service message prefix */
  private final static String PREFIX = "A";

  /** Service send offer */
  private final static String SEND =
    "Send application message to transport layer";

  /** Service message count */
  private int messageCount;

  /** Service provider events */
  private Vector<ProtocolEvent> serviceEvents;

  /** Service data unit input */
  private PDU serviceIn;

  /** Service data unit output */
  private PDU serviceOut;

  /** Service entity name */
  private String serviceName;

  /** Service provider */
  private ProtocolEntity serviceProvider;

  /** Service user */
  private ProtocolEntity serviceUser;

  /**
    Constructor for sources/sinks.

    @param serviceName	service name
 */
  public STACKApplication(String serviceName) {
    this.serviceName = serviceName;		// set service name
    initialise();				// initialise service entity
  }

  /**
    Return the service name.

    @return	service name
  */
  public String getName() {
    return(serviceName);			// return service name
  }

  /**
    Initialise the service entity.
  */
  public void initialise() {
    messageCount = 0;				// initialise message count
    serviceEvents = new Vector<ProtocolEvent>();// initialise service events
    serviceIn = null;				// initialise SDU input
    serviceOut = null;				// initialise SDU output
  }

 /**
    Return services currently offered.

    @return		list of services
  */
  public Vector<String> getServices() {
    Vector<String> list = new Vector<String>();	// initialise service list
    if (serviceOut == null)			// no SDU sent?
      list.addElement(SEND);			// add send SDU service to list
    return(list);				// return service list
  }

  /**
    Perform service.

    @param service	service request
    @return		resulting service events
  */
  public Vector<ProtocolEvent> performService(String service) {
    serviceEvents = new Vector<ProtocolEvent>();// initialise service events
    if (service.equals(SEND)) {			// send request?
      String message = PREFIX + messageCount;	// create service message
      serviceOut = new STACKSdu(message);	// create SDU
      serviceEvents.addElement(			// add send event
	new ProtocolEvent(ProtocolEvent.SEND, serviceOut));
      transmitPDU(serviceOut, serviceProvider);	// send service message
      messageCount++;				// increment message count
    }
    return(serviceEvents);			// return service events
  }

  /**
    Receive an SDU.

    @param sdu		SDU
    @return		resulting service events
  */
  public Vector<ProtocolEvent> receivePDU(PDU sdu) {
    serviceEvents = new Vector<ProtocolEvent>();// initialise service events
    if (sdu != null) {				// non-empty SDU?
      ProtocolEntity sduSource = sdu.source;	// get SDU source
      String sduType = sdu.type;		// get SDU type
      if (sduSource.equals(serviceUser)) {	// service user message?
	serviceOut = sdu;			// store SDU from service user
      }
      else if (sduSource.equals(serviceProvider)) // service provider message?
	serviceOut = null;			// re-initialise SDU out
    }
    return(serviceEvents);			// return service events
  }

  /**
    Set the service provider.

    @param serviceProvider	service provider
  */
  public void setProvider(ProtocolEntity serviceProvider) {
    this.serviceProvider = serviceProvider;	// set service provider
  }

  /**
    Set the service user.

    @param serviceUser		service user
  */
  public void setUser(ProtocolEntity serviceUser) {
    this.serviceUser = serviceUser;		// set service user
  }

  /**
    Send an SDU.

    @param sdu		SDU
    @param dest		destination protocol entity
  */
  public void transmitPDU(PDU sdu, ProtocolEntity destination) {
    sdu.setSource(this);			// set source as this entity
    sdu.setDestination(destination);		// set destination
    Vector<ProtocolEvent> receiveEvents =	// receive SDU at destination
      destination.receivePDU(sdu);
  }

}

