import java.net.*;
import java.io.*;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;

class OnlineHandler extends Object implements Runnable {
   HostIP_Frame host;
   int port, hostport;
   String msg, name;
   Socket cli = null;
   BufferedReader in = null;
   ServerSocket socket = null;
   Thread runner;

   public OnlineHandler (int port, int hostport, HostIP_Frame host) {
      this.host = host;  
      this.port = port;
      this.hostport = hostport;
      runner = new Thread(this);
   }

   public void start () { runner.start(); }
   
   public void destroy () { runner.stop();  }

   public void run () {
      try {
	 socket = new ServerSocket(port);
	 host.messages.setText("Waiting for connection...");
	 while (true) {
	    host.messages.setText("");
	    cli = socket.accept();
	    String ip = cli.getInetAddress().toString();
	    in = 
	       new BufferedReader(new InputStreamReader(cli.getInputStream()));
	    try {
	       name = in.readLine();
	       msg = in.readLine();
	       if (!name.equals("") && !msg.equals("")) {
		  host.text.append(name+"> "+msg+"\n");
		  host.playit("sound/imrcv.au");
	       } else if (!msg.equals("")) {
		  host.updateBuddyListPartially();
		  System.out.println("Buddy list updated");
	       }
	    } catch (Exception e) {
	       host.messages.setText("Connection closed");
	       host.playit("sound/crash.au");
	    }
	    in.close();
	    cli.close();
	 }
      }
      catch (Exception e) { 
	 host.messages.setText("Handler:run:"+e.toString());
	 host.playit ("sound/crash.au");
      }
   }
}


class HostIP_Frame extends Frame implements ActionListener {
   JComboBox buddy, server;
   JRadioButton online, offline;
   ButtonGroup on_off_line;
   Button send, roster, rostea, leave;
   JTextArea texa, text;
   JTextField handle, messages, tosend;
   OnlineHandler handler;
   Socket cli;
   String current = null;
   URL url;

   public HostIP_Frame() {
      setLayout (new BorderLayout());
      Panel q = new Panel();
      q.setLayout(new BorderLayout());
      q.add("Center", tosend = new JTextField());
      tosend.setFont(new Font("Times New Roman", Font.PLAIN, 12));
      q.add("East", send = new Button("Send"));
      Panel p = new Panel();
      p.setLayout(new GridLayout(2,1,10,10));
      p.add(q);
      q = new Panel();
      q.setLayout(new GridLayout(1,4));
      q.add(new Label(""));
      q.add(online = new JRadioButton("Online", false));
      q.add(offline = new JRadioButton("Offline", true));
      q.add(leave = new Button("Exit"));
      p.add(q);
      add("South", p);
      q = new Panel();
      q.setLayout(new GridLayout(2,1));
      q.add(new JScrollPane(text = new JTextArea()));
      text.setFont(new Font("Times New Roman", Font.PLAIN, 12));
      q.add(new JScrollPane(texa = new JTextArea()));      
      texa.setFont(new Font("Times New Roman", Font.PLAIN, 12));
      add("Center", q);
      q = new Panel();
      q.setLayout(new BorderLayout());
      p = new Panel();
      p.setLayout(new GridLayout(4,1));
      p.add(server = new JComboBox());
      server.addItem("gauss.ececs.uc.edu");
      server.addItem("localhost");
      server.addItem("helios.ececs.uc.edu");
      server.addItem("boole.ececs.uc.edu");
      p.add(handle = new JTextField());
      handle.setFont(new Font("Times New Roman", Font.PLAIN, 12));
      p.add(buddy = new JComboBox());
      p.add(messages = new JTextField());
      messages.setFont(new Font("Times New Roman", Font.PLAIN, 12));
      q.add("Center", p);
      p = new Panel();
      p.setLayout(new GridLayout(4,2));
      p.add(new Label("Server"));
      p.add(new Label(""));
      p.add(new Label("Handle"));
      p.add(new Label(""));
      p.add(roster = new Button("Buddies"));
      p.add(rostea = new Button("Buddies"));
      p.add(new Label("Messages"));
      p.add(new Label(""));
      q.add("East", p);
      add("North", q);
      tosend.addActionListener(this);
      send.addActionListener(this);
      roster.addActionListener(this);
      rostea.addActionListener(this);
      online.addActionListener(this);
      offline.addActionListener(this);
      leave.addActionListener(this);
      on_off_line = new ButtonGroup();
      on_off_line.add(online);
      on_off_line.add(offline);
      handler = null;
      //url = getCodeBase();
   }

