package talk.swingui;

import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.awt.BorderLayout;
import java.net.*;
import java.io.*;

import talk.*;

/** Talk is the concrete implementation of ITalkApp.  This is the main
    entry point for the program.  It displays the main window, with
    controls for starting new connections.  When a connection is to be
    started, it creates a new TalkSession.  The TalkSession that asks
    TalkApp to create a veiw for it.

    @see ITalkView
*/
public class TalkApp extends JFrame implements ITalkApp {
  private JMenuBar myMenuBar = new JMenuBar();
  private JToolBar myToolBar = new JToolBar();
  private JDesktopPane myDesktop = new JDesktopPane();
  private Action myQuitAction;
  private Action myConnectAction;
  private talk.TalkOptions myOptions = new TalkOptions();

  private java.util.logging.Logger logger = Logger.getLogger();
  
  TalkApp() {
    this("JTalk");
  }

  TalkApp(String title) {
    super(title);

    myOptions = readOptions(getOptionsFileName());
    
    myQuitAction = new AbstractAction("Quit") {
      public void actionPerformed(ActionEvent e) {
	int choice = JOptionPane.showConfirmDialog(TalkApp.this,
						   "Really Quit?",
						   "Quit",
						   JOptionPane.YES_NO_OPTION);
	if (choice == 0)
	  saveAndExit();
      }
    };
    
    myConnectAction = new ConnectAction(
      new ImageIcon(getClass().getResource("connect.gif")));
      
    getContentPane().setLayout(new BorderLayout());
    
    JMenu fileMenu = new JMenu("File");
    fileMenu.add(myConnectAction);
    fileMenu.add(myQuitAction);
    myMenuBar.add(fileMenu);

    JMenu optionsMenu = new JMenu("Options");
    JCheckBoxMenuItem builtinTalkdOpt =
      new JCheckBoxMenuItem("Use Builtin Talk Server",
			    myOptions.getUseBuiltinServer());
    builtinTalkdOpt.addChangeListener(new ChangeListener() {
      public void stateChanged(ChangeEvent e) {
	JCheckBoxMenuItem item = (JCheckBoxMenuItem)e.getSource();
	myOptions.setUseBuiltinServer(item.isSelected());  
      }
    });
	
    optionsMenu.add(builtinTalkdOpt);
    myMenuBar.add(optionsMenu);
    
    
    setJMenuBar(myMenuBar);

    // toolbar
    myToolBar.add(myConnectAction);
    getContentPane().add(myToolBar, BorderLayout.NORTH);

    // main desktop
    getContentPane().add(myDesktop, BorderLayout.CENTER);

    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
	saveAndExit();
      }
    });

    if (myOptions.getUseBuiltinServer()) {
      Thread serverThread = new Thread() {
	public void run() {
	  TalkServer server = new TalkServer();
	  try {
	    server.mainLoop();
	  } catch (IOException e) {
	    System.out.println("Server caught an exception");
	    e.printStackTrace();
	  }
	}
      };
      serverThread.start();
    }
    setSize(640, 500);
    show();
  }

  private void saveAndExit() {
    logger.entering("TalkApp", "saveAndExit");
    saveOptions(myOptions, getOptionsFileName());
    System.exit(0);
  }
  
  private void startConnection() {
    String addrStr =
      JOptionPane.showInputDialog("Enter user address to connect to");

    TalkAddress raddr = null;
    TalkAddress laddr = null;
    if (addrStr != null && addrStr.length() > 0) {
      try {
	raddr = new TalkAddress(addrStr);
      } catch (BadAddressException e) {
	displayErrorMessage("Bad address format entered");
	return;
      }
      
      try {
	laddr = new TalkAddress(System.getProperty("user.name"));
      } catch (BadAddressException e) {
	laddr = new TalkAddress();
      }

      TalkSession session = new TalkSession(this);
      session.connect(raddr.userName, raddr.hostName, raddr.tty,
		      laddr.userName, laddr.hostName);
    }
  }

  public ITalkView createView(ITalkSession session, String title) {
    java.awt.Dimension viewSize = myDesktop.getSize(null);
    // new view size is 70% of the desktop size
    viewSize.setSize((int)((double)viewSize.width*0.9),
		     (int)((double)viewSize.height*0.8));
    TalkView newView = new TalkView(viewSize, session, title);
    myDesktop.add(newView);
    return newView;
  }

  public void displayErrorMessage(String msg) {
    JOptionPane.showMessageDialog(this, msg,
				  "Error: "+getTitle(),
				  JOptionPane.ERROR_MESSAGE);	
  }

  public TalkOptions getOptions() {
    return myOptions;
  }

  private class ConnectAction extends AbstractAction {
    public ConnectAction(Icon icon) {
      super("Connect", icon);
      putValue(Action.SHORT_DESCRIPTION, "Open New Connection");
    }
    public void actionPerformed(ActionEvent e) {
      startConnection();
    }
  }

  private String getOptionsFileName() {
    String home = System.getProperty("user.home");
    return home + System.getProperty("file.separator") + ".jtalkrc";
  }
  
  private TalkOptions readOptions(String fname) {
    ObjectInputStream in;
    try {
      in = new ObjectInputStream(new FileInputStream(fname));
    }
    catch (FileNotFoundException e) {
      return new TalkOptions();
    }
    catch (IOException e) {
      displayErrorMessage("Failed to open options file "+fname+": "+e);
      return new TalkOptions();
    }

    try {
      TalkOptions opts = (TalkOptions)in.readObject();
      in.close();
      return opts;
    } catch (Exception e) {
      displayErrorMessage("Failed to read options file "+fname+": "+e);
      return new TalkOptions();
    }
  }

  private void saveOptions(TalkOptions opts, String fname) {
    try {
      ObjectOutputStream out =
	new ObjectOutputStream(new FileOutputStream(fname));
      out.writeObject(opts);
      out.close();
    } catch (IOException e) {
      displayErrorMessage("Failed to write options file "+fname+": "+e);
    }
  } 
  
  public static void main(String[] args) {
    try {
      UIManager.setLookAndFeel(
        UIManager.getSystemLookAndFeelClassName() );
    } catch (Exception e) { }
    new TalkApp("JTalk 0.1");
  }
}
