package games.strategy.engine.data.changefactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import games.strategy.engine.data.Attachable;
import games.strategy.engine.data.BombingUnitDamageChange;
import games.strategy.engine.data.Change;
import games.strategy.engine.data.ChangeAttachmentChange;
import games.strategy.engine.data.CompositeChange;
import games.strategy.engine.data.GameData;
import games.strategy.engine.data.IAttachment;
import games.strategy.engine.data.PlayerID;
import games.strategy.engine.data.ProductionFrontier;
import games.strategy.engine.data.ProductionRule;
import games.strategy.engine.data.RelationshipType;
import games.strategy.engine.data.Resource;
import games.strategy.engine.data.ResourceCollection;
import games.strategy.engine.data.TechnologyFrontier;
import games.strategy.engine.data.Territory;
import games.strategy.engine.data.Unit;
import games.strategy.engine.data.UnitHitsChange;
import games.strategy.triplea.TripleAUnit;
import games.strategy.triplea.attachments.TechAttachment;
import games.strategy.triplea.delegate.TechAdvance;
import games.strategy.triplea.delegate.dataObjects.BattleRecords;
import games.strategy.util.IntegerMap;
/**
* All changes made to GameData should be made through changes produced here.
*
* <p>
* The way to change game data is to
* </p>
*
* <ol>
* <li>Create a change with a ChangeFactory.change** or ChangeFactory.set** method</li>
* <li>Execute that change through DelegateBridge.addChange()</li>
* </ol>
*
* <p>
* In this way changes to the game data can be co-ordinated across the network.
* </p>
*/
public class ChangeFactory {
public static final Change EMPTY_CHANGE = new Change() {
private static final long serialVersionUID = -5514560889478876641L;
@Override
protected void perform(final GameData data) {}
@Override
public Change invert() {
return this;
}
// when de-serializing, always return the singleton
private Object readResolve() {
return ChangeFactory.EMPTY_CHANGE;
}
@Override
public boolean isEmpty() {
return true;
}
};
public static Change changeOwner(final Territory territory, final PlayerID owner) {
return new OwnerChange(territory, owner);
}
public static Change changeOwner(final Collection<Unit> units, final PlayerID owner, final Territory location) {
return new PlayerOwnerChange(units, owner, location);
}
public static Change changeOwner(final Unit unit, final PlayerID owner, final Territory location) {
final ArrayList<Unit> list = new ArrayList<>(1);
list.add(unit);
return new PlayerOwnerChange(list, owner, location);
}
public static Change addUnits(final Territory territory, final Collection<Unit> units) {
return new AddUnits(territory.getUnits(), units);
}
public static Change removeUnits(final Territory territory, final Collection<Unit> units) {
return new RemoveUnits(territory.getUnits(), units);
}
public static Change addUnits(final PlayerID player, final Collection<Unit> units) {
return new AddUnits(player.getUnits(), units);
}
public static Change removeUnits(final PlayerID player, final Collection<Unit> units) {
return new RemoveUnits(player.getUnits(), units);
}
public static Change moveUnits(final Territory start, final Territory end, Collection<Unit> units) {
units = new ArrayList<>(units);
final List<Change> changes = new ArrayList<>(2);
changes.add(removeUnits(start, units));
changes.add(addUnits(end, units));
return new CompositeChange(changes);
}
public static Change changeProductionFrontier(final PlayerID player, final ProductionFrontier frontier) {
return new ProductionFrontierChange(frontier, player);
}
public static Change changePlayerWhoAmIChange(final PlayerID player, final String humanOrAI_colon_playerName) {
return new PlayerWhoAmIChange(humanOrAI_colon_playerName, player);
}
public static Change changeResourcesChange(final PlayerID player, final Resource resource, final int quantity) {
return new ChangeResourceChange(player, resource, quantity);
}
public static Change removeResourceCollection(final PlayerID id, final ResourceCollection rCollection) {
final CompositeChange cChange = new CompositeChange();
for (final Resource r : rCollection.getResourcesCopy().keySet()) {
cChange.add(new ChangeResourceChange(id, r, -rCollection.getQuantity(r)));
}
return cChange;
}
public static Change setProperty(final String property, final Object value, final GameData data) {
return new SetPropertyChange(property, value, data.getProperties());
}
/**
* Must already include existing damage to the unit. This does not add damage, it sets damage.
*/
public static Change unitsHit(final IntegerMap<Unit> newHits) {
return new UnitHitsChange(newHits);
}
/**
* Must already include existing damage to the unit. This does not add damage, it sets damage.
*/
public static Change bombingUnitDamage(final IntegerMap<Unit> newDamage) {
return new BombingUnitDamageChange(newDamage);
}
public static Change addProductionRule(final ProductionRule rule, final ProductionFrontier frontier) {
return new AddProductionRule(rule, frontier);
}
public static Change removeProductionRule(final ProductionRule rule, final ProductionFrontier frontier) {
return new RemoveProductionRule(rule, frontier);
}
public static Change addAvailableTech(final TechnologyFrontier tf, final TechAdvance ta, final PlayerID player) {
return new AddAvailableTech(tf, ta, player);
}
public static Change removeAvailableTech(final TechnologyFrontier tf, final TechAdvance ta, final PlayerID player) {
return new RemoveAvailableTech(tf, ta, player);
}
public static Change attachmentPropertyChange(final IAttachment attachment, final Object newValue,
final String property) {
return new ChangeAttachmentChange(attachment, newValue, property);
}
/**
* You don't want to clear the variable first unless you are setting some variable where the setting method is
* actually adding things to a
* list rather than overwriting.
*/
public static Change attachmentPropertyChange(final IAttachment attachment, final Object newValue,
final String property, final boolean resetFirst) {
return new ChangeAttachmentChange(attachment, newValue, property, resetFirst);
}
/**
* You don't want to clear the variable first unless you are setting some variable where the setting method is
* actually adding things to a
* list rather than overwriting.
*/
public static Change attachmentPropertyChange(final Attachable attachment, final String attachmentName,
final Object newValue, final Object oldValue, final String property, final boolean clearFirst) {
return new ChangeAttachmentChange(attachment, attachmentName, newValue, oldValue, property, clearFirst);
}
/**
* You don't want to clear the variable first unless you are setting some variable where the setting method is
* actually adding things to a
* list rather than overwriting.
*/
public static Change attachmentPropertyReset(final IAttachment attachment, final String property) {
return new AttachmentPropertyReset(attachment, property);
}
public static Change genericTechChange(final TechAttachment attachment, final boolean value, final String property) {
return new GenericTechChange(attachment, value, property);
}
public static Change unitPropertyChange(final Unit unit, final Object newValue, final String propertyName) {
return new ObjectPropertyChange(unit, propertyName, newValue);
}
public static Change addBattleRecords(final BattleRecords records, final GameData data) {
return new AddBattleRecordsChange(records, data);
}
/** Creates new ChangeFactory. No need */
private ChangeFactory() {}
/**
* Creates a change of relationshipType between 2 players, for example: change Germany-France relationship from
* neutral to war.
*
* @return the Change of relationship between 2 players
*/
public static Change relationshipChange(final PlayerID player, final PlayerID player2,
final RelationshipType currentRelation, final RelationshipType newRelation) {
return new RelationshipChange(player, player2, currentRelation, newRelation);
}
/**
* Mark units as having no movement.
*
* @param units
* referring units
* @return change that contains marking of units as having no movement
*/
public static Change markNoMovementChange(final Collection<Unit> units) {
final CompositeChange change = new CompositeChange();
for (final Unit unit : units) {
if (TripleAUnit.get(unit).getMovementLeft() > 0) {
change.add(markNoMovementChange(unit));
}
}
if (change.isEmpty()) {
return EMPTY_CHANGE;
}
return change;
}
public static Change markNoMovementChange(final Unit unit) {
return unitPropertyChange(unit, TripleAUnit.get(unit).getMaxMovementAllowed(), TripleAUnit.ALREADY_MOVED);
}
}