   public void playit (String soundclip) {  
      //try { play (new URL(url+soundclip)); } 
      //catch (Exception e) { System.out.println("playit:"+e.toString()); }
   }

   void goOnline () {
      String msg;
      if (handle.getText() == null) {
	 playit("sound/crash.au");
	 return;
      }
      if (handler != null) {
	 online.setSelected(false);
	 offline.setSelected(true);
	 return;
      }
      playit ("sound/dooropen.au");
      try {
	 cli = new Socket((String)server.getSelectedItem(), 8081);
	 DataOutputStream out = new DataOutputStream(cli.getOutputStream());
	 BufferedReader in = 
	    new BufferedReader(new InputStreamReader(cli.getInputStream()));
	 int port = (int)(Math.random()*1000+8100);
	 current = handle.getText();
	 out.writeBytes(current+" "+String.valueOf(port)+"\n");
	 messages.setText(msg = in.readLine());
	 System.out.println("Handler:port="+port+" hostport="+msg+"|");
	 out.close();
	 in.close();
	 cli.close();
	 cli = null;
	 StringTokenizer t = new StringTokenizer(msg, " ");
	 t.nextToken();
	 int ipaddress = Integer.parseInt(t.nextToken());
	 handler = new OnlineHandler(port, ipaddress, this);
	 handler.start();
      } catch (Exception e) {
	 messages.setText("actionPerformed:online:"+e.toString());
	 online.setSelected(false);
	 offline.setSelected(true);
	 playit ("sound/crash.au");
	 return;
      }
   }

   void goOffline () {
      if (handler == null) return;
      handler.destroy();
      handler = null;
      playit ("sound/doorslam.au");
      try {
	 cli = new Socket((String)server.getSelectedItem(), 8083);
	 DataOutputStream out = new DataOutputStream(cli.getOutputStream());
	 BufferedReader in = 
	    new BufferedReader(new InputStreamReader(cli.getInputStream()));
	 out.writeBytes(current+"\n");
	 messages.setText(in.readLine());
	 out.close();
	 in.close();
	 cli.close();
	 cli = null;
      } catch (Exception e) {
	 messages.setText("actionPerformed:offline:"+e.toString());
	 playit ("sound/crash.au");
	 return;
      }
   }

   void updateBuddyListFully () {
      playit ("sound/ring.au");
      try {
	 cli = new Socket((String)server.getSelectedItem(), 8082);
	 BufferedReader in = 
	    new BufferedReader(new InputStreamReader(cli.getInputStream()));
	 DataOutputStream out = new DataOutputStream(cli.getOutputStream());
	 out.writeBytes("get\n");
	 text.append("\n\nActive Buddies on "+
		     (String)server.getSelectedItem()+"\n");
	 text.append("---------------------------------------------\n");
	 String input = in.readLine();
	 String dup = input;
	 text.append(input.replace('|','\n'));
	 text.append("---------------------------------------------\n");
	 StringTokenizer t = new StringTokenizer(dup,"|");
	 String old_item = (String)buddy.getSelectedItem();
	 
	 boolean default_is_alive = false;
	 while (t.hasMoreTokens()) {
	    StringTokenizer g = new StringTokenizer(t.nextToken()," ");
	    String str = g.nextToken();
	    if (str.equals(old_item)) {
	       default_is_alive = true;
	       break;
	    }
	 }
	 
	 t = new StringTokenizer(dup,"|");
	 buddy.removeAllItems();
	 
	 if (old_item != null && !old_item.equals("") && default_is_alive) 
	    buddy.addItem(old_item);
	 
	 while (t.hasMoreTokens()) {
	    StringTokenizer g = new StringTokenizer(t.nextToken()," ");
	    String str = g.nextToken();
	    if (old_item != null && !old_item.equals("") &&
		old_item.equals(str)) continue;
	    buddy.addItem(str);
	 }
	 in.close();
	 cli.close();
	 cli = null;
      } catch (Exception e) { 
	 messages.setText("actionPerformed:roster:"+e.toString());
	 playit ("sound/crash.au");
      }
   }

