/**
 * Copyright (c) 2001/2003 Distributed Systems Research Group.
 * All rights reserved.
 *
 * For more information on Distributed Systems Research Group (DSRG),
 * please see <http://www.ics.agh.edu.pl/>.
 *
 * @author radzisz
 * file name: NoteClient.java
 *
 */
package edu.agh.sr.madej;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.rmi.NoSuchObjectException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.Naming;
import java.rmi.server.UnicastRemoteObject;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

/**
 * Klient.
 */
public class NoteBoardClient implements NoteBoardListener {

	JFrame frame = new JFrame("NoteClient");
	JTextArea textArea = new JTextArea(30, 60);
	JButton bClear = new JButton("clear");
	JButton bAppend = new JButton("append");
	JButton bLogin = new JButton("login");
	JButton bLogout = new JButton("logout");

	JTextField userName = new JTextField(10);
	JTextField userNick = new JTextField(10);
	JTextField userLastName = new JTextField(10);
	JTextField textField = new JTextField(50);

	NoteBoard board;
	String host;
	int port;
	User user;
	NoteBoardListener nbl;
	NoteBoardClient nbc;

	/**
	 * Konstruktor.
	 *
	 * @param host host, na ktorym dziala rejestr
	 * @param port port, na ktorym nasluchuje demon rejestru
	 */
	NoteBoardClient(String host, int port) {
		this.host = host;
		this.port = port;

		nbc = this;
		
		bClear.addActionListener(new ActionHandler());
		bLogin.addActionListener(new ActionHandler());
		bLogout.addActionListener(new ActionHandler());
		bAppend.addActionListener(new ActionHandler());

		frame.addWindowListener(new ActionHandler());

		JScrollPane scrollPane = new JScrollPane(textArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		textArea.setEditable(false);
		frame.getContentPane().add(scrollPane, BorderLayout.CENTER);

		JPanel bottomPanel = new JPanel();
		bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS));

		JPanel userPanel = new JPanel();
		userPanel.add(new JLabel("nick"));
		userPanel.add(userNick);
		userPanel.add(new JLabel("name"));
		userPanel.add(userName);
		userPanel.add(new JLabel("lastname"));
		userPanel.add(userLastName);
		userPanel.add(bLogin);
		userPanel.add(bLogout);
		bLogout.setEnabled(false);

		JPanel textPanel = new JPanel();
		textPanel.add(new JLabel("text"));
		textPanel.add(textField);
		textPanel.add(bAppend);

		JPanel buttonPanel = new JPanel();
		buttonPanel.add(bClear);

		bottomPanel.add(userPanel);
		bottomPanel.add(textPanel);
		bottomPanel.add(buttonPanel);

		frame.getContentPane().add(bottomPanel, BorderLayout.SOUTH);
		frame.pack();
		frame.setVisible(true);

		//init conenction with remote noteBoard
		initRemote();

		//make myself remotely accessible
		
		try {
			nbl = (NoteBoardListener)UnicastRemoteObject.exportObject(this);
		} catch (Exception ex) {
			log(ex.toString());
		}
	}
	
	/**
	 * Klasa zagniezdzona dostarczajaca interfejsu dla rejestracji obslugi zdarzen GUI.
	 */
	class ActionHandler extends WindowAdapter implements ActionListener {
	
		/**
		 * Metoda wywolywana w trakcie wystapienia zdarzenia ActionEvent
		 *
		 * @param e obiekt opisujacy zdarzenie
		 */
		public void actionPerformed(ActionEvent e) {
			if (e.getSource() == bClear)
				textArea.setText("");

			if (e.getSource() == bAppend) {
				if (user == null) {
					log("user is null!!!");
					return;
				}
				if (board == null) {
					log("not connected to board!!!");
					return;
				}
				
				//call the appendText on the remote board

				new NoteBoardClientThread(nbc);
			}

			if (e.getSource() == bLogin) {
				if (board == null) {
					log("not connected to board!!!");
					return;
				}
		
			  	//create User instance
				
			  	user = new UserImpl(userNick.getText(), userName.getText(), userLastName.getText());

			  	//register in board
			  	//by calling register() on board interface
			  	
			  	try {
			  		board.register(nbl, user);
			  	} catch (Exception ex) {
			  		log(ex.toString());
			  		user = null;
			  		return;
			  	}
			  	
			   	bLogin.setEnabled(false);
			   	bLogout.setEnabled(true);
			}

			if (e.getSource() == bLogout) {
			  	//unregister from board
			  	//by calling unregister() on board interface
			  	
			  	try {
			  		board.unRegister(nbl, user);
			  	} catch (Exception ex) {
			  		log(ex.toString());
			  	}
			  
			  	user = null;
			  	
			  	bLogin.setEnabled(true);
			   	bLogout.setEnabled(false);
			}
		}

		/**
		 * Metoda wywolywana w trakcie wystapienia zdarzenia WindowEvent
		 *
		 * @param e obiekt opisujacy zdarzenie
		 */
		public void windowClosing(WindowEvent e) {
			//logout - may throw exception
			//and make me not accessible remotely
			//disconnect remote object
			
			try {
				board.unRegister(nbl, user);
			} catch (Exception ex) { }
			
			try {
				UnicastRemoteObject.unexportObject(nbl, true);
			} catch (Exception ex) { }
			
			board = null;
			System.exit(0);
		}
	}

	/**
	 * Inicjalizacja referencji do zdalnego obiektu tablicy.
	 */
	private void initRemote() {
		try {
			String url = "//" + host + ":" + port + "/madej";
			Object obj = Naming.lookup(url);
				
			log("get object");
			board = (NoteBoard) obj;
		} catch (Exception e) {
			displayError(e.toString());
			e.printStackTrace();
		}

	}

	/**
	 * Metoda wywolywana w wyniku dopisania nowej linii tekstu na tablicy.
	 *
	 * @param text tekst
	 */
	public void onNewText(String text) {
		textArea.append(text+"\n");
	}

	/**
	 * Metoda logujaca.
	 * 
	 * @param text tekst do zalogowania
	 */
	private void log(String text) {
		textArea.append("local:" + text + "\n");
	}

	/**
	 * Statyczna metoda pozwalajaca na uruchomienie programu.
	 *
	 * @param args tablica argumentow
	 */
	public static void main(String[] args) {
		if (args.length == 2)
			try {
				new NoteBoardClient(args[0], Integer.parseInt(args[1]));
				return;
			} catch (Exception e) { }
		usage();
	}

	/**
	 * Wyswietla informacje o sposobie uzycia programu.
	 */
	private static void usage() {
		System.out.println("Usage: program <rmiDhost> <rmiDport>");
	}

	/**
	 * Wyswietla okno dialogowe z zadanym tekstem.
	 *
	 * @param text tekst
	 */
	void displayError(String text) {
		JOptionPane.showInternalMessageDialog(
			frame.getContentPane(),
			text,
			"error",
			JOptionPane.INFORMATION_MESSAGE);
	}
}