// TCP.java

package protocol;				// protocol package

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

import support.*;				// import Jasper support classes

/**
  This is the main class for the TCP simulation.

  @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 (26th July 2010, KJT): minor tidying; additions of constants
		  for initial values; addition of a loss rate; addition of
		  support for the slow-start TCP simulation
*/
public class TCP extends Protocol {

  // role constants

  /** Peer-to-peer role */
  public final static int PEER = 0;

  /** Client-server role */
  public final static int CLIENT = 1;

  /** Server role */
  public final static int SERVER = 2;

  // protocol constants

  /** Default medium loss rate */
  public final static float LOSS_RATE = 0.2f;

  // protocol constants

  /** Default initial sequence number for protocol A */
  public final static int INITIAL_SEQUENCE_A = 0;

  /** Default initial sequence number for protocol A */
  public final static int INITIAL_SEQUENCE_B = 100;

   /** Default initial window size for protocol A */
  public final static int INITIAL_WINDOW_A = 500;

  /** Default initial window size for protocol B */
  public final static int INITIAL_WINDOW_B = 400;

  /** Default segment size for protocol */
  public final static int SEGMENT_SIZE = 200;

  // service constants

  /** Default message size for service A */
  public final static int MESSAGE_SIZE_A = 100;

  /** Default message size for service A */
  public final static int MESSAGE_SIZE_B = 300;

  // simulation variables

  /** Protocol type ("cs", "pp", "ss") */
  private static String protocolSubtype;

  /** Service entities A and B */
  private TCPService servA, servB;

  /** Protocol entities A and B */
  private TCPProtocol protA, protB;

  /** Role of A and B */
  private int roleA, roleB;

  /** Names of A and B */
  private String nameA, nameB;

  /**
    Constructor for the TCP object

    @param type			protocol type ("cs", "pp", "ss")
    @exception			unknown protocol type
  */
  public TCP(String type) throws Exception {
    protocolSubtype =				// store protocol type in l. c.
      type.toLowerCase();
    medium = new TCPMedium();			// construct medium
    // medium.setMediumType(Medium.CONTROL_NOTHING);
    TCPProtocol.setSegmentSize(SEGMENT_SIZE);	// set protocol segment size
    if (protocolSubtype.equals("cs")) {		// client-server subtype?
      roleA = CLIENT;				// A is client
      nameA = "Client";
      roleB = SERVER;				// B is server
      nameB = "Server";
    }
    else if (protocolSubtype.equals("pp")) {	// peer-peer subtype?
      roleA = PEER;				// A is peer
      nameA = "User A";
      roleB = PEER;				// B is peer
      nameB = "User B";
    }
    else if (protocolSubtype.equals("ss")) {	// slow start subtype?
      roleA = PEER;				// A is peer
      nameA = "User A";
      roleB = PEER;				// B is peer
      nameB = "User B";
    }
    else					// unknown subtype
      throw new Exception("unknown protocol subtype '" + protocolSubtype + "'");
    ((TCPMedium) medium).setLossRate(LOSS_RATE);// set medium loss rate

    servA = new TCPService(nameA, roleA);	// create service A
    servB = new TCPService(nameB, roleB);	// create service B
    servA.setMessageSize(MESSAGE_SIZE_A);	// set service A message size
    servB.setMessageSize(MESSAGE_SIZE_B);	// set service B message size
    if (protocolSubtype.equals("ss"))		// slow start?
      protA =					// create protocol A
	new TCPProtocol(
	  medium, "Protocol A", roleA, INITIAL_SEQUENCE_A, INITIAL_WINDOW_A,
	  INITIAL_WINDOW_B, INITIAL_SEQUENCE_B);
    else					// client-server/peer-peer
       protA =					// create protocol A
	new TCPProtocol(medium, "Protocol A", roleA, INITIAL_SEQUENCE_A,
	  INITIAL_WINDOW_A);
    protB =					// create protocol B
      new TCPProtocol(medium, "Protocol B", roleB, INITIAL_SEQUENCE_B,
	INITIAL_WINDOW_B);
    servA.setProvider(protA);			// service A -> protocol A
    servB.setProvider(protB);			// service B -> protocol B
    protA.setUser(servA);			// protocol A -> service A
    protA.setPeer(protB);			// protocol A -> protocol B
    protB.setUser(servB);			// protocol B -> service B
    protB.setPeer(protA);			// protocol B -> protocol A

    entities = new Vector<ProtocolEntity>();	// initialise entities list
    entities.addElement(servA);			// add service A
    entities.addElement(protA);			// add protocol A
    entities.addElement(medium);		// add medium
    entities.addElement(protB);			// add protocol B
    entities.addElement(servB);			// add service B
  }

  /**
    Check if the protocol is slow start (i.e. the protocol subtype is for slow
    start).

    @return		true/false if slow start is/is not in use
  */
  public static boolean isSlowStart() {
    return(					// return check
      protocolSubtype.equals("ss"));		// slow start subtype
  }

  /**
    Set a TCP parameter.

    @param parameter		parameter
    @param value		value
  */
  public void setParameter(String parameter, String value) {
    if (parameter.equals("pushA")) {
      boolean push = Boolean.valueOf(value).booleanValue();
      servA.setPush(push);
      return;
    }
    else if (parameter.equals("pushB")) {
      boolean push = Boolean.valueOf(value).booleanValue();
      servB.setPush(push);
      return;
    }
    try {
      if (parameter.equals("lossRate")) {	// loss rate?
	float lossRate = Float.valueOf(value).floatValue();
	((TCPMedium) medium).setLossRate(lossRate);
      }
      else {					// other integer parameter
	int size = Integer.parseInt(value);
	if (parameter.equals("userAMessageSize"))
	  servA.setMessageSize(size);
	else if (parameter.equals("userBMessageSize"))
	  servB.setMessageSize(size);
	else if (parameter.equals("windowSizeA"))
	  protA.setWindowSizeDefault(size);
	else if (parameter.equals("windowSizeB"))
	  protB.setWindowSizeDefault(size);
	else if (parameter.equals("maxSendPacket"))
	  TCPProtocol.setSegmentSize(size);
	else
	  System.err.println("unknown parameter '" + parameter + ";");
      }
    }
    catch (NumberFormatException e) {		// invalid numeric value
      System.err.println(
	"invalid number '" + value + "' for '" + parameter + "'");
    }
  }

}

