package cz.agents.agentpolis.darptestbed.simmodel.agent.driver.logic; import com.google.common.collect.Sets; import cz.agents.agentpolis.darptestbed.global.Utils; import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.dispatching.protocol.DispatchingMessageProtocol; import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.driver.message.*; import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.passenger.message.DriverArrivedMessage; import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.passenger.protocol.PassengerMessageProtocol; import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.protocol.GeneralMessageProtocol; import cz.agents.agentpolis.darptestbed.simmodel.agent.data.TripInfo; import cz.agents.agentpolis.darptestbed.simmodel.agent.data.TripPlan; import cz.agents.agentpolis.darptestbed.simmodel.agent.data.generator.PassengersInAndOutPair; import cz.agents.agentpolis.darptestbed.simmodel.entity.vehicle.TestbedVehicle; import cz.agents.agentpolis.darptestbed.simmodel.environment.model.TestbedModel; import cz.agents.agentpolis.simmodel.agent.activity.movement.DriveVehicleActivity; import cz.agents.agentpolis.simmodel.environment.model.citymodel.transportnetwork.AllNetworkNodes; import cz.agents.agentpolis.simmodel.environment.model.query.AgentPositionQuery; import org.apache.log4j.Logger; /** * The basic features of a DriverAgent, especially his communication protocol * that enables him to contact other agents. * <p/> * The centralized communication means that the taxi driver communicates only * with the dispatching (control center). * * @author Lukas Canda */ public class DriverCentralizedLogic extends DriverLogicWithPassengerMessageProtocol { private static final Logger LOGGER = Logger.getLogger(DriverCentralizedLogic.class); private final DispatchingMessageProtocol dispatchingMessageProtocol; private TripPlan candidateTripPlan; private TripPlan oldPlan; private enum DriverState { WAITING_FOR_PASSENGERS, ACCEPTING_NEW_PLANS, WAITING_FOR_PLAN_CONFIRMATION } private DriverState driverState = DriverState.ACCEPTING_NEW_PLANS; public DriverCentralizedLogic(String agentId, PassengerMessageProtocol sender, GeneralMessageProtocol generalMessageProtocol, TestbedModel taxiModel, AgentPositionQuery positionQuery, AllNetworkNodes allNetworkNodes, Utils utils, TestbedVehicle vehicle, DriveVehicleActivity drivingActivity, DispatchingMessageProtocol dispatchingMessageProtocol) { super(agentId, sender, generalMessageProtocol, taxiModel, positionQuery, allNetworkNodes, utils, vehicle, drivingActivity); this.dispatchingMessageProtocol = dispatchingMessageProtocol; } // /** // * Accepts the message with the trip plan, which the driver should follow after he finishes the current one. // * // * @param tripPlan a list of nodes to visit, a map of passengers to get in // */ // public void acceptTripPlan(TripPlan tripPlan) { // if (this.getTripPlan() != null) { // this.extendTripPlan(tripPlan); // } else { // this.setTripPlan(tripPlan); // } // // this.driveNextPartOfTripPlan(); // } /** * Accepts the message with the trip plan, which the driver should follow. * * @param tripPlan a list of nodes to visit, a map of passengers to get in */ public void setTripPlan(TripPlan tripPlan) { if (isTripPlanAcceptable(tripPlan)) { LOGGER.debug("Accepted plan - " + getAgentId() + "\nNEW: " + tripPlan + "\nOLD: " + this.getTripPlan()); candidateTripPlan = tripPlan; oldPlan = this.getTripPlan(); dispatchingMessageProtocol.driverDispatchingProtocol.sendMessage(taxiModel.getDispatching().getId(), new DriverNewPlanAcceptMessage(new TripInfo(getAgentId(), getVehicle().getId()))); driverState = DriverState.WAITING_FOR_PLAN_CONFIRMATION; } else { LOGGER.debug("Rejected plan - " + getAgentId() + ": " + tripPlan); dispatchingMessageProtocol.driverDispatchingProtocol.sendMessage(taxiModel.getDispatching().getId(), new DriverNewPlanRejectMessage(new TripInfo(getAgentId(), getVehicle().getId()))); } } private boolean isTripPlanAcceptable(TripPlan tripPlan) { return driverState == DriverState.ACCEPTING_NEW_PLANS && Sets.symmetricDifference(getPassengersOnBoard(), tripPlan.getPassengersOnBoard()).isEmpty(); } protected void driveNextPartOfTripPlan() { switch (driverState) { case ACCEPTING_NEW_PLANS: if (getTripPlan() == null) return; long driverPosition = positionQuery.getCurrentPositionByNodeId(getAgentId()); PassengersInAndOutPair nodeWithBoardingAndDisembarkingPassengers = getTripPlan().getNodeWithBoardingAndDisembarkingPassengers(driverPosition); boolean hasList = nodeWithBoardingAndDisembarkingPassengers == null; boolean oldIsEverybodyOnBoard = hasList || nodeWithBoardingAndDisembarkingPassengers.getIn() == null || nodeWithBoardingAndDisembarkingPassengers.getIn().isEmpty(); boolean oldIsEverybodyOffBoard = hasList || nodeWithBoardingAndDisembarkingPassengers.getOff() == null || nodeWithBoardingAndDisembarkingPassengers.getOff().isEmpty(); super.driveNextPartOfTripPlan(); if (!oldIsEverybodyOnBoard || !oldIsEverybodyOffBoard) { driverState = DriverState.WAITING_FOR_PASSENGERS; } break; case WAITING_FOR_PASSENGERS: oldIsEverybodyOnBoard = isEverybodyOnBoard(); oldIsEverybodyOffBoard = isEverybodyOffBoard(); super.driveNextPartOfTripPlan(); if (oldIsEverybodyOnBoard && oldIsEverybodyOffBoard) { driverState = DriverState.ACCEPTING_NEW_PLANS; } break; case WAITING_FOR_PLAN_CONFIRMATION: break; } } @Override protected void sendTaxiArrivedLateMessageToDispatching(String passengerId) { dispatchingMessageProtocol.driverDispatchingProtocol.sendMessage(taxiModel.getDispatching().getId(), new DriverReportsLateForPassengerMessage(passengerId, new TripInfo(getAgentId(), getVehicle().getId()))); } @Override protected void sendTaxiArrivedToPickup(String passengerId) { LOGGER.debug("Sending pickup: " + passengerId); sender.sendMessage(passengerId, new DriverArrivedMessage(getAgentId(), new TripInfo(getAgentId(), this.getVehicle().getId()))); dispatchingMessageProtocol.driverDispatchingProtocol.sendMessage(taxiModel.getDispatching().getId(), new DriverReportsPassengerIsInMessage(passengerId, new TripInfo(this.getAgentId(), this.getVehicle().getId()))); } @Override protected void sendTaxiArrivedToDropOff(String passengerId) { sender.sendMessage(passengerId, new DriverArrivedMessage(getAgentId(), new TripInfo(getAgentId(), this.getVehicle().getId()))); dispatchingMessageProtocol.driverDispatchingProtocol.sendMessage(taxiModel.getDispatching().getId(), new DriverReportsPassengerHasLeftMessage(passengerId, new TripInfo(this.getAgentId(), this.getVehicle().getId()))); } @Override public final boolean isDecentralized() { return false; } public void planConfirmed() { if (driverState == DriverState.WAITING_FOR_PLAN_CONFIRMATION) { driverState = DriverState.ACCEPTING_NEW_PLANS; super.setTripPlan(candidateTripPlan); candidateTripPlan = null; oldPlan = null; driveNextPartOfTripPlan(); } } public void planFailed() { if (driverState == DriverState.WAITING_FOR_PLAN_CONFIRMATION) { driverState = DriverState.ACCEPTING_NEW_PLANS; super.setTripPlan(oldPlan); candidateTripPlan = null; oldPlan = null; driveNextPartOfTripPlan(); } } }