/**
 * 
 */
package jist.swans.rate;

import jist.runtime.Main;
import jist.swans.Constants;
import jist.swans.mac.MacAddress;
import jist.swans.mac.MacInfo;
import jist.swans.misc.Message;
import jist.swans.misc.MessageAnno;
import jist.swans.misc.Util;

/**
 * This abstract class serves as a base for rate control algorithms in
 * high-latency systems, where rate adaption is not and cannot be performed on a
 * transmission attempt basis but only on a packet transmission basis. All
 * algorithms based on this class provide an object called multi rate retry
 * chain, which holds bit-rates and attempt counts for the transmission of the
 * current packet. If a transmission attempt fails, there is no feedback to the
 * algorithm; instead the transmission rate for the next attempt is taken from
 * the multi rate retry chain that was earlier provided by the algorithm. See
 * "RR-5208 - IEEE 802.11 Rate Adaptation: A Practical Approach" at
 * http://www.inria.fr/rrrt/rr-5208.html for details on low- and high-latency
 * systems and further implications.
 * 
 * @author ofriedri
 */
public abstract class AbstractRcaHighLatency extends AbstractRca {

  /**
   * The multi rate retry chain to use for the current packet transmission.
   */
  protected MultiRateRetryChain m_mrrc = null;

  /**
   * @param macInfo
   */
  public AbstractRcaHighLatency(MacInfo macInfo) {
    super(macInfo);
  }

  /*
   * (non-Javadoc)
   * 
   * @see jist.swans.rate.RateControlAlgorithmIF#getControlRate(jist.swans.mac.MacAddress,
   *      int)
   */
  public int getControlRate(MacAddress nextHop, int dataRate) {
    // no packets have yet been received/reported
    int[] basicRates = s_macRateInfo.getBasicRates(nextHop);
    if (m_lastDataRate == Constants.BANDWIDTH_INVALID) {
      int idx = Util.isInArray(basicRates, Constants.BASIC_RATES_80211AG[0]);
      if (idx >= 0)
        return basicRates[idx];
      return basicRates[0];
    }
    if (Util.isInArray(Constants.BITRATES_OFDM, m_lastDataRate) >= 0)
      return Constants.BASIC_RATES_80211AG[0];
    else if (Util.isInArray(Constants.BITRATES_DSSS, m_lastDataRate) >= 0)
      return Constants.BASIC_RATES_80211BG[0];
    return basicRates[0];
  }

  /**
   * <p>
   * This implementation uses the multi rate retry chain (mrrc) generated by the
   * derived algorithm to return the next bit-rate without interaction with the
   * actual algorithm.
   * </p>
   * <p>
   * Call this method at the beginning of your overriding implementation, e.g.
   * super.getNextDataRate(packet, anno, nextHop, frameLen, triesBefore).
   * </p>
   * 
   * @see jist.swans.rate.RateControlAlgorithmIF#getNextDataRate(jist.swans.misc.Message,
   *      jist.swans.misc.MessageAnno, java.lang.Object, int, int)
   */
  public int getNextDataRate(Message packet, MessageAnno anno, Object nextHop,
      int frameLen, int triesBefore) {
    // Tx rates have already been calculated for this packet
    Util.assertion(triesBefore > 0);
    if (Main.ASSERT)
      Util.assertion(m_mrrc != null && m_mrrc.getSize() > 0);

    int idx, sum = 0;
    try {
    	for(idx = 0; idx < m_mrrc.getSize(); idx++) {
  			sum += m_mrrc.tries[idx];
  			if (triesBefore < sum)
  				break;
      }
    } catch (ArrayIndexOutOfBoundsException a) {
      throw new RuntimeException("Tries: " + triesBefore + " mrcc:" + m_mrrc, a);
    }

    if (Main.ASSERT)
      Util.assertion(idx < m_mrrc.getSize() && triesBefore <= sum
          && m_mrrc.tries[idx] > 0);

    return m_mrrc.bitrates[idx];
  }

}
