package SimpleChatOne;

// Fri Oct 15 18:07:43 EST 2004
//
// Written by Sean R. Owens, sean at guild dot net, released to the
// public domain.  Share and enjoy.  Since some people argue that it is
// impossible to release software to the public domain, you are also free
// to use this code under any version of the GPL, LPGL, or BSD licenses,
// or contact me for use of another license.
// http://darksleep.com/player

import java.net.Socket;
import java.net.ServerSocket;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;

public class Handler implements Runnable {
    private final static int READ_BUF_SIZE=1024;
    private final static int SAVE_BUF_SIZE=10240;
    private Socket sock = null;
    private Switchboard switchboard = null;
    private InputStream sockInput = null;
    private OutputStream sockOutput = null;
    private Thread myThread = null;
    private byte[] bufferedData = null;	// This is where we keep bytes we've read until we get a \n
    private boolean loggedIn = false;
    private String name="NotLoggedIn";
    public String getName() { return name; }

    public Handler(Socket sock, Switchboard switchboard, String messageOfTheDay) throws IOException {
	this.sock = sock;
	this.switchboard = switchboard;
	sockInput = sock.getInputStream();
	sockOutput = sock.getOutputStream();
	bufferedData = new byte[SAVE_BUF_SIZE];
	name = sock.getRemoteSocketAddress().toString();
	myThread = new Thread(this);
	try {
	    sockOutput.write(messageOfTheDay.getBytes(), 0, messageOfTheDay.getBytes().length);
	    // This call to flush() is optional - we're saying go
	    // ahead and send the data now instead of buffering
	    // it.
	    sockOutput.flush();
	}
	catch (IOException e) {
	}
	// Note that if we call myThread.start() now, we run the risk
	// of this new thread calling run before we're finished
	// constructing.  We can't count on the fact that we call
	// .start() last - javac or the jvm might have reordered the
	// above lines.  The class constructing us must wait for the
	// constructor to return and then call start() on us.
	System.out.println(this.getClass().getName()+": New handler created.");
    }

    public void start() {
	myThread.start();
    }
    
    public synchronized void write(byte[] data, int numBytesRead) {
	try {
	    sockOutput.write(data, 0, numBytesRead);
	    // This call to flush() is optional - we're saying go
	    // ahead and send the data now instead of buffering
	    // it.
	    sockOutput.flush();
	}
	catch (IOException e){
	    try {
		System.err.println(this.getClass().getName()+": Error writing to socket, closing socket.");
		sock.close();
	    }
	    catch (Exception e2){
		System.err.println(this.getClass().getName()+": Exception while closing socket, e2="+e2);
		e.printStackTrace(System.err);
	    }
	    switchboard.remove(this);
	}
    }

    // This method is responsible for processing the bytes we've read.
    // In the interest of clarity, it is not using the most efficient
    // approach.  In particular, it is not trying to be to clever to
    // avoid copying the data around.
    public void process(byte[] data, int numBytes) {
	// For this version of SimpleChat, all we're going to do is
	// forward data onto the other chatters.
	switchboard.sendToAllConnections(this, data, numBytes);
    }

    // All this method does is wait for some bytes from the
    // connection, read them, then write them back again, until the
    // socket is closed from the other side.
    public void run() {
	System.out.println(this.getClass().getName()+": Handler run() starting.");
	byte[] buf = new byte[READ_BUF_SIZE];
	while(true) {
	    int numBytesRead = 0;
	    try {
		// This call to read() will wait forever, until the
		// program on the other side either sends some data,
		// or closes the socket.
		numBytesRead = sockInput.read(buf, 0, buf.length);
		if(numBytesRead < 0) {
		    System.err.println(this.getClass().getName()+": Tried to read from socket, read() returned < 0,  Closing socket.");
		    break;
		}
		System.err.println(this.getClass().getName()+": Received "+numBytesRead+" bytes, sending to other clients: "+new String(buf));

		process(buf, numBytesRead);
	    }
	    catch (Exception e){
		e.printStackTrace(System.err);
		break;
	    }
	}

	try {
	    System.err.println(this.getClass().getName()+":Closing socket.");
	    sock.close();
	}
	catch (Exception e) {
	    System.err.println(this.getClass().getName()+":Exception while closing socket, e="+e);
	    e.printStackTrace(System.err);
	}
	switchboard.remove(this);
    }
}

