package net.sf.colossus.appmain;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import net.sf.colossus.common.Constants;
import net.sf.colossus.common.Options;
import net.sf.colossus.common.WhatNextManager;
import net.sf.colossus.common.WhatNextManager.WhatToDoNext;
import net.sf.colossus.guiutil.KFrame;
import net.sf.colossus.guiutil.SaveWindow;
/**
* Startup code for network Client
*
* @author David Ripton
*/
@SuppressWarnings("serial")
public class NetworkClientDialog extends KFrame
{
private static final Logger LOGGER = Logger
.getLogger(NetworkClientDialog.class.getName());
private final Object mutex;
private final Options netclientOptions;
private final Options stOptions;
private final WhatNextManager whatNextManager;
private String playerName;
private String hostname;
private int port;
private final SaveWindow saveWindow;
private final JComboBox<String> nameBox;
private final JComboBox<String> hostBox;
private final JComboBox<String> portBox;
public NetworkClientDialog(Object mutex, final WhatNextManager whatNextMgr)
{
super("Client startup options");
getContentPane().setLayout(new GridLayout(0, 2));
net.sf.colossus.util.InstanceTracker.register(this, "only one");
this.mutex = mutex;
this.whatNextManager = whatNextMgr;
this.stOptions = whatNextMgr.getStartOptions();
// player, preferred host (or null) and port from main() / cmdline
this.playerName = stOptions.getStringOption(Options.runClientPlayer);
this.hostname = stOptions.getStringOption(Options.runClientHost);
this.port = stOptions.getIntOption(Options.runClientPort);
// LRU list of hosts, and window geometry from NetClient cf file
netclientOptions = new Options(Constants.OPTIONS_NET_CLIENT_NAME);
netclientOptions.loadOptions();
Container panel = getContentPane();
panel.add(new JLabel(
stOptions.getOption(Options.runSpectatorClient) ? "Spectator name"
: "Player name"));
Set<String> nameChoices = new TreeSet<String>();
nameChoices.add(playerName);
nameChoices.add(Constants.username);
nameBox = new JComboBox<String>(new Vector<String>(nameChoices));
nameBox.setEditable(true);
nameBox.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
playerName = (String)nameBox.getSelectedItem();
}
});
nameBox.setSelectedItem(playerName);
panel.add(nameBox);
panel.add(new JLabel("Server hostname"));
Set<String> hostChoices = new TreeSet<String>();
String preferred = initServerNames(hostname, hostChoices,
netclientOptions);
this.hostname = preferred;
hostBox = new JComboBox<String>(new Vector<String>(hostChoices));
hostBox.setEditable(true);
hostBox.setSelectedItem(preferred);
hostBox.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
hostname = (String)hostBox.getSelectedItem();
}
});
panel.add(hostBox);
panel.add(new JLabel("Server port"));
Set<String> portChoices = new TreeSet<String>();
portChoices.add("" + port);
portChoices.add("" + Constants.defaultPort);
portBox = new JComboBox<String>(
portChoices.toArray(new String[portChoices.size()]));
portBox.setEditable(true);
portBox.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
port = Integer.parseInt((String)portBox.getSelectedItem());
}
});
panel.add(portBox);
JButton goButton = new JButton("Go");
goButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
doRunNetClient();
}
});
panel.add(goButton);
JButton quitButton = new JButton(Constants.quitGame);
quitButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
whatNextMgr.setWhatToDoNext(WhatToDoNext.QUIT_ALL, true);
dispose();
}
});
panel.add(quitButton);
addWindowListener(new WindowAdapter()
{
@Override
public void windowClosing(WindowEvent e)
{
whatNextMgr.setWhatToDoNext(WhatToDoNext.GET_PLAYERS_DIALOG,
false);
dispose();
}
});
pack();
saveWindow = new SaveWindow(netclientOptions, "NetworkClientDialog");
saveWindow.restoreOrCenter(this);
setVisible(true);
}
/* Public and static for Start.java.
* Initializes the hostChoices set for the ComboBox with
* - current running host name and IP
* - wantedHost hostname got as parameter (got from cmdline),
* can be null
* - LRU list from cf file
* Returns the "preferred" servername, i.e. the one that shall be
* set as preselected item in the hostbox. The preferred one is
* server name the one given as parameter, or if none, then the
* one last used from LRU list (or if even that is empty, defaults
* to current hostname).
*/
public static String initServerNames(String wantedHost,
Set<String> hostChoices, Options netclientOptions)
{
String preferred = null;
try
{
InetAddress ia = InetAddress.getLocalHost();
String hostAddr = ia.getHostAddress();
if (hostAddr != null)
{
hostChoices.add(hostAddr);
preferred = ia.getHostAddress();
}
String hostName = ia.getHostName();
if (hostName != null)
{
hostChoices.add(hostName);
preferred = ia.getHostName();
}
}
catch (UnknownHostException ex)
{
LOGGER.log(Level.SEVERE, "Can not resolve host", ex);
}
// LRU, i.e. serverName0 is the one last time used,
// that's why we go backwards.
// Combobox will display them alphabetically anyway,
// so make at least the last-used-one be preselected.
for (int i = Constants.numSavedServerNames - 1; i >= 0; i--)
{
String serverName = netclientOptions
.getStringOption(Options.serverName + i);
if (serverName != null)
{
hostChoices.add(serverName);
preferred = serverName;
}
}
if (wantedHost != null && !wantedHost.equals(""))
{
// given one overrides all others: add it and make it preferred:
hostChoices.add(wantedHost);
preferred = wantedHost;
}
// Just as paranoid fail-safe, should never happen:
else if (preferred == null)
{
preferred = "localhost";
}
else
{
// no name given - default to what we otherwise decided
// to be the "preferred" one.
// No asignment here - caller will assing his "hostname"
// be become what we give back
}
return preferred;
}
@Override
public Dimension getMinimumSize()
{
return new Dimension(350, 200);
}
@Override
public Dimension getPreferredSize()
{
return getMinimumSize();
}
@Override
public void dispose()
{
// Dispose dialog and notify main() so that game starts:
super.dispose();
synchronized (mutex)
{
mutex.notify();
}
}
private void doRunNetClient()
{
stOptions.setOption(Options.runClientPlayer, playerName);
stOptions.setOption(Options.runClientHost, hostname);
stOptions.setOption(Options.runClientPort, port);
// prepend used hostname to LRU list
saveHostname(netclientOptions);
saveWindow.save(this);
netclientOptions.saveOptions();
whatNextManager.setWhatToDoNext(WhatToDoNext.START_NET_CLIENT, false);
dispose();
}
/**
* Put the chosen hostname as first to the LRU sorted list
* in NetClient cf file.
*/
private void saveHostname(Options netclientOptions)
{
if (netclientOptions == null)
{
return;
}
List<String> names = new ArrayList<String>();
// Last used one to front of LRU list:
names.add(hostname);
for (int i = 0; i < Constants.numSavedServerNames; i++)
{
String serverName = netclientOptions
.getStringOption(Options.serverName + i);
if (serverName != null)
{
// Don't add it twice:
if (!serverName.equals(hostname))
{
names.add(serverName);
}
}
}
for (int i = 0; i < names.size() && i < Constants.numSavedServerNames; i++)
{
netclientOptions.setOption(Options.serverName + i, names.get(i));
}
}
}