import java.net.*;
import java.awt.TextArea;
import java.util.*;
import java.io.*;

public class RTCPReceiver extends Thread {
   SessionInfo snInfo;
   InetAddress group;
   int         port;
   TextArea    partiList;
   byte []     buf;
   byte []     data;
   int         dataLen;
   static final int  MAXMSGLEN=4096;
   MulticastSocket   rtcpRcvSock;
   DataInputStream   in;
   DatagramPacket    rcvPkt;
   static final byte SR=128-200;
   static final byte RR=128-201;
   static final byte SDES=128-202;
   static final byte BYE=128-203; 
   static final boolean Debug=true;
   
   public RTCPReceiver(InetAddress ia, int p, SessionInfo si,
            TextArea ta)
   {
      group = ia;
      port = p;
      snInfo = si;
      partiList = ta;
      buf = new byte[MAXMSGLEN];
      rcvPkt = new DatagramPacket(buf, buf.length);
      try{
         rtcpRcvSock = new MulticastSocket(port);
      }catch(IOException e){
         System.out.println("RTCPReceiver: create socket-->"+e);
      }
   }
   
   public void run(){
      byte     b1, b2;
      byte []  msgbuf=null;
      int      ssrc;
      int      spCount;       // Sender packet count
      int      soCount;       // Sender octet count
      byte     RC, PT, SC;
      short    pktlen, len;
      String   msg;
      String   CNAME=null;
      String   NAME=null;
      String   EMAIL=null;
      int      nread=0;
      
      try{
         rtcpRcvSock.joinGroup(group);
      }catch(IOException e){
         System.out.println("RTCPReceiver: joinGroup-->"+e);
      }
      
      while (true){
         try{
            rtcpRcvSock.receive(rcvPkt);
         }catch(IOException e){
            System.out.println("RTCPReceiver: receive-->"+e);
         }
         
         data = rcvPkt.getData();
         dataLen = rcvPkt.getLength();
         in = new DataInputStream(new ByteArrayInputStream(data));
         try{
            // first two bytes
            b1 = in.readByte();
            RC = (byte)(b1 & 0x1f);
            PT = in.readByte();
            
            // packet length
            pktlen = in.readShort();
            
            // SSRC
            ssrc = in.readInt();
            nread=8;          // already read 8 bytes
            if (Debug){
               System.out.println("RTCPReceiver.run: b1-->"+b1+", PT-->"+PT+
                     " , ssrc-->"+ssrc+", datalen-->"+dataLen);
            }
            
            switch (PT) {
               case SR:         // SR
                  in.readInt();  // NTP timestamp1
                  in.readInt();  // NTP timestamp2
                  in.readInt();  // RTP timestamp
                  spCount = in.readInt();
                  soCount = in.readInt();
                  nread += 20;
                  snInfo.addSenders(1);
                  
                  // now skip all RC's 
                  // each RC block is 6 32bit words
                  in.skipBytes(RC*24);
                  nread += RC*24;
                  if (Debug){
                     System.out.println("RTCPReceiver.run:SR read");
                  }                     
                  break;
                
                case RR:        // RR
                  // skip all RC's 
                  // each RC block is 6 32bit words
                  in.skipBytes(RC*24);
                  nread += RC*24;
                  if (Debug){
                     System.out.println("RTCPReceiver.run:RR read");
                  }                     
                  break;
            }
            
            // now we should have SDES 
            
            SC = (byte)(in.readByte() & 0x1f);
            PT = in.readByte();
            len = in.readShort();
            ssrc = in.readInt();
            nread += 8;
            if (PT == SDES){
               for (int i=0;i<SC;i++){
                  byte type = in.readByte();
                  nread += 1;
                  byte chunkLen = (byte)(in.readByte()*4-2);
                  nread += 1;
                  msgbuf = new byte[chunkLen];
                  in.readFully(msgbuf);
                  nread += chunkLen;
                  switch (type){
                     case 1:
                        CNAME = new String(msgbuf);
                        break;
                     case 2: 
                        NAME = new String(msgbuf);
                        break;
                     case 3:
                        EMAIL = new String(msgbuf);
                        break;
                     default:
                        System.out.println
                           ("RTCPReceiver:unrecognized chunk-->"+type);
                        break;
                  }
               } 
               if (Debug){
                  System.out.println("RTCPReceiver.run:SDES read. ssrc="+ssrc);
                  System.out.println("CNAME="+CNAME+",NAME="+NAME+",EMAIL="+EMAIL);
               }                     
               ParticipantInfo pi = new ParticipantInfo(ssrc,
                     CNAME, NAME, EMAIL);
               if (snInfo.addParticipant(pi)){
                  snInfo.addMembers(1);
                  partiList.append(CNAME);
                  partiList.append("\n");
               } 
               if (Debug){
                  System.out.println("RTCPReceiver.run: CNAME-->"+CNAME
                     +", NAME-->"+NAME+", EMAIL-->"+EMAIL);
               }
            }else{
               if (Debug){
                  System.out.println("RTCPReceiver.run: We expect SDES here.");
               }
            }
            
            // Now we should have BYE, if any 
            if (nread < dataLen){         // Still have data to read
               if (Debug){
                  System.out.println("RTCPReceiver.run:nread-->"+nread+",dataLen-->"+dataLen);
               }                                    
               SC = (byte)(in.readByte() & 0x1f);
               PT = in.readByte();
               len = in.readShort();
               ssrc = in.readInt();
               nread += 8;
            
               if (PT == BYE){      // BYE packet
                  ParticipantInfo pi = snInfo.getInfo(ssrc);
                  if (pi == null){
                     System.out.println("Trying to remove entries not exist! SSRC="+ssrc);
                  }
                  snInfo.removeParticipant(ssrc);
                  snInfo.addMembers(-1);
                  String lvmsg = "Just left: "+pi.CNAME + "\n";
                  if (Debug){
                     System.out.println("lvmsg="+lvmsg);
                  }
                  partiList.append(lvmsg);
                  //partiList.append("\n");
                  if (Debug){
                     System.out.println("RTCPReceiver.run:BYE read");
                  }                     
               }else{
                  if (Debug){
                     System.out.println("RTCPReceiver.run: We expect BYE here.");
                  }
               }
            }               
         }catch(IOException e){
            System.out.println("RTCPReceiver: read-->"+e);
         }
         rcvPkt.setLength(MAXMSGLEN);
         //rcvPkt.setLength(0);
      }
   }
   
     
}
