package rescuecore2.standard.kernel.comms;
import java.util.Collection;
import java.util.Map;
import kernel.AbstractCommunicationModel;
import rescuecore2.messages.Command;
import rescuecore2.config.Config;
import rescuecore2.worldmodel.Entity;
import rescuecore2.worldmodel.EntityID;
import rescuecore2.worldmodel.WorldModel;
import rescuecore2.misc.collections.LazyMap;
import rescuecore2.log.Logger;
import rescuecore2.standard.entities.StandardWorldModel;
import rescuecore2.standard.entities.StandardEntity;
import rescuecore2.standard.entities.StandardEntityURN;
import rescuecore2.standard.entities.FireBrigade;
import rescuecore2.standard.entities.FireStation;
import rescuecore2.standard.entities.PoliceForce;
import rescuecore2.standard.entities.PoliceOffice;
import rescuecore2.standard.entities.AmbulanceTeam;
import rescuecore2.standard.entities.AmbulanceCentre;
import rescuecore2.standard.entities.Human;
import rescuecore2.standard.messages.AKSay;
import rescuecore2.standard.messages.AKTell;
/**
The legacy communication model: fire brigades talk to fire brigades and the fire station, police to police, ambulance to ambulance and centres talk to centres.
*/
public class StandardCommunicationModel extends AbstractCommunicationModel {
private static final String SAY_RANGE_KEY = "comms.standard.say.range";
private static final String PLATOON_MAX_KEY = "comms.standard.platoon.max";
private static final String MAX_SIZE_KEY = "comms.standard.size.max";
private StandardWorldModel world;
private int sayDistance;
private int maxSize;
private int platoonMax;
private int fsMax;
private int poMax;
private int acMax;
private Map<EntityID, Integer> uttered;
private Map<EntityID, Integer> heard;
/**
Construct a StandardCommunicationModel.
*/
public StandardCommunicationModel() {
uttered = new LazyMap<EntityID, Integer>() {
@Override
public Integer createValue() {
return 0;
}
};
heard = new LazyMap<EntityID, Integer>() {
@Override
public Integer createValue() {
return 0;
}
};
}
@Override
public String toString() {
return "Standard communication model";
}
@Override
public void initialise(Config config, WorldModel<? extends Entity> model) {
super.initialise(config, model);
world = StandardWorldModel.createStandardWorldModel(model);
sayDistance = config.getIntValue(SAY_RANGE_KEY);
maxSize = config.getIntValue(MAX_SIZE_KEY);
platoonMax = config.getIntValue(PLATOON_MAX_KEY);
fsMax = world.getEntitiesOfType(StandardEntityURN.FIRE_BRIGADE).size() * 2;
acMax = world.getEntitiesOfType(StandardEntityURN.AMBULANCE_TEAM).size() * 2;
poMax = world.getEntitiesOfType(StandardEntityURN.POLICE_FORCE).size() * 2;
}
@Override
public void process(int time, Collection<? extends Command> agentCommands) {
super.process(time, agentCommands);
uttered.clear();
heard.clear();
for (Command next : agentCommands) {
try {
if (next instanceof AKSay) {
processSay((AKSay)next);
}
if (next instanceof AKTell) {
processTell((AKTell)next);
}
}
catch (InvalidMessageException e) {
Logger.warn("Invalid message: " + next, e);
}
}
}
private void processSay(AKSay say) throws InvalidMessageException {
EntityID senderID = say.getAgentID();
StandardEntity sender = world.getEntity(senderID);
if (!(sender instanceof Human)) {
throw new InvalidMessageException("Agent " + senderID + " is not a human: " + (sender == null ? "null" : sender.getClass().getName()));
}
byte[] data = say.getContent();
if (data.length > maxSize) {
throw new InvalidMessageException("Agent " + senderID + " sent an oversize message: " + data.length + " > " + maxSize);
}
int count = uttered.get(senderID);
int max = getMessageMax(sender);
if (count >= getMessageMax(sender)) {
throw new InvalidMessageException("Agent " + senderID + " has uttered too many messages: " + count + " >= " + max);
}
uttered.put(senderID, count + 1);
for (StandardEntity receiver : world.getEntitiesOfType(StandardEntityURN.CIVILIAN,
StandardEntityURN.FIRE_BRIGADE,
StandardEntityURN.FIRE_STATION,
StandardEntityURN.AMBULANCE_TEAM,
StandardEntityURN.AMBULANCE_CENTRE,
StandardEntityURN.POLICE_FORCE,
StandardEntityURN.POLICE_OFFICE)) {
int h = heard.get(receiver.getID());
if (h >= getMessageMax(receiver)) {
continue;
}
int distance = world.getDistance(sender, receiver);
if (distance <= sayDistance) {
addHearing(receiver, say);
heard.put(receiver.getID(), h + 1);
}
}
}
private void processTell(AKTell tell) throws InvalidMessageException {
EntityID senderID = tell.getAgentID();
StandardEntity sender = world.getEntity(senderID);
if (!(sender instanceof Human)) {
throw new InvalidMessageException("Agent " + senderID + " is not a human: " + (sender == null ? "null" : sender.getClass().getName()));
}
byte[] data = tell.getContent();
if (data.length > maxSize) {
throw new InvalidMessageException("Agent " + senderID + " sent an oversize message: " + data.length + " > " + maxSize);
}
int count = uttered.get(senderID);
int max = getMessageMax(sender);
if (count >= getMessageMax(sender)) {
throw new InvalidMessageException("Agent " + senderID + " has uttered too many messages: " + count + " >= " + max);
}
uttered.put(senderID, count + 1);
for (StandardEntity receiver : world.getEntitiesOfType(StandardEntityURN.CIVILIAN,
StandardEntityURN.FIRE_BRIGADE,
StandardEntityURN.FIRE_STATION,
StandardEntityURN.AMBULANCE_TEAM,
StandardEntityURN.AMBULANCE_CENTRE,
StandardEntityURN.POLICE_FORCE,
StandardEntityURN.POLICE_OFFICE)) {
int h = heard.get(receiver.getID());
if (h >= getMessageMax(receiver)) {
continue;
}
if (canHear(receiver, sender)) {
addHearing(receiver, tell);
heard.put(receiver.getID(), h + 1);
}
}
}
private int getMessageMax(StandardEntity e) {
if (e instanceof FireStation) {
return fsMax;
}
if (e instanceof PoliceOffice) {
return poMax;
}
if (e instanceof AmbulanceCentre) {
return acMax;
}
if (e instanceof Human) {
return platoonMax;
}
return 0;
}
private boolean canHear(StandardEntity receiver, StandardEntity sender) {
if (receiver instanceof FireBrigade) {
return sender instanceof FireBrigade || sender instanceof FireStation;
}
if (receiver instanceof FireStation) {
return sender instanceof FireBrigade
|| sender instanceof FireStation
|| sender instanceof PoliceOffice
|| sender instanceof AmbulanceCentre;
}
if (receiver instanceof PoliceForce) {
return sender instanceof PoliceForce || sender instanceof PoliceOffice;
}
if (receiver instanceof PoliceOffice) {
return sender instanceof PoliceForce
|| sender instanceof FireStation
|| sender instanceof PoliceOffice
|| sender instanceof AmbulanceCentre;
}
if (receiver instanceof AmbulanceTeam) {
return sender instanceof AmbulanceTeam || sender instanceof AmbulanceCentre;
}
if (receiver instanceof AmbulanceCentre) {
return sender instanceof AmbulanceTeam
|| sender instanceof FireStation
|| sender instanceof PoliceOffice
|| sender instanceof AmbulanceCentre;
}
return false;
}
}