package brn.swans.app.rtcp;

import jist.runtime.JistAPI;
import brn.swans.app.rtp.msg.RtpMessage;

/**
 * The class RTPSenderInfo is used by an rtp end system for storing information
 * about itself. With the stored information it can create a SenderReport.
 */
public class RtpSenderInfo extends RtpParticipantInfo implements
    JistAPI.Timeless {

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

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

  /**
   * The time when the transmission was started.
   */
  protected long startTime;

  /**
   * The clock rate this sender increases the rtp time stamp.
   */
  protected int clockRate;

  /**
   * The initial rtp time stamp (insigned).
   */
  protected int timeStampBase;

  /**
   * The initial sequence number (unsigned).
   */
  protected short sequenceNumberBase;

  /**
   * The number of rtp data packets this sender has sent (unsigned).
   */
  protected int packetsSent;

  /**
   * The number of data bytes this sender has sent (unsigned).
   */
  protected int bytesSent;

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

  /**
   * Default constructor.
   */
  public RtpSenderInfo() {
    this(0);
  }

  public RtpSenderInfo(int ssrc) {
    super(ssrc);

    this.startTime = 0;
    this.clockRate = 0;
    this.timeStampBase = 0;
    this.sequenceNumberBase = 0;
    this.packetsSent = 0;
    this.bytesSent = 0;
  }

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

  /**
   * Sets the time (simTime) when this endsystem has started sending rtp
   * packets.
   */
  public void setStartTime(long startTime) {
    this.startTime = startTime;
  }

  /**
   * Sets the clock rate (in ticks per second) this sender increases the rtp
   * time stamp.
   */
  public void setClockRate(int clockRate) {
    this.clockRate = clockRate;
  }

  /**
   * Sets the initial rtp time stamp.
   */
  public void setTimeStampBase(int timeStampBase) {
    this.timeStampBase = timeStampBase;
  }

  /**
   * Sets the initial sequence number.
   */
  public void setSequenceNumberBase(short sequenceNumberBase) {
    this.sequenceNumberBase = sequenceNumberBase;
  }

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

  // ////////////////////////////////////////////////
  // Implementation
  //

  /**
   * Stores information about this outgoing RTPPacket.
   */
  public void processRTPPacket(RtpMessage packet, long arrivalTime) {
    packetsSent++;
    bytesSent += packet.getPayload().getSize();

    // call corresponding method of superclass
    // for setting _silentIntervals
    // it deletes the packet !!!
    super.processRTPPacket(packet, arrivalTime);
  }

  /**
   * Processes an incoming ReceptionReport for this sender.
   */
  public void processReceptionReport(ReceptionReport report, long arrivalTime) {
  }

  /**
   * Returns a SenderReport for this rtp endsystem. If it hasn't sent rtp data
   * packets during the last 2 rtcp intervals, it returns NULL.
   */
  public SenderReport senderReport(long now) {
    if (isSender()) {
      SenderReport senderReport = new SenderReport();
      // ntp time stamp is 64 bit integer

      long ntpSeconds = (long) now;
      long ntpFraction = (long) ((now - (long) ntpSeconds) * 65536.0 * 65536.0);

      senderReport.setNtpTimeStamp((long) (ntpSeconds << 32) + ntpFraction);
      senderReport.setRtpTimeStamp((int) (now - startTime) * clockRate);
      senderReport.setPacketCount(packetsSent);
      senderReport.setByteCount(bytesSent);
      return senderReport;
    } else {
      return null;
    }
  }

  /**
   * A sender info shall never be deleted!
   */
  public boolean toBeDeleted(long now) {
    return false;
  }

  /* (non-Javadoc)
   * @see java.lang.Object#hashCode()
   */
  public int hashCode() {
    final int PRIME = 31;
    int result = super.hashCode();
    result = PRIME * result + bytesSent;
    result = PRIME * result + clockRate;
    result = PRIME * result + packetsSent;
    result = PRIME * result + sequenceNumberBase;
    result = PRIME * result + (int) (startTime ^ (startTime >>> 32));
    result = PRIME * result + timeStampBase;
    return result;
  }

  /* (non-Javadoc)
   * @see java.lang.Object#equals(java.lang.Object)
   */
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (!super.equals(obj))
      return false;
    if (getClass() != obj.getClass())
      return false;
    final RtpSenderInfo other = (RtpSenderInfo) obj;
    if (bytesSent != other.bytesSent)
      return false;
    if (clockRate != other.clockRate)
      return false;
    if (packetsSent != other.packetsSent)
      return false;
    if (sequenceNumberBase != other.sequenceNumberBase)
      return false;
    if (startTime != other.startTime)
      return false;
    if (timeStampBase != other.timeStampBase)
      return false;
    return true;
  }

}
