package games.strategy.triplea.attachments;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import games.strategy.engine.data.Attachable;
import games.strategy.engine.data.DefaultAttachment;
import games.strategy.engine.data.GameData;
import games.strategy.engine.data.GameParseException;
import games.strategy.engine.data.IAttachment;
import games.strategy.engine.data.PlayerID;
import games.strategy.engine.data.UnitType;
import games.strategy.engine.data.annotations.GameProperty;
import games.strategy.engine.data.annotations.InternalDoNotExport;
import games.strategy.triplea.Constants;
import games.strategy.triplea.MapSupport;
@MapSupport
public class UnitSupportAttachment extends DefaultAttachment {
private static final long serialVersionUID = -3015679930172496082L;
private HashSet<UnitType> m_unitType = null;
@InternalDoNotExport
// Do Not Export
private boolean m_offence = false;
@InternalDoNotExport
// Do Not Export
private boolean m_defence = false;
@InternalDoNotExport
private boolean m_roll = false;
@InternalDoNotExport
private boolean m_strength = false;
private int m_bonus = 0;
private int m_number = 0;
@InternalDoNotExport
private boolean m_allied = false;
@InternalDoNotExport
private boolean m_enemy = false;
private String m_bonusType = null;
private ArrayList<PlayerID> m_players = new ArrayList<>();
private boolean m_impArtTech = false;
// strings
// roll or strength
private String m_dice;
// offence or defence
private String m_side;
private String m_faction;
public UnitSupportAttachment(final String name, final Attachable attachable, final GameData gameData) {
super(name, attachable, gameData);
}
public static Set<UnitSupportAttachment> get(final UnitType u) {
final Set<UnitSupportAttachment> supports = new HashSet<>();
final Map<String, IAttachment> map = u.getAttachments();
final Iterator<String> objsIter = map.keySet().iterator();
while (objsIter.hasNext()) {
final IAttachment attachment = map.get(objsIter.next());
final String name = attachment.getName();
if (name.startsWith(Constants.SUPPORT_ATTACHMENT_PREFIX)) {
supports.add((UnitSupportAttachment) attachment);
}
}
return supports;
}
public static UnitSupportAttachment get(final UnitType u, final String nameOfAttachment) {
final UnitSupportAttachment rVal = (UnitSupportAttachment) u.getAttachment(nameOfAttachment);
if (rVal == null) {
throw new IllegalStateException("No unit type attachment for:" + u.getName() + " with name:" + nameOfAttachment);
}
return rVal;
}
public static Set<UnitSupportAttachment> get(final GameData data) {
final Set<UnitSupportAttachment> supports = new HashSet<>();
data.acquireReadLock();
try {
final Iterator<UnitType> i = data.getUnitTypeList().iterator();
while (i.hasNext()) {
supports.addAll(get(i.next()));
}
} finally {
data.releaseReadLock();
}
return supports;
}
@GameProperty(xmlProperty = true, gameProperty = true, adds = false)
public void setUnitType(final String names) throws GameParseException {
if (names == null) {
m_unitType = null;
return;
}
m_unitType = new HashSet<>();
final String[] s = names.split(":");
for (final String element : s) {
final UnitType type = getData().getUnitTypeList().getUnitType(element);
if (type == null) {
throw new GameParseException("Could not find unitType. name:" + element + thisErrorMsg());
}
m_unitType.add(type);
}
}
@GameProperty(xmlProperty = true, gameProperty = true, adds = false)
public void setUnitType(final HashSet<UnitType> value) {
m_unitType = value;
}
@GameProperty(xmlProperty = true, gameProperty = true, adds = false)
public void setFaction(final String faction) throws GameParseException {
m_faction = faction;
if (faction == null) {
resetFaction();
return;
}
m_allied = false;
m_enemy = false;
final String[] s = faction.split(":");
for (final String element : s) {
if (element.equalsIgnoreCase("allied")) {
m_allied = true;
} else if (element.equalsIgnoreCase("enemy")) {
m_enemy = true;
} else {
throw new GameParseException(faction + " faction must be allied, or enemy" + thisErrorMsg());
}
}
}
public String getFaction() {
return m_faction;
}
public void resetFaction() {
m_allied = false;
m_enemy = false;
}
@GameProperty(xmlProperty = true, gameProperty = true, adds = false)
public void setSide(final String side) throws GameParseException {
if (side == null) {
resetSide();
return;
}
m_defence = false;
m_offence = false;
final String[] s = side.split(":");
for (final String element : s) {
if (element.equalsIgnoreCase("defence")) {
m_defence = true;
} else if (element.equalsIgnoreCase("offence")) {
m_offence = true;
} else {
throw new GameParseException(side + " side must be defence or offence" + thisErrorMsg());
}
}
m_side = side;
}
public String getSide() {
return m_side;
}
public void resetSide() {
m_side = null;
m_offence = false;
m_defence = false;
}
@GameProperty(xmlProperty = true, gameProperty = true, adds = false)
public void setDice(final String dice) throws GameParseException {
if (dice == null) {
resetDice();
return;
}
m_roll = false;
m_strength = false;
final String[] s = dice.split(":");
for (final String element : s) {
if (element.equalsIgnoreCase("roll")) {
m_roll = true;
} else if (element.equalsIgnoreCase("strength")) {
m_strength = true;
} else {
throw new GameParseException(dice + " dice must be roll or strength" + thisErrorMsg());
}
}
m_dice = dice;
}
public String getDice() {
return m_dice;
}
public void resetDice() {
m_dice = null;
m_roll = false;
m_strength = false;
}
@GameProperty(xmlProperty = true, gameProperty = true, adds = false)
public void setBonus(final String bonus) {
m_bonus = getInt(bonus);
}
@GameProperty(xmlProperty = true, gameProperty = true, adds = false)
public void setBonus(final Integer bonus) {
m_bonus = bonus;
}
public void resetBonus() {
m_bonus = 0;
}
@GameProperty(xmlProperty = true, gameProperty = true, adds = false)
public void setNumber(final String number) {
m_number = getInt(number);
}
@GameProperty(xmlProperty = true, gameProperty = true, adds = false)
public void setNumber(final Integer number) {
m_number = number;
}
public void resetNumber() {
m_number = 0;
}
@GameProperty(xmlProperty = true, gameProperty = true, adds = false)
public void setBonusType(final String type) {
if (type == null) {
m_bonusType = null;
return;
}
m_bonusType = type;
}
public void resetBonusType() {
m_bonusType = null;
}
/**
* Adds to, not sets. Anything that adds to instead of setting needs a clear function as well.
*/
@GameProperty(xmlProperty = true, gameProperty = true, adds = true)
public void setPlayers(final String names) throws GameParseException {
final String[] s = names.split(":");
for (final String element : s) {
final PlayerID player = getData().getPlayerList().getPlayerID(element);
if (player == null) {
throw new GameParseException("Could not find player. name:" + element + thisErrorMsg());
} else {
m_players.add(player);
}
}
}
@GameProperty(xmlProperty = true, gameProperty = true, adds = false)
public void setPlayers(final ArrayList<PlayerID> value) {
m_players = value;
}
public ArrayList<PlayerID> getPlayers() {
return m_players;
}
public void clearPlayers() {
m_players.clear();
}
public void resetPlayers() {
m_players = new ArrayList<>();
}
@GameProperty(xmlProperty = true, gameProperty = true, adds = false)
public void setImpArtTech(final String tech) {
m_impArtTech = getBool(tech);
}
@GameProperty(xmlProperty = true, gameProperty = true, adds = false)
public void setImpArtTech(final Boolean tech) {
m_impArtTech = tech;
}
public void resetImpArtTech() {
m_impArtTech = false;
}
public HashSet<UnitType> getUnitType() {
return m_unitType;
}
public int getNumber() {
return m_number;
}
public int getBonus() {
return m_bonus;
}
public boolean getAllied() {
return m_allied;
}
public boolean getEnemy() {
return m_enemy;
}
public boolean getRoll() {
return m_roll;
}
public boolean getStrength() {
return m_strength;
}
public boolean getDefence() {
return m_defence;
}
public boolean getOffence() {
return m_offence;
}
public String getBonusType() {
return m_bonusType;
}
public boolean getImpArtTech() {
return m_impArtTech;
}
/*
* following are all to support old artillery flags.
* boolean first is a cheat, adds a bogus support to a unit
* in the case that supportable units are declared before any artillery
*/
@InternalDoNotExport
public static void addRule(final UnitType type, final GameData data, final boolean first) throws GameParseException {
final String attachmentName =
(first ? Constants.SUPPORT_RULE_NAME_OLD_TEMP_FIRST : Constants.SUPPORT_RULE_NAME_OLD) + type.getName();
final UnitSupportAttachment rule = new UnitSupportAttachment(attachmentName, type, data);
rule.setBonus("1");
rule.setBonusType(Constants.OLD_ART_RULE_NAME);
rule.setDice("strength");
rule.setFaction("allied");
rule.setImpArtTech("true");
if (first) {
rule.setNumber("0");
} else {
rule.setNumber("1");
}
rule.setSide("offence");
if (first) {
rule.addUnitTypes(Collections.singleton(type));
} else {
rule.addUnitTypes(getTargets(data));
}
if (!first) {
rule.setPlayers(new ArrayList<>(data.getPlayerList().getPlayers()));
}
type.addAttachment(attachmentName, rule);
}
@InternalDoNotExport
private static Set<UnitType> getTargets(final GameData data) {
Set<UnitType> types = null;
for (final UnitSupportAttachment rule : get(data)) {
if (rule.getBonusType().equals(Constants.OLD_ART_RULE_NAME)) {
types = rule.getUnitType();
if (rule.getName().startsWith(Constants.SUPPORT_RULE_NAME_OLD_TEMP_FIRST)) {
// remove it because it is a "first", which is just a temporary one made to hold target info. what a hack.
final UnitType attachedTo = (UnitType) rule.getAttachedTo();
attachedTo.removeAttachment(rule.getName());
rule.setAttachedTo(null);
}
}
}
return types;
}
@InternalDoNotExport
private void addUnitTypes(final Set<UnitType> types) {
if (types == null) {
return;
}
if (m_unitType == null) {
m_unitType = new HashSet<>();
}
m_unitType.addAll(types);
}
@InternalDoNotExport
public static void setOldSupportCount(final UnitType type, final GameData data, final String count) {
for (final UnitSupportAttachment rule : get(data)) {
if (rule.getBonusType().equals(Constants.OLD_ART_RULE_NAME) && rule.getAttachedTo() == type) {
rule.setNumber(count);
}
}
}
@InternalDoNotExport
public static void addTarget(final UnitType type, final GameData data) throws GameParseException {
final Iterator<UnitSupportAttachment> iter = get(data).iterator();
boolean first = true;
while (iter.hasNext()) {
final UnitSupportAttachment rule = iter.next();
if (rule.getBonusType().equals(Constants.OLD_ART_RULE_NAME)) {
rule.addUnitTypes(Collections.singleton(type));
first = false;
}
}
// if first, it means we do not have any support attachments created yet. so create a temporary one on this unit
// just to hold the target
// info.
if (first) {
addRule(type, data, first);
}
}
@Override
public void validate(final GameData data) throws GameParseException {}
}