package rescuecore2.standard.kernel;
import java.util.Set;
import java.util.HashSet;
import java.util.regex.PatternSyntaxException;
import kernel.AgentRegistrar;
import kernel.ComponentManager;
import kernel.KernelException;
import rescuecore2.config.Config;
import rescuecore2.worldmodel.WorldModel;
import rescuecore2.worldmodel.Entity;
import rescuecore2.worldmodel.Property;
import rescuecore2.Constants;
import rescuecore2.standard.entities.FireBrigade;
import rescuecore2.standard.entities.FireStation;
import rescuecore2.standard.entities.AmbulanceTeam;
import rescuecore2.standard.entities.AmbulanceCentre;
import rescuecore2.standard.entities.PoliceForce;
import rescuecore2.standard.entities.PoliceOffice;
import rescuecore2.standard.entities.Civilian;
import rescuecore2.standard.entities.Human;
import rescuecore2.standard.entities.Road;
import rescuecore2.standard.entities.Area;
import rescuecore2.standard.entities.Building;
import rescuecore2.standard.entities.StandardPropertyURN;
import rescuecore2.standard.entities.StandardEntityURN;
import rescuecore2.standard.entities.StandardWorldModel;
import rescuecore2.standard.StandardConstants;
/**
Class that registers standard agents.
*/
public class StandardAgentRegistrar implements AgentRegistrar {
private static final Set<String> VISIBLE_CONFIG_OPTIONS = new HashSet<String>();
static {
VISIBLE_CONFIG_OPTIONS.add("kernel\\.agents\\.think-time");
VISIBLE_CONFIG_OPTIONS.add("kernel\\.agents\\.ignoreuntil");
VISIBLE_CONFIG_OPTIONS.add("kernel\\.startup\\.connect-time");
VISIBLE_CONFIG_OPTIONS.add(Constants.COMMUNICATION_MODEL_KEY.replace(".", "\\."));
VISIBLE_CONFIG_OPTIONS.add(Constants.PERCEPTION_KEY.replace(".", "\\."));
VISIBLE_CONFIG_OPTIONS.add("fire\\.tank\\.maximum");
VISIBLE_CONFIG_OPTIONS.add("fire\\.tank\\.refill-rate");
VISIBLE_CONFIG_OPTIONS.add("fire\\.extinguish\\.max-sum");
VISIBLE_CONFIG_OPTIONS.add("fire\\.extinguish\\.max-distance");
VISIBLE_CONFIG_OPTIONS.add(StandardConstants.FIRE_BRIGADE_COUNT_KEY.replace(".", "\\."));
VISIBLE_CONFIG_OPTIONS.add(StandardConstants.FIRE_STATION_COUNT_KEY.replace(".", "\\."));
VISIBLE_CONFIG_OPTIONS.add(StandardConstants.AMBULANCE_TEAM_COUNT_KEY.replace(".", "\\."));
VISIBLE_CONFIG_OPTIONS.add(StandardConstants.AMBULANCE_CENTRE_COUNT_KEY.replace(".", "\\."));
VISIBLE_CONFIG_OPTIONS.add(StandardConstants.POLICE_FORCE_COUNT_KEY.replace(".", "\\."));
VISIBLE_CONFIG_OPTIONS.add(StandardConstants.POLICE_OFFICE_COUNT_KEY.replace(".", "\\."));
VISIBLE_CONFIG_OPTIONS.add("comms\\.channels\\.count");
VISIBLE_CONFIG_OPTIONS.add("comms\\.channels\\.max\\.platoon");
VISIBLE_CONFIG_OPTIONS.add("comms\\.channels\\.max\\.centre");
VISIBLE_CONFIG_OPTIONS.add("comms\\.channels\\.\\d+\\.type");
VISIBLE_CONFIG_OPTIONS.add("comms\\.channels\\.\\d+\\.range");
VISIBLE_CONFIG_OPTIONS.add("comms\\.channels\\.\\d+\\.messages\\.size");
VISIBLE_CONFIG_OPTIONS.add("comms\\.channels\\.\\d+\\.messages\\.max");
VISIBLE_CONFIG_OPTIONS.add("comms\\.channels\\.\\d+\\.bandwidth");
VISIBLE_CONFIG_OPTIONS.add("clear\\.repair\\.rate");
VISIBLE_CONFIG_OPTIONS.add("clear\\.repair\\.distance");
VISIBLE_CONFIG_OPTIONS.add("perception\\.los\\.max-distance");
VISIBLE_CONFIG_OPTIONS.add("perception\\.los\\.precision\\.hp");
VISIBLE_CONFIG_OPTIONS.add("perception\\.los\\.precision\\.damage");
}
@Override
public void registerAgents(WorldModel<? extends Entity> world, Config config, ComponentManager manager) throws KernelException {
StandardWorldModel model = StandardWorldModel.createStandardWorldModel(world);
Config agentConfig = new Config(config);
try {
agentConfig.removeExceptRegex(VISIBLE_CONFIG_OPTIONS);
}
catch (PatternSyntaxException e) {
throw new KernelException(e);
}
agentConfig.setIntValue(StandardConstants.FIRE_BRIGADE_COUNT_KEY, model.getEntitiesOfType(StandardEntityURN.FIRE_BRIGADE).size());
agentConfig.setIntValue(StandardConstants.FIRE_STATION_COUNT_KEY, model.getEntitiesOfType(StandardEntityURN.FIRE_STATION).size());
agentConfig.setIntValue(StandardConstants.AMBULANCE_TEAM_COUNT_KEY, model.getEntitiesOfType(StandardEntityURN.AMBULANCE_TEAM).size());
agentConfig.setIntValue(StandardConstants.AMBULANCE_CENTRE_COUNT_KEY, model.getEntitiesOfType(StandardEntityURN.AMBULANCE_CENTRE).size());
agentConfig.setIntValue(StandardConstants.POLICE_FORCE_COUNT_KEY, model.getEntitiesOfType(StandardEntityURN.POLICE_FORCE).size());
agentConfig.setIntValue(StandardConstants.POLICE_OFFICE_COUNT_KEY, model.getEntitiesOfType(StandardEntityURN.POLICE_OFFICE).size());
Set<Entity> initialEntities = new HashSet<Entity>();
for (Entity e : world) {
maybeAddInitialEntity(e, initialEntities);
}
for (Entity e : world) {
if (e instanceof FireBrigade
|| e instanceof FireStation
|| e instanceof AmbulanceTeam
|| e instanceof AmbulanceCentre
|| e instanceof PoliceForce
|| e instanceof PoliceOffice
|| e instanceof Civilian) {
Set<Entity> s = new HashSet<Entity>(initialEntities);
s.remove(e);
s.add(e);
manager.registerAgentControlledEntity(e, s, agentConfig);
}
}
}
private void maybeAddInitialEntity(Entity e, Set<Entity> initialEntities) {
if (e instanceof Road) {
Road r = (Road)e.copy();
filterAreaProperties(r);
initialEntities.add(r);
}
if (e instanceof Building) {
Building b = (Building)e.copy();
filterBuildingProperties(b);
initialEntities.add(b);
}
if (e instanceof Human) {
if (!(e instanceof Civilian)) {
Human h = (Human)e.copy();
filterHumanProperties(h);
initialEntities.add(h);
}
}
}
private void filterAreaProperties(Area a) {
for (Property next : a.getProperties()) {
// Hide blockades
StandardPropertyURN urn = StandardPropertyURN.fromString(next.getURN());
switch (urn) {
case BLOCKADES:
next.undefine();
break;
default:
break;
}
}
}
private void filterBuildingProperties(Building b) {
filterAreaProperties(b);
for (Property next : b.getProperties()) {
// Hide ignition, fieryness, brokenness, temperature
StandardPropertyURN urn = StandardPropertyURN.fromString(next.getURN());
switch (urn) {
case IGNITION:
case FIERYNESS:
case BROKENNESS:
case TEMPERATURE:
next.undefine();
break;
default:
// Ignore
}
}
}
private void filterHumanProperties(Human h) {
for (Property next : h.getProperties()) {
// Human properties: POSITION, X, Y, WATER_QUANTITY
// Everything else should be undefined
StandardPropertyURN urn = StandardPropertyURN.fromString(next.getURN());
switch (urn) {
case X:
case Y:
case POSITION:
case WATER_QUANTITY:
break;
default:
next.undefine();
}
}
}
}