// Protocol.java

package support;				// protocol support package

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

/**
  This is the base class for protocols.

  @author	Iain A. Robin, Kenneth J. Turner
  @version	1.0 (1st September 1999, IAR): initial version
  <br/>		1.4 (9th March 2006, KJT): updated for JDK 1.5
  <br/>		1.5 (27th July 2010, KJT): minor tidying
*/
public abstract class Protocol {

  /** Protocol entity list */
  protected Vector<ProtocolEntity> entities;

  /** Protocol medium */
  protected Medium medium;

  /**
    Return the protocol entity list

    @return		protocol entities
  */
  public Vector<ProtocolEntity> getEntities() {
    return(entities);
  }

  /**
    Return the column used by the medium.

    @return		medium column number
  */
  public int getMediumColumn() {
    return(entities.indexOf(medium));
  }

  /**
    Return the random numbers maintained by a protocol. By default this does
    nothing, but can be overriden by particular protocols. The numbers are
    stored in a scenario file.

    @return		random number list
  */
  public Vector<Float> getRandomNumbers() {
    return(null);
  }

  /**
    Return the services offered by a protocol (normally overriden by an actual
    protocol).

    @return   The services value
  */
  public Vector<String> getServices() {
    Vector<String> list = new Vector<String>();
    for (Enumeration ee = entities.elements(); ee.hasMoreElements(); ) {
      ProtocolEntity entity = (ProtocolEntity) ee.nextElement();
      for (Enumeration se = entity.getServices().elements();
	se.hasMoreElements(); )
	list.addElement(entity.getName() + ": " + (String) se.nextElement());
    }
    return(list);
  }

  /**
    Initialise all protocol entities.
  */
  public void init() {
    for (Enumeration enumeration = entities.elements();
	 enumeration.hasMoreElements(); ) {
      ProtocolEntity entity = (ProtocolEntity) enumeration.nextElement();
      entity.initialise();
    }
  }

  /**
    Perform service specified by the action string. This consists of an entity
    name and a service. First, identify the entity providing the service.

    @param action	action
    @return		resulting protocol events
  */
  public Vector<ProtocolEvent> performService(String action) {
    for (Enumeration en = entities.elements(); en.hasMoreElements(); ) {
      ProtocolEntity entity = (ProtocolEntity) en.nextElement();
      String name = entity.getName();
      if (action.startsWith(name)) {
	String service =			// remove entity name and ":"
	  action.substring(name.length() + 2);
	Vector<ProtocolEvent> events =		// service string to entity
	  entity.performService(service);
	// check if any event contains a PDU whose timer needs to be enabled
	for (Enumeration enumeration = events.elements();
	     enumeration.hasMoreElements(); ) {
	  ProtocolEvent event = (ProtocolEvent) enumeration.nextElement();
	  if (event == null)
	    break;
	  PDU pdu = event.getPDU();
	  if (pdu == null)
	    break;
	  ProtocolEntity source = pdu.getSource();
	  if (source != null && source instanceof Timeouts) {
	    Timeouts sender = (Timeouts) source;
	    if (sender.hasTimer(pdu.type)) {	// this PDU type has a timer
	      sender.setTimer(pdu, entity == medium);
	      break;				// don't time response PDUs
	    }
	  }
	}
	return(events);
      }
    }
    return(null);				// entity name not recognised
  }

  /**
    This method is called by the protocol simulator. Override this method to
    allow protocol-specific parameters to be set externally (e.g. from
    JavaScript). The standard support is for a medium type.

    @param parameter	parameter name
    @param value	parameter value
  */
  public void setParameter(String parameter, String value) {
    if (parameter.equals("mediumType"))
      try {
	medium.setMediumType(Integer.parseInt(value));
      }
      catch (NumberFormatException exception) {	// invalid numeric value
	System.out.println("number format exception for parameter '" +
	  parameter + "' with value '" + value + "'");
      }
  }

  /**
    Set the random numbers maintained by a protocol. By default this does
    nothing, but can be overriden by particular protocols. The numbers are
    retrieved from a scenario file.

    @param randoms	random number list
  */
  public void setRandomNumbers(Vector<Float> randoms) {
  }

}


