package System;
import Agents.Agent;
import Agents.Behaviour.VehicleMoveBehaviour;
import Agents.Person;
import Agents.Vehicle;
import Entity.CustomStyle;
import Entity.Disaster;
import Entity.Hospital;
import Entity.IdPointPair;
import Entity.TrafficLight;
import GeographicInformation.BoundingBox;
import GeographicInformation.Cell;
import GeographicInformation.Location;
import GlobalData.CTANetwork;
import GlobalData.Constants;
import GlobalData.SharedData;
import Messaging.Message;
import Messaging.QueueParameters;
import Utilities.GenerateAttributes;
import Utilities.KmlUtility;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.postgis.Point;
/**
* Care taker agent for vehicle agents. This Cate Taker is responsible for
* civilian vehicles only. Therefore the vehilces will follow traffic rules, etc.
* Information exchange will exist between Traffic Light's Care Taker and
* the Vehicle's Cate Taker. All references to vehicles in this
* document will be civilian vehicles.
* @see CareTakerAgent
* @see Vehicle
* @see VehicleMoveBehaviour
*/
public class VehicleCTA extends CareTakerAgent {
HashMap<String, CustomStyle> vehicleStyles = new HashMap<String, CustomStyle>();
/**
* Total number of civilian vehicles
*/
private int totalNumberOfVehicles;
/**
* The list of locations where the agents are located.
*/
private ArrayList<Location> agentLocations;
/**
* The styles that represent the agents.
*/
private ArrayList<String> agentStyles;
/**
* Stop receiving messages when the flag is true.
*/
private boolean holdMessages = false;
private boolean restoreState = false;
/**
* Constructor to create the vehicle CTA
*/
public VehicleCTA() {
Utilities.Log.ConfigureLogger(); //Start the loggger
readConfigurations();// Read the configuration files.
createObjects();
buildCTAStatus();
addQueueListener();
setTotalNumberOfVehicles(SharedData.numberOfCivilVehicles);
Utilities.Log.logger.info("Vehicle CTA Started");
Utilities.Log.logger.info("Number of CTAs : " + CTANetwork.hosts.size() + " with a total of " + getTotalNumberOfVehicles() + "vehicles.");
}
/**
* Creates all the objects necessary for the CTA operation.
* @see EmergencyServiceCTA
* @see CareTakerAgent
*/
private void createObjects() {
CTAStatus = Collections.synchronizedMap(new HashMap<String, Integer>());
agents = new ArrayList<Agent>();
agentStyles = new ArrayList<String>();
}
private VehicleCTA(String filename) {
Utilities.Log.ConfigureLogger();
createObjects();
restoreState(filename);
addQueueListener();
restoreState = true;
Utilities.Log.logger.info("Restored state after " + currentTickNumber + " tick");
sendRestoreState();
Utilities.Log.logger.info("Sent Restored State Message");
long timeBeforewaiting = System.currentTimeMillis();
while (!checkIfAllCTAsDoneWithRestoreState()) {
try {
long timeNow = System.currentTimeMillis();
if (timeNow - timeBeforewaiting >= CTANetwork.MAXIMUM_TIME_OUT_FOR_SAVING_STATE) {
updateTimeOutList();
Utilities.Log.logger.info("Continuing with run after timeout for saving state");
break;
} else {
//wait until all CTAs are ready
Thread.sleep(500);
}
} catch (InterruptedException ex) {
Logger.getLogger(PeopleCTA.class.getName()).log(Level.SEVERE, null, ex);
}
}
buildCTAStatus();
Utilities.Log.logger.info("Number of CTAs : " + CTANetwork.hosts.size());
}
/**
* Create the individual cilillian vehicles.
*/
void createVehicles() {
//Create the civilian vehicles
for (int i = 0; i < SharedData.numberOfCivilVehicles; i++) {
IdPointPair homeBaseIdPointPair = GenerateAttributes.generateIdPointPairOnRoad();
long homebaseId = homeBaseIdPointPair.id;
IdPointPair currentLocationIdPointPair = GenerateAttributes.generateIdPointPairOnRoad();
long startcellId = currentLocationIdPointPair.id;
Point currentLocation = currentLocationIdPointPair.point;
Location homeBase = new Location(currentLocationIdPointPair.point, "");
int capacity = GenerateAttributes.generateCapacity();
int curLoad = GenerateAttributes.generateLoad(capacity);
Cell cell = new Cell(currentLocation, true);
int speed = GenerateAttributes.generateSpeed();
String type = Constants.VEHICLE_TYPE_CIVIL;
//Utilities.Log.logger.info(currentLocation.toString() + " " + homeBase.toString() + " " + lifeAttribs.toString());
Vehicle v = null;
try {
v = new Vehicle(capacity, curLoad, homeBase, cell, speed, type, startcellId, homebaseId);
} catch (InstantiationException ex) {
Utilities.Log.logger.info("Error creating a new vehicle. " + ex.getMessage());
//Since the vehicles could not be created exit the CTA
exitSystem();
}
agents.add(v);
agentStyles.add(Constants.VEHICLE_TYPE_CIVIL);
}
Utilities.Log.logger.info("Finished Creating Civilian Vehicles. Added " + agents.size() + " agents");
}
/**
* Check if all the agents are ready for next tick.
* @return true if all agents are ready.
*/
@Override
public boolean checkIfAllAgentsReadyForNextTick() {
/**TODO
* This logic can be changed to exit as soon as you find p.statusFlag as false
*/
int count = 0;
for (Agent p : agents) {
if (p.statusFlag) {
count++;
}
}
if ((count == agents.size()) && (count > 0)) {
return true;
} else {
return false;
}
}
/**
* Activate the agents, by calling their action methods
*/
@Override
public void activateAgentBehaviour() {
Collections.shuffle(agents);
for (Agent p : agents) {
p.run();
}
}
/**
* Cleanup operations performed by the care taker after each run of all agents.
* The cleanup operation adds the placemarks to the kml files and writes out
* the output. In addition it changes the status of the CTA to ready for next
* tick.
*/
private void cleanUp() {
sendReadyForTick();
Utilities.Log.logger.info(agents.size() + " yet to reach home");
//kmlUtility.addPlacemarks(agentLocations, agentStyles, currentTickNumber);
kmlUtility.addPlacemarks(agentLocations, agents, "vehicle", agentStyles,this.getCurrentTickNumber());
if (currentTickNumber % 50 == 0) {
writeKMLFile("vehicle");
kmlUtility = new KmlUtility(vehicleStyles);
}
for (String host : CTAStatus.keySet()) {
Utilities.Log.logger.info(host + " : " + CTAStatus.get(host));
}
if ((currentTickNumber % SharedData.saveStateAtTick == 0 && SharedData.isStateSaveEnabled) || initiateStateSave) {
initiateStateSave = false;
Utilities.Log.logger.info("Sending message for CTAs to save their respective states at tick: " + currentTickNumber);
sendSavingState(currentTickNumber);
beginStateSave();
holdMessages = true;
changeSavedCTAsToReady();
holdMessages = false;
}
}
/**
* This begins the process of saving states, for the CTA.
* After sending a message to other CTAs saying it is saving its state, it waits until every CTA is also doing the same.
* It then writes the state as binary data into a file, and sends a message saying it has completed saving state.
* It waits until all CTAs have completed saving their respective states before exiting the funtion.
*/
private void beginStateSave() {
// Check if all CTAs are saving state
long timeBeforewaiting = System.currentTimeMillis();
while (!checkIfAllCTAsReadyForStateSave()) {
try {
long timeNow = System.currentTimeMillis();
if (timeNow - timeBeforewaiting >= CTANetwork.MAXIMUM_TIME_OUT_FOR_SAVING_STATE) {
updateTimeOutList();
Utilities.Log.logger.info("Continuing with run after timeout for saving state");
break;
} else {
//wait until all CTAs are ready
Thread.sleep(500);
}
} catch (InterruptedException ex) {
Logger.getLogger(PeopleCTA.class.getName()).log(Level.SEVERE, null, ex);
}
}
saveCTAState();
initiateStateSave = false;
sendSavedState();
// Check if all CTAs have finished saving state
timeBeforewaiting = System.currentTimeMillis();
while (!checkIfAllCTAsDoneWithStateSave()) {
Utilities.Log.logger.info("Waiting for CTA to finish saving state");
try {
long timeNow = System.currentTimeMillis();
if (timeNow - timeBeforewaiting >= CTANetwork.MAXIMUM_TIME_OUT_FOR_SAVING_STATE) {
updateTimeOutList();
Utilities.Log.logger.info("Continuing with run after timeout for saved state");
break;
} else {
//wait until all CTAs are ready
Thread.sleep(500);
}
} catch (InterruptedException ex) {
Logger.getLogger(PeopleCTA.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
/**
* Return total number of vehicles
* @return total number of vehicles.
*/
public int getTotalNumberOfVehicles() {
return totalNumberOfVehicles;
}
/**
* This method is invoked when the disaster is triggered. The method performs
* the necessary state changes and informs the individual agents about the disaster.
*/
private void kaboom() {
// if (currentTickNumber % 5 != 0) {
// return;
// }
//this has to be done for all disasters for all agents
//check for people within a certain radius and reduce their health by a factor-this has to be parameterized sometime soon
//equation of a circle (x-h)^2+(y-k)^2=r^2 where (h,k) is the centre
//therefore, factor f= (xp-h)^2+(yp-k)^2-r^2
// f<0 implies within a radius. Health reduced as a factor of (r-f)/r so at the perimeter they still don't loose any health
Iterator<Disaster> iterator = SharedData.disasters.iterator();
while (iterator.hasNext()) {
Disaster boom = iterator.next();
if (boom.tick != currentTickNumber) {
return;
}
System.out.println("Disaster!!! Disaster!!!\n Bhagooo.... Bhaaagooo");
Double h = boom.getLatlon().getX();
Double k = boom.getLatlon().getY();
//Utilities.Log.logger.info("h: "+h.toString());
//Utilities.Log.logger.info("k: "+k.toString());
Double radius = boom.getIntensity() * 0.0008;
Double rsquare = radius * radius;
//Utilities.Log.logger.info("Radius square : " + rsquare.toString());
// if (boom.disasterTriggerTimeInTicks <= currentTickNumber) {
//cycle through all the people in the CTA
Iterator<Agent> vehicles = agents.iterator();
while (vehicles.hasNext()) {
Vehicle vehicle = (Vehicle) vehicles.next();
vehicle.notifyDisaster(boom);
// }
}
}
}
/**
* Create the all the style objects that will be used by the any of the
* vehicle agents
*/
private void createStyles() {
CustomStyle defaultVehicle = new CustomStyle(Constants.VEHICLE_SCALE, Constants.VEHICLE_DEFAULT_IMAGE);
//TODO change key (strings) to constants
vehicleStyles.put("civil", defaultVehicle);
kmlUtility = new KmlUtility(vehicleStyles);
}
/**
* Set total number of vehicles
* @param totalNumberOfVehicles total number of vehicles
*/
public void setTotalNumberOfVehicles(int totalNumberOfVehicles) {
this.totalNumberOfVehicles = totalNumberOfVehicles;
}
/**
* This method is called to set up the CTA for operation
*/
private void setUp() {
// Boot functions
if (Utilities.AIDGenerator.initializeAIDGen()) {
createStyles();
} else {
Utilities.Log.logger.info("AIDs cannot be generated");
//System.exit(0);
exitSystem();
}
// Generate Agents
if (!restoreState) {
createVehicles();
}
Utilities.Log.logger.info("Finished Vehicle SetUp");
sendReadyForTick();
}
/**
* The run agents calls the individual agents run methods and advances the
* agent by one tick. The CTA does not move forward untill all agents have
* completed their run behaviour once within a given timeout.
* The EmergencyService run agent calls the run method of the agents but does not
* check if the agents are home as these agents are active for the entire simulation,
* similar to a real emergency services.
* @see CareTakerAgent
*/
private void runAgents() {
activateAgentBehaviour();
agentLocations = new ArrayList<Location>();
agentStyles = new ArrayList<String>();
while (checkIfAllAgentsReadyForNextTick()) {
//Check if agent a given agent has reached the home base
for (int i = agents.size() - 1; i > -1; i--) {
if (((Vehicle) agents.get(i)).getAttributes().isAgentHome) {
agents.remove(i);
i = agents.size() - 1;
continue;
}
agents.get(i).statusFlag = false;
agentLocations.add(new Location(((Vehicle) agents.get(i)).getCurrentLocation(), ""));
agentStyles.add(((Vehicle) agents.get(i)).getAttributes().TYPE);
}
//String stamp = new SimpleDateFormat("hh-mm-ss-aaa_dd-MMMMM-yyyy").format(new Date()).toString();
//kmlutility.writeFile("kml/" + stamp + ".kml");
}
Utilities.Log.logger.info("VehicleCTA completed running agents.");
}
/**
* Any specific CTA initilizations are done here.
*/
private void initialize() {
}
/**
* This function checks if all the agents on this CTA have satisfied their
* objective, in which case the CTA has completed its task.
* @return true if all agents in the CTA have completed their objectives
*/
private boolean objectiveSatisfiedForAllAgents() {
int count = 0;
for (Agent p : agents) {
if (p.objectiveFlag) {
count++;
}
}
if (count == agents.size()) {
return true;
} else {
return false;
}
}
/**
* This method complets one iteration of the CTA's operation. The method
* terminates when all the agents in the CTA have completed their tasks.
*/
private void runCTA() {
try {
setUp();
//Runs until objectives for all agents is fulfilled
while (!objectiveSatisfiedForAllAgents()) {
initialize();
//Time out for waiting for other agents
long timeBeforewaiting = System.currentTimeMillis();
//now check if all agents are ready
while (!checkIfAllCTAsReadyForNextTick(holdMessages)) {
try {
long timeNow = System.currentTimeMillis();
if (timeNow - timeBeforewaiting >= CTANetwork.MAXIMUM_TIME_OUT_FOR_CTA) {
updateTimeOutList();
Utilities.Log.logger.info("Continuing with run after timeout");
break;
} else {
//wait until all CTAs are ready
Thread.sleep(500);
}
} catch (InterruptedException ex) {
Utilities.Log.logger.info(ex.getMessage());
//Since the runCTA was intrrupted, exit the CTA.
exitSystem();
}
}
if (initiateStateSave && currentTickNumber >= tickNumberForStateSave) {
} else {
kaboom();
holdMessages = true;
changeReadyCTAsToComputing();
// CTAsReadyForTick.clear();
// CTAsReadyForTick.addAll(CTAsCompletedRun);
holdMessages = false;
runAgents();
if (agents.size() < 300) {
SharedData.isDisasterTriggered = true;
}
Utilities.Log.logger.info("Current Tick Number: " + currentTickNumber);
currentTickNumber++;
}
cleanUp();
}
exitSystem();
} catch (Exception e) {
Utilities.Log.logger.error("Unable to complete work due to exection. Terminating " + e.getMessage());
e.printStackTrace();
exitSystem();
}
}
/**
* CTA Main function
* @param args currently no arguements are passed
*/
public static void main(String args[]) {
if (args.length == 0) {
VehicleCTA obj = new VehicleCTA();
obj.runCTA();
} else {
VehicleCTA obj = new VehicleCTA(args[0]);
obj.restoreState = true;
obj.runCTA();
}
}
/**
* this method is called by the CTA when it needs to terminate.
*/
private void exitSystem() {
sendDoneWithWork();
// sendFinishedExecutingCTA();
String stamp = new SimpleDateFormat("hh-mm-ss-aaa_dd-MMMMM-yyyy").format(new Date()).toString();
kmlUtility.writeFile("kml/" + stamp + ".kml");
System.exit(0);
}
/**
*
*/
@Override
protected void saveCTAState() {
FileOutputStream fos = null;
ObjectOutputStream out = null;
DataOutputStream dos = null;
String stamp = new SimpleDateFormat("hh-mm-ss-aaa_dd-MMMMM-yyyy").format(new Date()).toString();
String fileName = "savedstates/" + stamp + "_" + currentTickNumber + "_VehicleCTA.data";
try {
fos = new FileOutputStream(fileName);
out = new ObjectOutputStream(fos);
dos = new DataOutputStream(fos);
// Objects of PeopleCTA
//out.writeObject(kmlUtility);
//out.writeObject(queueManager);
out.writeObject(CTAStatus);
out.writeObject(agents);
out.writeObject(agentLocations);
out.writeObject(agentStyles);
// Objects of CTANetwork
out.writeObject(CTANetwork.hostQueueMap);
out.writeObject(CTANetwork.hostTypeMap);
out.writeObject(CTANetwork.hosts);
// Objects of SharedData
out.writeObject(SharedData.boundingBox);
out.writeObject(SharedData.ambulancePerHospital);
out.writeObject(SharedData.deadPeopleAgents);
out.writeObject(SharedData.disasters);
out.writeObject(SharedData.hospitals);
out.writeObject(SharedData.trafficLights);
out.writeObject(SharedData.injuredPeopleBeingServed);
out.writeObject(SharedData.injuredPeopleRescued);
out.writeObject(SharedData.newInjuredPeople);
out.writeObject(SharedData.pickedUpinjuredPeople);
dos.writeInt(SharedData.numberOfAgents);
dos.writeInt(SharedData.numberOfAmbulances);
dos.writeInt(SharedData.numberOfCivilVehicles);
dos.writeInt(SharedData.numberOfFireVehicles);
dos.writeInt(SharedData.numberOfPeopleCTA);
dos.writeInt(SharedData.numberOfPoliceVehicles);
dos.writeBoolean(SharedData.isDisasterTriggered);
dos.writeInt(currentTickNumber);
dos.writeInt(totalNumberOfVehicles);
dos.writeBoolean(holdMessages);
dos.close();
fos.close();
out.close();
Utilities.Log.logger.info("Saved State");
} catch (IOException ex) {
ex.printStackTrace();
}
}
/**
* Restores the state of this CTA from a file. Thsi will restore all objects of the CTA saved previously.
* The CTA will continue running from the point where state was restored, at the point in the file where it was previously saved
* @param filename
*/
@Override
protected void restoreState(String filename) {
FileInputStream fis = null;
ObjectInputStream in = null;
DataInputStream din = null;
try {
fis = new FileInputStream(filename);
in = new ObjectInputStream(fis);
din = new DataInputStream(fis);
//queueManager = (QueueManager) in.readObject();
CTAStatus = (Map<String, Integer>) in.readObject();
agents = (ArrayList<Agent>) in.readObject();
agentLocations = (ArrayList<Location>) in.readObject();
agentStyles = (ArrayList<String>) in.readObject();
CTANetwork.hostQueueMap = (HashMap<String, QueueParameters>) in.readObject();
CTANetwork.hostTypeMap = (HashMap<Integer, ArrayList<String>>) in.readObject();
CTANetwork.hosts = (ArrayList<String>) in.readObject();
SharedData.boundingBox = (BoundingBox) in.readObject();
SharedData.ambulancePerHospital = (List<Integer>) in.readObject();
SharedData.deadPeopleAgents = (List<Person>) in.readObject();
SharedData.disasters = (List<Disaster>) in.readObject();
SharedData.hospitals = (List<Hospital>) in.readObject();
SharedData.trafficLights = (List<TrafficLight>) in.readObject();
SharedData.injuredPeopleBeingServed = (List<Person>) in.readObject();
SharedData.injuredPeopleRescued = (List<Person>) in.readObject();
SharedData.newInjuredPeople = (List<Person>) in.readObject();
SharedData.pickedUpinjuredPeople = (List<Person>) in.readObject();
SharedData.numberOfAgents = (int) din.readInt();
SharedData.numberOfAmbulances = (int) din.readInt();
SharedData.numberOfCivilVehicles = (int) din.readInt();
SharedData.numberOfFireVehicles = (int) din.readInt();
SharedData.numberOfPeopleCTA = (int) din.readInt();
SharedData.numberOfPoliceVehicles = (int) din.readInt();
SharedData.isDisasterTriggered = (boolean) din.readBoolean();
currentTickNumber = (int) din.readInt();
totalNumberOfVehicles = (int) din.readInt();
holdMessages = (boolean) din.readBoolean();
din.close();
in.close();
fis.close();
} catch (IOException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
// }
}
}
/**
* This is the method called to handle any message received by this CTA
* @param message the message object form any other CTA
* @see CTANetwork
* @see Messaging.QueueParameters
* @see Messaging.QueueManager
*/
public void receivedMessage(Message message) {
//update status of the host from which message was received
while (holdMessages) {
}
switch (message.type) {
case CTANetwork.RMQ_TYPE_STATUS_UPDATE:
//Find out what type of status update it is
Utilities.Log.logger.info("VehicleCTA: Status Update Message");
Message statusType = (Message) message.messageObject;
switch (statusType.type) {
case CTANetwork.CTA_READY_FOR_NEXT_TICK:
Utilities.Log.logger.info("VehicleCTA: Ready for next Tick");
changeCTAStatus(statusType.hostName, statusType.type);
break;
case CTANetwork.CTA_DONE_WITH_WORK:
Utilities.Log.logger.info("VehicleCTA: Done with work");
changeCTAStatus(statusType.hostName, statusType.type);
break;
case CTANetwork.CTA_SAVING_STATE:
Utilities.Log.logger.info("Received state save message from " + statusType.hostName + "at tick: " + currentTickNumber);
tickNumberForStateSave = (Integer) statusType.messageObject;
initiateStateSave = true;
changeCTAStatus(statusType.hostName, statusType.type);
break;
case CTANetwork.CTA_SAVED_STATE:
Utilities.Log.logger.info("Received state saved message from " + statusType.hostName + "at tick: " + currentTickNumber);
changeCTAStatus(statusType.hostName, statusType.type);
break;
case CTANetwork.CTA_RESTORED_STATE:
Utilities.Log.logger.info("Received restored state message from " + statusType.hostName + "at tick: " + currentTickNumber);
changeCTAStatus(statusType.hostName, statusType.type);
break;
// case CTANetwork.CTA_COMPLETE_EXIT:
// Utilities.Log.logger.info("VehicleCTA: Done with work and Exitting.....");
// changeCTAStatus(statusType.hostName, statusType.type);
// break;
}
break;
case CTANetwork.RMQ_TYPE_AGENT_DATA:
//trafficLightStatus = (HashMap<Long, Integer>) message.messageObject;
SharedData.trafficLights = (ArrayList<TrafficLight>) message.messageObject;
Utilities.Log.logger.info("Received Traffic Light Status: No of Lights = " + SharedData.trafficLights.size());
break;
}
}
}