package TcpExamples;

import static TcpExamples.TcpSentryHandlerThread.APPROACH_THE_GATE;
import static TcpExamples.TcpSentryHandlerThread.HALT_WHO_GOES_THERE;
import static TcpExamples.TcpSentryHandlerThread.HOLD_IT_RIGHT_THERE;
import static TcpExamples.TcpSentryHandlerThread.SENTRY_WATCH_PRESENT;
import static TcpExamples.TcpSentryHandlerThread.YOU_MAY_PASS;
import static TcpExamples.TcpSentryHandlerThread.PAY_ATTENTION;
import java.io.*;
import java.net.*;

/**
 * This client program establishes a socket connection to the {@link TcpExamples.TcpSentryDispatchServer},
 * then checks how long it takes to read the single line it expects as a server response.
 * No fancy footwork here, it is pretty simple and similar to {@link TcpExamples.TcpExample3Client}.
 * 
 * @see TcpSentryDispatchServer
 * @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 Brutzman
 * @author Don McGregor
 * @author MV3500 class
 */
public class TcpSentryClient
{
    /** who is speaking, by role */
    static String ACTOR = "[client] ";
    
    /** Default constructor */
    public TcpSentryClient()
    {
        // no action needed here
    }
    static String DESTINATION_HOST = "localhost";
    static int    MAX_LOOP_COUNT   = 6;

    /**
     * Program invocation, execution starts here
     * @param args command-line arguments
     */
    public static void main(String[] args) {
        try
        {
            System.out.println("===============================================================================");
            System.out.println(ACTOR + "startup, menu 1h.TcpSentryClient, " + TcpSentryClient.class.getName());
            System.out.println(ACTOR + "up to " + MAX_LOOP_COUNT + " visitors may approach.");
            System.out.println("===============================================================================");
            for (int loopCount = 1; loopCount <= MAX_LOOP_COUNT; loopCount++) // loop then exit
            {
                System.out.println(ACTOR + "creating client side to connect new socket #" + loopCount + "...");

                // We request an IP to connect to ("localhost") and
                // port number at that IP (2317). This establishes
                // a connection to that IP in the form of the Socket
                // object; the server uses a ServerSocket to wait for
                // connections.

                // open a socket for each loop
		Socket socket = new Socket(DESTINATION_HOST, 2317);
                
////////////////////////////////////////////////////////////////////////////////////////////
// Assignment code
                String myName = new String();
                // input stream and output stream 
                InputStream    socketInputStream       = socket.getInputStream();
                Reader         socketInputStreamReader = new InputStreamReader(socketInputStream);
                BufferedReader socketBufferedReader    = new BufferedReader(socketInputStreamReader);

                OutputStream   socketOutputStream = socket.getOutputStream();
                PrintStream    socketPrintStream  = new PrintStream(socketOutputStream);
                
                while(true) // loop to handle query/response protocol
                {
                    String sentryQuery = socketBufferedReader.readLine(); // this line blocks
                    System.out.println (sentryQuery);
                    
                    if (sentryQuery.endsWith(SENTRY_WATCH_PRESENT))
                    {
                         // duly noted, do not respond to this and continue looping/processing
                         System.out.println (ACTOR + "(no response, observing situation)");
                    }
                    else if (sentryQuery.toLowerCase().contains("hello"))
                    {
                         if (!myName.isBlank())
                              System.out.println (ACTOR + "(" + myName + ") Hello officer.");
                         else System.out.println (ACTOR +                 " Hello officer."); // anonymous
                    }
                    else if (sentryQuery.endsWith(APPROACH_THE_GATE))
                    {
                         // duly noted, do not respond to this and drive forward
                         System.out.println (ACTOR + "(no response, driving forward to gate)");
                    }
                    else if (sentryQuery.endsWith(HALT_WHO_GOES_THERE))
                    {
                        System.out.println ("(visitors should type their name here)");
                        // user provides name from console
                        myName = System.console().readLine(); // this line blocks, awaiting keyboard input from user
                        socketPrintStream.println(ACTOR + myName); // send it back to dispatch server
    //                  System.out.println ("[trace] console return: " + myName);

                        if (myName.equalsIgnoreCase("quit") || myName.equalsIgnoreCase("exit"))
                        {
                            socketPrintStream.flush(); // ensure this final message goes through the socket
                            System.out.println (ACTOR + "Exiting the program.");
                            socket.close();
                            System.exit(0);
                        }
                    }
                    else if (sentryQuery.endsWith(PAY_ATTENTION))
                    {
                        // better listen better, the prior query wasn't handled together
                        // no response expected or provided
                    }
                    else if (sentryQuery.endsWith(YOU_MAY_PASS))
                    {
                         System.out.println (ACTOR + "Thank you officer.");
                         break;
                    }
                    else if (sentryQuery.endsWith(HOLD_IT_RIGHT_THERE))
                    {
                         System.out.println (ACTOR + "OK I am outta here!");
                         break;
                    }
                    // handling unexpected cases is important
                    else System.out.println (ACTOR + "I'm not sure what that means, say again please...");
                    
                } // continue looping until termination event occurs
                
                System.out.println("===============================================================================");
                // To push the sentry software further, launch multiple copies of this TcpSentryClient simultaneously
            }

////////////////////////////////////////////////////////////////////////////////////////////

            System.out.println(ACTOR + " complete");
            // main method now exits
        }
        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!");
            }
            else if (e instanceof java.net.ConnectException) 
            {
                System.out.println("*** Be sure to start the server before starting the client!");
            }
        }
        finally
        {
            System.out.println(TcpSentryClient.class.getName() + " all done.");
        }
    }
}