import java.net.*;
import java.io.*;
import java.util.StringTokenizer;

// A pure 1.1 variation of a class that appears in
// Core Web Programming from Prentice Hall Publishers.
// May be freely used or adapted.
// 1998 Marty Hall, http://www.apl.jhu.edu/~hall/java/.


//----------------------------------------------------
/** A simple HTTP server that generates a Web page
 *  showing all of the data that it received from
 *  the Web client (usually a browser). To use this,
 *  start it on the system of your choice, supplying
 *  a port number if you want something other than
 *  port 5555. Call this system server.com. Next,
 *  start a Web browser on the same or a different
 *  system, and connect to
 *  http://server.com:5555/whatever. The resultant
 *  Web page will show the data that your browser
 *  sent. For CGI programming, specify
 *  http://server.com:5555/whatever as the
 *  ACTION of your CGI form. You can send GET
 *  or POST data; either way the resultant page
 *  will show what your browser sent.
 */

public class EchoServer extends NetworkServer {
  protected int maxInputLines = 25;
  protected String serverName = "EchoServer 1.0";

  //----------------------------------------------------
  /** Supply a port number as a command-line
   *  argument. Otherwise port 5555 will be used.
   */
  
  public static void main(String[] args) {
    int port = 5555;
    if (args.length > 0)
      port = Integer.parseInt(args[0]);
    EchoServer echoServer = new EchoServer(port, 0);
    echoServer.listen();
  }

  public EchoServer(int port, int maxConnections) {
    super(port, maxConnections);
  }

  //----------------------------------------------------
  /** Overrides the NetworkServer handleConnection
   *  to read each line of data received, save it
   *  into an array of strings, then send it
   *  back embedded inside a PRE element in an
   *  HTML page.
   */
  
  public void handleConnection(Socket server)
      throws IOException{
    System.out.println
        (serverName + ": got connection from " +
         server.getInetAddress().getHostName());
    BufferedReader in =
      SocketUtil.getBufferedReader(server);
    PrintWriter out =
      SocketUtil.getPrintWriter(server);
    String[] inputLines = new String[maxInputLines];
    int i;
    for (i=0; i<maxInputLines; i++) {
      inputLines[i] = in.readLine();
      if (inputLines[i] == null)
        break;
      if (inputLines[i].length() == 0) {
        if (usingPost(inputLines)) {
          readPostData(inputLines, i, in);
          i = i + 2;
        }
        break;
      }
    }
    printHeader(out);
    for (int j=0; j<i; j++)
      out.println(inputLines[j]);
    printTrailer(out);
    server.close();
  }

  //----------------------------------------------------
  // Print top of a "standard" Web page.
  
  private void printHeader(PrintWriter out) {
    out.println
      ("HTTP/1.0 200 Document follows\r\n" +
       "Server: " + serverName + "\r\n" +
       "Content-Type: text/html\r\n" +
       "\r\n" +
       "<!DOCTYPE HTML PUBLIC " +
                "\"-//W3C//DTD HTML 3.2//EN\">\n" +
       "<HTML>\n" +
       "<HEAD>\n" +
       "  <TITLE>" + serverName + " Results</TITLE>\n" +
       "</HEAD>\n" +
       "\n" +
       "<BODY>\n" +
       "<H1>" + serverName + " Results</H1>\n" +
       "Here is the request line and request headers\n" +
       "sent by your browser:\n" +
       "<PRE>");
  }

  //----------------------------------------------------
  // Print bottom of a "standard" Web page.
  
  private void printTrailer(PrintWriter out) {
    out.println
      ("</PRE>\n" +
       "</BODY>\n" +
       "</HTML>\n");
  }

  //----------------------------------------------------
  // Normal Web page requests use GET, so this
  // server can simply read a line at a time.
  // However, CGI programs can use POST, in which
  // case we have to determine the number of POST bytes
  // that are sent so we know how much extra data
  // to read after the standard HTTP headers.
  
  private boolean usingPost(String[] inputs) {
    return(inputs[0].toUpperCase().startsWith("POST"));
  }

  private void readPostData(String[] inputs, int i,
                            BufferedReader in)
      throws IOException {
    int contentLength = contentLength(inputs);
    char[] postData = new char[contentLength];
    in.read(postData, 0, contentLength);
    inputs[++i] = new String(postData, 0, contentLength);
  }

  //----------------------------------------------------
  // Given a line that starts with CONTENT-LENGTH,
  // this returns the integer value specified.
  
  private int contentLength(String[] inputs) {
    String input;
    for (int i=0; i<inputs.length; i++) {
      if (inputs[i].length() == 0)
        break;
      input = inputs[i].toUpperCase();
      if (input.startsWith("CONTENT-LENGTH"))
        return(getLength(input));
    }
    return(0);
  }

  private int getLength(String length) {
    StringTokenizer tok = new StringTokenizer(length);
    tok.nextToken();
    return(Integer.parseInt(tok.nextToken()));
  }
}

