/**
 * Java RTP Library (jlibrtp)
 * Copyright (C) 2006 Arne Kepp
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package jlibrtp;

import java.net.InetSocketAddress;

/**
 * RTCP packets for Source Descriptions
 * 
 * @author Arne Kepp
 */
public class RtcpPktSDES extends RtcpPkt {
	/** Whether the RTP Session object should be inclduded */
	boolean reportSelf = true;
	/** The parent RTP Session object, holds participant database */
	RTPSession rtpSession = null;
	/** The participants to create SDES packets for */
	protected Participant[] participants = null;

	/**
	 * Constructor to create a new SDES packet
	 * 
	 * TODO: Currently the added participants are not actually encoded because
	 * the library lacks some support for acting as mixer or relay in other
	 * areas.
	 * 
	 * @param reportThisSession
	 *            include information from RTPSession as a participant
	 * @param rtpSession
	 *            the session itself
	 * @param additionalParticipants
	 *            additional participants to include
	 */
	protected RtcpPktSDES(boolean reportThisSession, RTPSession rtpSession,
			Participant[] additionalParticipants) {
		super.packetType = 202;
		// Fetch all the right stuff from the database
		reportSelf = reportThisSession;
		participants = additionalParticipants;
		this.rtpSession = rtpSession;
	}

	/**
	 * Constructor that parses a received packet
	 * 
	 * @param aRawPkt
	 *            the byte[] containing the packet
	 * @param start
	 *            where in the byte[] this packet starts
	 * @param socket
	 *            the address from which the packet was received
	 * @param partDb
	 *            the participant database
	 */
	protected RtcpPktSDES(byte[] aRawPkt, int start, InetSocketAddress socket,
			ParticipantDatabase partDb) {
		if (RTPSession.rtcpDebugLevel > 8) {
			System.out.println("  -> RtcpPktSDES(byte[], ParticipantDabase)");
		}
		rawPkt = aRawPkt;

		if (!super.parseHeaders(start) || packetType != 202) {
			if (RTPSession.rtpDebugLevel > 2) {
				System.out
						.println(" <-> RtcpPktSDES.parseHeaders() etc. problem");
			}
			super.problem = -202;
		} else {
			// System.out.println(" DECODE SIZE: " + super.length +
			// " itemcount " + itemCount );

			int curPos = 4 + start;
			int curLength;
			int curType;
			long ssrc;
			boolean endReached = false;
			boolean newPart;
			this.participants = new Participant[itemCount];

			// Loop over SSRC SDES chunks
			for (int i = 0; i < itemCount; i++) {
				ssrc = StaticProcs.bytesToUIntLong(aRawPkt, curPos);
				Participant part = partDb.getParticipant(ssrc);
				if (part == null) {
					if (RTPSession.rtcpDebugLevel > 1) {
						System.out
								.println("RtcpPktSDES(byte[], ParticipantDabase) adding new participant, ssrc:"
										+ ssrc + " " + socket);
					}

					part = new Participant(socket, socket, ssrc);
					newPart = true;
				} else {
					newPart = false;
				}

				curPos += 4;

				// System.out.println("PRE endReached " + endReached +
				// " curPos: " + curPos + " length:" + this.length +
				// (!endReached && (curPos/4) < this.length));

				while (!endReached && (curPos / 4) <= this.length) {
					// System.out.println("endReached " + endReached +
					// " curPos: " + curPos + " length:" + this.length);
					curType = (int) aRawPkt[curPos];

					if (curType == 0) {
						curPos += 4 - (curPos % 4);
						endReached = true;
					} else {
						curLength = (int) aRawPkt[curPos + 1];
						// System.out.println("curPos:"+curPos+" curType:"+curType+" curLength:"+curLength+" read from:"+(curPos
						// + 1));

						if (curLength > 0) {
							byte[] item = new byte[curLength];
							// System.out.println("curPos:"+curPos+" arawPkt.length:"+aRawPkt.length+" curLength:"+curLength);
							System.arraycopy(aRawPkt, curPos + 2, item, 0,
									curLength);

							switch (curType) {
							case 1:
								part.cname = new String(item);
								break;
							case 2:
								part.name = new String(item);
								break;
							case 3:
								part.email = new String(item);
								break;
							case 4:
								part.phone = new String(item);
								break;
							case 5:
								part.loc = new String(item);
								break;
							case 6:
								part.tool = new String(item);
								break;
							case 7:
								part.note = new String(item);
								break;
							case 8:
								part.priv = new String(item);
								break;
							}
							// System.out.println("TYPE " + curType + " value:"
							// + new String(item) );

						} else {
							switch (curType) {
							case 1:
								part.cname = null;
								break;
							case 2:
								part.name = null;
								break;
							case 3:
								part.email = null;
								break;
							case 4:
								part.phone = null;
								break;
							case 5:
								part.loc = null;
								break;
							case 6:
								part.tool = null;
								break;
							case 7:
								part.note = null;
								break;
							case 8:
								part.priv = null;
								break;
							}

						}
						curPos = curPos + curLength + 2;
					}
				}

				// Save the participant
				this.participants[i] = part;
				if (newPart)
					partDb.addParticipant(2, part);

				// System.out.println("HEPPPPPP " + participants[i].cname );
			}
		}
		if (RTPSession.rtcpDebugLevel > 8) {
			System.out.println("  <- RtcpPktSDES()");
		}
	}

