package brn.swans.app.rtcp;

import jist.runtime.JistAPI;
import jist.swans.misc.Pickle;

/**
 * The class ReceptionReport represents an rtp receiver report stored in an
 * RTPSenderReportPacket or RTPReceiverReport.
 */
public class ReceptionReport implements JistAPI.Timeless {

  // ////////////////////////////////////////////////
  // constants
  //

  // ////////////////////////////////////////////////
  // locals
  //

  /**
   * Size of this header = 6 * 4 octets
   */
  public static final int HEADER_SIZE = 6 * 4;

  /**
   * The ssrc identifier of the sender this ReceptionReport is for (unsigned).
   */
  protected int ssrc;

  /**
   * The fraction lost (unsigned).
   */
  protected byte fractionLost;

  /**
   * The number of packets expected minus the number of packets received.
   */
  protected int packetsLostCumulative;

  /**
   * The extended highest sequence number received (unsigned).
   */
  protected int extendedHighestSequenceNumber;

  /**
   * The interarrival jitter.
   */
  protected int jitter;

  /**
   * The rtp time stamp of the last SenderReport received from this source.
   */
  protected int lastSR;

  /**
   * The delay since the last SenderReport from this sender has been received in
   * units of 1/65536 seconds.
   */
  protected int delaySinceLastSR;

  // ////////////////////////////////////////////////
  // initialization
  //

  public ReceptionReport() {
    this.ssrc = 0;
    this.fractionLost = 0;
    this.packetsLostCumulative = 0;
    this.extendedHighestSequenceNumber = 0;
    this.jitter = 0;
    this.lastSR = 0;
    this.delaySinceLastSR = 0;
  }

  // ////////////////////////////////////////////////
  // accessors
  //

  public ReceptionReport(byte[] msg, int offset) {
    // Bytes 0-3: ssrc
    ssrc = (int)Pickle.arrayToUInt(msg, offset);
    // Byte 4: fraction lost
    fractionLost = (byte)Pickle.arrayToUByte(msg, offset + 4);
    // Bytes 5-7: cummulative number of packets lost
    packetsLostCumulative = (int)Pickle.arrayToUInt(msg, offset+5);
    // Bytes 8-11: extended highest sequence number received
    extendedHighestSequenceNumber = (int)Pickle.arrayToUInt(msg, offset+8);
    // Bytes 12-15: interarrival jitter
    jitter = (int)Pickle.arrayToUInt(msg, offset+12);
    // Bytes 16-19: last SR
    lastSR = (int)Pickle.arrayToUInt(msg, offset+16);
    // Bytes 20-23: delay since last SR
    delaySinceLastSR = (int)Pickle.arrayToUInt(msg, offset+20);
  }

  public int getDelaySinceLastSR() {
    return delaySinceLastSR;
  }

  public void setDelaySinceLastSR(int delaySinceLastSR) {
    this.delaySinceLastSR = delaySinceLastSR;
  }

  public int getSequenceNumber() {
    return extendedHighestSequenceNumber;
  }

  public void setSequenceNumber(int extendedHighestSequenceNumber) {
    this.extendedHighestSequenceNumber = extendedHighestSequenceNumber;
  }

  public byte getFractionLost() {
    return fractionLost;
  }

  public void setFractionLost(byte fractionLost) {
    this.fractionLost = fractionLost;
  }

  public int getJitter() {
    return jitter;
  }

  public void setJitter(int jitter) {
    this.jitter = jitter;
  }

  public int getLastSR() {
    return lastSR;
  }

  public void setLastSR(int lastSR) {
    this.lastSR = lastSR;
  }

  public int getPacketsLostCumulative() {
    return packetsLostCumulative;
  }

  public void setPacketsLostCumulative(int packetsLostCumulative) {
    this.packetsLostCumulative = packetsLostCumulative;
  }

  public int getSsrc() {
    return ssrc;
  }

  public void setSsrc(int ssrc) {
    this.ssrc = ssrc;
  }

  // ////////////////////////////////////////////////
  // overwrites
  //

  public String toString() {
    return ("ReceptionReport [" + "ssrc=" + ssrc + ", fractionLost="
        + fractionLost + ", packetsLostCumulative=" + packetsLostCumulative
        + ", extendedHighestSequenceNumber=" + extendedHighestSequenceNumber
        + ", jitter=" + jitter + ", lastSR=" + lastSR + ", delaySinceLastSR="
        + delaySinceLastSR + "]");
  }

  public void getBytes(byte[] msg, int offset) {
    // Bytes 0-3: ssrc
    Pickle.uintToArray(ssrc, msg, offset);
    // Byte 4: fraction lost
    Pickle.ubyteToArray(fractionLost, msg, offset + 4);
    // Bytes 5-7: cummulative number of packets lost
    Pickle.uintToArray((packetsLostCumulative & 0xFFFFFF), msg, offset+5);
    // Bytes 8-11: extended highest sequence number received
    Pickle.uintToArray(extendedHighestSequenceNumber, msg, offset+8);
    // Bytes 12-15: interarrival jitter
    Pickle.uintToArray(jitter, msg, offset+12);
    // Bytes 16-19: last SR
    Pickle.uintToArray(lastSR, msg, offset+16);
    // Bytes 20-23: delay since last SR
    Pickle.uintToArray(delaySinceLastSR, msg, offset+20);
  }

  /* (non-Javadoc)
   * @see java.lang.Object#hashCode()
   */
  public int hashCode() {
    final int PRIME = 31;
    int result = 1;
    result = PRIME * result + delaySinceLastSR;
    result = PRIME * result + extendedHighestSequenceNumber;
    result = PRIME * result + jitter;
    result = PRIME * result + lastSR;
    result = PRIME * result + packetsLostCumulative;
    result = PRIME * result + ssrc;
    return result;
  }

  /* (non-Javadoc)
   * @see java.lang.Object#equals(java.lang.Object)
   */
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    final ReceptionReport other = (ReceptionReport) obj;
    if (delaySinceLastSR != other.delaySinceLastSR)
      return false;
    if (extendedHighestSequenceNumber != other.extendedHighestSequenceNumber)
      return false;
    if (fractionLost != other.fractionLost)
      return false;
    if (jitter != other.jitter)
      return false;
    if (lastSR != other.lastSR)
      return false;
    if (packetsLostCumulative != other.packetsLostCumulative)
      return false;
    if (ssrc != other.ssrc)
      return false;
    return true;
  }

}
