package sd.model; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * Represents a single vehicle moving through the simulation. * * This class is a data object that holds the state of a vehicle, including: * - Its unique ID, type, and entry time. * - Its complete, pre-determined {@code route} (a list of intersection IDs). * - Its current position in the route ({@code currentRouteIndex}). * - Metrics for total time spent waiting at red lights and time spent crossing. * * This object is passed around the simulation, primarily inside {@link Event} * payloads and stored in {@link TrafficLight} queues. * * Implements {@link Serializable} so it can be sent between processes * or nodes (e.g., over a socket in a distributed version of the simulation). */ public class Vehicle implements Serializable { private static final long serialVersionUID = 1L; // --- Identity and configuration --- /** * Unique identifier for the vehicle (e.g., "V1", "V2"). */ private final String id; /** * The type of vehicle (BIKE, LIGHT, HEAVY). */ private final VehicleType type; /** * The simulation time (in seconds) when the vehicle was generated. */ private final double entryTime; /** * The complete, ordered list of destinations (intersection IDs and the * final exit "S"). Example: ["Cr1", "Cr3", "S"]. */ private final List route; /** * An index that tracks the vehicle's progress along its {@link #route}. * {@code route.get(currentRouteIndex)} is the vehicle's *current* * destination (i.e., the one it is traveling *towards* or *arriving at*). */ private int currentRouteIndex; // --- Metrics --- /** * The total accumulated time (in seconds) this vehicle has spent * waiting at red lights. */ private double totalWaitingTime; /** * The total accumulated time (in seconds) this vehicle has spent * actively crossing intersections. */ private double totalCrossingTime; /** * Constructs a new Vehicle. * * @param id The unique ID for the vehicle. * @param type The {@link VehicleType}. * @param entryTime The simulation time when the vehicle is created. * @param route The complete list of destination IDs (e.t., ["Cr1", "Cr2", "S"]). */ public Vehicle(String id, VehicleType type, double entryTime, List route) { this.id = id; this.type = type; this.entryTime = entryTime; // Create a copy of the route list to ensure immutability this.route = new ArrayList<>(route); this.currentRouteIndex = 0; // Starts at the first destination this.totalWaitingTime = 0.0; this.totalCrossingTime = 0.0; } /** * Advances the vehicle to the next stop in its route by * incrementing the {@link #currentRouteIndex}. * * This is typically called *after* a vehicle *arrives* at an intersection, * to set its *next* destination before it is queued. * * @return {@code true} if there is still at least one more destination * in the route, {@code false} if the vehicle has passed its * final destination. */ public boolean advanceRoute() { currentRouteIndex++; return currentRouteIndex < route.size(); } /** * Gets the current destination (the next intersection or exit) that * the vehicle is heading towards. * * @return The ID of the current destination (e.g., "Cr1"), or * {@code null} if the route is complete. */ public String getCurrentDestination() { return (currentRouteIndex < route.size()) ? route.get(currentRouteIndex) : null; } /** * Checks if the vehicle has completed its entire route. * * @return {@code true} if the route index is at or past the end * of the route list, {@code false} otherwise. */ public boolean hasReachedEnd() { return currentRouteIndex >= route.size(); } // --- Getters and metrics management --- /** * @return The vehicle's unique ID. */ public String getId() { return id; } /** * @return The vehicle's {@link VehicleType}. */ public VehicleType getType() { return type; } /** * @return The simulation time when the vehicle entered the system. */ public double getEntryTime() { return entryTime; } /** * @return A *copy* of the vehicle's complete route. */ public List getRoute() { // Return a copy to prevent external modification return new ArrayList<>(route); } /** * @return The current index pointing to the vehicle's destination in its route list. */ public int getCurrentRouteIndex() { return currentRouteIndex; } /** * @return The total accumulated waiting time in seconds. */ public double getTotalWaitingTime() { return totalWaitingTime; } /** * Adds a duration to the vehicle's total waiting time. * This is called by the simulation engine when a vehicle * starts crossing an intersection. * * @param time The duration (in seconds) to add. */ public void addWaitingTime(double time) { totalWaitingTime += time; } /** * @return The total accumulated crossing time in seconds. */ public double getTotalCrossingTime() { return totalCrossingTime; } /** * Adds a duration to the vehicle's total crossing time. * This is called by the simulation engine when a vehicle * finishes crossing an intersection. * * @param time The duration (in seconds) to add. */ public void addCrossingTime(double time) { totalCrossingTime += time; } /** * Calculates the vehicle's total time spent in the system so far. * This is a "live" calculation. * * @param currentTime The current simulation time. * @return The total elapsed time (in seconds) since the vehicle * was generated ({@code currentTime - entryTime}). */ public double getTotalTravelTime(double currentTime) { return currentTime - entryTime; } /** * @return A string summary of the vehicle's current state. */ @Override public String toString() { return String.format( "Vehicle{id='%s', type=%s, next='%s', route=%s}", id, type, getCurrentDestination(), route ); } }