package cz.agents.agentpolis.darptestbed.simmodel.agent.activity.movement;
import com.google.inject.Inject;
import cz.agents.agentpolis.darptestbed.global.Utils;
import cz.agents.agentpolis.darptestbed.siminfrastructure.logger.PassengerActivityLogger;
import cz.agents.agentpolis.darptestbed.simmodel.environment.model.TestbedModel;
import cz.agents.agentpolis.simmodel.environment.model.action.PassengerAction;
import cz.agents.agentpolis.simmodel.environment.model.action.callback.VehicleArrivedCallback;
import cz.agents.agentpolis.simmodel.environment.model.linkedentitymodel.sensor.LinkedEntitySensor;
import cz.agents.agentpolis.simmodel.environment.model.query.AgentPositionQuery;
import static com.google.common.base.Preconditions.checkArgument;
/**
* Through this activity, a passenger can get in a vehicle, that has arrived to
* the passenger's initial position. After that, he gets off at his target
* position.
*
* @author Lukas Canda
*/
public class TestbedPassengerActivity implements LinkedEntitySensor {
/**
* This action enables us to get in the vehicle
*/
protected final PassengerAction useVehicleAction;
/**
* A query to find the current position of an agent
*/
protected final AgentPositionQuery positionQuery;
/**
* A storage to save all data concerning taxi drivers and passengers
*/
protected final TestbedModel taxiModel;
/**
* A set of useful methods for searching paths, distances etc.
*/
protected final Utils utils;
/**
* Logs important events into the log file.
*/
protected final PassengerActivityLogger logger;
/**
* We need this class just to prevent crash.
*/
private final EmptyPassengerVehiclePlanCallback emptyCallback;
/**
* The id of the travelling passenger
*/
protected String passengerId;
/**
* The id of the taxi he's travelling with
*/
protected String vehicleId;
/**
* The number of the target node.
*/
protected long targetPosition;
/**
* The Callback to notify of finishing the trip (can be equal to null)
*/
protected TestbedPassengerActivityCallback passengerActivityCallback;
@Inject
public TestbedPassengerActivity(PassengerAction useVehicleAction, AgentPositionQuery positionQuery,
TestbedModel taxiModel, Utils utils, PassengerActivityLogger logger) {
this.useVehicleAction = useVehicleAction;
this.positionQuery = positionQuery;
this.taxiModel = taxiModel;
this.utils = utils;
this.logger = logger;
this.emptyCallback = new EmptyPassengerVehiclePlanCallback();
}
/**
* Get in the vehicle, that is just waiting on my position. Drive with it
* until it reaches my target node.
*
* @param passengerId the passenger who wants to travel
* @param vehicleId the vehicle he's going to travel with
* @param targetPosition the number of his target node
*/
public void useArrivedVehicle(String passengerId, String vehicleId, long targetPosition) {
this.passengerId = passengerId;
this.vehicleId = vehicleId;
this.targetPosition = targetPosition;
taxiModel.addPassengerOnBoard(passengerId, vehicleId);
checkArgument(useVehicleAction.getInVehicle(passengerId, vehicleId, this.emptyCallback, this),
"The passenger " + passengerId + " is not able to get into the vehicle with id " + vehicleId
+ ", because the vehicle has no free seats. " + taxiModel.getNumOfPassenOnBoard(vehicleId));
// log the event
Long currentPos = positionQuery.getCurrentPositionByNodeId(this.passengerId);
logger.logPassengerGotInVehicle(passengerId, currentPos, vehicleId);
}
/**
* Get in the vehicle, that is just waiting on my position. Drive with it
* until it reaches my target node.
*
* @param passengerId the passenger who wants to travel
* @param vehicleId the vehicle he's going to travel with
* @param targetPosition the number of his target node
* @param passengerActivityCallback callback to be called after reaching my target node
*/
public void useArrivedVehicle(String passengerId, String vehicleId, long targetPosition,
TestbedPassengerActivityCallback passengerActivityCallback) {
this.passengerActivityCallback = passengerActivityCallback;
this.useArrivedVehicle(passengerId, vehicleId, targetPosition);
}
/**
* The passenger always gets unlinked after arriving to arbitrary node
* (that's what drive method does automatically). If he hasn't arrived where
* he wanted, he needs to get back in.
*
* @param unlinkedFromEntityId the vehicle he's gotten unlinked from
*/
@Override
public void entityWasUnlinked(String unlinkedFromEntityId) {
Long currentPos = positionQuery.getCurrentPositionByNodeId(this.passengerId);
// have we arrived to our target position?
if (this.targetPosition == currentPos) {
taxiModel.removePassengerOnBoard(passengerId, vehicleId);
// log the event
logger.logPassengerGotOffVehicle(passengerId, currentPos, vehicleId);
if (passengerActivityCallback != null) {
passengerActivityCallback.tripFinished(this.targetPosition);
}
} else {
// if not, get in again and continue the journey
useVehicleAction.getInVehicle(passengerId, vehicleId, this.emptyCallback, this);
}
}
/**
* We need this class just to prevent crash.
*
* @author Zbynek Moler
*/
private static class EmptyPassengerVehiclePlanCallback implements VehicleArrivedCallback {
@Override
public void notifyPassengerAboutVehiclePlan(long fromNodeId, long toNodeId, String vehicleId) {
// Do nothing
}
@Override
public void notifyWaitingPassengerAboutVehiclePlan(long fromNodeId, long toNodeId, String vehicleId) {
// Do nothing
}
}
}