import java.io.PrintWriter;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.ServerSocket;
import java.util.Date;


public class tbServer {
    private static final int        maxque = 2;     // we are only allowing one client for now
    private static final int        port   = 6811;  // listen to this port

            static ServerSocket     SERV=null;
            static tbRobot          SEND=null;

    public static void main(String A[]) {
        try {
            // starting a network server
            SERV= new ServerSocket(port, maxque);

            // starting a command processor
            SEND=new tbRobot();

            System.out.println("TELEBOT SERVICE STARTED!");
            Log("server started");
            // server main loop
            while (true) {
                // The variable with thread is created
                // when a new connection is made
                new tbConnection(SERV.accept());
            }
        } catch (Exception e) {
            System.out.println("ERROR: (network) "+e.getMessage());
        }
        System.out.println("TELEBOT SERVICE STOPPED!");
        Log("server stopped");
    }

    public static void terminate(int level) {
        try {
            SERV.close();
        } catch (Exception e) { }
        System.out.println("TELEBOT SERVICE TERMINATED!");
        Log("server terminated");
        System.exit(level);
    }

    public synchronized static void Log(String memo) {
        try {
            PrintWriter LOG=new PrintWriter(new FileWriter("tbLOG.txt", true));
            LOG.println((new Date()).toString()+" : "+memo);
            LOG.flush();
            LOG.close();
        } catch (Exception e) {
            System.out.println("ERROR: (log file) "+e.getMessage());
        }
    }
}



class tbConnection implements Runnable {

    private static final int        maxcon = 10;
    private static tbConnection CLI[]=new tbConnection[maxcon+1];

    static {
        int c; for (c=0; c<=maxcon; c++) CLI[c]=null;
    }

    // Send message back to everybody
    private synchronized static void SendAll(String msg) {
        int c;
        for (c=1; c<=maxcon; c++)
            if (CLI[c]!=null)
                CLI[c].Send(msg);
    }

    private int             CO=0;
    private Socket          SO=null;
    private BufferedReader  SR=null;
    private PrintWriter     SW=null;
    private String          KTO=""; // client's address

    tbConnection(Socket client) {
        SO=client;
        // searching for an empty entry
        for (CO=1; CO<=maxcon; CO++) if (CLI[CO]==null) break;
        if (CO>maxcon) CO=0; else CLI[CO]=this;
        (new Thread(this, "Serving a Client")).start();
    }

    // Sends message back to current user
    private void Send(String msg) {
        try {
            SW.println(msg);
            SW.flush();
        } catch (Exception e) {
            try {
                SO.close();
            } catch (Exception f) {}
        }
    }
    
    // Discriminate Admin commands
    private void CAdm(String cmndline) {
             if (cmndline.equals("/DATE"))       CA_Date();
        else if (cmndline.equals("/PING"))       CA_Ping();
        else if (cmndline.equals("/QUIT PERMANENT")) CA_Quit();
        else if (cmndline.equals("/QUIT"))       CA_Restart();
        else if (cmndline.equals("/WHO"))        CA_Who();
        else if (cmndline.startsWith("/ECHO "))  CA_Echo(cmndline);
        else Send("/???");
    }

    // Echoes back the current date and time
    private void CA_Date() {
        SendAll(CO+"> \""+(new Date()).toString()+"\"");
    }

    // Echoes a message to all users
    private void CA_Echo(String echo) {
        SendAll(CO+"> \""+echo.substring(5)+"\"");
    }

    // pings back the individual user
    private void CA_Ping() {
        Send(CO+"> PONG");
    }

    // Quits current robot server with ERRORLEVEL 10
    private void CA_Quit() {
        tbServer.Log("Quit requested  by "+KTO);
        System.out.println("Quit requested  by "+KTO);
        SendAll(CO+"> QUIT");
        tbServer.terminate(10);
    }

    // Quits current robot server (restarts if looped batch)
    private void CA_Restart() {
        tbServer.Log("reset requested  by "+KTO);
        System.out.println("reset requested  by "+KTO);
        SendAll(CO+"> RESTART");
        tbServer.terminate(0);
    }
    // List all current users
    private void CA_Who() {
        int c;
        for (c=1; c<=maxcon; c++)
            if (CLI[c]!=null)
                Send(c+"="+CLI[c].KTO);
    }

    // Pass the command to the robot
    private void CRob(String cmndline) {
		try {
			SendAll(CO+">"+(tbServer.SEND).runCommand(cmndline) );
		} catch (Exception e) { 
			System.out.println("ERROR: "+e.getMessage());
		}
	}
	


    // Send service rejection notice
    private void CRej() {
        tbServer.Log("rejected   (+) from "+KTO);
        System.out.println("rejected   (+) from "+KTO);
        SendAll("s> Server reached its capacity");
        Send("MAX NUMBER OF CLIENTS REACHED");
        Send("PLEASE TRY AGAIN LATER, SORRY");
    }

    private void CBye() {
        int c;
        for (c=1; c<=maxcon; c++)
            if (CLI[c]!=null) return;
    }

    public void run() {
        try {
            // storing the client's IP address
            KTO=(SO.getInetAddress()).toString();

            // create a stream for reading via socket connection
            SR=new BufferedReader(new InputStreamReader(SO.getInputStream()));
            // create a stream for writing via socket connection
            SW=new PrintWriter (SO.getOutputStream());

            SendAll(CO+"> Welcome all!");
            if (CO>0) {
                tbServer.Log("connected  ("+CO+") from "+KTO);
                System.out.println("connected  ("+CO+") from "+KTO);
                while (true) {
                    String line=SR.readLine();
                    if (line==null) break;
//                  System.out.println("COMMAND: "+line);
                    if (line.startsWith("/"))       CAdm(line);
                    else                            CRob(line);
                }
            } else CRej();
            SO.close();
        } catch (Exception e) {
            System.out.println("ERROR: (connection) "+e.getMessage());
        }
        tbServer.Log("disconnect ("+CO+") from "+KTO);
        System.out.println("disconnect ("+CO+") from "+KTO);
        CLI[CO]=null;
        SendAll(CO+"> Bye bye!");
        CBye();
    }

}


syntax highlighted by Code2HTML, v. 0.8.11