package jmeetup;

import java.io.*;
import java.net.*;
import java.util.*;

/**
 * Handles an individual connection with a 
 * JMeetUp client
 *
 * @version 1.0
 * @author  Prof. David Bernstein, James Madison University
 */
public class ConnectionHandler implements Runnable
{
    private volatile boolean       keepRunning;
    private BufferedReader         in;
    private PrintWriter            out;
    private Socket                 s;
    private String                 username;
    private Thread                 controlThread;
    private Server                 server;


    /**
     * Construct a new ConnectionHandler
     *
     * @param s        The Socket to use
     * @param server   The "controlling" server
     */
    public ConnectionHandler(Socket s, Server server)
       throws IOException
    {
       this.server = server;
       this.s = s;

       in = new BufferedReader(
          new InputStreamReader(
             s.getInputStream()));


       out = new PrintWriter(s.getOutputStream());
    }


    /**
     * Handle a check
     */
    private void handleCheck()
    {
       Enumeration<Proposal>   e;
       Proposal                p;


       e = server.getProposals();
       while (e.hasMoreElements()) 
       {
          p = e.nextElement();
          out.print(p+"<BR/>");
       }
       out.print("\n");
       out.flush();
    }


    /**
     * Handle a choice
     */
    private void handleChoose(String number)
    {
       int   id;

       try 
       {
          id = Integer.parseInt(number);
          server.addProponent(id, username);
          out.println("OK");
          out.flush();
       }
       catch (NumberFormatException nfe)
       {
          out.println(number+" is an invalid choice!");
          out.flush();
       }
    }


    /**
     * Handle a login
     */
    private void handleLogin(String name)
    {
       // Only change the username if it hasn't 
       // already been set
       if (username == null) 
       {
          username = name;
          System.out.println("["+username+"]  on "+
                             s.getInetAddress()+", "+
                             s.getPort());
       }
    }


    /**
     * Handle a logout
     */
    private void handleLogout()
    {
       // Close the socket and stop the thread
       stop();
    }


    /**
     * Handle a port change
     *
     * @param s   The port
     */
    private void handlePort(String s)
    {
       int    port;

       try 
       {
          port = Integer.parseInt(s);
          server.setSenderPort(this, port);
       }
       catch (NumberFormatException nfe) 
       {
          // Don't change the port
       }
    }


    /**
     * Handle a proposal
     *
     * @param description   The texr of the proposal
     */
    private void handlePropose(String description)
    {
       server.addProposal(username, description);
       out.println("OK");
       out.flush();
    }


    /**
     * Handle a talk command
     *
     * @param message   The message to send
     */
    private void handleTalk(String message)
    {
       server.broadcast("["+username+"]  "+message);
       out.println("OK");
       out.flush();
    }


    /**
     * Run this ConnectionHandler
     */
    public void run()
    {
       String             argument, command, line, name, value;
       StringTokenizer    st;


       while (keepRunning) 
       {
          try
          {
             line = in.readLine();

             command  = "";
             argument = "";
             st = new StringTokenizer(line, ":");

             // Parse the command
             if (st.hasMoreTokens()) command  = st.nextToken();
             if (st.hasMoreTokens()) 
             {
                argument = st.nextToken().trim();
             }
             else
             {
                if (!command.equals("check")) 
                {
                   argument = command;
                   command  = "talk";
                }
             }

             // Process the command
             //
             // Note: This could be improved with the 
             // Command Pattern
             if (command.equals("check"))
             {
                handleCheck();
             }
             else if (command.equals("choose"))
             {
                handleChoose(argument);
             } 
             else if (command.equals("login")) 
             {
                handleLogin(argument);
             } 
             else if (command.equals("logout")) 
             {
                handleLogout();
             } 
             else if (command.equals("port")) 
             {
                handlePort(argument);
             } 
             else if (command.equals("propose")) 
             {
                handlePropose(argument);
             } 
             else if (command.equals("talk")) 
             {
                handleTalk(argument);
             }
          } 
          catch (IOException ioe) 
          {
             // Ignore it
          }
       }

       // The thread is about to die
       try 
       {
          in.close();
          out.close();
          s.close();
       } 
       catch (IOException ioe) 
       {
          // Ignore
       }

       controlThread = null;
    }



    /**
     * Start the new thread of execution
     */
    public void start()
    {
       if (controlThread == null)
       {
          keepRunning = true;
          controlThread = new Thread(this);

          controlThread.start();
       }
    }


    /**
     * Stop the thread of execution
     */
    public void stop()
    {
       keepRunning = false;
    }
}
