/*
 * RITChat.java
 *
 * Version:
 *    $Id$
 *
 * Revisions:
 *    $Log$
 */

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;

import java.net.UnknownHostException;

import java.util.Set;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.HashMap;
import java.util.Map;
import java.util.Collections;

import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.event.*;

/**
 * A simple text based chat client.  Supports a single chat session.
 * The following commands are accepted:
 *
 *    handles                --> displays known handles
 *    register <name>        --> Register handle with name service
 *    chat <handle>          --> Initiate a chat with the specified user
 *    accept                 --> Accept the current chat request
 *    quit                   --> Terminate program
 */

public class RITChat {

    // The server managing our sessions
    private static ChatServer server = null;

    // Registration flag
    private static boolean registered = false;

    // The active handles
    private static Set activeHandles = null;

    // Vector of active users
    private static Vector vlist = new Vector();

    // JList of active users
    private static JList jvlist;

    // Vector of requests
    private static Vector rlist = new Vector();

    // JList of requests
    private static JList jrlist;

    // Status label
    private static JLabel stateLabel;

    private static class Request {

	ChatSession session;

	public Request( ChatSession s ) {
	    session = s;
	}

	public String toString() {
	    return session.remoteHandle()
		+ " [" + session.getRequestTime() + "]";
	}
    } // Request

    /**
     * Read commands and execute commands entered from the keyboard.
     * The user may specify the address of the server from the command
     * line.
     *
     * @param args command line arugments (optional host and port for server)
     */

