package games.strategy.triplea.delegate.dataObjects;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map.Entry;
import games.strategy.engine.data.PlayerID;
import games.strategy.engine.data.SerializationProxySupport;
import games.strategy.engine.data.Territory;
import games.strategy.net.GUID;
import games.strategy.triplea.delegate.IBattle.BattleType;
import games.strategy.triplea.delegate.dataObjects.BattleRecord.BattleResultDescription;
import games.strategy.triplea.oddsCalculator.ta.BattleResults;
/**
* The Purpose of this class is to record various information about combat,
* in order to use it for conditions and other things later.
*/
public class BattleRecords implements Serializable {
private static final long serialVersionUID = 1473664374777905497L;
private final HashMap<PlayerID, HashMap<GUID, BattleRecord>> m_records;
public BattleRecords() {
this.m_records = new HashMap<>();
}
public BattleRecords(final HashMap<PlayerID, HashMap<GUID, BattleRecord>> records) {
this.m_records = records;
}
@SerializationProxySupport
public Object writeReplace() {
return new SerializationProxy(this);
}
@SerializationProxySupport
private static class SerializationProxy implements Serializable {
private static final long serialVersionUID = 3837818110273155404L;
private final HashMap<PlayerID, HashMap<GUID, BattleRecord>> records;
public SerializationProxy(final BattleRecords battleRecords) {
this.records = battleRecords.m_records;
}
private Object readResolve() {
return new BattleRecords(records);
}
}
// Create copy
public BattleRecords(final BattleRecords records) {
m_records = new HashMap<>();
for (final Entry<PlayerID, HashMap<GUID, BattleRecord>> entry : records.m_records.entrySet()) {
final PlayerID p = entry.getKey();
final HashMap<GUID, BattleRecord> record = entry.getValue();
final HashMap<GUID, BattleRecord> map = new HashMap<>();
for (final Entry<GUID, BattleRecord> entry2 : record.entrySet()) {
map.put(entry2.getKey(), new BattleRecord(entry2.getValue()));
}
m_records.put(p, map);
}
}
public static Collection<BattleRecord> getAllRecords(final BattleRecords brs) {
final Collection<BattleRecord> records = new ArrayList<>();
for (final HashMap<GUID, BattleRecord> playerMap : brs.m_records.values()) {
for (final BattleRecord r : playerMap.values()) {
records.add(r);
}
}
return records;
}
public static Collection<BattleRecord> getRecordsForPlayerID(final PlayerID player, final BattleRecords brs) {
final Collection<BattleRecord> playerRecords = new ArrayList<>();
if (brs.m_records.get(player) == null) {
return playerRecords;
}
for (final Entry<GUID, BattleRecord> entry : brs.m_records.get(player).entrySet()) {
playerRecords.add(entry.getValue());
}
return playerRecords;
}
public static int getLostTUVforBattleRecords(final Collection<BattleRecord> brs, final boolean attackerLostTUV,
final boolean includeNullPlayer) {
int totalLostTUV = 0;
for (final BattleRecord br : brs) {
if (!includeNullPlayer && (br.getDefender() == null || br.getAttacker() == null || br.getDefender().isNull()
|| br.getAttacker().isNull())) {
continue;
}
if (attackerLostTUV) {
totalLostTUV += br.getAttackerLostTUV();
} else {
totalLostTUV += br.getDefenderLostTUV();
}
}
return totalLostTUV;
}
public static boolean getWereThereBattlesInTerritoriesMatching(final Collection<BattleRecord> brs,
final PlayerID attacker, final PlayerID defender, final String battleType,
final Collection<Territory> anyOfTheseTerritories) {
for (final BattleRecord br : brs) {
if (anyOfTheseTerritories.contains(br.getBattleSite())) {
if (attacker != null && !attacker.equals(br.getAttacker())) {
continue;
}
if (defender != null && !defender.equals(br.getDefender())) {
continue;
}
if (!battleType.equalsIgnoreCase("any")) {
continue;
}
return true;
// TODO: do more types.... (maybe make a much better enum class that covers both WhoWon and
// BattleResultDescription in a single enum
// with multiple variables for each enum to cover the different tiers of detail (ie: won/lost/draw vs
// conquer/blitz/etc.)
}
}
return false;
}
public void removeBattle(final PlayerID currentPlayer, final GUID battleID) {
final HashMap<GUID, BattleRecord> current = m_records.get(currentPlayer);
// we can't count on this being the current player. If we created a battle using edit mode, then the battle might be
// under a different
// player.
if (current == null || !current.containsKey(battleID)) {
for (final Entry<PlayerID, HashMap<GUID, BattleRecord>> entry : m_records.entrySet()) {
if (entry.getValue() != null && entry.getValue().containsKey(battleID)) {
entry.getValue().remove(battleID);
return;
}
}
throw new IllegalStateException("Trying to remove info from battle records that do not exist");
}
current.remove(battleID);
}
public void addRecord(final BattleRecords other) {
for (final PlayerID p : other.m_records.keySet()) {
final HashMap<GUID, BattleRecord> currentRecord = m_records.get(p);
if (currentRecord != null) {
// this only comes up if we use edit mode to create an attack for a player who's already had their turn and
// therefore already has
// their record.
final HashMap<GUID, BattleRecord> additionalRecords = other.m_records.get(p);
for (final Entry<GUID, BattleRecord> entry : additionalRecords.entrySet()) {
final GUID guid = entry.getKey();
final BattleRecord br = entry.getValue();
if (currentRecord.containsKey(guid)) {
throw new IllegalStateException("Should not be adding battle record for player " + p.getName()
+ " when they are already on the record. " + "Trying to add: " + br.toString());
} else {
currentRecord.put(guid, br);
}
}
m_records.put(p, currentRecord);
} else {
m_records.put(p, other.m_records.get(p));
}
}
}
public void removeRecord(final BattleRecords other) {
for (final PlayerID p : other.m_records.keySet()) {
final HashMap<GUID, BattleRecord> currentRecord = m_records.get(p);
if (currentRecord == null) {
throw new IllegalStateException("Trying to remove a player records but records do not exist");
}
final HashMap<GUID, BattleRecord> toRemoveRecords = other.m_records.get(p);
for (final Entry<GUID, BattleRecord> entry : toRemoveRecords.entrySet()) {
final GUID guid = entry.getKey();
if (!currentRecord.containsKey(guid)) {
throw new IllegalStateException("Trying to remove a battle record but record does not exist");
} else {
currentRecord.remove(guid);
}
}
}
}
public void addBattle(final PlayerID currentPlayerAndAttacker, final GUID battleID, final Territory battleSite,
final BattleType battleType) {
HashMap<GUID, BattleRecord> current = m_records.get(currentPlayerAndAttacker);
if (current == null) {
current = new HashMap<>();
}
final BattleRecord initial = new BattleRecord(battleSite, currentPlayerAndAttacker, battleType);
current.put(battleID, initial);
m_records.put(currentPlayerAndAttacker, current);
}
public void addResultToBattle(final PlayerID currentPlayer, final GUID battleID, final PlayerID defender,
final int attackerLostTUV, final int defenderLostTUV, final BattleResultDescription battleResultDescription,
final BattleResults battleResults) {
final HashMap<GUID, BattleRecord> current = m_records.get(currentPlayer);
if (current == null) {
throw new IllegalStateException("Trying to add info to battle records that do not exist");
}
if (!current.containsKey(battleID)) {
throw new IllegalStateException("Trying to add info to a battle that does not exist");
}
final BattleRecord record = current.get(battleID);
record.setResult(defender, attackerLostTUV, defenderLostTUV, battleResultDescription, battleResults);
}
public void clear() {
m_records.clear();
}
public boolean isEmpty() {
return m_records.isEmpty();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("[");
for (final Entry<PlayerID, HashMap<GUID, BattleRecord>> entry : m_records.entrySet()) {
sb.append(", ");
sb.append(entry.getKey().getName());
sb.append("={");
final StringBuilder sb2 = new StringBuilder("");
for (final Entry<GUID, BattleRecord> entry2 : entry.getValue().entrySet()) {
sb2.append(", ");
final String guid = entry2.getKey().toString();
sb2.append(guid.substring(Math.max(0, Math.min(guid.length(), 7 * guid.length() / 8)), guid.length()));
sb2.append(":");
sb2.append(entry2.getValue().toString());
}
sb.append(sb2.toString().replaceFirst(", ", ""));
sb.append("}");
}
sb.append("]");
return sb.toString().replaceFirst(", ", "");
}
}