package cz.agents.agentpolis.darptestbed.simmodel.agent.dispatching.logic;
import com.google.common.collect.Maps;
import cz.agents.agentpolis.darptestbed.global.Utils;
import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.driver.message.*;
import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.driver.protocol.DriverCentralizedMessageProtocol;
import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.passenger.message.OrderConfirmation;
import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.passenger.protocol.PassengerMessageProtocol;
import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.protocol.GeneralMessageProtocol;
import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.requestconsumer.message.ProposalAccept;
import cz.agents.agentpolis.darptestbed.siminfrastructure.communication.requestconsumer.message.ProposalReject;
import cz.agents.agentpolis.darptestbed.siminfrastructure.planner.TestbedPlanner;
import cz.agents.agentpolis.darptestbed.simmodel.agent.data.Request;
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.darptestbed.simmodel.environment.model.TestbedVehicleStorage;
import cz.agents.agentpolis.siminfrastructure.planner.trip.Trip;
import cz.agents.agentpolis.siminfrastructure.planner.trip.Trips;
import cz.agents.agentpolis.simmodel.environment.model.citymodel.transportnetwork.AllNetworkNodes;
import cz.agents.agentpolis.simmodel.environment.model.query.AgentPositionQuery;
import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
public class DispatchingLogicExample extends DispatchingLogic {
private static final Logger LOGGER = Logger.getLogger(DispatchingLogicExample.class);
public DispatchingLogicExample(String agentId, PassengerMessageProtocol sender,
DriverCentralizedMessageProtocol driverCentralizedMessageProtocol,
GeneralMessageProtocol generalMessageProtocol, TestbedModel taxiModel,
AgentPositionQuery positionQuery, AllNetworkNodes allNetworkNodes, Utils utils, TestbedPlanner pathPlanner,
TestbedVehicleStorage vehicleStorage) {
super(agentId, sender, driverCentralizedMessageProtocol, generalMessageProtocol, taxiModel, positionQuery,
allNetworkNodes, utils,
pathPlanner, vehicleStorage);
}
@Override
public void processNewRequest(Request request) {
// print out the request for debugging purposes
LOGGER.info(" Request: [" + utils.toHoursAndMinutes(request.getTimeWindow().getEarliestDeparture())
+ "] from " + request.getPassengerId() + ", latest departure: "
+ utils.toHoursAndMinutes(request.getTimeWindow().getLatestDeparture()) + " " + request);
// check if there are any free taxi drivers
if (taxiModel.getTaxiDriversFree().size() == 0) {
// if there are no free drivers, dispatcher needs to reject the
// request
this.sendRequestReject(request.getPassengerId(), request);
LOGGER.info(" Reply: REJECT [no free taxis]");
return;
}
// loop over all free taxi drivers
for (String taxiDriverId : taxiModel.getTaxiDriversFree()) {
// get the object representation of this driver's vehicle
TestbedVehicle taxiVehicle = vehicleStorage.getEntityById(taxiModel.getVehicleId(taxiDriverId));
// skip those taxi drivers, who have currently full capacity
if (taxiModel.getNumOfPassenOnBoard(taxiModel.getVehicleId(taxiDriverId)) >= taxiVehicle.getCapacity()) {
continue;
}
// skip those taxis, which don't meet some of the passenger's
// special requirements (wheel chair support, child seat, etc.)
if (!taxiVehicle.getVehicleEquipments().containsAll(request.getAdditionalRequirements())) {
continue;
}
// compute the driving time between the passenger and the driver
double timeToPassenger = utils.computeDrivingTime(taxiDriverId, request.getPassengerId());
// compute when this driver could pick up the passenger
long pickUpTime = utils.getCurrentTime() + (long) timeToPassenger;
// if this driver is able to pick up the passenger within his
// departure time window ...
if (pickUpTime <= request.getTimeWindow().getLatestDeparture()) {
// plan the trips (paths)
// (1) from driver to passenger's departure node and
// (2) from origin to arrival node
Trip toPassenger = utils.planTrip(taxiVehicle.getId(),
positionQuery.getCurrentPositionByNodeId(taxiDriverId), request.getFromNode());
Trip toDestination = utils.planTrip(taxiVehicle.getId(), request.getFromNode(), request.getToNode());
// concatenate those two trips into a drivePath for the driver
Trips drivePath = new Trips();
if (toPassenger != null && toPassenger.numOfCurrentTripItems() > 0)
drivePath.addTrip(toPassenger);
if (toDestination != null && toDestination.numOfCurrentTripItems() > 0)
drivePath.addTrip(toDestination);
// if we didn't successfully find and concatenate two required
// trips, skip this driver
if (drivePath.numTrips() != 2)
continue;
// create a pickup map for this path (tells driver where he
// should pick up which passengers)
Map<Long, PassengersInAndOutPair> pickUpAndDropOffMap = Maps.newHashMap();
pickUpAndDropOffMap.put(request.getFromNode(),
new PassengersInAndOutPair(new HashSet<>(Arrays.asList(request.getPassengerId())),
new HashSet<String>()));
pickUpAndDropOffMap.put(request.getToNode(),
new PassengersInAndOutPair(new HashSet<String>(),
new HashSet<>(Arrays.asList(request.getPassengerId()))));
// send the driver on this path
TripPlan tripPlan = new TripPlan(drivePath, pickUpAndDropOffMap);
// confirm the request and tell the passenger which car will
// pick him/her up
sendMessageDispatcherSendsOutTaxi(taxiDriverId, tripPlan);
sendMessageDispatcherAcceptsRequest(request, new TripInfo(taxiDriverId, taxiVehicle.getId()));
// flag this driver as "busy"
taxiModel.setTaxiBusy(taxiVehicle.getId());
// print some debug information
LOGGER.info(" Reply: ACCEPT [sending " + taxiVehicle.getId() + "]");
LOGGER.info(" Trips:\n\n" + tripPlan.getTrips().toString());
// once we've sent the driver out, we can finish the execution
// of this function
return;
}
}
sendRequestReject(request.getPassengerId(), request);
LOGGER.info(" Reply: REJECT [suitable taxi not found]");
}
@Override
public void processRequests() {
// TODO Auto-generated method stub
}
@Override
public void confirmOrder(ProposalAccept proposalAccept) {
sender.sendMessage(proposalAccept.proposal.getPassengerId(), new OrderConfirmation(new TripInfo(
proposalAccept.proposal.getDriverId(), proposalAccept.proposal.getVehicleId())));
}
@Override
public void processRejectedProposal(ProposalReject proposalReject) {
taxiModel.setTaxiBusy(proposalReject.proposal.getVehicleId());
}
@Override
public void processPassengerInVehicle(DriverReportsPassengerIsInMessage passengerIsInTaxiMessage) {
}
@Override
public void processPassengerOffVehicle(DriverReportsPassengerHasLeftMessage driverReportsPassengerHasLeftMessage) {
}
@Override
public void processDriverArrivedLateForPassengerPickup(
DriverReportsLateForPassengerMessage driverArrivedLateForPassenger) {
}
@Override
public void processDriverAcceptsNewPlan(DriverNewPlanAcceptMessage driverNewPlanAcceptMessage) {
sendFinalPlanConfirmation(driverNewPlanAcceptMessage.tripInfo.getDriverId());
}
@Override
public void processDriverRejectsNewPlan(DriverNewPlanRejectMessage driverNewPlanRejectMessage) {
sendFinalPlanFailure(driverNewPlanRejectMessage.tripInfo.getDriverId());
}
}