import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.util.*;

public class Wb implements WindowListener, ActionListener{
   static Frame mainFrm;
   static InetAddress sessionAddr;
   static String   localName;
   static String   localEmail;
   static int      port;
   static boolean Debug=true;
   static TextArea ta_names, ta_output;
   static TextField tf_input;
   static int SSRC;
   static short sendSeqNum;
   RTPSender   rtpSender;
   ParticipantInfo we;
   static RTCPHandler   rtcpHandler;
   static RTPReceiver rtpReceiver;
   static SessionInfo sessionList;
   static SenderCount senderCnt;
   private static boolean left=true;
      
   public Wb() {
      mainFrm = new Frame();
      mainFrm.addWindowListener(this);
      getSessionParm();
      left=false;
      mainFrm.setTitle("Java Whiteboard: "+localName);
      SSRC = new Random().nextInt();
      sessionList = new SessionInfo();
      sendSeqNum = (short) (new Random().nextLong()%Short.MAX_VALUE);
      //senderCnt = new SenderCount();
      rtpSender = new RTPSender(SSRC, sendSeqNum, sessionAddr, 
            port, sessionList, localName); 
   }
      
   public static void main(String [] argv){
      String CNAME = null;
      
      Wb myWb = new Wb();
      myWb.mainFrm.setSize(new Dimension(580,450));
      Font menuFont = new Font("Helvetica", Font.PLAIN, 14);
      
      // Create and add menu items to the main frame
      // File menu -- Start/Join Session
      //              Drop Session
      //              Exit
      MenuBar mBar = new MenuBar();
      Menu fileMenu = new Menu("File");
      
      // Create menu items
      MenuItem miDrop = new MenuItem("Leave Session");
      miDrop.setFont(menuFont);
      miDrop.setActionCommand("drop");
      //miDrop.disable();
      miDrop.addActionListener(myWb);
      
      MenuItem miExit = new MenuItem("Exit");
      miExit.setFont(menuFont);
      miExit.setActionCommand("exit");
      miExit.addActionListener(myWb);
      
      // Add menu items to the menu 
      fileMenu.add(miDrop);
      fileMenu.addSeparator();
      fileMenu.add(miExit);
      
      // Add menu to the menu bar
      fileMenu.setFont(menuFont);
      mBar.add(fileMenu);
      
      // Add menu bar to the main frame
      myWb.mainFrm.setMenuBar(mBar);
      
      // Add components to the main frame
      GridBagLayout gbLayout = new GridBagLayout();
      GridBagConstraints gbConstraints = new GridBagConstraints();
      myWb.mainFrm.setLayout(gbLayout);
      
      gbConstraints.insets=new Insets(5,5,5,5);
                        
      gbConstraints.weightx = 1000;
      gbConstraints.weighty = 1000;
      gbConstraints.fill = GridBagConstraints.BOTH;
      
      // TextArea for the output of messages received from network
      ta_output = new TextArea(20, 60);
      ta_output.setEditable(false);
      addComponent(myWb.mainFrm, ta_output, gbLayout, gbConstraints,
                  1,0,5,1);
      
      // TextArea for session participant            
      ta_names = new TextArea(20,20);
      ta_names.setEditable(false);
      addComponent(myWb.mainFrm, ta_names, gbLayout, gbConstraints, 
                  1, 5, 1, 1);

      // Text field for user input
      gbConstraints.weightx = 1000;
      gbConstraints.weighty = 1;
      Label lbl_input = new Label("Enter text here:");
      addComponent(myWb.mainFrm, lbl_input, gbLayout, gbConstraints,
                  2,0,1,1);
                  
      gbConstraints.weightx = 1;
      tf_input = new TextField(70);
      tf_input.addKeyListener(myWb.rtpSender);
      addComponent(myWb.mainFrm, tf_input, gbLayout, gbConstraints,
                  2,1,4,1);
      
      // Create a receiver and run it in a different thread 
      rtpReceiver = new RTPReceiver(myWb.sessionAddr,
            myWb.port, myWb.ta_output);
      rtpReceiver.start();
      
      try{
         CNAME = localName+"@"+(InetAddress.getLocalHost().getHostName());
      }catch(Exception e){
         System.out.println("Wb.main: Unknown host-->"+e);
      }
      myWb.we = new ParticipantInfo(myWb.SSRC, CNAME, myWb.localName, myWb.localEmail);
      rtcpHandler = new RTCPHandler(myWb.sessionAddr, myWb.port+1,
            sessionList, ta_names,senderCnt, myWb.we);
      rtcpHandler.start();
   
      // Show the main frame 
      myWb.mainFrm.pack();           
      myWb.mainFrm.show();
   }//Wb.main

   
   // Put up a dialog for user to fill in session parameters:
   //    -- User's name
   //    -- User's Emain address
   //    -- Session multicast address
   //    -- Session port number
   void getSessionParm(){
   
      Dialog parmDlg = new Dialog(mainFrm, "Start/Join Session");

      Label lbl_lname = new Label("Your Name:");
      TextField tf_lname = new TextField(20);
      Label lbl_lemail = new Label("Your E-Mail address:");
      TextField tf_lemail = new TextField(30);
      Label lbl_rname = new Label("Remote Name or Address:");
      TextField tf_raddr = new TextField(30);
      Label lbl_rport = new Label("Remote Port Number:");
      TextField tf_rport = new TextField(6);
      
      // OK button is clicked when user finishes
      Button btn_ok = new Button("  OK  ");
      // OKListener handles user click on OK button
      class OkListener implements ActionListener {
         boolean finished = false;
         public void actionPerformed(ActionEvent ae){
            TextComponent c;
            Dialog dlg;
            GridBagLayout gl=new GridBagLayout();
            GridBagConstraints gc = new GridBagConstraints();
            Dialog pDlg = (Dialog)((Button)ae.getSource()).getParent();
            
            finished = true;
              
            c = (TextComponent)pDlg.getComponent(1);  //local name
            localName = c.getText();
            c = (TextComponent)pDlg.getComponent(3);  //local email
            localEmail = c.getText();
            c = (TextComponent)pDlg.getComponent(5);  //remote addr
            String sAddr = c.getText();
            c = (TextComponent)pDlg.getComponent(7);  //port
            String sPort = c.getText();
             
            Button b_ok = new Button("  OK  ");
            b_ok.addActionListener(new ActionListener(){
               public void actionPerformed(ActionEvent ae){
                  if (Debug)
                     System.out.println("Debug: OK clicked in session dlg.");
                  ((Dialog)((Button)ae.getSource()).getParent()).dispose();
               }
            });

            
            if (localName.length() == 0 || localEmail.length() == 0 ||
               sAddr.length() == 0 || sPort.length() == 0){
               // if any field is not filled in, we are not finished
               finished = false;
               if (Debug)
                  System.out.println("Debug: Some field is not filled in.");
               // ask the user to try again, use a dialog to do this
               dlg = new Dialog(mainFrm, "Stop");
               dlg.setLayout(gl);
               gc.anchor = GridBagConstraints.CENTER;
               gc.weightx = gc.weighty = 1;
               gc.insets = new Insets(10,10,10,10);
               addComponent(dlg, new Label("Please fill in all fields!"),
                  gl,gc, 0,0,3,1); 
               addComponent(dlg, b_ok, gl, gc, 1,1,1,1);
               dlg.setModal(true);
               dlg.pack();
               dlg.show();
               return;
            }
            try{
            if (Integer.parseInt(sPort)<0||Integer.parseInt(sPort)>65536){
               // if the port number is not valid, we are not finished
               finished = false;
               // Ask the user to try again, use a dialog to do this
               dlg = new Dialog(mainFrm, "Stop");
               dlg.setLayout(gl);
               gc.anchor = GridBagConstraints.CENTER;
               gc.weightx = gc.weighty = 1;
               gc.insets = new Insets(10,10,10,10);
               addComponent(dlg, new Label("Invalid Port Number!"),
                  gl,gc, 0,0,3,1); 
               addComponent(dlg, b_ok, gl, gc, 1,1,1,1);
               dlg.setModal(true);
               dlg.pack();
               dlg.show();
               return;
            }
            }catch(NumberFormatException e){
               // User does not give a number in "Port" field
               finished = false;
               dlg = new Dialog(mainFrm, "Stop");
               dlg.setLayout(gl);
               gc.anchor = GridBagConstraints.CENTER;
               gc.weightx = gc.weighty = 1;
               gc.insets = new Insets(10,10,10,10);
               addComponent(dlg, new Label("Invalid Port Number!"),
                  gl,gc, 0,0,3,1); 
               addComponent(dlg, b_ok, gl, gc, 1,1,1,1);
               dlg.setModal(true);
               dlg.pack();
               dlg.show();
               return;
            }
            
            port = Integer.parseInt(sPort);
            
            try {
               sessionAddr = InetAddress.getByName(sAddr);
            }catch(UnknownHostException e){
               // User gives an invalid IP address
               finished = false;
               dlg = new Dialog(mainFrm, "Stop");
               dlg.setLayout(gl);
               gc.anchor = GridBagConstraints.CENTER;
               gc.weightx = gc.weighty = 1;
               gc.insets = new Insets(10,10,10,10);
               addComponent(dlg, new Label("Invalid remote IP address!"),
                  gl,gc, 0,0,3,1); 
               addComponent(dlg, b_ok, gl, gc, 1,1,1,1);
               dlg.setModal(true);
               dlg.pack();
               dlg.show();
               return;
            }
         if (!(sessionAddr.isMulticastAddress())){
               // The IP address user gives is not a multicast address   
               finished = false;
               dlg = new Dialog(mainFrm, "Stop");
               dlg.setLayout(gl);
               gc.anchor = GridBagConstraints.CENTER;
               gc.weightx = gc.weighty = 1;
               gc.insets = new Insets(10,10,10,10);
               addComponent(dlg, new Label("Please use multicast address!"),
                  gl,gc, 0,0,3,1); 
               addComponent(dlg, b_ok, gl, gc, 1,1,1,1);
               dlg.setModal(true);
               dlg.pack();
               dlg.show();
         }
         if (finished) pDlg.dispose();
         return;
         }
      }//class OKListener
      ActionListener okl = new OkListener();
      btn_ok.addActionListener(okl);
      
      Button btn_cancel = new Button("Cancel");
      class CancelListener implements ActionListener {
         public void actionPerformed(ActionEvent ae){
            //dispose the dialog
            ((Dialog)((Button)ae.getSource()).getParent()).dispose();  
            System.exit(-1);
         }
      }// class CancelListener
      ActionListener cl = new CancelListener();
      btn_cancel.addActionListener(cl);
      
      
      GridBagLayout gbl = new GridBagLayout();
      GridBagConstraints gbc = new GridBagConstraints();
      parmDlg.setLayout(gbl);
      gbc.weightx=1;
      gbc.weighty=1;
      gbc.insets = new Insets(5,5,5,5);
      gbc.anchor = GridBagConstraints.WEST;
      
      addComponent(parmDlg, lbl_lname, gbl,gbc,0,0,1,1);  //Component 0
      addComponent(parmDlg, tf_lname,  gbl,gbc,0,1,3,1);  //Component 1
      addComponent(parmDlg, lbl_lemail,gbl,gbc,1,0,1,1);  //Component 2
      addComponent(parmDlg, tf_lemail, gbl,gbc,1,1,3,1);  //Component 3
      addComponent(parmDlg, lbl_rname, gbl,gbc,2,0,1,1);  //Component 4
      addComponent(parmDlg, tf_raddr,  gbl,gbc,2,1,3,1);  //Component 5
      addComponent(parmDlg, lbl_rport, gbl,gbc,3,0,1,1);  //Component 6
      addComponent(parmDlg, tf_rport,  gbl,gbc,3,1,3,1);  //Component 7
      addComponent(parmDlg, btn_ok,    gbl,gbc,4,1,1,1);  //Component 8
      addComponent(parmDlg, btn_cancel,gbl,gbc,4,2,1,1);  //Component 9
      parmDlg.setResizable(false);
      parmDlg.setModal(true);
      parmDlg.pack();
      parmDlg.show();

   }//getSessionParm()      
   
