import java.net.*;
import java.io.*;
import java.awt.*;

public class RTCPHandler extends Thread{
   InetAddress group;
   int         port;
   SenderCount sndCount;
   SessionInfo snInfo;
   TextArea    nameList;
   int         SSRC;                // own SSRC
   ParticipantInfo we;
   private MulticastSocket rtcpSendSock;   
   private byte [] buf;
   byte [] SRPacket;
   byte [] RRPacket;
   byte [] BYEPacket;
   RTCPReceiver rtcpReceiver;
   private static final boolean Debug=true;
   
 
   public RTCPHandler(InetAddress ia, int p, SessionInfo si,TextArea ta, 
         SenderCount sc, ParticipantInfo pi){
      group = ia;
      sndCount = sc;
      port = p;
      snInfo = si;
      nameList = ta;
      we = pi;
      
      if (Debug) {
         System.out.println("RTCPHandler: port-->"+port);
      }
      try{
         rtcpSendSock = new MulticastSocket(port);
      }catch(IOException e){
         System.out.println("RTCPHandler: create socket-->"+e);
         System.exit(-1);
      }
      RTCPPacket packets = new RTCPPacket(we);
      SRPacket = packets.getSRPacket();
      RRPacket = packets.getRRPacket();
      BYEPacket = packets.getBYEPacket();
      rtcpReceiver = new RTCPReceiver(group, port, snInfo, nameList);
      rtcpReceiver.start();
   }
   
   public  void run(){
      DatagramPacket packet;      
      try{      
         sleep(snInfo.rtcp_interval());
      }catch(Exception e){
         System.out.println("RTCPHandler: sleep interrupted-->"+e);
      }
      while (true){
         if (snInfo.we_sent()){
             packet = new DatagramPacket(SRPacket,SRPacket.length, group, port);
         }else{
             packet = new DatagramPacket(RRPacket,RRPacket.length, group, port);
         }
         snInfo.setWe_sent(false); 
         snInfo.resetSenders(); 
         try {
            rtcpSendSock.send(packet);
         }catch(IOException e){
            System.out.println("RTCPHandler.run: packet send-->"+e);
         }
         try{      
            sleep(snInfo.rtcp_interval());
         }catch(Exception e){
            System.out.println("RTCPHandler: sleep interrupted-->"+e);
         }
      }
   }
   
         
   public void leave(){
      try {
      DatagramPacket packet = new DatagramPacket(BYEPacket, 
               BYEPacket.length, group, port);
      rtcpSendSock.send(packet);
      }catch(IOException e){
         System.out.println("RTCPHandler: leave-->"+e);
      }
   }
        
}
   
class RTCPPacket {
   private ByteArrayOutputStream baos;
   private DataOutputStream dos;
   ParticipantInfo we;
   byte [] SRPacket;
   byte [] RRPacket;
   byte [] BYEPacket;
   static final byte SR=128-200;
   static final byte RR=128-201;
   static final byte SDES=128-202;
   static final byte BYE=128-203; 
   private static final boolean Debug=true;

