/*
* EU2Country.java
*
* Created on June 23, 2006, 2:23 PM
*/
package eug.specific.eu2;
import eug.shared.GenericList;
import eug.shared.GenericObject;
import eug.shared.ObjectVariable;
import eug.shared.Utilities;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
*
* @author Michael Myers
*/
public class EU2Country extends EU2SpecificObject {
public List<GenericObject> cities;
public List<GenericObject> milUnits;
/**
* Creates a new instance of EU2Country
*/
public EU2Country(GenericObject go, EU2Scenario s) {
super(go, s);
cities = go.getChildren("city");
cities.addAll(go.getChildren("tradingpost"));
initMilUnits();
sortProvLists(); // just for fun
}
private void initMilUnits() {
milUnits = go.getChildren("landunit");
for (GenericObject navalunit : go.getChildren("navalunit")) {
milUnits.add(navalunit);
for (GenericObject landunit : navalunit.getChildren("landunit"))
milUnits.add(landunit);
}
}
private final void sortProvLists() {
go.getList("ownedprovinces").sort();
go.getList("controlledprovinces").sort();
go.getList("knownprovinces").sort();
go.getList("nationalprovinces").sort();
}
public String getTag() {
return go.getString("tag");
}
public void changeTag(String newTag) {
scenario.changeCountryTag(getTag(), newTag);
go.setString("tag", newTag);
}
public String getName() {
return scenario.getDisplayName(getTag());
}
public int getCapital() {
for (GenericObject city : cities) {
if (!city.hasString("capital"))
return city.getInt("location");
}
return -1; // will never happen except for REB, PIR, MER, and NAT
}
public String getReligion() {
return go.getChild("religion").getString("type");
}
public List<String> getCulture() {
final GenericObject cultures = go.getChild("culture");
final List<String> cul = new ArrayList<String>(cultures.nbVar());
for (ObjectVariable culture : cultures.values)
cul.add(culture.getValue());
return cul;
}
public double getTreasury() {
return go.getDouble("treasury");
}
public double getInflation() {
return go.getDouble("inflation");
}
public double getVP() {
return go.getDouble("vp");
}
public double getBadBoy() {
return go.getDouble("badboy");
}
public int nbOwned() {
return go.getList("ownedprovinces").size();
}
public Province owned(int pos) {
final GenericList owned = go.getList("ownedprovinces");
if (pos >= owned.size()) {
System.err.println("Invalid pos id: "+pos);
return null;
}
return scenario.getProvince(Integer.parseInt(owned.get(pos)));
}
public boolean ownsProvince(int id) {
return go.getList("ownedprovinces").contains(Integer.toString(id));
}
public int nbControlled() {
return go.getList("controlledprovinces").size();
}
public boolean controllsProvince(int id) {
try {
return go.getList("controlledprovinces").contains(Integer.toString(id));
} catch (ArrayIndexOutOfBoundsException ex) {
System.err.println("Error in country " + getTag());
throw ex;
}
}
public boolean isSameCulture(Province prov) {
final List<String> cultures = getCulture();
final String provCul = prov.getCulture();
for (String culture : cultures) {
if (culture.equals(provCul))
return true;
}
return false;
}
public boolean isSameReligion(Province prov) {
return getReligion().equals(prov.getReligion());
}
public boolean isCore(Province prov) {
return isCore(prov.getId());
}
public boolean isCore(int id) {
return go.getList("nationalprovinces").contains(Integer.toString(id));
}
public double getPopulation(int id) {
double pop = getCity(id).getDouble("population");
if (pop < 0.0)
return 0.0;
return pop;
}
public boolean hasBailiff(int id) {
return getCity(id).getString("bailiff").equals("yes");
}
public boolean hasJudge(int id) {
return getCity(id).getString("courthouse").equals("yes");
}
public boolean hasGovernor(int id) {
return getCity(id).getString("cityrights").equals("yes");
}
public boolean hasFactory(int id) {
return getCity(id).hasString("manufactory");
}
public boolean hasShipyard(int id) {
return getCity(id).getString("shipyard").equals("yes");
}
public boolean hasBarrack(int id) {
return getCity(id).getString("barrack").equals("yes");
}
public int getFortressLevel(int id) {
return getFortress0(getCity(id));
}
private static int getFortress0(GenericObject city) {
try {
// just typecast, since there should only be whole-number levels
return (int) city.getChild("fortress").getDouble("level");
} catch (NullPointerException ex) {
// There wasn't a fortress, so the level is 0
return 0;
}
}
public List<Integer> getRichProvs() {
final List<Integer> ret = new ArrayList<Integer>();
// final List<String> cultures = getCulture();
// final String religion = getReligion();
final int MIN_TAX = 10;
final int MIN_GOLD = 10;
final String gold = scenario.getDisplayName("gold");
for (GenericObject city : cities) {
Province prov = scenario.getProvince(city.getInt("location"));
if ( ( prov.getIncome() >= MIN_TAX ||
(prov.getGoods().equals(gold) && prov.getMine() >= MIN_GOLD) )
// && religion.equals(prov.getReligion())
// && cultures.contains(prov.getCulture())
)
ret.add(city.getInt("location"));
}
sortByTax(ret);
return ret;
}
public List<Integer> getCitiesLowFortress(int max) {
final List<Integer> ret = new ArrayList<Integer>();
for (GenericObject city : cities)
if (getFortress0(city) <= max)
ret.add(city.getInt("location"));
return ret;
}
public List<Integer> getVulnerableRichProvs() {
List<Integer> ret = getRichProvs();
ret.retainAll(getCitiesLowFortress(2));
return ret;
}
public List<Integer> getFavorableCitiesNoBailiff() {
final List<Integer> ret = new ArrayList<Integer>();
final List<String> cultures = getCulture();
final String religion = getReligion();
final int MIN_TAX = 5;
for (GenericObject city : cities) {
Province prov = scenario.getProvince(city.getInt("location"));
if (cultures.contains(prov.getCulture()) &&
religion.equals(prov.getReligion()) &&
!city.getString("bailiff").equals("yes") &&
prov.getIncome() >= MIN_TAX)
ret.add(city.getInt("location"));
}
return ret;
}
public List<Integer> getBailiffNoJudge() {
final List<Integer> ret = new ArrayList<Integer>();
for (GenericObject city : cities) {
if (city.getString("bailiff").equals("yes") &&
!city.getString("courthouse").equals("yes"))
ret.add(city.getInt("location"));
}
return ret;
}
public List<Integer> getBailiffNoJudge(int minTaxVal) {
final List<Integer> ret = new ArrayList<Integer>();
for (GenericObject city : cities) {
int loc = city.getInt("location");
if (city.getString("bailiff").equals("yes") &&
!city.getString("courthouse").equals("yes") &&
scenario.getProvince(loc).getIncome() >= minTaxVal)
ret.add(loc);
}
return ret;
}
public List<Integer> getOwnedProvs() {
final List<Integer> ret = new ArrayList<Integer>();
for (String id : go.getList("ownedprovinces"))
ret.add(Integer.parseInt(id));
return ret;
}
public List<Integer> getControlledProvs() {
final List<Integer> ret = new ArrayList<Integer>();
for (String id : go.getList("controlledprovinces"))
ret.add(Integer.parseInt(id));
return ret;
}
public List<Integer> getNationalProvs() {
final List<Integer> ret = new ArrayList<Integer>();
for (String id : go.getList("nationalprovinces"))
ret.add(Integer.parseInt(id));
return ret;
}
public List<Integer> getOwnedNotControlled() {
final List<Integer> ret = getOwnedProvs();
ret.removeAll(getControlledProvs());
return ret;
}
public List<Integer> getOwnedNotCore() {
final List<Integer> ret = getOwnedProvs();
ret.removeAll(getNationalProvs());
return ret;
}
public List<Integer> getControlledNotOwned() {
final List<Integer> ret = getControlledProvs();
ret.removeAll(getOwnedProvs());
return ret;
}
public String getFactory(int id) {
return getCity(id).getString("manufactory");
}
public java.util.Map<Integer, String> getFactories() {
final java.util.Map<Integer, String> ret =
new java.util.HashMap<Integer, String>();
String tmp;
for (GenericObject city : cities) {
tmp = city.getString("manufactory");
if (tmp.length() != 0)
ret.put(city.getInt("location"), tmp);
}
return ret;
}
public List<Integer> getShipyards() {
final List<Integer> ret = new ArrayList<Integer>();
for (GenericObject city : cities) {
if (city.getString("shipyard").equals("yes"))
ret.add(city.getInt("location"));
}
return ret;
}
public List<Integer> getBarracks() {
final List<Integer> ret = new ArrayList<Integer>();
for (GenericObject city : cities) {
if (city.getString("barrack").equals("yes"))
ret.add(city.getInt("location"));
}
return ret;
}
private final GenericObject getCity(int id) {
for (GenericObject obj : cities)
if (Integer.parseInt(obj.getString("location")) == id)
return obj;
return null;
}
public double getRelation(String tag) {
tag = tag.substring(0,3).toUpperCase();
GenericObject diplomacy = go.getChild("diplomacy");
for (GenericObject relation : diplomacy.children) {
if (relation.getString("tag").equals(tag))
return relation.getDouble("value");
}
return 0.0; // What is the default relation??
}
// *** Military ***
// Army
public double numInf() {
double inf = 0.0;
for (GenericObject unit : milUnits) {
if (unit.name.equals("landunit"))
inf += unit.getDouble("inf");
else { // naval
for (GenericObject unit2 : unit.getChildren("landunit")) {
inf += unit2.getDouble("inf");
}
}
}
return inf;
}
public double numCav() {
double cav = 0.0;
for (GenericObject unit : milUnits) {
if (unit.name.equals("landunit"))
cav += unit.getDouble("cav");
else { // naval
for (GenericObject unit2 : unit.getChildren("landunit"))
cav += unit2.getDouble("cav");
}
}
return cav;
}
public double numArt() {
double art = 0.0;
for (GenericObject unit : milUnits) {
if (unit.name.equals("landunit"))
art += unit.getDouble("art");
else { // naval
for (GenericObject unit2 : unit.getChildren("landunit"))
art += unit2.getDouble("art");
}
}
return art;
}
public double numLandTroops() {
double num = 0.0;
for (GenericObject unit : milUnits) {
if (unit.name.equals("landunit")) {
num += unit.getDouble("inf");
num += unit.getDouble("cav");
num += 100*unit.getDouble("art");
} else { // naval
for (GenericObject unit2 : unit.getChildren("landunit")) {
num += unit2.getDouble("inf");
num += unit2.getDouble("cav");
num += 100*unit2.getDouble("art");
}
}
}
return num;
}
// Navy
public double numWarships() {
double ws = 0.0;
for (GenericObject unit : milUnits) {
if (unit.name.equals("navalunit"))
ws += unit.getDouble("warships");
}
return ws;
}
public double numGalleys() {
double gl = 0.0;
for (GenericObject unit : milUnits) {
if (unit.name.equals("navalunit"))
gl += unit.getDouble("galleys");
}
return gl;
}
public double numTransports() {
double tr = 0.0;
for (GenericObject unit : milUnits) {
if (unit.name.equals("navalunit"))
tr += unit.getDouble("transports");
}
return tr;
}
public double numShips() {
double num = 0.0;
for (GenericObject unit : milUnits) {
if (unit.name.equals("navalunit")) {
num += unit.getDouble("warships");
num += unit.getDouble("galleys");
num += unit.getDouble("transports");
}
}
return num;
}
// Miscellaneous
public double getTotalPopulation() {
// Trading posts are not included. Should they be?
double pop = 0.0;
for (GenericObject city : cities)
pop += city.getDouble("population");
return pop;
}
// Technology
public int getLandTech() {
return getTech("land");
}
public int getNavalTech() {
return getTech("naval");
}
public int getTradeTech() {
return getTech("trade");
}
public int getInfraTech() {
return getTech("infra");
}
public int getStability() {
return getTech("stability");
}
public int getTech(String type) {
return go.getChild("technology").getChild(type).getInt("level");
}
public String getTechGroup() {
return go.getChild("technology").getString("group");
}
public int getPolicyValue(String type) {
return go.getChild("policy").getInt(type);
}
// public static GenericObject createCountry(String tag, EU2Scenario s) {
// final GenericObject ctry = new GenericObject(s.go, "country");
//
// ctry.a
//
// return new EU2Country(ctry, s);
// }
public void printInfo() {
System.out.println();
System.out.println(getName() + " has " + numInf() + " infantry, " +
numCav() + " cavalry, and " + numArt() + " artillery.");
System.out.println("It supports " + numLandTroops() +
" land troops and " + numShips() + " ships with " +
Utilities.formatPop(getTotalPopulation()) + " population.");
System.out.println();
System.out.println("Same-religion, same-culture cities with base tax >= 5 and no bailiff:");
printList(getFavorableCitiesNoBailiff());
System.out.println();
if (getInfraTech() >= 4) {
System.out.println("Provinces with base tax >= 10 with bailiff but no judge:");
printList(getBailiffNoJudge(10));
}
System.out.println();
System.out.println("Vulnerable rich cities:");
printDetailedList(getVulnerableRichProvs());
System.out.println();
System.out.println("Owned but not controlled:");
printList(getOwnedNotControlled());
System.out.println();
System.out.println("Controlled but not owned");
printList(getControlledNotOwned());
System.out.println();
}
private final java.util.Comparator<Integer> SORT_BY_TAX = new java.util.Comparator<Integer>() {
public int compare(Integer i1, Integer i2) {
return Integer.valueOf(scenario.getProvince(i1).getIncome())
.compareTo(Integer.valueOf(scenario.getProvince(i2).getIncome()));
}
};
public List<Integer> sortByTax(List<Integer> ids) {
java.util.Collections.sort(ids, SORT_BY_TAX);
return ids;
}
private void printList(List<Integer> ids) {
System.out.format("%4s %12s %10s %10s%n", "ID", "Name", "Income", "Goods");
sortByTax(ids);
for (int id : ids) {
Province prov = scenario.getProvince(id);
System.out.format("%4d %12s %2d %17s%n",
prov.getId(), prov.getName(), prov.getIncome(), prov.getGoods());
}
}
private void printDetailedList(List<Integer> ids) {
System.out.format("%4s %12s %10s %10s %12s %10s%n", "ID", "Name", "Income", "Goods", "Population", "Fortress level");
sortByTax(ids);
for (int id : ids) {
Province prov = scenario.getProvince(id);
GenericObject city = getCity(id);
System.out.format("%4d %12s %2d %17s %8.3f %2d%n",
prov.getId(), prov.getName(), prov.getIncome(),
prov.getGoods(), city.getDouble("population"),
getFortress0(city));
}
}
//
// *** MUTATORS ***
//
public void setTech(String type, int level) {
go.getChild("technology").getChild(type).setInt("level", level);
}
public void setLandTech(int level) {
setTech("land", level);
}
public void setNavalTech(int level) {
setTech("naval", level);
}
public void setInfraTech(int level) {
setTech("infra", level);
}
public void setTradeTech(int level) {
setTech("trade", level);
}
public void setStability(int level) {
setTech("stability", level);
}
public void addUnit(GenericObject unit) {
go.addChild(unit);
milUnits.add(unit);
}
public void removeUnit(GenericObject unit) {
go.removeChild(unit);
milUnits.remove(unit);
}
public GenericObject removeCity(int id) {
String sid = Integer.toString(id);
if (!go.getList("ownedprovinces").delete(sid))
throw new RuntimeException("tried to remove province "+sid+" from "+getName()+", which didn't own it!");
go.getList("controlledprovinces").delete(sid);
for (int i = 0; i < cities.size(); i++) {
GenericObject city = cities.get(i);
if (city.getString("location").equals(sid)) {
cities.remove(i);
go.removeChild(city);
return city;
}
}
throw new RuntimeException("couldn't find a city in province "+sid);
}
public void addCity(GenericObject city) {
go.getList("ownedprovinces").add(city.getInt("location"));
if (!go.getList("controlledprovinces").contains(city.getString("location")))
go.getList("controlledprovinces").add(city.getInt("location"));
cities.add(city);
go.addChild(city);
}
public void addControlledProv(int id) {
go.getList("controlledprovinces").add(id);
}
public void removeControlledProv(int id) {
go.getList("controlledprovinces").delete(Integer.toString(id));
}
public void addNationalProv(int id) {
go.getList("nationalprovinces").add(id);
}
public void removeNationalProv(int id) {
go.getList("nationalprovinces").delete(Integer.toString(id));
}
//
// *** MERGING ***
//
private static final String[] techs = { "land", "naval", "trade", "infra"/*, "stability" */};
public void merge(EU2Country other) {
for (String tech : techs)
setTech(tech, (getTech(tech) + other.getTech(tech)) / 2);
other.transferAllUnitsTo(this);
other.transferAllCitiesTo(this);
go.getList("nationalprovinces").addAll(other.go.getList("nationalprovinces"));
scenario.removeCountry(other);
}
public void mergeUnits() {
java.util.Map<Integer, List<GenericObject>> landLoc =
new java.util.HashMap<Integer, List<GenericObject>>(milUnits.size());
java.util.Map<Integer, List<GenericObject>> navalLoc =
new java.util.HashMap<Integer, List<GenericObject>>(milUnits.size());
int location;
for (GenericObject unit : milUnits) {
if (unit.name.equals("landunit")) {
location = unit.getInt("location");
if (landLoc.get(location) == null)
landLoc.put(location, new ArrayList<GenericObject>());
landLoc.get(location).add(unit);
} else {
location = unit.getInt("location");
if (navalLoc.get(location) == null)
navalLoc.put(location, new ArrayList<GenericObject>());
navalLoc.get(location).add(unit);
}
}
GenericObject base;
double inf, cav, art;
boolean first;
for (List<GenericObject> list : landLoc.values()) {
if (list.size() <= 1)
continue;
base = list.get(0);
inf = 0.0; cav = 0.0; art = 0.0;
first = true;
for (GenericObject tmp : list) {
inf += tmp.getDouble("inf");
cav += tmp.getDouble("cav");
art += tmp.getDouble("art");
if (first)
first = false;
else
go.removeChild(tmp);
}
base.setDouble("inf", inf);
base.setDouble("cav", cav);
base.setDouble("art", art);
}
double warships, galleys, transports;
GenericObject tmpTrans;
for (List<GenericObject> list : navalLoc.values()) {
if (list.size() <= 1)
continue;
tmpTrans = null;
base = list.get(0);
warships = 0.0; galleys = 0.0; transports = 0.0;
first = true;
for (GenericObject tmp : list) {
warships += tmp.getDouble("warships");
galleys += tmp.getDouble("galleys");
transports += tmp.getDouble("transports");
if (tmpTrans == null)
tmpTrans = tmp.getChild("landunit");
if (first)
first = false;
else
go.removeChild(tmp);
}
base.setDouble("warships", warships);
base.setDouble("galleys", galleys);
base.setDouble("transports", transports);
if (tmpTrans != null)
base.addChild(tmpTrans);
}
initMilUnits();
}
public void transferAllUnitsTo(EU2Country other) {
for (GenericObject unit : milUnits) {
other.addUnit(unit);
go.removeChild(unit);
}
this.initMilUnits();
other.initMilUnits();
}
public void transferCity(int id, EU2Country other) {
GenericObject city = getCity(id);
other.addCity(city);
go.removeChild(city);
cities.remove(city);
go.getList("ownedprovinces").delete(Integer.toString(id));
go.getList("controlledprovinces").delete(Integer.toString(id));
}
public void transferAllCitiesTo(EU2Country other) {
for (GenericObject city : cities) {
other.addCity(city);
go.removeChild(city);
String loc = city.getString("location");
if (!go.getList("ownedprovinces").delete(loc))
System.err.println("tried to remove province "+loc+" from "+getName()+", which didn't own it!");
go.getList("controlledprovinces").delete(loc);
}
}
}