package tools.map.xml.creator;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import com.google.common.collect.Maps;
import games.strategy.ui.SwingAction;
import games.strategy.ui.Util;
public class UnitPlacementsPanel extends ImageScrollPanePanel {
private final String[] players = MapXmlHelper.getPlayersListInclNeutral();
private UnitPlacementsPanel() {}
public static void layout(final MapXmlCreator mapXmlCreator) {
setMapXmlCreator(mapXmlCreator);
final UnitPlacementsPanel panel = new UnitPlacementsPanel();
panel.layout(mapXmlCreator.getStepActionPanel());
mapXmlCreator.setAutoFillAction(SwingAction.of(e -> {
panel.paintPreparation(null);
panel.repaint();
}));
}
@Override
protected void paintCenterSpecifics(final Graphics g, final String centerName, final FontMetrics fontMetrics,
final Point item, final int textStartX) {
final Map<String, Map<String, Integer>> placements = MapXmlHelper.getUnitPlacementsMap().get(centerName);
String placementString = "";
for (final Entry<String, Map<String, Integer>> placementEntry : placements.entrySet()) {
int totalPlacements = 0;
for (final Entry<String, Integer> playerPlacement : placementEntry.getValue().entrySet()) {
totalPlacements += playerPlacement.getValue();
}
if (totalPlacements > 0) {
if (placementString.length() > 0) {
placementString += " / ";
}
placementString +=
(placementEntry.getKey() == null ? "Neutral" : placementEntry.getKey()) + " " + totalPlacements;
}
}
if (placementString.length() > 0) {
final Rectangle2D placementStringBounds = fontMetrics.getStringBounds(placementString, g);
final Rectangle2D centerStringBounds = fontMetrics.getStringBounds(centerName, g);
final double wDiff = (centerStringBounds.getWidth() - placementStringBounds.getWidth()) / 2;
g.setColor(Color.yellow);
g.fillRect(Math.max(0, textStartX - 2 + (int) wDiff), item.y + 6, (int) placementStringBounds.getWidth() + 4,
(int) placementStringBounds.getHeight());
g.setColor(Color.red);
g.drawString(placementString, Math.max(0, textStartX + (int) wDiff), item.y + 17);
}
g.setColor(Color.red);
}
@Override
protected void paintPreparation(final Map<String, Point> centers) {
for (final String centerName : centers.keySet()) {
if (MapXmlHelper.getUnitPlacementsMap().get(centerName) == null) {
MapXmlHelper.putUnitPlacements(centerName, new HashMap<>());
}
}
}
@Override
protected void paintOwnSpecifics(final Graphics g, final Map<String, Point> centers) {}
@Override
protected void mouseClickedOnImage(final Map<String, Point> centers, final MouseEvent e) {
final Optional<String> terrNameOptional = Util.findTerritoryName(e.getPoint(), polygons);
if (!terrNameOptional.isPresent()) {
return;
}
final String territoryName = terrNameOptional.get();
final Map<String, Map<String, Integer>> placements = MapXmlHelper.getUnitPlacementsMap().get(territoryName);
String suggestedPlayer;
if (placements.isEmpty()) {
suggestedPlayer = MapXmlHelper.getTerritoryOwnershipsMap().get(territoryName);
} else {
suggestedPlayer = placements.keySet().iterator().next();
}
final String inputText = (String) JOptionPane.showInputDialog(null,
"For which player you want to place units in territory '" + territoryName + "'?",
"Choose Unit Owner for placement in "
+ territoryName,
JOptionPane.QUESTION_MESSAGE, null, players, // Array of choices
(suggestedPlayer == null ? players[0] : suggestedPlayer)); // Initial choice
if (inputText == null) {
return;
}
Map<String, Integer> playerPlacements = placements.get(inputText);
if (playerPlacements == null) {
playerPlacements = Maps.newLinkedHashMap();
// TODO: show unit panel and get new playerPlacements
}
final Dimension screenResolution = Toolkit.getDefaultToolkit().getScreenSize();
final int availHeight = screenResolution.height - 120;
final int availWidth = screenResolution.width - 40;
final TerritoryPlacementPanel territoryPlacementPanel = new TerritoryPlacementPanel(playerPlacements,
MapXmlHelper.getProductionFrontiersMap().get(inputText), territoryName, inputText);
final JScrollPane scroll = new JScrollPane(territoryPlacementPanel);
scroll.setBorder(BorderFactory.createEmptyBorder());
scroll.setPreferredSize(new Dimension((scroll.getPreferredSize().width > availWidth ? availWidth
: (scroll.getPreferredSize().width + (scroll.getPreferredSize().height > availHeight ? 20 : 0))),
(scroll.getPreferredSize().height > availHeight ? availHeight : (scroll
.getPreferredSize().height + (scroll.getPreferredSize().width > availWidth ? 26 : 0)))));
final int option = JOptionPane.showOptionDialog(null, scroll,
"Enter Unit Placements of player '" + inputText + "' in territory '" + territoryName + "'",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE, null, null, null);
if (option == JOptionPane.OK_OPTION) {
if (territoryPlacementPanel.placementsExist()) {
placements.put(inputText, territoryPlacementPanel.getPlayerPlacements());
} else {
placements.remove(inputText);
}
}
repaint();
}
class TerritoryPlacementPanel extends JPanel {
private static final long serialVersionUID = 6152898248749261730L;
private Map<String, Integer> playerPlacements = null;
public boolean placementsExist() {
for (final int value : playerPlacements.values()) {
if (value > 0) {
return true;
}
}
return false;
}
public TerritoryPlacementPanel(final Map<String, Integer> playerPlacements,
final List<String> playerUnitTypes, final String territory, final String player) {
super();
final TerritoryPlacementPanel me = this;
if (playerPlacements == null) {
throw new NullPointerException();
}
final JTextField[] countFields = new JTextField[playerUnitTypes.size()];
// copy playPlacements map
this.playerPlacements = playerPlacements.entrySet().stream()
.map(e -> new AbstractMap.SimpleEntry<>(e.getKey(), new Integer(e.getValue())))
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
this.setLayout(new GridBagLayout());
final JTextArea title = new JTextArea("Choose units");
title.setBackground(this.getBackground());
title.setEditable(false);
// title.setColumns(15);
title.setWrapStyleWord(true);
final Insets nullInsets = new Insets(0, 0, 0, 0);
this.add(title, new GridBagConstraints(0, 0, 7, 1, 0, 0.5, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL,
nullInsets, 0, 0));
// Buttons
final Dimension buttonDim = new Dimension(75, 20);
final JButton buttonPlaceNone = new JButton("Place None");
buttonPlaceNone.setPreferredSize(buttonDim);
buttonPlaceNone.addActionListener(e -> {
for (final JTextField countField : countFields) {
if (!countField.getText().equals("0")) {
countField.setText("0");
countField.requestFocus();
}
}
me.requestFocus();
me.updateUI();
});
final LinkedHashMap<String, Integer> allPlayerPlacements = new LinkedHashMap<>(playerPlacements);
final ArrayList<String> emptyPlayerUnitTypes = new ArrayList<>(playerUnitTypes);
emptyPlayerUnitTypes.removeAll(this.playerPlacements.keySet());
for (final String unitType : emptyPlayerUnitTypes) {
allPlayerPlacements.put(unitType, 0);
}
final JButton buttonReset = new JButton("Reset");
buttonReset.setPreferredSize(buttonDim);
buttonReset.addActionListener(e -> {
int fieldIndex = 0;
for (final Entry<String, Integer> placement : allPlayerPlacements.entrySet()) {
countFields[fieldIndex].setText(placement.getValue().toString());
countFields[fieldIndex].requestFocus();
++fieldIndex;
}
me.playerPlacements.putAll(playerPlacements);
me.requestFocus();
me.updateUI();
});
// Input lines
int rowIndex = 1;
final Dimension textFieldDim = new Dimension(25, 20);
for (final Entry<String, Integer> placement : allPlayerPlacements.entrySet()) {
final String unitType = placement.getKey();
this.add(new JLabel(unitType), new GridBagConstraints(1, rowIndex, 1, 1, 0, 0, GridBagConstraints.WEST,
GridBagConstraints.HORIZONTAL, nullInsets, 0, 0));
final JTextField textFieldCount = new JTextField(placement.getValue().toString());
textFieldCount.setPreferredSize(textFieldDim);
countFields[rowIndex - 1] = textFieldCount;
textFieldCount.addFocusListener(new FocusListener() {
final String unitTypeString = unitType;
String prevValue = textFieldCount.getText();
@Override
public void focusLost(final FocusEvent arg0) {
final String newValue = textFieldCount.getText().trim();
if (newValue.equals(prevValue)) {
return;
}
final int newValueInteger;
try {
newValueInteger = Integer.parseInt(newValue);
if (newValueInteger < 0) {
throw new NumberFormatException();
}
} catch (final NumberFormatException nfe) {
JOptionPane.showMessageDialog(me, "'" + newValue + "' is no valid integer value.", "Input error",
JOptionPane.ERROR_MESSAGE);
textFieldCount.setText(prevValue);
SwingUtilities.invokeLater(() -> textFieldCount.requestFocus());
return;
}
// LinkedHashMap<String, Integer> playerPlacements =
// MapXMLHelper.unitPlacements.get(territory).get(player);
if (me.playerPlacements == null) {
me.playerPlacements = Maps.newLinkedHashMap();
// MapXMLHelper.putunitPlacements.get(territory)(player, playerPlacements);
}
me.playerPlacements.put(unitTypeString, newValueInteger);
}
@Override
public void focusGained(final FocusEvent arg0) {
textFieldCount.selectAll();
}
});
this.add(textFieldCount, new GridBagConstraints(2, rowIndex, 1, 1, 0, 0, GridBagConstraints.WEST,
GridBagConstraints.HORIZONTAL, new Insets(0, 4, 0, 0), 0, 0));
rowIndex++;
}
this.add(buttonPlaceNone, new GridBagConstraints(0, rowIndex, 7, 1, 0, 0.5, GridBagConstraints.EAST,
GridBagConstraints.NONE, nullInsets, 0, 0));
this.add(buttonReset,
new GridBagConstraints(3, rowIndex, 7, 1, 0, 0.5, GridBagConstraints.EAST, GridBagConstraints.NONE,
nullInsets, 0, 0));
// return territoryPlacementPanel;
}
public Map<String, Integer> getPlayerPlacements() {
return playerPlacements;
}
}
}