    public static void main( String args[] ) {
	String nsHost = NetworkChatServer.DEFAULT_NS_HOST;
	int nsPort = NetworkChatServer.DEFAULT_NS_PORT;

	// Handle the command line stuff

	if ( args.length != 1 ) {
	    System.err.println( 
	        "Usage:  java myID" );
	    System.exit( 1 );
	}

	// Create the server
	try {
	    server = new NetworkChatServer( nsHost, nsPort );
	} catch ( UnknownHostException e ) {
	    System.err.println( "RITChat:  Invalid host" );
	    System.exit( 1 );
	} catch ( IOException e ) {
	    System.err.println( "RITChat:  " + e.getMessage() );
	    System.exit( 1 );
	}

	jvlist = new JList( vlist );
	jrlist = new JList( rlist );

	stateLabel = new JLabel( "Status Messages ....." );

	// Set up the listener to handle packet updates
	server.addChatListener( 
	    new ChatListener() {
		public void registeredUsers( Set users ) {
		    activeHandles = users;
		    Vector v = new Vector( users );
		    Collections.sort( v );
		    if( !v.equals( vlist ) ) {
			vlist = v;
			jvlist.setListData( v );
		    }
		    // System.out.println( "Update action." );
		    synchronized( vlist ) {
			if( !registered ) {
			    registered = true;
			    vlist.notifyAll();
			}
		    }
		}
		public void chatRequest( ChatSession session ) {
		    System.out.println( "\nChat request from " +
					session.remoteHandle() + "..." );
		    rlist.add( new Request( session ) );
		    jrlist.setListData( rlist );
		    //connections.put( session.remoteHandle(), session );
			// request = session;
		}
	    }
	);

	// Enable the server
	server.setEnabled( true );
	/*
	synchronized( vlist ) {
	    while( !registered ) {
		try {
		    vlist.wait();
		} catch( InterruptedException e ) {
		}
	    }
	}
	*/
	if( vlist.contains( args[0] ) ) {
	    System.out.println( "Duplicate handle: " + args[0] );
	    System.exit(1);
	}

	// Register ourselves
	try {
	    server.register( args[0] );
	} catch (ChatException e ) {
	    System.out.println( e.getMessage() );
	}

	// Plumbing for keyboard input
	// in = new BufferedReader( new InputStreamReader( System.in ) );

	JFrame win = new JFrame( args[0] );
        win.addWindowListener( new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

	win.setLocationRelativeTo( null );

	win.getContentPane().setLayout( new BorderLayout() );
	// JLabel stateLabel = new JLabel( "State Messages Go Here ..." );
	win.getContentPane().add( "North", stateLabel );

	Box lists = new Box( BoxLayout.Y_AXIS );
	win.getContentPane().add( "Center", lists );

	JScrollPane userList = new JScrollPane( jvlist );
	userList.setPreferredSize( new Dimension( 100, 0 ) );
	jvlist.setVisibleRowCount( 5 );
	lists.add( userList );

	JScrollPane connectList = new JScrollPane( jrlist );
	connectList.setPreferredSize( new Dimension( 100, 0 ) );
	jrlist.setVisibleRowCount( 5 );
	lists.add( connectList );

	JPanel buttons = new JPanel( new GridLayout( 0, 1) );
	JButton send = new JButton( "Send" );
	buttons.add( send );
	JButton receive = new JButton( "Receive" );
	buttons.add( receive );
	JButton disconnect = new JButton( "Disconnect" );
	buttons.add( disconnect );
	JButton quit = new JButton( "Quit" );
	buttons.add( quit );
	send.addActionListener( new ActionListener(){
	    public void actionPerformed( ActionEvent e ) {
		send();
	    }
	});
	receive.addActionListener( new ActionListener(){
	    public void actionPerformed( ActionEvent e ) {
		receive();
	    }
	});
	disconnect.addActionListener( new ActionListener(){
	    public void actionPerformed( ActionEvent e ) {
		disconnect();
	    }
	});
	quit.addActionListener( new ActionListener(){
	    public void actionPerformed( ActionEvent e ) {
		System.exit( 0 );
	    }
	});
	win.getContentPane().add( "East", buttons );
	win.pack();
	win.show();
    }

    private static class ChatFrame extends JFrame {
	ChatSession session = null;
	Reader reader = null;
	Writer writer = null;
	JTextPane text = new JTextPane();
	JScrollPane scroll = new JScrollPane( text );
	String title;

	ChatFrame( String title ) {
	    super( title );
	    this.title = title;
	    text.setPreferredSize( new Dimension( 300, 100 ) );
	    getContentPane().add( scroll );
	    addWindowListener(new WindowAdapter() {
		public void windowClosing(WindowEvent e) {
		    new Thread(){
			public void run() {
			    try {
				if( session != null ) session.close();
				if( reader != null ) reader.close();
				if( writer != null ) writer.close();
			    } catch( IOException ex ) {
				System.out.println( ex.getMessage() );
			    }
			}
		    }.start();
		    dispose();
		}
	    });
	}

	void setSession( ChatSession s ) {
	    session = s;
	    reader = s.getReader();
	    writer = s.getWriter();
	    new Thread() {
		public void run() {
		    int c;
		    Document doc = text.getDocument();
		    try {
			while( ( c = reader.read() ) != -1) {
			    doc.insertString( doc.getLength(),
					      Character.toString( (char)c ),
					      null );
			}
			setTitle( title + " ***Disconnected***" );
			reader.close();
			writer.close();
		    } catch ( IOException e ) {
			System.out.println( e.getMessage() );
			setTitle( title + " ***Disconnected***" );
		    } catch ( BadLocationException e ) {
			System.out.println( e.getMessage() );
		    }
		}
	    }.start();
	    text.addKeyListener( new KeyAdapter() {
		public void keyTyped( KeyEvent e ) {
		    char c = e.getKeyChar();
		    Document doc = text.getDocument();
		    try {
			writer.write( c );
			writer.flush();
		    } catch ( IOException ex ) {
			System.out.println( ex.getMessage() );
			setTitle( title + " ***Disconnected***" );
		    }
		}
	    });
	}
    } // ChatFrame

    private static void send() {
	final String s = (String)jvlist.getSelectedValue();
	System.out.println( s );
	if( s != null ) {
	    final ChatFrame f = new ChatFrame( "To: " + s );
	    f.pack();
	    f.show();
	    stateLabel.setText( "Connecting to " + s );
	    new Thread() {
		public void run() {
		    try {
			ChatSession session = server.chat( s );
			System.out.println( session );
			f.setSession( session );
		    } catch ( ChatException e ) {
			stateLabel.setText( e.getMessage() );
		    }
		}
	    }.start();
	} else {
	    stateLabel.setText( "No Selection" );
	}
    }

    private static void receive() {
	Request request = (Request)jrlist.getSelectedValue();
	if( request != null ) {
	    ChatSession session = request.session;
	    System.out.println( session );
	    ChatFrame f = new ChatFrame( "From: " + session.remoteHandle() );
	    f.pack();
	    f.show();
	    stateLabel.setText( "Accepting from: " + session.remoteHandle() );
	    f.setSession( session );
	    rlist.remove( request );
	    jrlist.setListData( rlist );
	}
    }

    private static void disconnect() {
    }
    /*
    private static Object selection( JList jl) {
	return jl.getSelectedValue();
    }
    */
} // RITChat
