mirror of https://github.com/FreeCol/freecol.git
581 lines
18 KiB
Java
581 lines
18 KiB
Java
/**
|
|
* Copyright (C) 2002-2007 The FreeCol Team
|
|
*
|
|
* This file is part of FreeCol.
|
|
*
|
|
* FreeCol is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* FreeCol is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with FreeCol. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package net.sf.freecol.client.gui.panel;
|
|
|
|
import net.sf.freecol.client.FreeColClient;
|
|
import net.sf.freecol.client.gui.i18n.Messages;
|
|
import net.sf.freecol.common.model.Specification;
|
|
import net.sf.freecol.common.model.Building;
|
|
import net.sf.freecol.common.model.Colony;
|
|
import net.sf.freecol.common.model.ColonyTile;
|
|
import net.sf.freecol.common.model.Europe;
|
|
import net.sf.freecol.common.model.GoodsType;
|
|
import net.sf.freecol.common.model.Location;
|
|
import net.sf.freecol.common.model.Player;
|
|
import net.sf.freecol.common.model.Tile;
|
|
import net.sf.freecol.common.model.Unit;
|
|
import net.sf.freecol.common.model.UnitType;
|
|
import net.sf.freecol.common.model.WorkLocation;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Iterator;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* holds labour statistics for the labour report
|
|
*/
|
|
public class LabourData {
|
|
private static final LocationData.Getter UNITS_IN_EUROPE_GETTER = new LocationData.Getter() {
|
|
public LocationData getLocationData(UnitData unitData) {
|
|
return unitData.unitsInEurope;
|
|
}
|
|
};
|
|
private static final LocationData.Getter UNITS_AT_SEA_GETTER = new LocationData.Getter() {
|
|
public LocationData getLocationData(UnitData unitData) {
|
|
return unitData.unitsAtSea;
|
|
}
|
|
};
|
|
private static final LocationData.Getter UNITS_ON_LAND_GETTER = new LocationData.Getter() {
|
|
public LocationData getLocationData(UnitData unitData) {
|
|
return unitData.unitsOnLand;
|
|
}
|
|
};
|
|
|
|
public static class ProductionData {
|
|
/**
|
|
* number of colonists
|
|
*/
|
|
private int colonists;
|
|
|
|
/**
|
|
* protential production
|
|
*/
|
|
private int production;
|
|
|
|
public void addProduction(int production) {
|
|
colonists = getColonists() + 1;
|
|
this.production = this.getProduction() + production;
|
|
}
|
|
|
|
public int getColonists() {
|
|
return colonists;
|
|
}
|
|
|
|
public int getProduction() {
|
|
return production;
|
|
}
|
|
|
|
private void add(ProductionData data) {
|
|
colonists += data.colonists;
|
|
production += data.production;
|
|
}
|
|
}
|
|
|
|
public static class LocationData {
|
|
|
|
public interface Getter {
|
|
LocationData getLocationData(UnitData unitData);
|
|
}
|
|
|
|
/**
|
|
* associated unit data
|
|
*/
|
|
private UnitData unitData;
|
|
|
|
/**
|
|
* if this is the total for the unit data
|
|
*/
|
|
private boolean isTotal;
|
|
|
|
/**
|
|
* experts working in their expert field
|
|
*/
|
|
private ProductionData workingProfessionals = new ProductionData();
|
|
|
|
/**
|
|
* lumberjacks working as something else
|
|
*/
|
|
private int workingAmateurs;
|
|
|
|
/**
|
|
* others working as lumberjacks
|
|
*/
|
|
private ProductionData otherWorkingAmateurs = new ProductionData();
|
|
|
|
/**
|
|
* net production of goods
|
|
*/
|
|
private int netProduction;
|
|
|
|
/**
|
|
* teachers
|
|
*/
|
|
private int teachers;
|
|
|
|
/**
|
|
* students learning this job (i.e. lumberjacks, not free colonists)
|
|
*/
|
|
private int otherStudents;
|
|
|
|
/**
|
|
* of of the other studends
|
|
*/
|
|
private String otherStudentsName;
|
|
|
|
/**
|
|
* students in their old type (i.e. free colonists, not lumberjacks)
|
|
*/
|
|
private int students;
|
|
|
|
/**
|
|
* not working colonists
|
|
*/
|
|
private int notWorking;
|
|
|
|
public LocationData(UnitData unitData) {
|
|
this(unitData, false);
|
|
}
|
|
|
|
public LocationData(UnitData unitData, boolean total) {
|
|
this.unitData = unitData;
|
|
isTotal = total;
|
|
}
|
|
|
|
public int getOtherStudents() {
|
|
return otherStudents;
|
|
}
|
|
|
|
public String getOtherStudentsName() {
|
|
return otherStudentsName;
|
|
}
|
|
|
|
public void addOtherStudent(String name) {
|
|
otherStudents++;
|
|
otherStudentsName = name;
|
|
}
|
|
|
|
public ProductionData getWorkingProfessionals() {
|
|
return workingProfessionals;
|
|
}
|
|
|
|
public ProductionData getOtherWorkingAmateurs() {
|
|
return otherWorkingAmateurs;
|
|
}
|
|
|
|
public int getNetProduction() {
|
|
return netProduction;
|
|
}
|
|
|
|
public int getTotalColonists() {
|
|
//count as if the unit was already teached, this makes teaching easier to plan
|
|
//other working amateurs are not counted per default
|
|
return workingAmateurs + workingProfessionals.getColonists() + notWorking +
|
|
teachers + otherStudents - students;
|
|
}
|
|
|
|
public int getTotalProduction() {
|
|
return workingProfessionals.getProduction() + otherWorkingAmateurs.getProduction();
|
|
}
|
|
|
|
/**
|
|
* in the summary for all unit types, some rows are skipped
|
|
*
|
|
* @return the rows to display the unit data
|
|
*/
|
|
public int getRowCount() {
|
|
boolean isSummary = getUnitData().isSummary();
|
|
|
|
int rows = 0;
|
|
if (workingProfessionals.getColonists() > 0) rows++;
|
|
if (workingAmateurs > 0) rows++;
|
|
if (!isSummary && otherWorkingAmateurs.getColonists() > 0) rows++;
|
|
if (teachers > 0) rows++;
|
|
if (students > 0) rows++;
|
|
if (!isSummary && otherStudents > 0) rows++;
|
|
if (notWorking > 0) rows++;
|
|
|
|
return rows;
|
|
}
|
|
|
|
public boolean isTraining() {
|
|
return teachers > 0 || students > 0 || otherStudents > 0;
|
|
}
|
|
|
|
public int getWorkingAmateurs() {
|
|
return workingAmateurs;
|
|
}
|
|
|
|
public int getTeachers() {
|
|
return teachers;
|
|
}
|
|
|
|
public int getStudents() {
|
|
return students;
|
|
}
|
|
|
|
public int getNotWorking() {
|
|
return notWorking;
|
|
}
|
|
|
|
public UnitData getUnitData() {
|
|
return unitData;
|
|
}
|
|
|
|
public boolean isTotal() {
|
|
return isTotal;
|
|
}
|
|
|
|
private void add(LocationData data) {
|
|
workingProfessionals.add(data.workingProfessionals);
|
|
workingAmateurs += data.workingAmateurs;
|
|
otherWorkingAmateurs.add(data.otherWorkingAmateurs);
|
|
|
|
teachers += data.teachers;
|
|
students += data.students;
|
|
otherStudents += data.otherStudents;
|
|
notWorking += data.notWorking;
|
|
|
|
if (data.otherStudents > 0) {
|
|
otherStudentsName = data.otherStudentsName;
|
|
}
|
|
//net production is calculated separately
|
|
}
|
|
}
|
|
|
|
public static class UnitData {
|
|
|
|
private UnitType unitType;
|
|
|
|
private boolean summary = false;
|
|
|
|
/**
|
|
* Map[Colony, colony details]]
|
|
*/
|
|
private Map<Colony, LocationData> details = new LinkedHashMap<Colony, LocationData>();
|
|
|
|
private LocationData total = new LocationData(this, true);
|
|
private LocationData unitsAtSea = new LocationData(this);
|
|
private LocationData unitsOnLand = new LocationData(this);
|
|
private LocationData unitsInEurope = new LocationData(this);
|
|
|
|
public UnitData(UnitType unitType) {
|
|
this.unitType = unitType;
|
|
|
|
if (unitType == null) {
|
|
summary = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* get labour data (create on demand)
|
|
*
|
|
* @param colony
|
|
* @return labour data
|
|
*/
|
|
private LocationData getLocationData(Colony colony) {
|
|
LocationData colonyData = details.get(colony);
|
|
if (colonyData == null) {
|
|
colonyData = new LocationData(this);
|
|
details.put(colony, colonyData);
|
|
}
|
|
return colonyData;
|
|
}
|
|
|
|
public String getUnitName() {
|
|
if (isSummary()) {
|
|
return null;
|
|
}
|
|
return Messages.message(unitType.getNameKey());
|
|
}
|
|
|
|
public boolean hasDetails() {
|
|
return getTotal().getRowCount() > 0;
|
|
}
|
|
|
|
public int getUnitSummaryRowCount() {
|
|
//minimum 1 row to show the unit symbol
|
|
return Math.max(1, getTotal().getRowCount());
|
|
}
|
|
|
|
public UnitType getUnitType() {
|
|
return unitType;
|
|
}
|
|
|
|
public LocationData getTotal() {
|
|
return total;
|
|
}
|
|
|
|
public LocationData getUnitsAtSea() {
|
|
return unitsAtSea;
|
|
}
|
|
|
|
public LocationData getUnitsOnLand() {
|
|
return unitsOnLand;
|
|
}
|
|
|
|
public LocationData getUnitsInEurope() {
|
|
return unitsInEurope;
|
|
}
|
|
|
|
public Map<Colony, LocationData> getDetails() {
|
|
return details;
|
|
}
|
|
|
|
public boolean isSummary() {
|
|
return summary;
|
|
}
|
|
|
|
public boolean showProduction() {
|
|
return !summary && unitType.getExpertProduction() != null;
|
|
}
|
|
|
|
public boolean showNetProduction() {
|
|
return showProduction() && unitType.getExpertProduction().isStorable();
|
|
}
|
|
|
|
public GoodsType getExpertProduction() {
|
|
if (summary) {
|
|
return null;
|
|
}
|
|
return getUnitType().getExpertProduction();
|
|
}
|
|
}
|
|
|
|
private Map<GoodsType, UnitData> experts = new LinkedHashMap<GoodsType, UnitData>();
|
|
|
|
private Map<String, UnitData> unitDataMap = new LinkedHashMap<String, UnitData>();
|
|
|
|
private UnitData summary = new UnitData(null);
|
|
|
|
private UnitData missionary;
|
|
|
|
private UnitData pioneer;
|
|
|
|
private UnitData soldier;
|
|
|
|
private UnitData scout;
|
|
|
|
public LabourData(FreeColClient client) {
|
|
Specification spec = client.getGame().getSpecification();
|
|
for (UnitType unitType : spec.getUnitTypeList()) {
|
|
if (!unitType.isAvailableTo(client.getMyPlayer())) {
|
|
continue;
|
|
}
|
|
GoodsType production = unitType.getExpertProduction();
|
|
if (production != null) {
|
|
experts.put(production, getUnitData(unitType));
|
|
}
|
|
|
|
if (unitType.hasAbility("model.ability.expertPioneer")) {
|
|
pioneer = getUnitData(unitType);
|
|
} else if (unitType.hasAbility("model.ability.expertSoldier")) {
|
|
soldier = getUnitData(unitType);
|
|
} else if (unitType.hasAbility("model.ability.expertScout")) {
|
|
scout = getUnitData(unitType);
|
|
} else if (unitType.hasAbility("model.ability.expertMissionary")) {
|
|
missionary = getUnitData(unitType);
|
|
}
|
|
}
|
|
|
|
gatherData(client.getMyPlayer());
|
|
}
|
|
|
|
private void gatherData(Player player) {
|
|
List<UnitType> labourTypes = getLabourTypes(player);
|
|
|
|
Iterator<Unit> units = player.getUnitIterator();
|
|
while (units.hasNext()) {
|
|
Unit unit = units.next();
|
|
if (!labourTypes.contains(unit.getType())) {
|
|
continue;
|
|
}
|
|
|
|
Location location = unit.getLocation();
|
|
|
|
UnitData data = getUnitData(unit.getType());
|
|
|
|
if (location instanceof WorkLocation) {
|
|
incrementColonyCount(location.getColony(), unit, data);
|
|
} else if (location instanceof Europe) {
|
|
incrementOutsideWorker(data, unit, UNITS_IN_EUROPE_GETTER);
|
|
} else if (location instanceof Tile && ((Tile) location).getSettlement() != null) {
|
|
incrementColonyCount((Colony) ((Tile) location).getSettlement(), unit, data);
|
|
} else if (location instanceof Unit) {
|
|
incrementOutsideWorker(data, unit, UNITS_AT_SEA_GETTER);
|
|
} else {
|
|
incrementOutsideWorker(data, unit, UNITS_ON_LAND_GETTER);
|
|
}
|
|
}
|
|
summarize();
|
|
|
|
for (UnitData unitData : unitDataMap.values()) {
|
|
LocationData total = unitData.getTotal();
|
|
|
|
GoodsType expertProduction = unitData.getUnitType().getExpertProduction();
|
|
if (expertProduction != null) {
|
|
for (Colony colony : player.getColonies()) {
|
|
LocationData data = unitData.details.containsKey(colony) ? unitData.getLocationData(colony) : null;
|
|
|
|
int netProduction = colony.getProductionNetOf(expertProduction);
|
|
if (data != null) {
|
|
data.netProduction = netProduction;
|
|
}
|
|
total.netProduction += netProduction;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static List<UnitType> getLabourTypes(Player player) {
|
|
List<UnitType> unitTypes = player.getSpecification().getUnitTypeList();
|
|
ArrayList<UnitType> labourTypes = new ArrayList<UnitType>();
|
|
for (UnitType unitType : unitTypes) {
|
|
if (unitType.hasSkill() && unitType.isAvailableTo(player)) {
|
|
labourTypes.add(unitType);
|
|
}
|
|
}
|
|
return labourTypes;
|
|
}
|
|
|
|
private void summarize() {
|
|
for (UnitData unitData : unitDataMap.values()) {
|
|
summarize(unitData, UNITS_IN_EUROPE_GETTER);
|
|
summarize(unitData, UNITS_AT_SEA_GETTER);
|
|
summarize(unitData, UNITS_ON_LAND_GETTER);
|
|
|
|
for (final Colony colony : unitData.details.keySet()) {
|
|
summarize(unitData, new LocationData.Getter() {
|
|
public LocationData getLocationData(UnitData data) {
|
|
return data.getLocationData(colony);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
private void summarize(UnitData data, LocationData.Getter getter) {
|
|
LocationData unitLocation = getter.getLocationData(data);
|
|
LocationData summaryLocation = getter.getLocationData(summary);
|
|
|
|
data.total.add(unitLocation);
|
|
summaryLocation.add(unitLocation);
|
|
summary.total.add(unitLocation);
|
|
}
|
|
|
|
private void incrementOutsideWorker(UnitData unitData, Unit unit, LocationData.Getter getter) {
|
|
switch (unit.getRole()) {
|
|
case DRAGOON:
|
|
case SOLDIER:
|
|
incrementOutsideWorker(unitData, unit, soldier, getter);
|
|
break;
|
|
case MISSIONARY:
|
|
incrementOutsideWorker(unitData, unit, missionary, getter);
|
|
break;
|
|
case PIONEER:
|
|
incrementOutsideWorker(unitData, unit, pioneer, getter);
|
|
break;
|
|
case SCOUT:
|
|
incrementOutsideWorker(unitData, unit, scout, getter);
|
|
break;
|
|
default:
|
|
getter.getLocationData(unitData).notWorking++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void incrementOutsideWorker(UnitData expert, Unit unit, UnitData workingAs, LocationData.Getter getter) {
|
|
if (unit.getType() == workingAs.unitType) {
|
|
getter.getLocationData(expert).workingProfessionals.colonists++;
|
|
} else {
|
|
getter.getLocationData(expert).workingAmateurs++;
|
|
|
|
getter.getLocationData(workingAs).otherWorkingAmateurs.colonists++;
|
|
}
|
|
}
|
|
|
|
private void incrementColonyCount(final Colony colony, Unit unit, UnitData unitData) {
|
|
|
|
Location location = unit.getLocation();
|
|
if (!(location instanceof WorkLocation)) {
|
|
incrementOutsideWorker(unitData, unit, new LocationData.Getter() {
|
|
public LocationData getLocationData(UnitData data) {
|
|
return data.getLocationData(colony);
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
|
|
LocationData colonyData = unitData.getLocationData(colony);
|
|
Unit teacher = unit.getTeacher();
|
|
if (teacher != null) {
|
|
colonyData.students++;
|
|
|
|
UnitData learning = getUnitData(Unit.getUnitTypeTeaching(teacher.getType(), unit.getType()));
|
|
learning.getLocationData(colony).addOtherStudent(unitData.getUnitName());
|
|
}
|
|
|
|
GoodsType currentlyWorking = unit.getWorkType();
|
|
int production;
|
|
if (location instanceof Building) {
|
|
Building building = (Building) location;
|
|
|
|
if (building.getType().hasAbility("model.ability.teach")) {
|
|
colonyData.teachers++;
|
|
return;
|
|
}
|
|
|
|
production = building.applyModifiers(building.getUnitProductivity(unit));
|
|
} else {
|
|
production = ((ColonyTile) location).getProductionOf(unit, currentlyWorking);
|
|
}
|
|
|
|
UnitData workingAs = experts.get(currentlyWorking);
|
|
|
|
if (workingAs.getUnitType() == unit.getType()) {
|
|
colonyData.getWorkingProfessionals().addProduction(production);
|
|
} else {
|
|
colonyData.workingAmateurs++;
|
|
|
|
workingAs.getLocationData(colony).otherWorkingAmateurs.addProduction(production);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* get profession data (create on demand)
|
|
*
|
|
* @param unitType goods unitType
|
|
* @return profession data
|
|
*/
|
|
public UnitData getUnitData(UnitType unitType) {
|
|
UnitData data = unitDataMap.get(unitType.getId());
|
|
if (data == null) {
|
|
data = new UnitData(unitType);
|
|
unitDataMap.put(unitType.getId(), data);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
public UnitData getSummary() {
|
|
return summary;
|
|
}
|
|
}
|