"""
<Author>
  Michael Moshofsky

<Start Date>
  Febuary 15, 2009

<Description>
  TCP uses a retransmission timer to ensure data delivery in the absence of any feedback 
  from the remote data receiver. The duration of this timer is referred to as retransmission 
  timeout (RTO). This class uses the smoothed round trip time (SRTT) algorithm to calculate
  the RTO. The algorithm is described in detail at http://tools.ietf.org/html/rfc2988.

  The best way to measure Round Trip Time Measurements (RTT measurement) is to use TCP 
  timestamp option which a description can be found at:
  http://tools.ietf.org/html/rfc1323#section-3.

  Defaults Used (can be altered):
    - Initial RTO: 1.0 seconds
    - Granularity: 0.1 seconds
    - k(multiple): 4
    - alpha      : 1/8
    - beta       : 1/4

<Usage>
  Public Objects:
    SmoothedRoundTripTime - calculates the RTO based on measurements inputed.

  Public Methods:
    SmoothedRoundTripTime() - get a new SRTT object
    setGranularity(g) - set the granularity value.
    setK(k) - set the value of the multiple k.
    setAlpha(a) - set the value of alpha.
    setBeta(b) - set the value of beta.
    getCurRTO() - returns current value of RTO
    inputRTTValue(newMeasurement) - calculates new value of RTO based on measurement passed in.
                                    Returns the new RTO value.

  Private Methods:
    max(val1, val2) - returns the max value.
    absVal(x) - returns the positive value of x.

"""




class SmoothedRoundTripTime:

  def __init__(self):
    """
    <Purpose>
      Initializes an object that will calc RTO values using SRTT.

    <Arguments>
      None

    <Exceptions>
      None

    <Returns>
      A new SmoothRoundTripTime object.
    """

    # initial RTO time is 1 second.
    self.curRTO = 1.0

    # Default granularity is .1 seconds
    self.granularity = .1
    # Default k value of 4
    self.k = 4

    # Defualt alpha = 1/8, beta = 1/4
    self.alpha = 1/8
    self.beta = 1/4

    self.curSRTT = None
    self.curRTTVAR = None

    self.numMeasurements = 0



  # Returns the current RTO value
  def getCurRTO():
    return self.curRTO

  def inputRTTValue(newMeasurement):
    """
    <Purpose>
      Calculates the new RTO value using SRTT with the new
      measurement passed in.

    <Arguments>
      newMeasurement - RTT measurement preferably using RTTM
      found at http://tools.ietf.org/html/rfc1323#section-3.

    <Exceptions>
      None

    <Returns>
      The new RTO value.
    """

    if (self.numMeasurements == 0):
      self.curSRTT = newMeasurement
      self.curRTTVAR = newMeasurement / 2
      self.curRTO = self.curSRTT + max(self.granularity, self.k * self.curRTTVAR)
    else:
      self.curRTTVAR = (1 - self.beta) * self.curRTTVAR + self.beta * absVal(self.curSRTT - newMeasurement)
      self.curSRTT = (1 - self.alpha) * self.curSRTT + self.alpha * newMeasurement
      self.curRTO = self.curSRTT + max(self.granularity, self.k * self.curRTTVAR)
    self.numMeasurements += 1
    return self.curRTO


  # Sets the granularity
  def setGranularity(g):
      self.granularity = g

  # Sets the multiple k
  def setK(k):
    self.k = k

  # Sets the value of alpha
  def setAlpha(a):
    self.alpha = a

  # Sets the value of beta
  def setBeta(b):
    self.beta = b


### Private Methods ###

  def max(val1, val2):
    """
    <Purpose>
      Find and return the max value.

    <Arguments>
      val1 - first number, val2 - second number 

    <Exceptions>
      None

    <Returns>
      The max of val1 and val2
    """
    if (val1 >= val2):
      return val1
    else:
      return val2

  def absVal(x):
    """
    <Purpose>
      Find and return the absolute value of x.

    <Arguments>
      x - a number

    <Exceptions>
      None

    <Returns>
      |x|
    """
    if (x < 0):
      return -1 * x
    else:
      return x