   // A utility method, add component to a container with GridBagLayout
   private static void addComponent(Container ct, Component cp, GridBagLayout g,
                           GridBagConstraints gc, int row, int column,
                           int width, int height)
   {
      gc.gridx = column;
      gc.gridy = row;
      gc.gridwidth = width;
      gc.gridheight = height;
      
      g.setConstraints(cp, gc);
      ct.add(cp);
   }
      
   // Handles window closing event
   public void windowClosing(WindowEvent we){
      mainFrm.dispose();
      System.exit(0);
   }
   
   // Handles menu selection event
   public void actionPerformed(ActionEvent ae){
      String cmd = ae.getActionCommand();
               
      if (cmd.equals("drop") && !left){
         left=true;
         rtpReceiver.leave();
         rtpReceiver.stop();
         rtcpHandler.leave();
         rtcpHandler.stop();
      }else if (cmd.equals("exit")){
         rtpReceiver.leave();
         rtpReceiver.stop();
         rtcpHandler.leave();
         rtcpHandler.stop();
         mainFrm.dispose();
         System.exit(0);
      }
   }//Wb.actionPerformed()
      
   public void windowActivated(WindowEvent we){}
   public void windowClosed(WindowEvent we){}
   public void windowDeactivated(WindowEvent we){}
   public void windowIconified(WindowEvent we){}
   public void windowDeiconified(WindowEvent we){}
   public void windowOpened(WindowEvent we){}
   
}//class Wb
     
      
