package talk.awtui;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.net.*;
import java.io.*;

import talk.*;

class OutputListener implements TalkListener {
  private ITalkSession mySession;
  public OutputListener(ITalkSession session) {
    mySession = session;
  }
  
  public boolean textAppended(String s) {
    mySession.sendUserInput(s);
    return true;
  }
}

public class Talk extends Frame implements ITalkApp, ITalkView {
  // GUI components
  private ITalkEditor localText;
  private ITalkEditor remoteText;
  private TextField remoteAddressField;
  private TextField localAddressField;
  private Button quitBn;
  private Button connectBn;
  private Button disconnectBn;
  private Label statusBar;

  // communication 
  private TalkAddress callee;
  private TalkAddress caller;
  //private ITalkEngine myEngine;
  private ITalkSession mySession;
  private TalkOptions myOptions = new TalkOptions();
  
  public Talk(TalkAddress addr) {
    callee = addr;
    try {
      caller = new TalkAddress(System.getProperty("user.name"));
    } catch (BadAddressException e) {
      caller = new TalkAddress();
    }
    
    setFont(new Font("Helvetica", Font.PLAIN, 15));

    setLayout(new GridBagLayout());
    
    GridBagConstraints c = new GridBagConstraints();
    
    c.gridwidth = GridBagConstraints.REMAINDER;
    c.fill = GridBagConstraints.BOTH;

    // add a button panel at the top
    Panel btns = new Panel();
    btns.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 5));
    quitBn = new Button("Quit");
    connectBn = new Button("Connect");
    disconnectBn = new Button("Disconnect");
    disconnectBn.setEnabled(false);
    btns.add(quitBn);
    btns.add(connectBn);
    btns.add(disconnectBn);
    add(btns, c);

    // add the address entry fields
    Panel entry = new Panel();	// address entry
    entry.setLayout(new GridBagLayout());
    GridBagConstraints ec = new GridBagConstraints();
    ec.fill = GridBagConstraints.BOTH;
    ec.insets = new Insets(0, 2, 0, 2);

    // add remote address
    entry.add(new Label("Remote Address:"), ec);
    ec.weightx = 1.0;
    ec.gridwidth = GridBagConstraints.REMAINDER;
    remoteAddressField = new TextField();
    entry.add(remoteAddressField, ec);
    remoteAddressField.setText(callee.getAddressStr());

    // and local address
    ec.gridwidth = 1;
    ec.weightx = 0.0;
    entry.add(new Label("Local address:"), ec);
    ec.weightx = 1.0;
    ec.gridwidth = GridBagConstraints.REMAINDER;
    localAddressField = new TextField();
    entry.add(localAddressField, ec);
    localAddressField.setText(caller.getAddressStr());
    
    add(entry, c);

    // add main text entries
    c.weightx = 1.0;
    c.weighty = 1.0;

    remoteText = new TalkEdit(10, 80);
    remoteText.setEditable(false);
    add((TalkEdit)remoteText, c);

    localText = new TalkEdit(10, 80);
    localText.setEditable(false);
    add((TalkEdit)localText, c);

    // add a status label at the bottom
    c.weightx = 0.0;
    c.weighty = 0.0;
    statusBar = new Label();
    add(statusBar, c);

    // make sure it exits if user closes the window with the window
    // manager
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
	mySession.disconnect();
	System.exit(0);
      }
    });

    // set up button actions.
    quitBn.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
	mySession.disconnect();
	System.exit(0);
      }
    });
    connectBn.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
	doConnect();
      }
    });
    
    disconnectBn.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
	setStatusText("disconnect pressed");
	mySession.disconnect();
      }
    });

    // set up remoteAddressField action
    remoteAddressField.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
	String addrStr = remoteAddressField.getText();
	TalkAddress newAddr = new TalkAddress();
	try {
	  newAddr = new TalkAddress(addrStr);
	} catch (BadAddressException ex) {
	  setStatusText("Bad address format entered");
	}
	setStatusText("remote address is " + newAddr);
      }
    });
  }

  private void doConnect() {
    setStatusText("connect pressed");
    connectBn.setEnabled(false);
    localText.setEditable(false);
    localAddressField.setEditable(false);
    remoteAddressField.setEditable(false);
	
    try {
      callee = new TalkAddress(remoteAddressField.getText());
      caller = new TalkAddress(localAddressField.getText());
    } catch (BadAddressException ex) {
      setStatusText("Bad address format entered");
      connectBn.setEnabled(true);
      return;
    }

    mySession = new TalkSession(this);
    mySession.connect(callee.userName, callee.hostName, callee.tty,
		      caller.userName, caller.hostName);
  }
  
  public ITalkView createView(ITalkSession session, String title) {
    localText.addTalkListener(new OutputListener(session));
    return this;
  }
  
  private void setStatusText(String txt) {
    statusBar.setText(txt);
    System.err.println(txt);
  }

  public void connected(String withWho) {
    localText.clear();
    remoteText.clear();
    localText.setEditable(true);
    disconnectBn.setEnabled(true);
  }

  public void disconnected() {
    connectBn.setEnabled(true);
    disconnectBn.setEnabled(false);
    localText.setEditable(false);
    localText.removeTalkListeners();
    localAddressField.setEditable(true);
    remoteAddressField.setEditable(true);
  }

  public void connectFailed(String why) {
    connectBn.setEnabled(true);
    disconnectBn.setEnabled(false);
    localAddressField.setEditable(true);
    remoteAddressField.setEditable(true);
  }

  public void displayStatusMessage(String msg) {
    setStatusText(msg);
  }

  public void displayErrorMessage(String msg) {
    setStatusText(msg);
  }

  public void displayRemoteInput(String input) {
    remoteText.append(input);
  }

  public void displayBackspace() {
    remoteText.backspace();
  }

  public TalkOptions getOptions() {
    return myOptions;
  }
    
  public static void main(String args[]) {
    String addrStr = "";
    TalkAddress addr = new TalkAddress();
    if (args.length > 0) {
      addrStr = args[0];
      for (int i = 1; i < args.length; i++)
	addrStr += " " + args[i];
      try {
	addr = new TalkAddress(addrStr);
      } catch (BadAddressException e) {
	System.err.println("BadAddress format on the command-line");
      }
    }

      
    Talk talk = new Talk(addr);
    //talk.myOptions.setUseBuiltinServer(true);

    if (talk.myOptions.getUseBuiltinServer()) {
      Thread serverThread = new Thread() {
	public void run() {
	  TalkServer server = new TalkServer();
	  try {
	    server.mainLoop();
	  } catch (IOException e) {
	    Logger.getLogger().info("Server caught an exception");
	    e.printStackTrace();
	  }
	}
      };
      serverThread.start();
    }
    
    talk.setTitle("JTalk 0.1");
    talk.pack();
    talk.setVisible(true);
  }
}
