package brn.swans.app.rtp.msg;

import java.util.Arrays;

import jist.swans.misc.Message;

/**
 * An RTPMpegPacket is intended to be capsulated into an RTPPacket when
 * transmitting mpeg data with rtp under the rtp audio/video profile. It stores
 * information about the mpeg data as described in rfc 2250. This implementation
 * doesn't transport real mpeg data. It is intended to simulate storing mpeg
 * data by adding length. Currently only one header field (picture type) is
 * filled with the right value. The values for the other header fields can't be
 * determined by reading the gdf file.
 *
 * http://www.faqs.org/rfcs/rfc2250.html
 *
 * Note: A single packet may only contain up to one mpeg picture, or a picture
 * may be broken up into several packets. If present, the picture header is always
 * the first payload in the packet (in the absense of gop and sequence headers).
 */
public class RtpMpegMessage implements Message {

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

  /**
   * Header length is 4 byte.
   */
  public static final int HEADER_LENGTH = 4;

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

  /**
   * Not used.
   */
  protected int mzb;

  /**
   * Not used.
   */
  protected boolean two;

  /**
   * Not used.
   */
  protected int temporalReference;

  /**
   * Not used.
   */
  protected boolean activeN;

  /**
   * Not used.
   */
  protected boolean newPictureHeader;

  /**
   * Not used.
   */
  protected boolean sequenceHeaderPresent;

  /**
   * Beginning-of-slice (BS) (1 bit). Set when the start of the packet payload
   * is a slice start code, or when a slice start code is preceded only by one
   * or more of a Video_Sequence_Header, GOP_header and/or Picture_Header.
   */
  protected boolean beginningOfSlice;

  /**
   * End-of-slice (ES) (1 bit). Set when the last byte of the payload is the end
   * of an MPEG slice.
   */
  protected boolean endOfSlice;

  /**
   * The picture type of the frame this packet belongs to.
   */
  protected int pictureType;

  /**
   * Not used.
   */
  protected int fbv;

  /**
   * Not used.
   */
  protected int bfc;

  /**
   * Not used.
   */
  protected int ffv;

  /**
   * Not used.
   */
  protected int ffc;

  /**
   * The actual payload.
   */
  protected Message payload;

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

  public RtpMpegMessage() {
    this.mzb = 0;
    this.two = false;
    this.temporalReference = 0;
    this.activeN = false;
    this.newPictureHeader = false;
    this.sequenceHeaderPresent = false;
    this.beginningOfSlice = false;
    this.endOfSlice = false;
    this.pictureType = 0;
    this.fbv = 0;
    this.bfc = 0;
    this.ffv = 0;
    this.ffc = 0;
    this.payload = null;
  }

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

  public Message getPayload() {
    return payload;
  }

  public void setPayload(Message payload) {
    this.payload = payload;
  }

  public int getPictureType() {
    return pictureType;
  }

  public void setPictureType(int pictureType) {
    this.pictureType = pictureType;
  }

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

  public void getBytes(byte[] msg, int offset) {
    Arrays.fill(msg, offset, offset + getSize(), (byte) 0);
  }

  public int getSize() {
    return HEADER_LENGTH + (null != payload ? payload.getSize() : 0);
  }

  /* (non-Javadoc)
   * @see java.lang.Object#hashCode()
   */
  public int hashCode() {
    final int PRIME = 31;
    int result = 1;
    result = PRIME * result + (activeN ? 1231 : 1237);
    result = PRIME * result + (beginningOfSlice ? 1231 : 1237);
    result = PRIME * result + bfc;
    result = PRIME * result + (endOfSlice ? 1231 : 1237);
    result = PRIME * result + fbv;
    result = PRIME * result + ffc;
    result = PRIME * result + ffv;
    result = PRIME * result + mzb;
    result = PRIME * result + (newPictureHeader ? 1231 : 1237);
    result = PRIME * result + ((payload == null) ? 0 : payload.hashCode());
    result = PRIME * result + pictureType;
    result = PRIME * result + (sequenceHeaderPresent ? 1231 : 1237);
    result = PRIME * result + temporalReference;
    result = PRIME * result + (two ? 1231 : 1237);
    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 RtpMpegMessage other = (RtpMpegMessage) obj;
    if (activeN != other.activeN)
      return false;
    if (beginningOfSlice != other.beginningOfSlice)
      return false;
    if (bfc != other.bfc)
      return false;
    if (endOfSlice != other.endOfSlice)
      return false;
    if (fbv != other.fbv)
      return false;
    if (ffc != other.ffc)
      return false;
    if (ffv != other.ffv)
      return false;
    if (mzb != other.mzb)
      return false;
    if (newPictureHeader != other.newPictureHeader)
      return false;
    if (payload == null) {
      if (other.payload != null)
        return false;
    } else if (!payload.equals(other.payload))
      return false;
    if (pictureType != other.pictureType)
      return false;
    if (sequenceHeaderPresent != other.sequenceHeaderPresent)
      return false;
    if (temporalReference != other.temporalReference)
      return false;
    if (two != other.two)
      return false;
    return true;
  }

}
