enum VehicleType { CAR, BIKE, TRUCK } abstract class Vehicle { private String licenseNumber; private VehicleType type; public Vehicle(String licenseNumber, VehicleType type) { this.licenseNumber = licenseNumber; this.type = type; } public VehicleType getType() { return type; } public String getLicenseNumber() { return licenseNumber; } } class Car extends Vehicle { public Car(String licenseNumber) { super(licenseNumber, VehicleType.CAR); } } class Bike extends Vehicle { public Bike(String licenseNumber) { super(licenseNumber, VehicleType.BIKE); } } class Truck extends Vehicle { public Truck(String licenseNumber) { super(licenseNumber, VehicleType.TRUCK); } } class ParkingSpot { private final int spotNumber; private final VehicleType supportedType; private boolean isOccupied; private Vehicle parkedVehicle; public ParkingSpot(int spotNumber, VehicleType supportedType) { this.spotNumber = spotNumber; this.supportedType = supportedType; this.isOccupied = false; } public boolean canPark(Vehicle vehicle) { return !isOccupied && vehicle.getType() == supportedType; } public void park(Vehicle vehicle) { if (canPark(vehicle)) { this.parkedVehicle = vehicle; this.isOccupied = true; } } public void vacate() { this.parkedVehicle = null; this.isOccupied = false; } public boolean isOccupied() { return isOccupied; } public int getSpotNumber() { return spotNumber; } } class ParkingFloor { private final int floorNumber; private List spots; public ParkingFloor(int floorNumber, List spots) { this.floorNumber = floorNumber; this.spots = spots; } public ParkingSpot findAvailableSpot(Vehicle vehicle) { for (ParkingSpot spot : spots) { if (spot.canPark(vehicle)) { return spot; } } return null; } public int getFloorNumber() { return floorNumber; } public List getSpots() { return spots; } } class Ticket { private Vehicle vehicle; private int floorNumber; private int spotNumber; private LocalDateTime entryTime; private LocalDateTime exitTime; private double costPerHour = 10.0; public Ticket(Vehicle vehicle, int floorNumber, int spotNumber) { this.vehicle = vehicle; this.floorNumber = floorNumber; this.spotNumber = spotNumber; this.entryTime = LocalDateTime.now(); } public void markExit() { this.exitTime = LocalDateTime.now(); } public double calculateBill() { if (exitTime == null) { throw new IllegalStateException("Vehicle has not exited yet!"); } long durationInHours = Math.max(1, Duration.between(entryTime, exitTime).toHours()); return durationInHours * costPerHour; } public Vehicle getVehicle() { return vehicle; } public int getFloorNumber() { return floorNumber; } public int getSpotNumber() { return spotNumber; } } class ParkingLot { private List floors; private Map activeTickets = new HashMap<>(); public ParkingLot(List floors) { this.floors = floors; } public Ticket parkVehicle(Vehicle vehicle) { for (ParkingFloor floor : floors) { ParkingSpot spot = floor.findAvailableSpot(vehicle); if (spot != null) { spot.park(vehicle); Ticket ticket = new Ticket(vehicle, floor.getFloorNumber(), spot.getSpotNumber()); activeTickets.put(vehicle.getLicenseNumber(), ticket); System.out.println("Vehicle parked at floor " + floor.getFloorNumber() + " in spot " + spot.getSpotNumber()); return ticket; } } System.out.println("No available spot for vehicle type: " + vehicle.getType()); return null; } public double vacateSpot(String licenseNumber) { Ticket ticket = activeTickets.get(licenseNumber); if (ticket == null) { System.out.println("No active ticket found for vehicle: " + licenseNumber); return 0.0; } ParkingFloor floor = floors.get(ticket.getFloorNumber()); ParkingSpot spot = floor.getSpots().get(ticket.getSpotNumber()); spot.vacate(); ticket.markExit(); double bill = ticket.calculateBill(); activeTickets.remove(licenseNumber); System.out.println("Vehicle with license " + licenseNumber + " exited. Bill: $" + bill); return bill; } } public class ParkingLotDemo { public static void main(String[] args) throws InterruptedException { List floor1Spots = new ArrayList<>(); floor1Spots.add(new ParkingSpot(0, VehicleType.CAR)); floor1Spots.add(new ParkingSpot(1, VehicleType.BIKE)); List floor2Spots = new ArrayList<>(); floor2Spots.add(new ParkingSpot(0, VehicleType.TRUCK)); floor2Spots.add(new ParkingSpot(1, VehicleType.CAR)); ParkingFloor floor1 = new ParkingFloor(0, floor1Spots); ParkingFloor floor2 = new ParkingFloor(1, floor2Spots); ParkingLot parkingLot = new ParkingLot(Arrays.asList(floor1, floor2)); Vehicle car1 = new Car("CAR123"); Vehicle bike1 = new Bike("BIKE456"); Vehicle truck1 = new Truck("TRUCK789"); Ticket ticket1 = parkingLot.parkVehicle(car1); Ticket ticket2 = parkingLot.parkVehicle(bike1); Ticket ticket3 = parkingLot.parkVehicle(truck1); Thread.sleep(2000); // Simulate time spent in parking parkingLot.vacateSpot(car1.getLicenseNumber()); parkingLot.vacateSpot(bike1.getLicenseNumber()); parkingLot.vacateSpot(truck1.getLicenseNumber()); } } /* UML Diagram visit to visualize: https://www.planttext.com/ @startuml enum VehicleType { CAR BIKE TRUCK } abstract class Vehicle { - licenseNumber: String - type: VehicleType + getLicenseNumber(): String + getType(): VehicleType } class Car class Bike class Truck Vehicle <|-- Car Vehicle <|-- Bike Vehicle <|-- Truck class ParkingSpot { - spotNumber: int - supportedType: VehicleType - isOccupied: boolean - parkedVehicle: Vehicle + canPark(Vehicle): boolean + park(Vehicle): void + vacate(): void } class ParkingFloor { - floorNumber: int - spots: List + findAvailableSpot(Vehicle): ParkingSpot + getFloorNumber(): int + getSpots(): List } class Ticket { - vehicle: Vehicle - floorNumber: int - spotNumber: int - entryTime: LocalDateTime - exitTime: LocalDateTime - costPerHour: double + markExit(): void + calculateBill(): double } class ParkingLot { - floors: List - activeTickets: Map + parkVehicle(Vehicle): Ticket + vacateSpot(String): double } Vehicle --> VehicleType ParkingFloor "1" *-- "*" ParkingSpot ParkingLot "1" o-- "*" ParkingFloor ParkingLot --> Ticket Ticket --> Vehicle @enduml */