package brn.swans.app.rtcp.msg;

import java.util.ArrayList;
import java.util.List;

import jist.swans.misc.Message;
import jist.swans.misc.MessageBytes;

/**
 * An rtcp compound packet acts as container for rtcp packets, which are
 * transmitted in an RTCPCompoundPacket. Every RTCPCompoundPacket must consist
 * at least one RTCPSenderReportPacketof RTCPReceiverReportPacket and one
 * RTCPSDESPacket. This class doesn't check if these requirements are met.
 */
public class RtcpCompoundMessage implements Message {

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

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

  /**
   * The cArray in which the rtcp packets are stored.
   */
  protected List rtcpPackets;

  /**
   * Length of this packet in bytes.
   */
  protected int length;

  /**
   * Time when the packet arrived.
   */
  private long arrivalTime;

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

  public RtcpCompoundMessage() {
    // an empty rtcp compound packet has length 0 bytes
    length = 0;
    rtcpPackets = new ArrayList();
  }

  public RtcpCompoundMessage(byte[] msg, int offset) {
    this();

    while (offset < msg.length) {
      RtcpMessage rtcpPacket = RtcpMessage.fromBytes(msg, offset);

      offset += rtcpPacket.getLength();
      addRTCPPacket(rtcpPacket);
    }
  }

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

  /**
   * Adds an RTCPPacket to this RTCPCompoundPacket.
   */
  public void addRTCPPacket(RtcpMessage rtcpPacket) {
    rtcpPackets.add(rtcpPacket);
    // the size of the rtcp compound packet increases
    // by the size of the added rtcp packet
    length += rtcpPacket.getLength();
  }

  public int getLength() {
    return length;
  }

  public List getRtcpPackets() {
    return rtcpPackets;
  }

  public long getArrivalTime() {
    return arrivalTime;
  }

  public void setArrivalTime(long arrivalTime) {
    this.arrivalTime = arrivalTime;
  }

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

  public String toString() {
    String ret = "RTCPCompoundPacket [";
    for (int i = 0; i < rtcpPackets.size(); i++) {
      ret += rtcpPackets.get(i).toString();
    }

    return (ret + "]");
  }

  // ////////////////////////////////////////////////
  // message interface
  //

  public void getBytes(byte[] msg, int offset) {
    for (int i = 0; i < rtcpPackets.size(); i++) {
      RtcpMessage rtcpPacket = (RtcpMessage) rtcpPackets.get(i);
      rtcpPacket.getBytes(msg, offset);
      offset += rtcpPacket.getSize();
    }
  }

  public int getSize() {
    return length;
  }

  public static RtcpCompoundMessage fromBytes(Message msg) {
    if (msg instanceof RtcpCompoundMessage)
      return (RtcpCompoundMessage)msg;

    return new RtcpCompoundMessage(((MessageBytes)msg).getBytes(), 0);
  }

  /* (non-Javadoc)
   * @see java.lang.Object#hashCode()
   */
  public int hashCode() {
    final int PRIME = 31;
    int result = 1;
    result = PRIME * result + (int) (arrivalTime ^ (arrivalTime >>> 32));
    result = PRIME * result + length;
    result = PRIME * result + ((rtcpPackets == null) ? 0 : rtcpPackets.hashCode());
    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 RtcpCompoundMessage other = (RtcpCompoundMessage) obj;
    if (arrivalTime != other.arrivalTime)
      return false;
    if (length != other.length)
      return false;
    if (rtcpPackets == null) {
      if (other.rtcpPackets != null)
        return false;
    } else if (!rtcpPackets.equals(other.rtcpPackets))
      return false;
    return true;
  }

}
