Skip to content

Commit

Permalink
Migration of resource reports to use plugin data based construction a…
Browse files Browse the repository at this point in the history
…nd support serialization.
  • Loading branch information
humbledaisy committed Mar 22, 2023
1 parent 3565aae commit ba3bc66
Show file tree
Hide file tree
Showing 13 changed files with 2,931 additions and 160 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ public abstract class PeriodicReport {
* Creates the periodic report from the given report period
*
* @throws ContractException
* <li>if the report period is null</li>
* <li>{@linkplain ReportError#NULL_REPORT_PERIOD} if the report period is null</li>
* <li>{@linkplain ReportError.NULL_REPORT_LABEL} if the report period is null</li>
*/
public PeriodicReport(ReportLabel reportLabel, ReportPeriod reportPeriod) {
if (reportPeriod == null) {
Expand Down
201 changes: 132 additions & 69 deletions gcm4/src/main/java/plugins/resources/reports/PersonResourceReport.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.Set;

import nucleus.ReportContext;
import nucleus.SimulationStateContext;
import plugins.people.datamanagers.PeopleDataManager;
import plugins.people.events.PersonAdditionEvent;
import plugins.people.events.PersonImminentRemovalEvent;
Expand All @@ -17,8 +18,6 @@
import plugins.reports.support.PeriodicReport;
import plugins.reports.support.ReportHeader;
import plugins.reports.support.ReportItem;
import plugins.reports.support.ReportLabel;
import plugins.reports.support.ReportPeriod;
import plugins.resources.datamanagers.ResourcesDataManager;
import plugins.resources.events.PersonResourceUpdateEvent;
import plugins.resources.events.ResourceIdAdditionEvent;
Expand All @@ -35,7 +34,7 @@
*
* region -- the region identifier
*
* Resource -- the resource identifier
* resource -- the resource identifier
*
* people_with_resource -- the number of people in the region who have at least
* one unit of the given resource
Expand All @@ -46,13 +45,13 @@
*
*/
public final class PersonResourceReport extends PeriodicReport {
public PersonResourceReport(ReportLabel reportLabel, ReportPeriod reportPeriod, boolean reportPeopleWithoutResources, boolean reportZeroPopulations, ResourceId... resourceIds) {
super(reportLabel, reportPeriod);
this.reportPeopleWithoutResources = reportPeopleWithoutResources;
this.reportZeroPopulations = reportZeroPopulations;
for (ResourceId resourceId : resourceIds) {
this.resourceIds.add(resourceId);
}
public PersonResourceReport(PersonResourceReportPluginData personResourceReportPluginData) {
super(personResourceReportPluginData.getReportLabel(), personResourceReportPluginData.getReportPeriod());
this.reportPeopleWithoutResources = personResourceReportPluginData.getReportPeopleWithoutResources();
this.reportZeroPopulations = personResourceReportPluginData.getReportZeroPopulations();
this.includedResourceIds.addAll(personResourceReportPluginData.getIncludedResourceIds());
this.excludedResourceIds.addAll(personResourceReportPluginData.getExcludedResourceIds());
this.includeNewResourceIds = personResourceReportPluginData.getDefaultInclusionPolicy();
}

/**
Expand All @@ -69,19 +68,23 @@ private static enum InventoryType {
* The resources that will be used in this report. They are derived from the
* values passed in the init() method.
*/
private Set<ResourceId> resourceIds = new LinkedHashSet<>();

private final boolean includeNewResourceIds;

private final Set<ResourceId> includedResourceIds = new LinkedHashSet<>();
private final Set<ResourceId> currentResourceIds = new LinkedHashSet<>();
private final Set<ResourceId> excludedResourceIds = new LinkedHashSet<>();
/*
* Boolean for controlling the reporting of people with out resources. Set
* in the init() method.
*/
private boolean reportPeopleWithoutResources;
private final boolean reportPeopleWithoutResources;

/*
* Boolean for controlling the reporting of people with out resources. Set
* in the init() method.
*/
private boolean reportZeroPopulations;
private final boolean reportZeroPopulations;

// Mapping of the (regionId, resource Id, InventoryType) to
// sets of person id. Maintained via the processing of events.
Expand Down Expand Up @@ -120,7 +123,7 @@ protected void flush(ReportContext reportContext) {
final ReportItem.Builder reportItemBuilder = ReportItem.builder();
for (final RegionId regionId : regionMap.keySet()) {
final Map<ResourceId, Map<InventoryType, Set<PersonId>>> resourceMap = regionMap.get(regionId);
for (final ResourceId resourceId : resourceIds) {
for (final ResourceId resourceId : currentResourceIds) {
final Map<InventoryType, Set<PersonId>> inventoryMap = resourceMap.get(resourceId);

final int positiveCount = inventoryMap.get(InventoryType.POSITIVE).size();
Expand Down Expand Up @@ -153,7 +156,7 @@ private void handlePersonAdditionEvent(ReportContext reportContext, PersonAdditi
PersonId personId = personAdditionEvent.personId();
final RegionId regionId = regionsDataManager.getPersonRegion(personId);

for (final ResourceId resourceId : resourceIds) {
for (final ResourceId resourceId : currentResourceIds) {
final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId);
if (personResourceLevel > 0) {
add(regionId, resourceId, InventoryType.POSITIVE, personId);
Expand All @@ -171,7 +174,7 @@ private void handlePersonImminentRemovalEvent(ReportContext reportContext, Perso

RegionId regionId = regionsDataManager.getPersonRegion(personId);

for (ResourceId resourceId : resourceIds) {
for (ResourceId resourceId : currentResourceIds) {
Long amount = resourcesDataManager.getPersonResourceLevel(resourceId, personId);
if (amount > 0) {
remove(regionId, resourceId, InventoryType.POSITIVE, personId);
Expand All @@ -185,47 +188,45 @@ private void handlePersonImminentRemovalEvent(ReportContext reportContext, Perso

private void handlePersonResourceUpdateEvent(ReportContext reportContext, PersonResourceUpdateEvent personResourceUpdateEvent) {
ResourceId resourceId = personResourceUpdateEvent.resourceId();
if (!resourceIds.contains(resourceId)) {
return;
}
PersonId personId = personResourceUpdateEvent.personId();
long currentLevel = personResourceUpdateEvent.currentResourceLevel();
long previousLevel = personResourceUpdateEvent.previousResourceLevel();
long amount = currentLevel - previousLevel;

if (amount == 0) {
return;
}
if (amount > 0) {
final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId);
if (personResourceLevel == amount) {
final RegionId regionId = regionsDataManager.getPersonRegion(personId);
if (isCurrentProperty(resourceId)) {
PersonId personId = personResourceUpdateEvent.personId();
long currentLevel = personResourceUpdateEvent.currentResourceLevel();
long previousLevel = personResourceUpdateEvent.previousResourceLevel();
long amount = currentLevel - previousLevel;

if (amount == 0) {
return;
}
if (amount > 0) {
final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId);
if (personResourceLevel == amount) {
final RegionId regionId = regionsDataManager.getPersonRegion(personId);

if (reportPeopleWithoutResources) {
remove(regionId, resourceId, InventoryType.ZERO, personId);
if (reportPeopleWithoutResources) {
remove(regionId, resourceId, InventoryType.ZERO, personId);
}
add(regionId, resourceId, InventoryType.POSITIVE, personId);
}
add(regionId, resourceId, InventoryType.POSITIVE, personId);
}
} else {
amount = -amount;
final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId);
if (personResourceLevel == 0) {
final RegionId regionId = regionsDataManager.getPersonRegion(personId);
remove(regionId, resourceId, InventoryType.POSITIVE, personId);
if (reportPeopleWithoutResources) {
add(regionId, resourceId, InventoryType.ZERO, personId);
} else {
amount = -amount;
final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId);
if (personResourceLevel == 0) {
final RegionId regionId = regionsDataManager.getPersonRegion(personId);
remove(regionId, resourceId, InventoryType.POSITIVE, personId);
if (reportPeopleWithoutResources) {
add(regionId, resourceId, InventoryType.ZERO, personId);
}
}
}
}

}

private void handlePersonRegionUpdateEvent(ReportContext reportContext, PersonRegionUpdateEvent personRegionUpdateEvent) {
PersonId personId = personRegionUpdateEvent.personId();
RegionId previousRegionId = personRegionUpdateEvent.previousRegionId();
RegionId currentRegionId = personRegionUpdateEvent.currentRegionId();

for (final ResourceId resourceId : resourceIds) {
for (final ResourceId resourceId : currentResourceIds) {
final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId);
if (personResourceLevel > 0) {
remove(previousRegionId, resourceId, InventoryType.POSITIVE, personId);
Expand All @@ -242,6 +243,66 @@ private void handlePersonRegionUpdateEvent(ReportContext reportContext, PersonRe
private RegionsDataManager regionsDataManager;
private ResourcesDataManager resourcesDataManager;

private boolean isCurrentProperty(ResourceId resourceId) {
return currentResourceIds.contains(resourceId);
}

private boolean addToCurrentResourceIds(ResourceId resourceId) {

// There are eight possibilities:

/*
* P -- the default inclusion policy
*
* I -- the property is explicitly included
*
* X -- the property is explicitly excluded
*
* C -- the property should be on the current properties
*
*
* P I X C Table
*
* TRUE TRUE FALSE TRUE
*
* TRUE FALSE FALSE TRUE
*
* FALSE TRUE FALSE TRUE
*
* FALSE FALSE FALSE FALSE
*
* TRUE TRUE TRUE FALSE -- not possible
*
* TRUE FALSE TRUE FALSE
*
* FALSE TRUE TRUE FALSE -- not possible
*
* FALSE FALSE TRUE FALSE
*
*
* Two of the cases above are contradictory since a property cannot be
* both explicitly included and explicitly excluded
*
*/

// if X is true then we don't add the property
if (excludedResourceIds.contains(resourceId)) {
return false;
}

// if both P and I are false we don't add the property
boolean included = includedResourceIds.contains(resourceId);

if (!included && !includeNewResourceIds) {
return false;
}

// we have failed to reject the property
currentResourceIds.add(resourceId);

return true;
}

/**
*
* @throws ContractException
Expand All @@ -260,26 +321,13 @@ protected void prepare(final ReportContext reportContext) {
reportContext.subscribe(PersonImminentRemovalEvent.class, this::handlePersonImminentRemovalEvent);
reportContext.subscribe(PersonRegionUpdateEvent.class, this::handlePersonRegionUpdateEvent);
reportContext.subscribe(RegionAdditionEvent.class, this::handleRegionAdditionEvent);

/*
* If no resources were selected, then assume that all are desired.
*/
if (resourceIds.size() == 0) {
resourceIds.addAll(resourcesDataManager.getResourceIds());
}

/*
* Ensure that the resources are valid
*/
final Set<ResourceId> validResourceIds = resourcesDataManager.getResourceIds();
for (final ResourceId resourceId : resourceIds) {
if (!validResourceIds.contains(resourceId)) {
throw new ContractException(ResourceError.UNKNOWN_RESOURCE_ID, resourceId);
}
}

reportContext.subscribe(PersonResourceUpdateEvent.class, this::handlePersonResourceUpdateEvent);
reportContext.subscribe(ResourceIdAdditionEvent.class, this::handleResourceIdAdditionEvent);
reportContext.subscribeToSimulationState(this::recordSimulationState);

for (final ResourceId resourceId : resourcesDataManager.getResourceIds()) {
addToCurrentResourceIds(resourceId);
}

/*
* Build the tuple map to empty sets of people in preparation for people
Expand All @@ -291,7 +339,7 @@ protected void prepare(final ReportContext reportContext) {
final Map<ResourceId, Map<InventoryType, Set<PersonId>>> resourceMap = new LinkedHashMap<>();
regionMap.put(regionId, resourceMap);

for (final ResourceId resourceId : resourceIds) {
for (final ResourceId resourceId : currentResourceIds) {
final Map<InventoryType, Set<PersonId>> inventoryMap = new LinkedHashMap<>();
resourceMap.put(resourceId, inventoryMap);
for (final InventoryType inventoryType : InventoryType.values()) {
Expand All @@ -306,7 +354,7 @@ protected void prepare(final ReportContext reportContext) {
* Place the initial population in the mapping
*/
for (final PersonId personId : peopleDataManager.getPeople()) {
for (final ResourceId resourceId : resourceIds) {
for (final ResourceId resourceId : currentResourceIds) {
final RegionId regionId = regionsDataManager.getPersonRegion(personId);

final long personResourceLevel = resourcesDataManager.getPersonResourceLevel(resourceId, personId);
Expand All @@ -322,6 +370,22 @@ protected void prepare(final ReportContext reportContext) {

}

private void recordSimulationState(ReportContext reportContext, SimulationStateContext simulationStateContext) {
PersonResourceReportPluginData.Builder builder = simulationStateContext.get(PersonResourceReportPluginData.Builder.class);
for (ResourceId resourceId : includedResourceIds) {
builder.includeResourceId(resourceId);
}
for (ResourceId resourceId : excludedResourceIds) {
builder.excludeResourceId(resourceId);
}
builder.setDefaultInclusion(includeNewResourceIds);
builder.setReportLabel(getReportLabel());
builder.setReportPeriod(getReportPeriod());
builder.setReportPeopleWithoutResources(reportPeopleWithoutResources);
builder.setReportZeroPopulations(reportZeroPopulations);

}

private void handleRegionAdditionEvent(ReportContext reportContext, RegionAdditionEvent regionAdditionEvent) {
RegionId regionId = regionAdditionEvent.getRegionId();

Expand All @@ -330,7 +394,7 @@ private void handleRegionAdditionEvent(ReportContext reportContext, RegionAdditi
final Map<ResourceId, Map<InventoryType, Set<PersonId>>> resourceMap = new LinkedHashMap<>();
regionMap.put(regionId, resourceMap);

for (final ResourceId resourceId : resourceIds) {
for (final ResourceId resourceId : currentResourceIds) {
final Map<InventoryType, Set<PersonId>> inventoryMap = new LinkedHashMap<>();
resourceMap.put(resourceId, inventoryMap);
for (final InventoryType inventoryType : InventoryType.values()) {
Expand All @@ -346,16 +410,15 @@ private void handleRegionAdditionEvent(ReportContext reportContext, RegionAdditi
* Removes a person to the set of people associated with the given tuple
*/
private void remove(final RegionId regionId, final ResourceId resourceId, final InventoryType inventoryType, final PersonId personId) {
if (resourceIds.contains(resourceId)) {
if (currentResourceIds.contains(resourceId)) {
final Set<PersonId> people = regionMap.get(regionId).get(resourceId).get(inventoryType);
people.remove(personId);
}
}

private void handleResourceIdAdditionEvent(ReportContext reportContext, ResourceIdAdditionEvent resourceIdAdditionEvent) {
ResourceId resourceId = resourceIdAdditionEvent.resourceId();
if (!resourceIds.contains(resourceId)) {
resourceIds.add(resourceId);
if (addToCurrentResourceIds(resourceId)) {
for (RegionId regionID : regionMap.keySet()) {
Map<ResourceId, Map<InventoryType, Set<PersonId>>> map = regionMap.get(regionID);
Map<InventoryType, Set<PersonId>> invMap = new LinkedHashMap<>();
Expand Down
Loading

0 comments on commit ba3bc66

Please sign in to comment.