// TalkServer.java
//
// This program is created by modifying an example from the book 
// _Java in a Nutshell_ by David Flanagan. You may study, use, modify, 
// and distribute this example for any purpose. This program is 
// provided WITHOUT WARRANTY either expressed or implied.
//
// Clients can connect to this server program. Lines sent from
// each of the clients is sent to all clients so that they can
// "talk" with each other.
//
// (C) Henrik Björkman 1997
//
// History:
// 0.0 Created by Henrik Björkman 1997-05-02

import java.io.*;
import java.net.*;

public class TalkServer extends Thread 
{
  public final static int DEFAULT_PORT = 6789;
  protected int port;
  protected ServerSocket listen_socket;
  TalkConnection[] connection=new TalkConnection[32];    


  // Exit with an error message, when an exception occurs.
  public static void fail(Exception e, String msg) 
  {
    System.err.println(msg + ": " +  e);
    System.exit(1);
  }
    
  // Create a ServerSocket to listen for connections on;  start the thread.
  public TalkServer(int port) 
  {
    if (port == 0) port = DEFAULT_PORT;
    this.port = port;
    try { listen_socket = new ServerSocket(port); }
    catch (IOException e) { fail(e, "Exception creating server socket"); }
    System.out.println("TalkServer: listening on port " + port);
    this.start();
  }
    
  // The body of the server thread.  Loop forever, listening for and
  // accepting connections from clients.  For each connection, 
  // create a Connection object to handle communication through the
  // new Socket.
  public void run() 
  {
    try 
    {
      while(true) 
      {
        int i=0;
        Socket client_socket = listen_socket.accept();

        while(i<connection.length)
        {
          if (connection[i]==null) break;
          i++;
        }
        
        if (i<connection.length)
        {
          System.out.println("TalkServer: Connect "+i);
          connection[i] = new TalkConnection(this, client_socket);
        }
        else
        {
          disconnectSocket(client_socket,"Sorry to many connections.");
        }

      }
    }
    catch (IOException e) 
    { 
      fail(e, "TalkServer: Exception while listening for connections");
    }
  }

  public void disconnectSocket(Socket socket,String msg)
  {
    try 
    { 
      PrintStream out = new PrintStream(socket.getOutputStream());
      out.println(msg);
      socket.close();
    }
    catch (IOException e) 
    {
      System.err.println("TalkServer: " + e);
      return;
    }
  }

  public void sendToAll(String str)
  {
    int i;
    for (i=0;i<connection.length;i++)
    {
      if (connection[i]!=null) {connection[i].send(str);}
    }
  }

  public void byebye(TalkConnection connection)
  {
    int i;
    for (i=0;i<this.connection.length;i++)
    {
      if (this.connection[i]==connection) 
      {
        System.out.println("TalkServer: Disconnect "+i);
        this.connection[i]=null;
      }
    }
  }


  public static void printLocalHostName()
  {
    try 
    {
      InetAddress inet_address=InetAddress.getLocalHost();
      String local_name=inet_address.getHostName();
      System.out.println("TalkServer: local host name " + local_name);
    }
    catch (UnknownHostException e)
    { 
      fail(e, "local host: ");
    }
  }

    
  // Start the server up, listening on an optionally specified port
  public static void main(String[] args) 
  {
    int port = 0;
    if (args.length == 1) 
    {
      try { port = Integer.parseInt(args[0]);  }
      catch (NumberFormatException e) { port = 0; }
    }

    printLocalHostName();

    new TalkServer(port);
  }
}


// This class is the thread that handles all communication with a client
class TalkConnection extends Thread 
{
  protected Socket client;
  protected DataInputStream in;
  protected PrintStream out;
  protected TalkServer talk_server;

  // Initialize the streams and start the thread
  public TalkConnection(TalkServer talk_server, Socket client_socket) 
  {
    this.talk_server=talk_server;
    client = client_socket;
    try 
    { 
      in = new DataInputStream(client.getInputStream());
      out = new PrintStream(client.getOutputStream());
    }
    catch (IOException e) 
    {
      try { client.close(); } catch (IOException e2) { ; }
      System.err.println("Exception while getting socket streams: " + e);
      return;
    }
    this.start();
  }

  public void send(String str)
  {
    out.println(str);
  }

    
  // Provide the service.
  // Read a line, reverse it, send it back.  
  public void run() 
  {
    String line;
    StringBuffer revline;
    int len;
    try 
    {
      for(;;) 
      {
        // read in a line
        line = in.readLine();
        if (line == null) break;

        talk_server.sendToAll(line);
      }
    }
    catch (IOException e) { ; }
    finally 
    { 
      talk_server.byebye(this);
      try {client.close();} catch (IOException e2) {;} 
    }
  }
}

