// This example is from the book _Java in a Nutshell_ by David Flanagan.
// Written by David Flanagan.  Copyright (c) 1996 O'Reilly & Associates.
// You may study, use, modify, and distribute this example for any purpose.
// This example is provided WITHOUT WARRANTY either expressed or implied.
// Modified by tsaiwn@csie.nctu.edu.tw with BufferedReader to read data
// .. plus, handling EOF / disconnection request

import java.io.*;
import java.net.*;
public class Server extends Thread {
    public final static int DEFAULT_PORT = 6789;
    protected int port;
    protected ServerSocket listen_socket;
    
    // 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 Server(int port) {  // constructor
        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("Server: listening on port " + port);
        this.start();
    } // Server constructor
    
    // 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) {  // accept( ) will wait someone to connect me
                Socket client_socket = listen_socket.accept();
                Connection c = new Connection(client_socket);  // thread
            } // while(true); Loop forever to serve clients
        }
        catch (IOException e) { 
            fail(e, "Exception while listening for connections");
        }
    } // run
    
    // 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; }
        }
        new Server(port);
    } // main
} // class Server ends here

// This class is the thread that handles all communication with a client
class Connection extends Thread {
    protected Socket client;
    protected DataInputStream dis;
    protected InputStreamReader isr;
    protected BufferedReader in;
    protected PrintStream out;
    protected InetAddress who;   // Client IP_address
    protected String name;   // Client Host_Name
    
    // Initialize the streams and start the thread
    public Connection(Socket client_socket) {   // constructor
        client = client_socket;
        who = client.getInetAddress( );  // by tsaiwn
        name = " " + who.getHostName( );
        java.util.Date now = new java.util.Date( );
        System.err.println(""+who+name+" entered at " + now);  // by tsaiwn
        try { 
            dis = new DataInputStream(client.getInputStream());
            isr = new InputStreamReader(dis);
            in  = new BufferedReader(isr);   // by tsaiwn@csie.nctu.edu.tw
            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();
    } // Connection constructor
        
    // Provide the service.
    // Read a line, reverse it, send it back.
    public void run() {
        String line;
        StringBuffer revline;
        int len;
        try {
            for(;;) {  // loop forever
                // read in a line
                try {
                   line = in.readLine();
                } catch (EOFException e) { line = null; }
                if (line == null) break;
                System.err.println(""+line.length()+" "+line); // tsaiwn
                // reverse it
                len = line.length();
      if(len==1) if( (int)(line.charAt(0)) == 3 )  break;  // CTRL_C
      if(len==1) if( (int)(line.charAt(0)) == 26 )  break;  // CTRL_Z
                revline = new StringBuffer(len);
                for(int i = len-1; i >= 0; i--) 
                    revline.insert(len-1-i, line.charAt(i));
                // and write out the reversed line
                out.println(revline);
            }
        } catch (IOException e) { ; }
        finally { try {client.close();} catch (IOException e2) {;}
           java.util.Date now = new java.util.Date( );
           System.err.println(""+who+name+" leaving at " + now);
        }
    } // run
} // class Connection

