package games.strategy.triplea.ui;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.util.Collection;
import java.util.Collections;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import games.strategy.engine.data.GameData;
import games.strategy.engine.data.PlayerID;
import games.strategy.engine.data.Territory;
import games.strategy.engine.data.Unit;
import games.strategy.engine.gamePlayer.IPlayerBridge;
import games.strategy.triplea.attachments.PlayerAttachment;
import games.strategy.triplea.delegate.GameStepPropertiesHelper;
import games.strategy.triplea.delegate.Matches;
import games.strategy.triplea.delegate.dataObjects.PlaceableUnits;
import games.strategy.triplea.delegate.remote.IAbstractPlaceDelegate;
import games.strategy.triplea.util.UnitCategory;
import games.strategy.triplea.util.UnitSeperator;
import games.strategy.util.CompositeMatch;
import games.strategy.util.CompositeMatchOr;
import games.strategy.util.Match;
public class PlacePanel extends AbstractMovePanel {
private static final long serialVersionUID = -4411301492537704785L;
private final JLabel actionLabel = new JLabel();
private final JLabel m_leftToPlaceLabel = new JLabel();
private PlaceData m_placeData;
private final SimpleUnitPanel m_unitsToPlace;
/** Creates new PlacePanel. */
public PlacePanel(final GameData data, final MapPanel map, final TripleAFrame frame) {
super(data, map, frame);
m_undoableMovesPanel = new UndoablePlacementsPanel(data, this);
m_unitsToPlace = new SimpleUnitPanel(map.getUIContext());
m_leftToPlaceLabel.setText("Units left to place:");
}
@Override
public void display(final PlayerID id) {
super.display(id, " place");
}
private void refreshActionLabelText(final boolean bid) {
SwingUtilities
.invokeLater(() -> actionLabel.setText(getCurrentPlayer().getName() + " place" + (bid ? " for bid" : "")));
}
public PlaceData waitForPlace(final boolean bid, final IPlayerBridge playerBridge) {
setUp(playerBridge);
// workaround: meant to be in setUpSpecific, but it requires a variable
refreshActionLabelText(bid);
waitForRelease();
cleanUp();
return m_placeData;
}
private boolean canProduceFightersOnCarriers() {
return games.strategy.triplea.Properties.getProduceFightersOnCarriers(getData());
}
private boolean canProduceNewFightersOnOldCarriers() {
return games.strategy.triplea.Properties.getProduceNewFightersOnOldCarriers(getData());
}
private boolean isLHTR_Carrier_Production_Rules() {
return games.strategy.triplea.Properties.getLHTRCarrierProductionRules(getData());
}
private final MapSelectionListener PLACE_MAP_SELECTION_LISTENER = new DefaultMapSelectionListener() {
@Override
public void territorySelected(final Territory territory, final MouseDetails e) {
if (!getActive() || (e.getButton() != MouseEvent.BUTTON1)) {
return;
}
final int[] maxUnits = new int[1];
final Collection<Unit> units = getUnitsToPlace(territory, maxUnits);
if (units.isEmpty()) {
return;
}
final UnitChooser chooser =
new UnitChooser(units, Collections.emptyMap(), getData(), false, getMap().getUIContext());
final String messageText = "Place units in " + territory.getName();
if (maxUnits[0] >= 0) {
chooser.setMaxAndShowMaxButton(maxUnits[0]);
}
final Dimension screenResolution = Toolkit.getDefaultToolkit().getScreenSize();
final int availHeight = screenResolution.height - 120;
final int availWidth = screenResolution.width - 40;
final JScrollPane scroll = new JScrollPane(chooser);
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(getTopLevelAncestor(), scroll, messageText,
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, null, null);
if (option == JOptionPane.OK_OPTION) {
final Collection<Unit> choosen = chooser.getSelected();
m_placeData = new PlaceData(choosen, territory);
updateUnits();
if (choosen.containsAll(units)) {
m_leftToPlaceLabel.setText("");
}
release();
}
}
};
private Collection<Unit> getUnitsToPlace(final Territory territory, final int[] maxUnits) {
getData().acquireReadLock();
try {
// not our territory
if (!territory.isWater() && !territory.getOwner().equals(getCurrentPlayer())) {
if (GameStepPropertiesHelper.isBid(getData())) {
final PlayerAttachment pa = PlayerAttachment.get(territory.getOwner());
if ((pa == null || pa.getGiveUnitControl() == null || !pa.getGiveUnitControl().contains(getCurrentPlayer()))
&& !territory.getUnits().someMatch(Matches.unitIsOwnedBy(getCurrentPlayer()))) {
return Collections.emptyList();
}
} else {
return Collections.emptyList();
}
}
// get the units that can be placed on this territory.
Collection<Unit> units = getCurrentPlayer().getUnits().getUnits();
if (territory.isWater()) {
if (!(canProduceFightersOnCarriers() || canProduceNewFightersOnOldCarriers()
|| isLHTR_Carrier_Production_Rules() || GameStepPropertiesHelper.isBid(getData()))) {
units = Match.getMatches(units, Matches.UnitIsSea);
} else {
final CompositeMatch<Unit> unitIsSeaOrCanLandOnCarrier =
new CompositeMatchOr<>(Matches.UnitIsSea, Matches.UnitCanLandOnCarrier);
units = Match.getMatches(units, unitIsSeaOrCanLandOnCarrier);
}
} else {
units = Match.getMatches(units, Matches.UnitIsNotSea);
}
if (units.isEmpty()) {
return Collections.emptyList();
}
final IAbstractPlaceDelegate placeDel = (IAbstractPlaceDelegate) getPlayerBridge().getRemoteDelegate();
final PlaceableUnits production = placeDel.getPlaceableUnits(units, territory);
if (production.isError()) {
JOptionPane.showMessageDialog(getTopLevelAncestor(), production.getErrorMessage(), "No units",
JOptionPane.INFORMATION_MESSAGE);
return Collections.emptyList();
}
maxUnits[0] = production.getMaxUnits();
return production.getUnits();
} finally {
getData().releaseReadLock();
}
}
private void updateUnits() {
final Collection<UnitCategory> unitCategories = UnitSeperator.categorize(getCurrentPlayer().getUnits().getUnits());
m_unitsToPlace.setUnitsFromCategories(unitCategories, getData());
}
@Override
public String toString() {
return "PlacePanel";
}
@Override
protected final void cancelMoveAction() {
getMap().showMouseCursor();
getMap().setMouseShadowUnits(null);
}
@Override
protected final void undoMoveSpecific() {
m_leftToPlaceLabel.setText("Units left to place:");
updateUnits();
}
@Override
protected final void cleanUpSpecific() {
getMap().removeMapSelectionListener(PLACE_MAP_SELECTION_LISTENER);
}
@Override
protected final void setUpSpecific() {
getMap().addMapSelectionListener(PLACE_MAP_SELECTION_LISTENER);
}
@Override
protected boolean doneMoveAction() {
if (getCurrentPlayer().getUnits().size() > 0) {
final int option = JOptionPane.showConfirmDialog(getTopLevelAncestor(),
"You have not placed all your units yet. Are you sure you want to end your turn?", "TripleA",
JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE);
// TODO COMCO add code here to store the units until next time
if (option != JOptionPane.YES_OPTION) {
return false;
}
}
m_placeData = null;
return true;
}
@Override
protected boolean setCancelButton() {
return false;
}
@Override
protected final void addAdditionalButtons() {
add(leftBox(m_leftToPlaceLabel));
add(m_unitsToPlace);
updateUnits();
}
}