// Fig. 10.9: MessengerClient.java
// This program provides implementation for user login
// and client connection with server.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
import java.util.*;

import org.w3c.dom.*;
import org.xml.sax.*;
import javax.xml.parsers.*;
import com.sun.xml.tree.XmlDocument;

public class MessengerClient extends JFrame {
   private JPanel centerPanel, namePanel;
   private JLabel status, nameLab;
   private JTextField name;
   private ImageIcon bug;
   private JButton submit;
   private Socket clientSocket;
   private OutputStream output;
   private InputStream input;
   private boolean keepListening;
   private ClientStatus clientStatus;
   private Document users;
   private Vector conversations;
   private DocumentBuilderFactory factory;
   private DocumentBuilder builder;

   public MessengerClient()
   {
      // create GUI
      super ( "Messenger Client" );

      try
      {
         // obtain the default parser
         factory = DocumentBuilderFactory.newInstance();

         // get DocumentBuilder
         builder = factory.newDocumentBuilder();
      } 
      catch ( ParserConfigurationException pce ) {
         pce.printStackTrace();
      }


      Container c = getContentPane();

      centerPanel = new JPanel( new GridLayout( 2, 1 ) );

      namePanel = new JPanel();

      nameLab = new JLabel( "Please enter your name: " );
      namePanel.add( nameLab );

      name = new JTextField( 15 );
      namePanel.add( name );

      centerPanel.add( namePanel );

      bug = new ImageIcon( "travelbug.jpg" );
      submit = new JButton( "Submit", bug );
      submit.setEnabled( false );
      centerPanel.add( submit );

      submit.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e ) {
               loginUser();
            }
         }
      );

      c.add( centerPanel, BorderLayout.CENTER );

      status = new JLabel( "Status: Not connected" );
      c.add( status, BorderLayout.SOUTH );

      addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e ) {
               System.exit( 0 );
            }
         }
      );

      setSize( 200, 200 );
      show();
   }

   public void runMessengerClient()
   {
      try {
         clientSocket = new Socket(
            InetAddress.getByName( "127.0.0.1" ), 5000 );
         status.setText( "Status: Connected to " +
            clientSocket.getInetAddress().getHostName() );

         // get input and output streams
         output = clientSocket.getOutputStream();
         input = clientSocket.getInputStream();

         submit.setEnabled( true );
         keepListening = true;

         int bufferSize = 0;

         while ( keepListening ) {

            bufferSize = input.available();

            if ( bufferSize > 0 ) {
               byte buf[] = new byte[ bufferSize ];

               input.read( buf );

               InputSource source = new InputSource( 
                  new ByteArrayInputStream( buf ) );
               Document message;

               try {

                  // obtain document object from XML document
                  message = builder.parse( source );

                  if ( message != null ) 
                     messageReceived( message );

               } 
               catch ( SAXException se ) {
                  se.printStackTrace();         
               }
               catch ( Exception e ) {
                  e.printStackTrace();
               }
            } 
         }

         input.close();
         output.close();
         clientSocket.close();
         System.exit( 0 );
      } 
      catch ( IOException e ) {
         e.printStackTrace();
         System.exit( 1 );
      }
   }

   public void loginUser()
   {
      // create Document with user login
      Document submitName = builder.newDocument();
      Element root = submitName.createElement( "user" );

      submitName.appendChild( root );
      root.appendChild( 
         submitName.createTextNode( name.getText() ) );
 
      send( submitName );
   }

   public Document getUsers()
   { 
      return users;
   }

   public void stopListening()
   {
      keepListening = false;
   }

   public void messageReceived( Document message )
   {
      Element root = message.getDocumentElement();

      if ( root.getTagName().equals( "nameInUse" ) ) 
         // did not enter a unique name
         JOptionPane.showMessageDialog( this,
           "That name is already in use." +
           "\nPlease enter a unique name." );
      else if ( root.getTagName().equals( "users" ) ) {
         // entered a unique name for login
         users = message;
         clientStatus = new ClientStatus( name.getText(), this );
         conversations = new Vector();
         hide();
      } 
      else if ( root.getTagName().equals( "update" ) ) {

         // either a new user login or a user logout
         String type = root.getAttribute( "type" );
         NodeList userElt = root.getElementsByTagName( "user" );
         String updatedUser = 
            userElt.item( 0 ).getFirstChild().getNodeValue();

         // test for login or logout
         if ( type.equals( "login" ) )   
            // login
            // add user to onlineUsers Vector
            // and update usersList
            clientStatus.add( updatedUser );
         else {
            // logout
            // remove user from onlineUsers Vector
            // and update usersList
            clientStatus.remove( updatedUser );

            // if there is an open conversation, inform user
            int index = findConversationIndex( updatedUser );

            if ( index != -1 ) {
               Conversation receiver = 
                  ( Conversation ) conversations.elementAt( index );

               receiver.updateGUI( updatedUser + " logged out" );
               receiver.disableConversation();
            }
         }
      } 
      else if ( root.getTagName().equals( "message" ) ) {
         String from = root.getAttribute( "from" );
         String messageText = root.getFirstChild().getNodeValue();

         // test if conversation already exists
         int index = findConversationIndex( from );

         if ( index != -1 ) { 
            // conversation exists
            Conversation receiver = 
               ( Conversation ) conversations.elementAt( index );
            receiver.updateGUI( from + ":  " + messageText );
         } 
         else { 
            // conversation does not exist
            Conversation newConv =
               new Conversation( from, clientStatus, this );
            newConv.updateGUI( from + ":  " + messageText );
         }
      } 
   }

   public int findConversationIndex( String userName ) 
   {
      // find index of specified Conversation
      // in Vector conversations
      // if no corresponding Conversation is found, return -1
      for ( int i = 0; i < conversations.size(); i++ ) {
         Conversation current = 
            ( Conversation ) conversations.elementAt( i );

         if ( current.getTarget().equals( userName ) ) 
            return i;
      }

      return -1;
   }

   public void addConversation( Conversation newConversation ) 
   {
      conversations.add( newConversation );
   }
    
   public void removeConversation( String userName ) 
   {
      conversations.removeElementAt(
         findConversationIndex( userName ) );
   }
 
   public void send( Document message )
   {
      try {

        // write to output stream          
        ( ( XmlDocument ) message).write( output ); 
      }
      catch ( IOException e ) {
         e.printStackTrace();
      }
   }  

   public static void main( String args [] )
   {
      MessengerClient cm = new MessengerClient();

      cm.runMessengerClient();
   }
}
/*
 **************************************************************************
 * (C) Copyright 2001 by Deitel & Associates, Inc. and Prentice Hall.     *
 * All Rights Reserved.                                                   *
 *                                                                        *
 * DISCLAIMER: The authors and publisher of this book have used their     *
 * best efforts in preparing the book. These efforts include the          *
 * development, research, and testing of the theories and programs        *
 * to determine their effectiveness. The authors and publisher make       *
 * no warranty of any kind, expressed or implied, with regard to these    *
 * programs or to the documentation contained in these books. The authors *
 * and publisher shall not be liable in any event for incidental or       *
 * consequential damages in connection with, or arising out of, the       *
 * furnishing, performance, or use of these programs.                     *
 **************************************************************************
*/




