package games.strategy.triplea.delegate;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import games.strategy.engine.data.GameData;
import games.strategy.engine.data.PlayerID;
import games.strategy.engine.data.Route;
import games.strategy.engine.data.Territory;
import games.strategy.engine.data.Unit;
import games.strategy.engine.pbem.PBEMMessagePoster;
import games.strategy.triplea.delegate.dataObjects.MoveValidationResult;
import games.strategy.triplea.delegate.remote.IMoveDelegate;
/**
* An abstraction of MoveDelegate in order to allow other delegates to extend this.
*/
public abstract class AbstractMoveDelegate extends BaseTripleADelegate implements IMoveDelegate {
// A collection of UndoableMoves
protected List<UndoableMove> m_movesToUndo = new ArrayList<>();
// protected final TransportTracker m_transportTracker = new TransportTracker();
// if we are in the process of doing a move. this instance will allow us to resume the move
protected MovePerformer m_tempMovePerformer;
public static enum MoveType {
DEFAULT, SPECIAL
}
public AbstractMoveDelegate() {}
/**
* Called before the delegate will run.
*/
@Override
public void start() {
super.start();
if (m_tempMovePerformer != null) {
m_tempMovePerformer.initialize(this);
m_tempMovePerformer.resume();
m_tempMovePerformer = null;
}
}
/**
* Called before the delegate will stop running.
*/
@Override
public void end() {
super.end();
m_movesToUndo.clear();
}
@Override
public Serializable saveState() {
final AbstractMoveExtendedDelegateState state = new AbstractMoveExtendedDelegateState();
state.superState = super.saveState();
// add other variables to state here:
state.m_movesToUndo = m_movesToUndo;
state.m_tempMovePerformer = m_tempMovePerformer;
return state;
}
@Override
public void loadState(final Serializable state) {
final AbstractMoveExtendedDelegateState s = (AbstractMoveExtendedDelegateState) state;
super.loadState(s.superState);
// if the undo state wasnt saved, then dont load it. prevents overwriting undo state when we restore from an undo
// move
if (s.m_movesToUndo != null) {
m_movesToUndo = s.m_movesToUndo;
}
m_tempMovePerformer = s.m_tempMovePerformer;
}
@Override
public List<UndoableMove> getMovesMade() {
return new ArrayList<>(m_movesToUndo);
}
@Override
public String undoMove(final int moveIndex) {
if (m_movesToUndo.isEmpty()) {
return "No moves to undo";
}
if (moveIndex >= m_movesToUndo.size()) {
return "Undo move index out of range";
}
final UndoableMove moveToUndo = m_movesToUndo.get(moveIndex);
if (!moveToUndo.getcanUndo()) {
return moveToUndo.getReasonCantUndo();
}
moveToUndo.undo(m_bridge);
m_movesToUndo.remove(moveIndex);
updateUndoableMoveIndexes();
return null;
}
private void updateUndoableMoveIndexes() {
for (int i = 0; i < m_movesToUndo.size(); i++) {
m_movesToUndo.get(i).setIndex(i);
}
}
protected void updateUndoableMoves(final UndoableMove currentMove) {
currentMove.initializeDependencies(m_movesToUndo);
m_movesToUndo.add(currentMove);
updateUndoableMoveIndexes();
}
protected PlayerID getUnitsOwner(final Collection<Unit> units) {
// if we are not in edit mode, return m_player. if we are in edit mode, we use whoever's units these are.
if (units.isEmpty() || !BaseEditDelegate.getEditMode(getData())) {
return m_player;
} else {
return units.iterator().next().getOwner();
}
}
@Override
public String move(final Collection<Unit> units, final Route route) {
return move(units, route, Collections.emptyList());
}
@Override
public String move(final Collection<Unit> units, final Route route,
final Collection<Unit> transportsThatCanBeLoaded) {
return move(units, route, transportsThatCanBeLoaded, new HashMap<>());
}
@Override
public abstract String move(final Collection<Unit> units, final Route route,
final Collection<Unit> m_transportsThatCanBeLoaded, final Map<Unit, Collection<Unit>> newDependents);
public static MoveValidationResult validateMove(final MoveType moveType, final Collection<Unit> units,
final Route route, final PlayerID player, final Collection<Unit> transportsToLoad,
final Map<Unit, Collection<Unit>> newDependents, final boolean isNonCombat,
final List<UndoableMove> undoableMoves, final GameData data) {
if (moveType == MoveType.SPECIAL) {
return SpecialMoveDelegate.validateMove(units, route, player, transportsToLoad, newDependents, isNonCombat,
undoableMoves, data);
}
return MoveValidator.validateMove(units, route, player, transportsToLoad, newDependents, isNonCombat, undoableMoves,
data);
}
@Override
public Collection<Territory> getTerritoriesWhereAirCantLand(final PlayerID player) {
return new AirThatCantLandUtil(m_bridge).getTerritoriesWhereAirCantLand(player);
}
@Override
public Collection<Territory> getTerritoriesWhereAirCantLand() {
return new AirThatCantLandUtil(m_bridge).getTerritoriesWhereAirCantLand(m_player);
}
@Override
public Collection<Territory> getTerritoriesWhereUnitsCantFight() {
return new UnitsThatCantFightUtil(getData()).getTerritoriesWhereUnitsCantFight(m_player);
}
/**
* @param unit
* referring unit.
* @param end
* target territory
* @return the route that a unit used to move into the given territory
*/
public Route getRouteUsedToMoveInto(final Unit unit, final Territory end) {
return AbstractMoveDelegate.getRouteUsedToMoveInto(m_movesToUndo, unit, end);
}
/**
* This method is static so it can be called from the client side.
*
* @param undoableMoves
* list of moves that have been done
* @param unit
* referring unit
* @param end
* target territory
* @return the route that a unit used to move into the given territory.
*/
public static Route getRouteUsedToMoveInto(final List<UndoableMove> undoableMoves, final Unit unit,
final Territory end) {
final ListIterator<UndoableMove> iter = undoableMoves.listIterator(undoableMoves.size());
while (iter.hasPrevious()) {
final UndoableMove move = iter.previous();
if (!move.getUnits().contains(unit)) {
continue;
}
if (move.getRoute().getEnd().equals(end)) {
return move.getRoute();
}
}
return null;
}
public static BattleTracker getBattleTracker(final GameData data) {
return DelegateFinder.battleDelegate(data).getBattleTracker();
}
protected boolean isWW2V2() {
return games.strategy.triplea.Properties.getWW2V2(getData());
}
@Override
public void setHasPostedTurnSummary(final boolean hasPostedTurnSummary) {
// nothing for now
}
@Override
public boolean getHasPostedTurnSummary() {
return false;
}
@Override
public boolean postTurnSummary(final PBEMMessagePoster poster, final String title, final boolean includeSaveGame) {
return poster.post(m_bridge.getHistoryWriter(), title, includeSaveGame);
}
public abstract int PUsAlreadyLost(final Territory t);
public abstract void PUsLost(final Territory t, final int amt);
@Override
public Class<IMoveDelegate> getRemoteType() {
return IMoveDelegate.class;
}
}