import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.*;

/**
   A timezone client side that requests time conversion to server
   @author Sugiharto Widjaja
   @version 09/21/02
*/
public class TimeZoneClient
{
   /**
      Construct the timezone client
      @param host the host address
      @param port the port number of host
      @param panel the client panel
   */
   public TimeZoneClient(String host, int port, ClientPanel panel)
   {
      this.host = host;
      this.port = port;
      this.panel = panel;
      media = panel.getMedia();
   }

   /**
      Try to connect to timezone server
      @throws IOException
   */
   public boolean connectToServer()
   {
      try
      {
         timeSocket = new Socket(host, port);
         in = new BufferedReader(new InputStreamReader(timeSocket.getInputStream()));
         out = new PrintWriter(timeSocket.getOutputStream(), true);
         msg = new MsgListener(this, panel);
         msg.start();
         media.append("*** connected to " + host + " at port " + port + "\n");
         return true;
      }
      catch(IOException e)
      {
         media.append("*** Can't connect to " + host + " at port " + port + "\n");
         return false;
      }
   }

   /**
      Send message to server
      @param msg the message
   */
   public void sendMessage(String msg)
   {
      if(out != null)
        out.println(msg);
   }

   /**
      Disconnect from the server
      @throws Exception
   */
   public void disconnectFromServer()
   {
      try
      {
         timeSocket.close();
         msg = null;
      }
      catch(Exception e)
      {
         media.append("*** Can't close socket!!");
      }
   }

   /**
      Return the client socket
      @return the client socket
   */
   public Socket getSocket()
   {
      return timeSocket;
   }

   /**
      Get the reader to receive incoming messages from server
      @return the reader
   */
   public BufferedReader getReader()
   {
      return in;
   }

   // The client socket
   private Socket timeSocket;
   // The reader
   private BufferedReader in;
   // The writer
   private PrintWriter out;
   // The host name
   private String host;
   // The host port number
   private int port;
   // The listener to listen any incoming messages from server
   private MsgListener msg;
   // The client panel
   private ClientPanel panel;
   // The media to display all activities
   private JTextArea media;
}

/**
   Listener to listen to any incoming messages from server
   @author Sugiharto Widjaja
   @version 09/21/02
*/
class MsgListener extends Thread
{
   public MsgListener(TimeZoneClient s, ClientPanel panel)
   {
      /**
         Construct the listener
         @param s the timezone client
         @param panel the client panel
      */
      tzClient = s;
      this.panel = panel;
      media = panel.getMedia();
      in = tzClient.getReader();
   }

   /**
      Run infinitely listening to any server's incoming messages.
      @throw Exception
   */
   public void run()
   {
      try
      {
         boolean done = false;
         while(!done)
         {
            String inline = in.readLine();
            if(inline == null)
               done = true;
            else
            {
               if(processIncoming(inline.trim()))
                  done = true;
            }
         }
         tzClient.disconnectFromServer();
         media.append("*** Disconnecting from server\n");
         buttonsActionOnDisconnect();
      }
      catch(Exception e)
      {
         tzClient.disconnectFromServer();
         media.append("*** Disconnecting from server\n");
         buttonsActionOnDisconnect();
      }
   }

   /**
      process the incoming messages from server
      @param incoming the messages from server
      @return true if server disconnects, false otherwise
   */
   private boolean processIncoming(String incoming)
   {
      boolean disconnection = false;
      StringTokenizer token = new StringTokenizer(incoming, ">");
      String opCode = token.nextToken();
      if(opCode.equals("Q"))
         disconnection = true;
      else if(opCode.equals("E"))
         media.append("[SERVER] : Error found in your query. Please try again!\n");
      else if(opCode.equals("O"))
         printOutputToMedia(token.nextToken());
      return disconnection;
   }

   /**
      Print important messages from server to the media
      @param output the incoming messages from server
   */
   private void printOutputToMedia(String output)
   {
      StringTokenizer token = new StringTokenizer(output, ";");
      media.append("[SERVER] : Current date and time in " + token.nextToken() + " is " +
                   token.nextToken() + ", " + token.nextToken() + "\n");
      media.append("[SERVER] : Current date and time in " + token.nextToken() + " is " +
                   token.nextToken() + ", " + token.nextToken() + "\n");
   }

   /**
      Enable connect button and disable disconnect and send buttons upon disconnection
   */
   private void buttonsActionOnDisconnect()
   {
      panel.enableConnect();
      panel.disableDisconnect();
      panel.disableSend();
   }

   // The timezone client
   private TimeZoneClient tzClient;
   // The reader
   private BufferedReader in;
   // The client panel
   private ClientPanel panel;
   // The media
   private JTextArea media;
}