/*
 * Java Network Programming
 * Copyright (C) 2000 by Jeffrey E. Care (carej@ieee.org)
 *                       David Hollinger (hollingd@cs.rpi.edu)
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option) any
 * later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to
 *
 *     Free Software Foundation, Inc.
 *     59 Temple Place, Suite 330
 *     Boston, MA 02111-1307
 *     USA
 */
//package edu.rpi.cs.netprog.tcp;

import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;

public final class TCPEchoServer {

  //----------------------------------------------------------------------------
  // Private Constants
  //----------------------------------------------------------------------------

  // the default port for the TCP echo service
  //
  private static final int defaultPort = 7;

  //----------------------------------------------------------------------------
  // Public Constructors
  //----------------------------------------------------------------------------

  public TCPEchoServer (int port) {

    // allocate a TCP server socket to listen for connections
    //
    ServerSocket server = null;

    // create a new server socket; if there are any problems with the creation
    // we can simply exit after printing diagnostic info
    //
    try {

      server = new ServerSocket (port);
      log ("Server started on port " + port);
    }
    catch (IOException exp) {

      log ("Error opening server socket: " + exp.getMessage ());
      exp.printStackTrace ();

      System.exit (0);
    }

    // wait for connections; once a new connection comes in accept it and
    // spawn a new thread to handle it
    //
    while (true) {

      try {

        new EchoConnection (server.accept ());
      }
      catch (IOException exp) {

        log ("Error waiting for connection.");
      }
    }
  }

  //----------------------------------------------------------------------------
  // Private Class Methods
  //----------------------------------------------------------------------------

  private static final void log (String message) {

    System.err.println (message);
  }

  //----------------------------------------------------------------------------
  // Main
  //----------------------------------------------------------------------------

  public static void main (String[] argv) {

    int port = defaultPort;

    // check if a port was supplied on the command line
    //
    int argc = argv.length;
    if (argc > 0) {

      try {

        port = Integer.parseInt (argv[0]);
      }
      catch (Exception exp) {

        log ("Error parsing command line, defaulting to port " + defaultPort);
        port = defaultPort;
      }
    }

    new TCPEchoServer (port);
  }

  //----------------------------------------------------------------------------
  // Private Helper Classes
  //----------------------------------------------------------------------------

  // handle echo-request connections - this is an auto-starting thread
  //
  private class EchoConnection extends Thread {

    //--------------------------------------------------------------------------
    // Private Data Members
    //--------------------------------------------------------------------------

    private Socket sock;   // client this connection is talking to
    private Reader reader; // character stream from the client
    private Writer writer; // character stream to the client

    //--------------------------------------------------------------------------
    // Public Constructor
    //--------------------------------------------------------------------------

    public EchoConnection (Socket client) {

      // try to create character streams, if there are any problems just never
      // start this thread
      //
      try {

        sock = client;
        log ("request received");

        reader = new InputStreamReader  (sock.getInputStream ());
        writer = new OutputStreamWriter (sock.getOutputStream ());

        start ();
      }
      catch (IOException exp) {

        log ("Error creating read/write streams: " + exp.getMessage ());
        exp.printStackTrace ();

        return;
      }
    }

    //--------------------------------------------------------------------------
    // Public Overridden Thread Methods
    //--------------------------------------------------------------------------

    public void run () {

      final int max = 100;
      char[] data;
      int read;

      while (true) {

        try {

          data = new char[max];
          read = reader.read (data, 0, max);

          if (read == -1) return;
          if (read > 0) {

            log (new String (data, 0, read - 2));
            writer.write (data, 0, read);
            writer.flush ();
          }
        }
        catch (IOException exp) {

          log ("closed by peer");
          return;
        }
      }
    }

    //--------------------------------------------------------------------------
    // Public Methods
    //--------------------------------------------------------------------------

    public void log (String message) {

      System.err.print   ("<" + sock.getInetAddress ().getHostName () + ">: ");
      System.err.println (message);
    }

    public void log (char[] message) {

      System.err.print   ("<" + sock.getInetAddress ().getHostName () + ">: ");
      System.err.println (message);
    }

    public void log (Throwable t) {

      System.err.print   ("<" + sock.getInetAddress ().getHostName () + ">: ");
      System.err.println (t.getMessage ());
      t.printStackTrace  ();
    }
  }
}

