package games.strategy.engine.data.gameparser;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import games.strategy.debug.ClientLogger;
import games.strategy.engine.data.Attachable;
import games.strategy.engine.data.GameData;
import games.strategy.engine.data.IAttachment;
import games.strategy.engine.delegate.IDelegate;
import games.strategy.engine.xml.TestAttachment;
import games.strategy.engine.xml.TestDelegate;
import games.strategy.triplea.attachments.CanalAttachment;
import games.strategy.triplea.attachments.PlayerAttachment;
import games.strategy.triplea.attachments.PoliticalActionAttachment;
import games.strategy.triplea.attachments.RelationshipTypeAttachment;
import games.strategy.triplea.attachments.RulesAttachment;
import games.strategy.triplea.attachments.TechAbilityAttachment;
import games.strategy.triplea.attachments.TechAttachment;
import games.strategy.triplea.attachments.TerritoryAttachment;
import games.strategy.triplea.attachments.TerritoryEffectAttachment;
import games.strategy.triplea.attachments.TriggerAttachment;
import games.strategy.triplea.attachments.UnitAttachment;
import games.strategy.triplea.attachments.UnitSupportAttachment;
import games.strategy.triplea.attachments.UserActionAttachment;
import games.strategy.triplea.delegate.BattleDelegate;
import games.strategy.triplea.delegate.BidPlaceDelegate;
import games.strategy.triplea.delegate.BidPurchaseDelegate;
import games.strategy.triplea.delegate.EndRoundDelegate;
import games.strategy.triplea.delegate.EndTurnDelegate;
import games.strategy.triplea.delegate.InitializationDelegate;
import games.strategy.triplea.delegate.MoveDelegate;
import games.strategy.triplea.delegate.NoAirCheckPlaceDelegate;
import games.strategy.triplea.delegate.NoPUEndTurnDelegate;
import games.strategy.triplea.delegate.NoPUPurchaseDelegate;
import games.strategy.triplea.delegate.PlaceDelegate;
import games.strategy.triplea.delegate.PoliticsDelegate;
import games.strategy.triplea.delegate.PurchaseDelegate;
import games.strategy.triplea.delegate.RandomStartDelegate;
import games.strategy.triplea.delegate.SpecialMoveDelegate;
import games.strategy.triplea.delegate.TechActivationDelegate;
import games.strategy.triplea.delegate.TechnologyDelegate;
import games.strategy.triplea.delegate.UserActionDelegate;
import games.strategy.twoIfBySea.delegate.InitDelegate;
/**
* This class creates objects referred to by game XMLs via the 'javaClass' property, eg:
*
* <pre>
* <attachment name="territoryAttachment" attachTo="Rason"
* javaClass="games.strategy.triplea.attachments.TerritoryAttachment" type="territory">
* </pre>
*
* <p>
* In the above example, we are going to map the String value "games.strategy.triplea.attachments.TerritoryAttachment"
* to a class constructor.
* </p>
*
* <p>
* Note: attachments and delegates are initialized slightly differently, one is is no-arg the other has initialization
* parameters.
* </p>
*/
public class XmlGameElementMapper {
// these keys are package protected to allow test to have access to known good keys
@VisibleForTesting
static final String BATTLE_DELEGATE_NAME = "games.strategy.triplea.delegate.BattleDelegate";
@VisibleForTesting
static final String CANAL_ATTACHMENT_NAME = "games.strategy.triplea.attachments.CanalAttachment";
/* Maps a name (given as an XML attribute value) to a supplier function that creates the corresponding delegate */
private final ImmutableMap<String, Supplier<IDelegate>> delegateMap =
ImmutableMap.<String, Supplier<IDelegate>>builder()
.put(BATTLE_DELEGATE_NAME, BattleDelegate::new)
.put("games.strategy.triplea.delegate.BidPlaceDelegate", BidPlaceDelegate::new)
.put("games.strategy.triplea.delegate.BidPurchaseDelegate", BidPurchaseDelegate::new)
.put("games.strategy.triplea.delegate.EndRoundDelegate", EndRoundDelegate::new)
.put("games.strategy.triplea.delegate.EndTurnDelegate", EndTurnDelegate::new)
.put("games.strategy.triplea.delegate.InitializationDelegate", InitializationDelegate::new)
.put("games.strategy.triplea.delegate.MoveDelegate", MoveDelegate::new)
.put("games.strategy.triplea.delegate.NoAirCheckPlaceDelegate", NoAirCheckPlaceDelegate::new)
.put("games.strategy.triplea.delegate.NoPUEndTurnDelegate", NoPUEndTurnDelegate::new)
.put("games.strategy.triplea.delegate.NoPUPurchaseDelegate", NoPUPurchaseDelegate::new)
.put("games.strategy.triplea.delegate.PlaceDelegate", PlaceDelegate::new)
.put("games.strategy.triplea.delegate.PoliticsDelegate", PoliticsDelegate::new)
.put("games.strategy.triplea.delegate.PurchaseDelegate", PurchaseDelegate::new)
.put("games.strategy.triplea.delegate.RandomStartDelegate", RandomStartDelegate::new)
.put("games.strategy.triplea.delegate.SpecialMoveDelegate", SpecialMoveDelegate::new)
.put("games.strategy.triplea.delegate.TechActivationDelegate", TechActivationDelegate::new)
.put("games.strategy.triplea.delegate.TechnologyDelegate", TechnologyDelegate::new)
.put("games.strategy.triplea.delegate.UserActionDelegate", UserActionDelegate::new)
.put("games.strategy.twoIfBySea.delegate.EndTurnDelegate",
games.strategy.twoIfBySea.delegate.EndTurnDelegate::new)
.put("games.strategy.twoIfBySea.delegate.InitDelegate", InitDelegate::new)
.put("games.strategy.twoIfBySea.delegate.PlaceDelegate",
games.strategy.twoIfBySea.delegate.PlaceDelegate::new)
.put("games.strategy.engine.xml.TestDelegate", TestDelegate::new)
.build();
/*
* Maps a name (given as an XML attribute value) to a function that can create attachment objects.
*/
private final ImmutableMap<String, Function<AttachmentData, IAttachment>> attachmentMap =
ImmutableMap.<String, Function<AttachmentData, IAttachment>>builder()
.put(CANAL_ATTACHMENT_NAME, attachmentData -> new CanalAttachment(attachmentData.name,
attachmentData.attachable, attachmentData.gameData))
.put("games.strategy.triplea.attachments.PlayerAttachment",
attachmentData -> new PlayerAttachment(attachmentData.name, attachmentData.attachable,
attachmentData.gameData))
.put("games.strategy.triplea.attachments.PoliticalActionAttachment",
attachmentData -> new PoliticalActionAttachment(attachmentData.name, attachmentData.attachable,
attachmentData.gameData))
.put("games.strategy.triplea.attachments.RelationshipTypeAttachment",
attachmentData -> new RelationshipTypeAttachment(attachmentData.name, attachmentData.attachable,
attachmentData.gameData))
.put("games.strategy.triplea.attachments.RulesAttachment",
attachmentData -> new RulesAttachment(attachmentData.name, attachmentData.attachable,
attachmentData.gameData))
.put("games.strategy.triplea.attachments.TechAbilityAttachment",
attachmentData -> new TechAbilityAttachment(attachmentData.name, attachmentData.attachable,
attachmentData.gameData))
.put("games.strategy.triplea.attachments.TechAttachment", attachmentData ->
new TechAttachment(attachmentData.name, attachmentData.attachable, attachmentData.gameData))
.put("games.strategy.triplea.attachments.TerritoryAttachment",
attachmentData -> new TerritoryAttachment(attachmentData.name, attachmentData.attachable,
attachmentData.gameData))
.put("games.strategy.triplea.attachments.TerritoryEffectAttachment",
attachmentData -> new TerritoryEffectAttachment(attachmentData.name, attachmentData.attachable,
attachmentData.gameData))
.put("games.strategy.triplea.attachments.TriggerAttachment",
attachmentData -> new TriggerAttachment(attachmentData.name, attachmentData.attachable,
attachmentData.gameData))
.put("games.strategy.triplea.attachments.UnitAttachment",
attachmentData -> new UnitAttachment(attachmentData.name, attachmentData.attachable,
attachmentData.gameData))
.put("games.strategy.triplea.attachments.UnitSupportAttachment",
attachmentData -> new UnitSupportAttachment(attachmentData.name, attachmentData.attachable,
attachmentData.gameData))
.put("games.strategy.triplea.attachments.UserActionAttachment",
attachmentData -> new UserActionAttachment(attachmentData.name, attachmentData.attachable,
attachmentData.gameData))
.put("games.strategy.engine.xml.TestAttachment", attachmentData -> new TestAttachment(attachmentData.name,
attachmentData.attachable, attachmentData.gameData))
.build();
/** Small data holder class. */
private static class AttachmentData {
private final String name;
private final Attachable attachable;
private final GameData gameData;
AttachmentData(String name, Attachable attachable, GameData gameData) {
this.name = name;
this.attachable = attachable;
this.gameData = gameData;
}
}
/**
* Loads a new instance of the given class.
* Assumes a zero argument constructor.
*/
public Optional<IDelegate> getDelegate(final String className) {
if (!delegateMap.containsKey(className)) {
handleMissingObjectError("delegate", className);
return Optional.empty();
}
Supplier<IDelegate> delegateFactory = delegateMap.get(className);
return Optional.of(delegateFactory.get());
}
private static void handleMissingObjectError(String typeLabel, String value) {
ClientLogger.logError("Could not find " + typeLabel + " '" + value + "'. This is can be a map configuration"
+ " problem, and would need to be fixed in the map XML. Or, the map XML is using a feature from a newer game"
+ " engine version, and you will need to install the latest TripleA for it to be enabled. Meanwhile, the"
+ " functionality provided by this " + typeLabel + " will not available.");
}
public Optional<IAttachment> getAttachment(String javaClass, String name, Attachable attachable, GameData data) {
if (!attachmentMap.containsKey(javaClass)) {
handleMissingObjectError("attachment", javaClass);
return Optional.empty();
}
final Function<AttachmentData, IAttachment> attachmentFactoryFunction = attachmentMap.get(javaClass);
return Optional.of(attachmentFactoryFunction.apply(new AttachmentData(name, attachable, data)));
}
}