package TcpExamples;

import java.io.IOException;
import java.net.*;

/**
 * This server program works a bit differently by creating and dispatching a
 * new thread to handle multiple incoming socket connections, one after another, all running in parallel.
 * This advanced technique is often used in high=performance high=capacity server programs.
 * 
 * @see TcpSentryClient
 * @see TcpSentryHandlerThread
 * @see TcpExample4Client
 * @see TcpExample4DispatchServer
 * @see TcpExample4HandlerThread
 *
 * @see <a href="../../../src/TcpExamples/TcpSentryTerminalLog.txt" target="blank">TcpSentryTerminalLog.txt</a>
 * @see <a href="../../../src/TcpExamples/TcpExample4SequenceDiagram.png" target="blank">TcpExample4SequenceDiagram.png</a>
 * @see <a href="../../../src/TcpExamples/TcpExample4SequenceSketch.png" target="blank">TcpExample4SequenceSketch.png</a>
 *
 * @author Don McGregor
 * @author Don Brutzman
 * @author MV3500 class
 */
public class TcpSentryDispatchServer
{
    /** who is speaking, by role */
    static String ACTOR = "[dispatcher] ";
            
    /** Default constructor */
    public TcpSentryDispatchServer()
    {
        // default constructor
    }
    /**
     * Program invocation, execution starts here
     * @param args command-line arguments
     */
    public static void main(String[] args)
    {
        try {
            ServerSocket                   serverSocket = new ServerSocket(2317);
            Socket                         serverSocketConnection;
            TcpSentryHandlerThread sentryHandlerThread;

            int connectionCount = 0; // state variable

            System.out.println("===============================================================================");
            System.out.println(ACTOR + "startup, menu 1g.TcpSentryServer, " + TcpSentryDispatchServer.class.getName());
            
            while (true) // infinite loop, handling client connections and dispatching another handler thread
            {
                System.out.println(ACTOR + "waiting and ready to accept socket connection from a new client...");
                serverSocketConnection = serverSocket.accept(); // block! until connected

                connectionCount++; // now unblocked, we have gotten another connection
                
                // TODO option for the student, provide initial message *to the client*
                // that we are handing off to a dispatch thread... because that is polite behavior.
                // Plenty of code in Example3, we instead let our proxy thread
                // TcpSentryHandlerThread introduce itself to the client.
                
                System.out.println(ACTOR + "received socket connection, creating handlerThread for visitor #" + connectionCount + "...");
                
                // hand off this aready-created and connected socket to constructor
                sentryHandlerThread = new TcpSentryHandlerThread(serverSocketConnection); // creation logs a message
                sentryHandlerThread.start();// invokes the run() method in that object, which sends initial reply on the socket
                System.out.println(ACTOR + "a new sentry is now dispatched and running, using socket connection #" + connectionCount);
                System.out.println("===============================================================================");
                
                // while(true) continue looping, serverSocket is still waiting for another customer client
            }
        } 
        catch (IOException e) {
            System.out.println("*** " + ACTOR + "Problem with networking,"); // describe what is happening
            System.out.println("    " + e);
            // Provide more helpful information to user if exception occurs due to running twice at one time
            if (e instanceof java.net.BindException)         {
                System.out.println("*** Be sure to stop any other running instances of programs using this port!");
            }
            System.exit(-1);
        }
        finally
        {
            System.out.println(TcpSentryDispatchServer.class.getName() + " all done.");
        }
        System.out.println("==============================================================================="); // execution complete
    }
}