package games.strategy.triplea;
import java.awt.Frame;
import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.swing.SwingUtilities;
import games.strategy.debug.ClientLogger;
import games.strategy.engine.data.GameData;
import games.strategy.engine.data.IUnitFactory;
import games.strategy.engine.data.PlayerID;
import games.strategy.engine.data.Unit;
import games.strategy.engine.data.UnitType;
import games.strategy.engine.framework.IGame;
import games.strategy.engine.framework.IGameLoader;
import games.strategy.engine.framework.LocalPlayers;
import games.strategy.engine.framework.ServerGame;
import games.strategy.engine.gamePlayer.IGamePlayer;
import games.strategy.engine.message.IChannelSubscribor;
import games.strategy.engine.message.IRemote;
import games.strategy.sound.ClipPlayer;
import games.strategy.sound.DefaultSoundChannel;
import games.strategy.sound.HeadlessSoundChannel;
import games.strategy.sound.ISound;
import games.strategy.sound.SoundPath;
import games.strategy.triplea.ai.fastAI.FastAI;
import games.strategy.triplea.ai.proAI.ProAI;
import games.strategy.triplea.ai.weakAI.DoesNothingAI;
import games.strategy.triplea.ai.weakAI.WeakAI;
import games.strategy.triplea.delegate.EditDelegate;
import games.strategy.triplea.player.ITripleAPlayer;
import games.strategy.triplea.ui.HeadlessUIContext;
import games.strategy.triplea.ui.IUIContext;
import games.strategy.triplea.ui.TripleAFrame;
import games.strategy.triplea.ui.display.HeadlessDisplay;
import games.strategy.triplea.ui.display.ITripleADisplay;
import games.strategy.triplea.ui.display.TripleADisplay;
@MapSupport
public class TripleA implements IGameLoader {
private static final long serialVersionUID = -8374315848374732436L;
public static final String HUMAN_PLAYER_TYPE = "Human";
public static final String WEAK_COMPUTER_PLAYER_TYPE = "Easy (AI)";
public static final String FAST_COMPUTER_PLAYER_TYPE = "Fast (AI)";
public static final String PRO_COMPUTER_PLAYER_TYPE = "Hard (AI)";
public static final String DOESNOTHINGAI_COMPUTER_PLAYER_TYPE = "Does Nothing (AI)";
protected transient ITripleADisplay display;
protected transient ISound soundChannel;
protected transient IGame game;
@Override
public Set<IGamePlayer> createPlayers(final Map<String, String> playerNames) {
final Set<IGamePlayer> players = new HashSet<>();
for (final String name : playerNames.keySet()) {
final String type = playerNames.get(name);
if (type.equals(WEAK_COMPUTER_PLAYER_TYPE)) {
players.add(new WeakAI(name, type));
} else if (type.equals(FAST_COMPUTER_PLAYER_TYPE)) {
players.add(new FastAI(name, type));
} else if (type.equals(PRO_COMPUTER_PLAYER_TYPE)) {
players.add(new ProAI(name, type));
} else if (type.equals(DOESNOTHINGAI_COMPUTER_PLAYER_TYPE)) {
players.add(new DoesNothingAI(name, type));
} else if (type.equals(HUMAN_PLAYER_TYPE) || type.equals(CLIENT_PLAYER_TYPE)) {
final TripleAPlayer player = new TripleAPlayer(name, type);
players.add(player);
} else {
throw new IllegalStateException("Player type not recognized:" + type);
}
}
return players;
}
@Override
public void shutDown() {
if (game != null && soundChannel != null) {
game.removeSoundChannel(soundChannel);
// set sound channel to null to handle the case of shutdown being called multiple times.
// If/when shutdown is called exactly once, then the null assignment should be unnecessary.
soundChannel = null;
}
if (display != null) {
game.removeDisplay(display);
display.shutDown();
display = null;
}
}
@Override
public void startGame(final IGame game, final Set<IGamePlayer> players, final boolean headless)
throws InvocationTargetException {
this.game = game;
if (game.getData().getDelegateList().getDelegate("edit") == null) {
// An evil hack: instead of modifying the XML, force an EditDelegate by adding one here
final EditDelegate delegate = new EditDelegate();
delegate.initialize("edit", "edit");
game.getData().getDelegateList().addDelegate(delegate);
if (game instanceof ServerGame) {
((ServerGame) game).addDelegateMessenger(delegate);
}
}
final LocalPlayers localPlayers = new LocalPlayers(players);
if (headless) {
final IUIContext uiContext = new HeadlessUIContext();
uiContext.setDefaultMapDir(game.getData());
uiContext.setLocalPlayers(localPlayers);
display = new HeadlessDisplay();
soundChannel = new HeadlessSoundChannel();
game.addDisplay(display);
game.addSoundChannel(soundChannel);
// technically not needed because we won't have any "local human players" in a headless game.
connectPlayers(players, null);
} else {
try {
SwingUtilities.invokeAndWait(() -> {
final TripleAFrame frame;
frame = new TripleAFrame(game, localPlayers);
display = new TripleADisplay(frame);
game.addDisplay(display);
soundChannel = new DefaultSoundChannel(localPlayers);
game.addSoundChannel(soundChannel);
frame.setSize(700, 400);
frame.setVisible(true);
ClipPlayer.play(SoundPath.CLIP_GAME_START);
connectPlayers(players, frame);
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.toFront();
});
} catch (InterruptedException e) {
ClientLogger.logQuietly(e);
}
}
}
private static void connectPlayers(final Set<IGamePlayer> players, final TripleAFrame frame) {
for (final IGamePlayer player : players) {
if (player instanceof TripleAPlayer) {
((TripleAPlayer) player).setFrame(frame);
}
}
}
/**
* Return an array of player types that can play on the server.
*/
@Override
public String[] getServerPlayerTypes() {
return new String[] {HUMAN_PLAYER_TYPE, WEAK_COMPUTER_PLAYER_TYPE, FAST_COMPUTER_PLAYER_TYPE,
PRO_COMPUTER_PLAYER_TYPE, DOESNOTHINGAI_COMPUTER_PLAYER_TYPE};
}
@Override
public Class<? extends IChannelSubscribor> getDisplayType() {
return ITripleADisplay.class;
}
@Override
public Class<? extends IChannelSubscribor> getSoundType() {
return ISound.class;
}
@Override
public Class<? extends IRemote> getRemotePlayerType() {
return ITripleAPlayer.class;
}
@Override
public IUnitFactory getUnitFactory() {
return new IUnitFactory() {
private static final long serialVersionUID = 5684926837825766505L;
@Override
public Unit createUnit(final UnitType type, final PlayerID owner, final GameData data) {
return new TripleAUnit(type, owner, data);
}
};
}
}