package games.strategy.engine.framework.startup.ui;
import static com.google.common.base.Preconditions.checkNotNull;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import org.yaml.snakeyaml.Yaml;
import games.strategy.debug.ClientLogger;
import games.strategy.engine.ClientContext;
import games.strategy.engine.ClientFileSystemHelper;
import games.strategy.engine.config.GameEngineProperty;
import games.strategy.engine.config.PropertyReader;
import games.strategy.engine.framework.map.download.DownloadUtils;
import games.strategy.engine.framework.startup.mc.SetupPanelModel;
import games.strategy.engine.lobby.client.LobbyClient;
import games.strategy.engine.lobby.client.login.LobbyLogin;
import games.strategy.engine.lobby.client.login.LobbyServerProperties;
import games.strategy.engine.lobby.client.ui.LobbyFrame;
import games.strategy.triplea.UrlConstants;
import games.strategy.ui.SwingComponents;
import games.strategy.util.Version;
public class MetaSetupPanel extends SetupPanel {
private static final long serialVersionUID = 3926503672972937677L;
private JButton m_startLocal;
private JButton m_startPBEM;
private JButton m_hostGame;
private JButton m_connectToHostedGame;
private JButton m_connectToLobby;
private JButton m_enginePreferences;
private JButton m_ruleBook;
private JButton m_helpButton;
private final SetupPanelModel m_model;
public MetaSetupPanel(final SetupPanelModel model) {
this.m_model = model;
createComponents();
layoutComponents();
setupListeners();
setWidgetActivation();
}
private void createComponents() {
m_connectToLobby = new JButton("Play Online");
final Font bigButtonFont = new Font(m_connectToLobby.getFont().getName(), m_connectToLobby.getFont().getStyle(),
m_connectToLobby.getFont().getSize() + 3);
m_connectToLobby.setFont(bigButtonFont);
m_connectToLobby.setToolTipText("<html>Find Games Online on the Lobby Server. <br>"
+ "TripleA is MEANT to be played Online against other humans. <br>"
+ "Any other way is not as fun!</html>");
m_startLocal = new JButton("Start Local Game");
m_startLocal.setToolTipText("<html>Start a game on this computer. <br>"
+ "You can play against a friend sitting besides you (hotseat mode), <br>"
+ "or against one of the AIs.</html>");
m_startPBEM = new JButton("Start PBEM (Play-By-Email/Forum) Game");
m_startPBEM.setToolTipText("<html>Starts a game which will be emailed back and forth between all players, <br>"
+ "or be posted to an online forum or message board.</html>");
m_hostGame = new JButton("Host Networked Game");
m_hostGame.setToolTipText("<html>Hosts a network game, which people can connect to. <br>"
+ "Anyone on a LAN will be able to connect. <br>"
+ "Anyone from the internet can connect as well, but only if the host has configured port forwarding "
+ "correctly.</html>");
m_connectToHostedGame = new JButton("Connect to Networked Game");
m_connectToHostedGame
.setToolTipText("<html>Connects to someone's hosted game, <br>so long as you know their IP address.</html>");
m_enginePreferences = new JButton("Engine Preferences");
m_enginePreferences.setToolTipText("<html>Configure certain options related to the engine.");
m_ruleBook = new JButton("Rule Book");
m_helpButton = new JButton("Help");
m_ruleBook.setToolTipText("<html>Download a manual of how to play <br>"
+ "(it is also included in the directory TripleA was installed to).</html>");
}
private void layoutComponents() {
setLayout(new GridBagLayout());
// top space
add(new JPanel(), new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(00, 0, 0, 0), 0, 0));
add(m_connectToLobby, new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE,
new Insets(10, 0, 0, 0), 0, 0));
add(m_startLocal, new GridBagConstraints(0, 2, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE,
new Insets(10, 0, 0, 0), 0, 0));
add(m_startPBEM, new GridBagConstraints(0, 3, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE,
new Insets(10, 0, 0, 0), 0, 0));
add(m_hostGame, new GridBagConstraints(0, 4, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE,
new Insets(10, 0, 0, 0), 0, 0));
add(m_connectToHostedGame, new GridBagConstraints(0, 5, 1, 1, 0, 0, GridBagConstraints.CENTER,
GridBagConstraints.NONE, new Insets(10, 0, 0, 0), 0, 0));
add(m_enginePreferences, new GridBagConstraints(0, 6, 1, 1, 0, 0, GridBagConstraints.CENTER,
GridBagConstraints.NONE, new Insets(10, 0, 0, 0), 0, 0));
add(m_ruleBook, new GridBagConstraints(0, 8, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE,
new Insets(10, 0, 0, 0), 0, 0));
add(m_helpButton, new GridBagConstraints(0, 9, 1, 1, 0, 0, GridBagConstraints.CENTER, GridBagConstraints.NONE,
new Insets(10, 0, 0, 0), 0, 0));
// top space
add(new JPanel(), new GridBagConstraints(0, 100, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(00, 0, 0, 0), 0, 0));
}
private void setupListeners() {
m_startLocal.addActionListener(e -> m_model.showLocal());
m_startPBEM.addActionListener(e -> m_model.showPBEM());
m_hostGame.addActionListener(e -> m_model.showServer(MetaSetupPanel.this));
m_connectToHostedGame.addActionListener(e -> m_model.showClient(MetaSetupPanel.this));
m_connectToLobby.addActionListener(e -> connectToLobby());
m_enginePreferences.addActionListener(e -> enginePreferences());
m_ruleBook.addActionListener(e -> ruleBook());
m_helpButton.addActionListener(e -> helpPage());
}
private static void ruleBook() {
SwingComponents.newOpenUrlConfirmationDialog(UrlConstants.RULE_BOOK);
}
private static void helpPage() {
SwingComponents.newOpenUrlConfirmationDialog(UrlConstants.GITHUB_HELP);
}
private void enginePreferences() {
EnginePreferences.showEnginePreferences(this);
}
private void connectToLobby() {
final LobbyServerProperties props = getLobbyServerProperties();
final LobbyLogin login = new LobbyLogin(JOptionPane.getFrameForComponent(this), props);
final LobbyClient client = login.login();
if (client == null) {
return;
}
final LobbyFrame lobbyFrame = new LobbyFrame(client, props);
MainFrame.getInstance().setVisible(false);
MainFrame.getInstance().dispose();
lobbyFrame.setVisible(true);
}
private static Optional<List<Map<String, Object>>> loadYaml(final File yamlFile) {
String yamlContent;
try {
yamlContent = new String(Files.readAllBytes(yamlFile.toPath()));
} catch (final IOException e) {
ClientLogger.logQuietly("Failed to read from: " + yamlFile.getAbsolutePath(), e);
return Optional.empty();
}
final Yaml yaml = new Yaml();
@SuppressWarnings("unchecked")
final List<Map<String, Object>> yamlDataObj = (List<Map<String, Object>>) yaml.load(yamlContent);
if (yamlDataObj == null) {
return Optional.empty();
} else {
return Optional.of(yamlDataObj);
}
}
private static LobbyServerProperties getLobbyServerProperties() {
final PropertyReader propReader = ClientContext.propertyReader();
final String urlProp = propReader.readProperty(GameEngineProperty.LOBBY_PROPS_URL);
final File propFile = ClientFileSystemHelper.createTempFile();
try {
DownloadUtils.downloadFile(urlProp, propFile);
} catch (final IOException e) {
ClientLogger.logQuietly(
"Failed to download lobby server props file: " + urlProp + ", using the backup local property file instead.",
e);
}
Optional<List<Map<String, Object>>> yamlDataObj = loadYaml(propFile);
if (!yamlDataObj.isPresent()) {
// try reading properties from the local file as a backup
final String localFileProp = propReader.readProperty(GameEngineProperty.LOBBY_PROPS_BACKUP_FILE);
final File localFile = new File(ClientFileSystemHelper.getRootFolder(), localFileProp);
yamlDataObj = loadYaml(localFile);
if (!yamlDataObj.isPresent()) {
throw new IllegalStateException(
"Failed to read lobby properties from both: " + urlProp + ", and: " + localFile.getAbsolutePath());
}
}
final Map<String, Object> yamlProps = matchCurrentVersion(yamlDataObj.get());
final LobbyServerProperties lobbyProps = new LobbyServerProperties(yamlProps);
return lobbyProps;
}
private static Map<String, Object> matchCurrentVersion(final List<Map<String, Object>> lobbyProps) {
checkNotNull(lobbyProps);
final Version currentVersion = ClientContext.engineVersion().getVersion();
final Optional<Map<String, Object>> matchingVersionProps = lobbyProps.stream()
.filter(props -> currentVersion.equals(props.get("version")))
.findFirst();
return matchingVersionProps.orElse(lobbyProps.get(0));
}
@Override
public void setWidgetActivation() {
if (m_model == null || m_model.getGameSelectorModel() == null
|| m_model.getGameSelectorModel().getGameData() == null) {
m_startLocal.setEnabled(false);
m_startPBEM.setEnabled(false);
m_hostGame.setEnabled(false);
} else {
m_startLocal.setEnabled(true);
m_startPBEM.setEnabled(true);
m_hostGame.setEnabled(true);
}
}
@Override
public boolean canGameStart() {
// we cannot start
return false;
}
@Override
public void shutDown() {}
@Override
public boolean isMetaSetupPanelInstance() {
return true;
}
@Override
public void cancel() {
// nothing to do
}
}