   public RTCPPacket(ParticipantInfo pi){
      we = pi;
      int   i, sdesLen=0;
      
      baos = new ByteArrayOutputStream();
      dos = new DataOutputStream(baos);

      if (Debug){
         System.out.println("RTCPPacket:we.CNAME-->"+we.CNAME+", we.NAME-->"
               +we.NAME+",we.EMAIL-->"+we.EMAIL);
      }
      // create SR packet
      try{
         writeHeader(SR);
         // write SDES
         dos.writeByte(0x83);       // SC=3
         dos.writeByte(SDES);
         sdesLen = 1 + (we.CNAME.length()+5)/4 + (we.NAME.length()+5)/4
               +(we.EMAIL.length()+5)/4;
         dos.writeShort(sdesLen);      // len, will come back fix later
         dos.writeInt(we.SSRC);
         // now CNAME
         dos.writeByte(1);       // CNAME
         dos.writeByte((byte)((we.CNAME.length()+2+3)/4));  // length
         dos.writeBytes(we.CNAME);
         i = (we.CNAME.length()+2) % 4;
         if (Debug){
            System.out.println("RTCPPacket.SR/BYE:CNAME len-->"
               +we.CNAME.length()+", i-->"+i);
         } 
         if (i!=0){        
         // pad to 32 bit boundary
            do{
               dos.writeByte(0x00);
               i++;
            }while(i<4);
         }
         
         // NAME
         dos.writeByte(2);       // NAME
         dos.writeByte((byte)((we.NAME.length()+2+3)/4));  // length
         dos.writeBytes(we.NAME);
         i = (we.NAME.length()+2) % 4;
         if (Debug){
            System.out.println("RTCPPacket.SR/BYE:we.NAME len-->"
               +we.NAME.length()+", i-->"+i);
         } 
         if (i!=0){        
         // pad to 32 bit boundary
            do{
               dos.writeByte(0x00);
               i++;
            }while(i<4);
         }

         // EMAIL
         dos.writeByte(3);       // EMAIL
         dos.writeByte((byte)((we.EMAIL.length()+2+3)/4));  // length
         dos.writeBytes(we.EMAIL);
         i = (we.EMAIL.length()+2) % 4;
         if (Debug){
            System.out.println("RTCPPacket.SR/BYE:we.EMAIL len-->"
               +we.EMAIL.length()+", i-->"+i);
         } 
         if (i!=0){        
         // pad to 32 bit boundary
            do{
               dos.writeByte(0x00);
               i++;
            }while(i<4);
         }
                     
         SRPacket = baos.toByteArray();
         
         // BYE packet has a BYE part in addition to SR
         dos.writeByte(0x80);    // SC=0
         dos.writeByte(BYE);
         dos.writeShort(2);      // len, 2 32bits word
         dos.writeInt(we.SSRC);
         BYEPacket = baos.toByteArray();

         baos.reset();     // clean buffer for RR
         
         // now create RR packet
         writeHeader(RR);
         // write SDES
         dos.writeByte(0x83);    // SC=3
         dos.writeByte(SDES);
         dos.writeShort(sdesLen); 
         dos.writeInt(we.SSRC);
         // now CNAME
         dos.writeByte(1);       // CNAME
         dos.writeByte((byte)((we.CNAME.length()+2+3)/4));  // length
         dos.writeBytes(we.CNAME);
         i = (we.CNAME.length()+2) % 4;
         if (Debug){
            System.out.println("RTCPPacket.RR:CNAME len-->"
               +we.CNAME.length()+", i-->"+i);
         } 
         if (i!=0){        
         // pad to 32 bit boundary
            do{
               dos.writeByte(0x00);
               i++;
            }while(i<4);
         }
         
         // NAME
         dos.writeByte(2);       // NAME
         dos.writeByte((byte)((we.NAME.length()+2+3)/4));  // length
         dos.writeBytes(we.NAME);
         i = (we.NAME.length()+2) % 4;
         if (Debug){
            System.out.println("RTCPPacket.RR:we.NAME len-->"
               +we.NAME.length()+", i-->"+i);
         } 
         if (i!=0){        
         // pad to 32 bit boundary
            do{
               dos.writeByte(0x00);
               i++;
            }while(i<4);
         }

         // EMAIL
         dos.writeByte(3);       // EMAIL
         dos.writeByte((byte)((we.EMAIL.length()+2+3)/4));  // length
         dos.writeBytes(we.EMAIL);
         i = (we.EMAIL.length()+2) % 4;
         if (Debug){
            System.out.println("RTCPPacket.RR:we.EMAIL len-->"
               +we.EMAIL.length()+", i-->"+i);
         } 
         if (i!=0){        
         // pad to 32 bit boundary
            do{
               dos.writeByte(0x00);
               i++;
            }while(i<4);
         }
         RRPacket = baos.toByteArray();         
      }catch(IOException ie){
         System.out.println("RTCPPacket: I/O error-->"+ie);
      }
      try {
         baos.close();
         dos.close();
      }catch(IOException e){
         System.out.println("RTCPPacket: stream close-->"+e);
      }
   }

   void writeHeader(byte PT){
      byte b;
      b = (byte)(1<<7);       // V=2, P=0, RC=0
      try {
      dos.writeByte(b);
      dos.writeByte(PT);   // Payload type
      if (PT == SR) dos.writeShort(6);   // len=6 for SR RC=0
      else dos.writeShort(1);             // len = 1 for RR
      dos.writeInt(we.SSRC);     // Sender SSRC
      if (PT == SR){          // these only present in SR
         dos.writeInt(0);     // NTP, not used
         dos.writeInt(0);     // NTP
         dos.writeInt(0);     // RTP timestamp, not used
         dos.writeInt(0);
         dos.writeInt(0);
      }
      }catch(IOException e){
         System.out.println("RTCPPacket.writeHeader error:"+e);
      }
   }
  
   public byte [] getSRPacket(){
      return SRPacket;
   }
   
   public byte [] getRRPacket(){
      return RRPacket;
   }
   
   public byte [] getBYEPacket(){
      return BYEPacket;
   }
}
      
         
