package Agents; import Agents.Attributes.EmergencyServiceAttributes; import Agents.Behaviour.AmbulanceMoveBehaviour; import Agents.Behaviour.CompositeBehaviour; import Agents.Behaviour.FireMoveBehaviour; import Agents.Behaviour.PoliceMoveBehaviour; import Database.Sql; import Entity.Disaster; import Entity.Hospital; import GeographicInformation.Cell; import GeographicInformation.Location; import GlobalData.Constants; import GlobalData.SharedData; import Utilities.AIDGenerator; import org.postgis.Point; /** * This class defines a emergency service agent. This is essentially a emergency * vehicle i.e. police, fire or an ambulance. This agent has similar attributes * as that of a Vehicle agent but has a few extra parameters and different * behaviour and hence is a different class of agent. The agent behaviour will * depend on the type of emergency service the agent is impersonating. * @see Vehicle * @see AgentAttributes.VehicleAttributes * @see AgentAttributes.EmergencyServiceAttributes */ public class EmergencyService extends Agent { /** * EmergencyService agent's attributes * @see EmergencyServiceAttributes */ private EmergencyServiceAttributes attributes = null; /** * Constructor to create an emergency agent * @param type the type of emergency agent. Example fire, ambulance, etc. * @param myCapacity the number of people the agent can accomodate at a given time * @param speed the speed with which the agent moves * @param currentLoad the current number of people that the agent may be carrying * @param home the location of the agent's home base * @param currentloc the current location of the agent * @param startcellId the id of the cell in which the agent begins to move * @param homebaseId the location of the id of the cell where the home base is located * @throws InstantiationException * @see Constants */ public EmergencyService(String type, int myCapacity, int speed, int currentLoad, Location home, Cell currentloc, long startcellId, long homebaseId) throws InstantiationException { attributes = new EmergencyServiceAttributes(type, myCapacity, speed, home, currentloc, startcellId, homebaseId); AID = AIDGenerator.newID(getClass().toString().substring(6)); behaviour = new CompositeBehaviour(); //Depening on type of agent add an appropriate behaviour if (type.equals(Constants.VEHICLE_TYPE_AMBULANCE)) { behaviour.add(new AmbulanceMoveBehaviour()); } else if (type.equals(Constants.VEHICLE_TYPE_FIRE)) { behaviour.add(new FireMoveBehaviour()); } else if (type.equals(Constants.VEHICLE_TYPE_POLICE)) { behaviour.add(new PoliceMoveBehaviour()); } else { Utilities.Log.logger.info("EmergencyService: Error Unable to determine the Emergency Service Type "); System.exit(1); } } /** * Constructor to create an emergency agent * @param type the type of emergency agent eg. fire, ambulance, etc * @param myCapacity the number of people the agent can accomodate at a given time * @param speed the speed with which the agnet moves * @param currentLoad the current number of people that the agent may be carrying * @param home the location of the agent's home base * @param currentloc the current location of the agent * @param startcellId the id of the cell in which the agent begins to move * @param homebaseId the location of the id of the cell where the home base is located * @param hospital the hospital oobject i.e. the hospital to which the ambulance is associated to * @throws InstantiationException */ public EmergencyService(String type, int myCapacity, int speed, int currentLoad, Location home, Cell currentloc, long startcellId, long homebaseId, Hospital hospital) throws InstantiationException { attributes = new EmergencyServiceAttributes(type, myCapacity, speed, home, currentloc, startcellId, homebaseId, hospital); AID = AIDGenerator.newID(getClass().toString().substring(6)); behaviour = new CompositeBehaviour(); //Depening on type of agent add an appropriate behaviour if (type.equals(Constants.VEHICLE_TYPE_AMBULANCE)) { behaviour.add(new AmbulanceMoveBehaviour()); } else if (type.equals(Constants.VEHICLE_TYPE_FIRE)) { behaviour.add(new FireMoveBehaviour()); } else if (type.equals(Constants.VEHICLE_TYPE_POLICE)) { behaviour.add(new PoliceMoveBehaviour()); } else { Utilities.Log.logger.info("EmergencyService: Error Unable to determine the Emergency Service Type "); System.exit(1); } } /** * Constructor to create an emergency agent * @param type the type of emergency agent eg. fire, ambulance, etc * @param myCapacity the number of people the agent can accomodate at a given time * @param speed the speed with which the agnet moves * @param currentLoad the current number of people that the agent may be carrying * @param hospital the hospital oobject i.e. the hospital to which the ambulance is associated to * @throws InstantiationException */ public EmergencyService(String type, int myCapacity, int speed, int currentLoad, Hospital hospital) throws InstantiationException { attributes = new EmergencyServiceAttributes(type, myCapacity, speed, currentLoad, hospital); AID = AIDGenerator.newID(getClass().toString().substring(6)); behaviour = new CompositeBehaviour(); //Depening on type of agent add an appropriate behaviour if (type.equals(Constants.VEHICLE_TYPE_AMBULANCE)) { behaviour.add(new AmbulanceMoveBehaviour()); } else if (type.equals(Constants.VEHICLE_TYPE_FIRE)) { behaviour.add(new FireMoveBehaviour()); } else if (type.equals(Constants.VEHICLE_TYPE_POLICE)) { behaviour.add(new PoliceMoveBehaviour()); } else { Utilities.Log.logger.info("EmergencyService: Error Unable to determine the Emergency Service Type "); System.exit(1); } } /** * This method is called to notify the agent about a disaster * @param disaster the disaster that has taken place */ public void notifyDisaster(Disaster disaster) { processDisaster(disaster); } /** * This method performs the necessary state changes and processes the given * disaster. This methods makes the agent aware of a disaster * @param disaster the disaster that has taken place */ private void processDisaster(Disaster disaster) { if (attributes.TYPE.equals(Constants.VEHICLE_TYPE_AMBULANCE)) { this.pickInjuredAgentFromDisaster(); } else { this.attributes.setHomeBase(new Location(disaster.getLatlon(), "")); this.getBestPath(getCurrentLocation(), SharedData.disasters.get(0).getLatlon(), Constants.COST_COLUMN_EMERGENCY_VEHICLE, Constants.TABLE_VEHICLE_CELLS); } } /** * Returns the EmergencyService agent attributes * @return EmergencyService agent attributes */ public EmergencyServiceAttributes getAttributes() { return this.attributes; } /** * Set the EmergencyService agent attributes * @param emergencyAttributes EmergencyService agent attributes */ public void setAttributes(EmergencyServiceAttributes emergencyAttributes) { this.attributes = emergencyAttributes; } /** * return the current location of the EmergencyService agent * @return current location of the EmergencyService agent */ public Point getCurrentLocation() { return attributes.currentCellLocation.getLatLon(); } /** * The run method of a agent performs the all of the agent behaviours. */ @Override public void run() { if (SharedData.isDisasterTriggered) { //Is the disaster Triggered can add &&!statusFlag if (attributes.TYPE.equals(Constants.VEHICLE_TYPE_AMBULANCE)) { //Is type Ambulance if (this.getCurrentLocation().equals(attributes.getHospital().getLatLon())) { //Is Agent Idle? i.e. is the currentLocation = HOspital? if (attributes.getPassengers().size() > 0) { // There are some passengers in the ambulance, Drop them off dropInjuredAgentAtHospital(); } else { //get a new person to go to. pickInjuredAgentFromDisaster(); } //behaviour.run(attributes); behaviour.run(attributes); } else { //Agent is NOT idle, Check if its home i.e has the ambulance reached the disaster location attributes.isAgentHome = isHomeStatus(); // update the home status if (attributes.isAgentHome) {// Agent has reached home //Swap the locations and get the next best path. NOTE: clear isHomeFlag reverseDirections(); attributes.isAgentHome = false; } else { //behaviour.run(attributes); behaviour.run(attributes); } } statusFlag = true; } else { //If the vehicle is not a ambulance type if (!statusFlag) { //Check the status flag attributes.isAgentHome = isHomeStatus(); // update the home status if (!attributes.isAgentHome) { //behaviour.run(attributes); behaviour.run(attributes); } else { objectiveFlag = true; } statusFlag = true;//Function call done } } } //if the disaster is not triggered, the agents are not calling theit behaviour methods else { statusFlag = true; //Function call done } } /** * Only the ambulance calls this method. Drops critically injured agents at the respective hospital */ private void dropInjuredAgentAtHospital() { for (Person p : attributes.getPassengers()) { int index = SharedData.injuredPeopleBeingServed.indexOf(p); SharedData.injuredPeopleRescued.add(SharedData.injuredPeopleBeingServed.remove(index)); } attributes.getPassengers().clear(); setCurrentLocation(attributes.getHospital().getLatLon()); //NOTE: Do not clear isAgentHome flag } /** * Only the ambulance calls this method. A free ambulance calls this method * to pick up a critically injured agent form the disaster locations */ private void pickInjuredAgentFromDisaster() { setCurrentLocation(attributes.getHospital().getLatLon()); //Current location is hospital if (SharedData.newInjuredPeople.size() != 0) { Person passenger = SharedData.newInjuredPeople.remove(0); setHomeBase(new Location(passenger.getCurrentCellLocation().getLatLon(), "")); //destination is the person injured. attributes.getPassengers().add(passenger); // Add the injured person to the passenger list SharedData.injuredPeopleBeingServed.add(passenger); //Remove form newInjured and add it to injuredBeingServed this.getBestPath(getCurrentLocation(), attributes.getHomeBase().getLatLon(), Constants.COST_COLUMN_EMERGENCY_VEHICLE, Constants.TABLE_VEHICLE_CELLS);//Calculate the new best path attributes.isAgentHome = false; // Clear the home flag } } /** * Only the ambulance calls this method. This method is called by the ambulance * once it reaches a critically injured person at a disaster location */ private void reverseDirections() { setCurrentLocation(attributes.getHomeBase().getLatLon()); // Set current location to injured agent's location setHomeBase(new Location(attributes.getHospital().getLatLon(), "")); //set the home lcoation to the hospital's location this.getBestPath(getCurrentLocation(), attributes.getHomeBase().getLatLon(), Constants.COST_COLUMN_EMERGENCY_VEHICLE, Constants.TABLE_VEHICLE_CELLS); //Update the list of picked up people to be sent to people CTA for (Person passenger : attributes.getPassengers()) { SharedData.pickedUpinjuredPeople.add(passenger); } Utilities.Log.logger.info("EmergencyService: Picked up some people: " + SharedData.pickedUpinjuredPeople.size()); } /** * Returns the best path between any two given locations * @param startPoint start location * @param endPoint destination * @param costColumn cost set to use to evaluate the best path * @param cellsTable the set of cells to use to form the path */ public void getBestPath(Point startPoint, Point endPoint, String costColumn, String cellsTable) { this.attributes.currentCellIndex = 0; this.attributes.bestRouteToHome = Sql.getBestPathForPerson(startPoint, endPoint, costColumn, cellsTable); } /** * Returns the best path between any two given locations * @param startPoint start location * @param endPointId destination * @param costColumn cost set to use to evaluate the best path * @param cellsTable the set of cells to use to form the path */ public void getBestPath(Point startPoint, long endPointId, String costColumn, String cellsTable) { this.attributes.currentCellIndex = 0; this.attributes.bestRouteToHome = Sql.getBestPathForPerson(startPoint, endPointId, costColumn, cellsTable); } /** * Returns the best path based on the start cell and home base of the agent */ public void getBestPath() { this.attributes.currentCellIndex = 0; this.attributes.bestRouteToHome = Sql.getBestPathForPerson(attributes.startCellId, attributes.homeBaseId, Constants.COST_COLUMN_REGULAR_VEHICLE, Constants.TABLE_VEHICLE_CELLS); } /** * This method checks if the EmergencyService agent has reached its destination * or not * @return true when the EmergencyService has reached its destination */ protected boolean isHomeStatus() { if (attributes.currentCellIndex < attributes.bestRouteToHome.size() - 1) { return false; } else { return true; } } /** * Sets the EmergencyService agent's current location * @param location EmergencyService agent's current location */ public void setCurrentLocation(Point location) { attributes.currentCellLocation.setLatLon(location); } /** * Sets the EmergencyService agent's home base * @param homeBase EmergencyService agent's home base */ public void setHomeBase(Location homeBase) { this.attributes.homeBase = homeBase; } /** * Return the current load of the EmergencyService agent * @return the current load on the EmergencyService agent */ public int getCurrentLoad() { return this.attributes.currentLoad; } /** * Sets the curent load of the EmergencyService agent * @param currentLoad Current load of the EmergencyService agent */ public void setCurrentLoad(int currentLoad) { this.attributes.currentLoad = currentLoad; } /** * Check if the EmergencyService agent has reached its destination * @return boolean true if the EmergencyService agent has reached its destination */ public boolean isHome() { return this.isHome(); } /** * Set the home status flag for EmergencyService agent. * @param isHome */ public void setIsHome(boolean isHome) { this.attributes.setIsHome(isHome); } /** * Return the home base of the EmergencyService agent * @return home base of the EmergencyService agent */ public Location getHomeBase() { return attributes.homeBase; } /** * Compare two EmergencyService agents, return true if their IDs are equal. * @param obj * @return true if vehicle ids are equal. */ @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Vehicle other = (Vehicle) obj; if (this.AID.equals(other.AID)) { return true; } return false; } /** * Return hash code of the EmergencyService agent object * @return hash code of the EmergencyService agent object */ @Override public int hashCode() { throw new UnsupportedOperationException("Can't create a vehicle without any attributes"); } }