   void updateBuddyListPartially () {
      playit ("sound/ring.au");
      try {
	 cli = new Socket((String)server.getSelectedItem(), 8082);
	 BufferedReader in = 
	    new BufferedReader(new InputStreamReader(cli.getInputStream()));
	 DataOutputStream out = new DataOutputStream(cli.getOutputStream());
	 out.writeBytes("get\n");
	 String input = in.readLine();
	 String dup = input;
	 StringTokenizer t = new StringTokenizer(dup,"|");
	 String old_item = (String)buddy.getSelectedItem();
	 
	 boolean default_is_alive = false;
	 while (t.hasMoreTokens()) {
	    StringTokenizer g = new StringTokenizer(t.nextToken()," ");
	    String str = g.nextToken();
	    if (str.equals(old_item)) {
	       default_is_alive = true;
	       break;
	    }
	 }
	 
	 t = new StringTokenizer(dup,"|");
	 buddy.removeAllItems();
	 
	 if (old_item != null && !old_item.equals("") && default_is_alive) 
	    buddy.addItem(old_item);
	 
	 while (t.hasMoreTokens()) {
	    StringTokenizer g = new StringTokenizer(t.nextToken()," ");
	    String str = g.nextToken();
	    if (old_item != null && !old_item.equals("") &&
		old_item.equals(str)) continue;
	    buddy.addItem(str);
	 }
	 in.close();
	 cli.close();
	 cli = null;
      } catch (Exception e) { 
	 messages.setText("actionPerformed:roster:"+e.toString());
	 playit ("sound/crash.au");
      }
   }

   void sendit () {
      try {
	 cli = new Socket((String)server.getSelectedItem(), 8080);
	 BufferedReader in = 
	    new BufferedReader(new InputStreamReader(cli.getInputStream()));
	 DataOutputStream out = new DataOutputStream(cli.getOutputStream());
	 String header = current+" "+buddy.getSelectedItem();
	 out.writeBytes(header+"\n");
	 out.writeBytes(tosend.getText()+"\n");
	 if (!in.readLine().equals("ok")) {
	    messages.setText(buddy.getSelectedItem()+" is not online");
	    playit ("sound/crash.au");
	 } else {
	    texa.append(tosend.getText()+"\n");
	    playit ("sound/imsend.au");
	    messages.setText("");
	 }
	 tosend.setText("");
	 in.close();
	 out.close();
	 cli.close();
      } catch (NullPointerException f) {
	 messages.setText(buddy.getSelectedItem()+" is not on line");
	 playit ("sound/crash.au");
      } catch (Exception e) { 
	 messages.setText("actionPerformed:send:"+e.toString());
	 playit ("sound/crash.au");
      }
   }
   
   public void actionPerformed (ActionEvent evt) {
      if (evt.getSource() == online) goOnline();
      else if (evt.getSource() == offline) goOffline();
      else if (evt.getSource() == rostea) updateBuddyListFully();
      else if (evt.getSource() == roster) updateBuddyListPartially();
      else if (evt.getSource() == send || evt.getSource() == tosend) sendit();
      else if (evt.getSource() == leave) { goOffline(); System.exit(0); }
   }
}   

public class HostIP_App {
   public static void main (String arg[]) {
      HostIP_Frame host = new HostIP_Frame();
      host.setSize(400,600);
      host.show();
   }
}