// STACKDataLink.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 transport layer of a protocol stack.

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

  /** Service message prefix (and suffix) */
  private final static String PREFIX = "L";

  /** Service receive offer */
  private final static String RECEIVE =
    "Send data link message to network layer";

  /** Service send offer */
  private final static String SEND =
    "Send data link message to physical 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 STACKDataLink(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)			// SDU from service user?
      list.addElement(SEND);			// add send SDU service to list
    else if (serviceIn != null)			// SDU from service provider?
      list.addElement(RECEIVE);			// 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 =				// create service message
	PREFIX + messageCount + ":" + serviceOut.getSDU() +
	  ":" + PREFIX + messageCount;
      PDU sdu = new STACKSdu(message);		// create SDU
      serviceEvents.addElement(			// add send event
	new ProtocolEvent(ProtocolEvent.SEND, sdu));
      transmitPDU(sdu, serviceProvider);	// send service message
      messageCount++;				// increment message count
      serviceOut = null;			// re-initialise SDU out
    }
    else if (service.equals(RECEIVE)) {		// receive request?
      String message = serviceIn.getSDU();	// get SDU data
      int colon = message.indexOf(':');		// get first colon location
      if (colon >= 0)				// colon present?
	message = message.substring(colon + 1);	// remove prefix
      colon = message.lastIndexOf(':');		// get last colon location
      if (colon >= 0)				// colon present?
	message = message.substring(0, colon);	// remove prefix
      serviceIn = new STACKSdu(message);	// create new message
      transmitPDU(serviceIn, serviceUser);	// send service message
      serviceEvents.addElement(			// add receive event
	new ProtocolEvent(ProtocolEvent.SEND, serviceIn));
      serviceIn = null;				// re-initialise SDU in
    }
    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?
	serviceIn = sdu;			// store SDU from provider
    }
    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);
  }

}