	/**
	 * Encode the packet into a byte[], saved in .rawPkt
	 * 
	 * CompRtcpPkt will call this automatically
	 */
	protected void encode() {
		byte[] temp = new byte[1450];
		byte[] someBytes = StaticProcs.uIntLongToByteWord(this.rtpSession.ssrc);
		System.arraycopy(someBytes, 0, temp, 4, 4);
		int pos = 8;

		String tmpString = null;
		for (int i = 1; i < 9; i++) {
			switch (i) {
			case 1:
				tmpString = this.rtpSession.cname;
				break;
			case 2:
				tmpString = this.rtpSession.name;
				break;
			case 3:
				tmpString = this.rtpSession.email;
				break;
			case 4:
				tmpString = this.rtpSession.phone;
				break;
			case 5:
				tmpString = this.rtpSession.loc;
				break;
			case 6:
				tmpString = this.rtpSession.tool;
				break;
			case 7:
				tmpString = this.rtpSession.note;
				break;
			case 8:
				tmpString = this.rtpSession.priv;
				break;
			}

			if (tmpString != null) {
				someBytes = tmpString.getBytes();
				temp[pos] = (byte) i;
				temp[pos + 1] = (byte) someBytes.length;
				System.arraycopy(someBytes, 0, temp, pos + 2, someBytes.length);
				// System.out.println("i: "+i+" pos:"+pos+" someBytes.length:"+someBytes.length);
				pos = pos + someBytes.length + 2;
				// if(i == 1 ) {
				// System.out.println("trueeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" +
				// tmpString);
				// }
			}
		}
		int leftover = pos % 4;
		if (leftover == 1) {
			temp[pos] = (byte) 0;
			temp[pos + 1] = (byte) 1;
			pos += 3;
		} else if (leftover == 2) {
			temp[pos] = (byte) 0;
			temp[pos + 1] = (byte) 0;
			pos += 2;
		} else if (leftover == 3) {
			temp[pos] = (byte) 0;
			temp[pos + 1] = (byte) 3;
			pos += 5;
		}

		// TODO Here we ought to loop over participants, if we're doing SDES for
		// other participants.

		super.rawPkt = new byte[pos];
		itemCount = 1;
		// This looks wrong, but appears to be fine..
		System.arraycopy(temp, 0, super.rawPkt, 0, pos);
		writeHeaders();
	}

	/**
	 * Debug purposes only
	 */
	public void debugPrint() {
		System.out.println("RtcpPktSDES.debugPrint() ");
		if (participants != null) {
			for (int i = 0; i < participants.length; i++) {
				Participant part = participants[i];
				System.out.println("     part.ssrc: " + part.ssrc
						+ "  part.cname: " + part.cname + " part.loc: "
						+ part.loc);
			}
		} else {
			System.out
					.println("     nothing to report (only valid for received packets)");
		}
	}
}
