// MUXService.java

package protocol;				// protocol package

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

import support.*;				// import Jasper support classes

/**
  This is the class that supports sources/sinks for (de)multiplexing.

  @author	Kenneth J. Turner
  @version	1.0 (20th July 2010, KJT): initial version
*/

public class MUXService implements ProtocolEntity {

  /** Service send offer */
  private final static String SEND = "Send data from ";

  /** Service source offer */
  private final static String SOURCE = "Source ";

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

  /** PDU sent by service */
  private PDU sduSent;

  /** Service entity count */
  public static int serviceCount = 2;

  /** Service mode (true = source, false = sink) */
  public boolean serviceMode;

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

  /** Service overwriting (true = overwrite, false = no overwrite) */
  public static boolean serviceOverwrite;

  /** Service provider */
  private MUXProtocol serviceProvider;

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

  /**
    Constructor for sources/sinks.

    @param serviceName	service name
  */
  public MUXService(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
  }

 /**
    Return services currently offered.

    @return		list of services
  */
  public Vector<String> getServices() {
    Vector<String> list = new Vector<String>();	// initialise service list
    if (serviceMode) {				// source mode?
      int first =				// get protocol peer's first SDU
	serviceProvider.getPeer().getProtocolIn().firstSDU();
      if (first == -1 ||			// protocol peer has no data or
	  serviceOverwrite) {			// overwrite?
	for (int i = 0; i < serviceCount; i++) {// go through sources
	  String data =				// get SDU data for source
	    serviceProvider.getProtocolOut().getSDU(i);
	  first =				// get provider's first SDU
	    ((MUXProtocol) serviceProvider).getProtocolOut().firstSDU();
	  boolean mode =			// get provider mode
	    serviceProvider.getMode();
	  if ((!mode && data == null) ||	// sync and no source data or
	      (mode && first == -1) ||		// async and no provider data or
	      serviceOverwrite) {		// overwrite?
	    String service = SEND + SOURCE + i; // send from source service
	    list.addElement(service);		// add service to list
	  }
	}
      }
    }
    return(list);				// return service list
  }

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

  /**
    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.startsWith(SEND)) {		// send request?
      String message = "D" + messageCount;	// create data message
      int sourceStart =				// get start of source index
	service.indexOf(SOURCE) + SOURCE.length();
      int source =				// get source index
	Integer.parseInt(service.substring(sourceStart));
      PDU sdu = new MUXSdu(source, message);	// create SDU
      serviceEvents.addElement(			// add send event
	new ProtocolEvent(ProtocolEvent.SEND, sdu));
      transmitPDU(sdu, 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
    serviceEvents.addElement(			// deliver SDU
      new ProtocolEvent(ProtocolEvent.DELIVER, sdu));
    return(serviceEvents);			// return service events
  }

  /**
    Set the service count.

    @param serviceCount	service count
  */
  public void setCount(int serviceCount) {
    this.serviceCount = serviceCount;		// set service count
  }

  /**
    Set the service mode.

    @param serviceMode	service mode (true = source, false = sink)
  */
  public void setMode(boolean serviceMode) {
    this.serviceMode = serviceMode;		// set service mode
  }

  /**
    Set service overwriting.

    @param serviceOverwrite	service overwriting (true = overwrite,
				false = no overwrite)
  */
  public void setOverwrite(boolean serviceOverwrite) {
    this.serviceOverwrite = serviceOverwrite;	// set overwriting setting
  }

  /**
    Set the service provider.

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

  /**
    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);
    for (int i = 0; i < receiveEvents.size(); i++) // go through receive events
      serviceEvents.addElement(			// append receive event
	receiveEvents.get(i));
    sduSent = sdu;				// stored the sent SDU
  }

}

