diff --git a/README.md b/README.md index f87f5c1..23e6d56 100644 --- a/README.md +++ b/README.md @@ -1 +1,17 @@ -# TODO \ No newline at end of file +# Car Booking CLI +## Part 1 - Initial Implementation +This is a CLI application that enables an admin for a car company to book cars and view users. +The menu looks as follows: +``` +1️⃣ - Book Car +2️⃣ - View All User Booked Cars +3️⃣ - View All Bookings +4️⃣ - View Available Cars +5️⃣ - View Available Electric Cars +6️⃣ - View all users +7️⃣ - Exit +``` + +## Further Instructions / Information +The full information can be found in the link below: +https://amigoscode.com/learn/java-cli-build/lectures/cc280bc8-cd3b-4d6c-94ab-666fc1a9349f diff --git a/src/main/java/Main.java b/src/main/java/Main.java deleted file mode 100644 index 23a46d3..0000000 --- a/src/main/java/Main.java +++ /dev/null @@ -1,11 +0,0 @@ - -// TODO 1. create a new branch called initial-implementation -// TODO 2. create a package with your name. i.e com.franco and move this file inside the new package -// TODO 3. implement https://amigoscode.com/learn/java-cli-build/lectures/3a83ecf3-e837-4ae5-85a8-f8ae3f60f7f5 - -public class Main { - - public static void main(String[] args) { - System.out.println("Java Master Class"); - } -} diff --git a/src/main/java/com/stan/Main.java b/src/main/java/com/stan/Main.java new file mode 100644 index 0000000..56226b9 --- /dev/null +++ b/src/main/java/com/stan/Main.java @@ -0,0 +1,137 @@ +package com.stan; +// TODO 1. create a new branch called initial-implementation +// TODO 2. create a package with your name. i.e com.franco and move this file inside the new package +// TODO 3. implement https://amigoscode.com/learn/java-cli-build/lectures/3a83ecf3-e837-4ae5-85a8-f8ae3f60f7f5 + +import com.stan.booking.Booking; +import com.stan.booking.BookingDao; +import com.stan.booking.BookingService; +import com.stan.car.Car; +import com.stan.car.CarDao; +import com.stan.car.CarService; +import com.stan.user.User; +import com.stan.user.UserDao; +import com.stan.user.UserService; + +import java.util.Scanner; + +public class Main { + public static void main(String[] args) { + CarDao carDao = new CarDao(); + BookingDao bookingDao = new BookingDao(); + CarService carService = new CarService(carDao, bookingDao); + + UserDao userDao = new UserDao(); + UserService userService = new UserService(userDao); + + + BookingService bookingService = new BookingService(bookingDao, userDao, carDao); + + try (Scanner scanner = new Scanner(System.in)) { + while (true) { + System.out.println(); + displayMenu(); + System.out.println(); + String userInput = scanner.nextLine(); + try { + int userInputNumber = Integer.parseInt(userInput); + if (userInputNumber < 1 || userInputNumber > 7) { + System.out.println(String.format("%d is not a valid option ❌", userInputNumber)); + continue; + } + } catch (NumberFormatException e) { + System.out.println("Invalid user input: " + userInput); + } + switch (userInput) { + case "1": + // Initially display all cars + Car[] cars = carService.getCars(); + for (Car car : cars) { + System.out.println(car); + } + System.out.println("➡️ select car reg number"); + String carRegNumber = scanner.nextLine(); + // Then display all users + User[] users = userService.getUsers(); + for (User user : users) { + System.out.println(user); + } + System.out.println("➡️ select user id"); + String userId = scanner.nextLine(); + bookingService.createBooking(carRegNumber, userId); + break; + case "2": + // Initially display all users + users = userService.getUsers(); + for (User user : users) { + System.out.println(user); + } + System.out.println("➡️ select user id"); + userId = scanner.nextLine(); + Car[] userCars = bookingService.getCarsByUserId(userId); + User user = userService.getUserById(userId); + if (userCars.length == 0) { + System.out.println("❌ user " + user + " has no cars booked"); + } else { + for (Car car : userCars) { + System.out.println(car); + } + } + break; + case "3": + Booking[] bookings = bookingService.getBookings(); + int bookingNumber = bookingService.getCurrentBookingNumber(); + if (bookingNumber == 0) { + System.out.println("No bookings available 😕"); + } else { + for (Booking booking : bookings) { + if (booking != null) { + System.out.println(booking); + } + } + } + break; + case "4": + cars = carService.getAvailableCars(); + if (cars.length == 0) { + System.out.println("❌ No cars available for renting"); + } else { + // probably can handle better with DTOs + for (Car car : cars) { + System.out.println(car); + } + } + break; + case "5": + Car[] electricCars = carService.getAvailableElectricCars(); + if (electricCars.length == 0) { + System.out.println("❌ No electric cars available for renting"); + } else { + for (Car car : electricCars) { + System.out.println(car); + } + } + break; + case "6": + users = userService.getUsers(); + for (User foundUser : users) { + System.out.println(foundUser); + } + break; + case "7": + return; + } + } + } + } + + public static void displayMenu() { + System.out.println("1️⃣ - Book Car"); + System.out.println("2️⃣ - View All User Booked Cars"); + System.out.println("3️⃣ - View All Bookings"); + System.out.println("4️⃣ - View Available Cars"); + System.out.println("5️⃣ - View Available Electric Cars"); + System.out.println("6️⃣ - View all users"); + System.out.println("7️⃣ - Exit"); + } +} diff --git a/src/main/java/com/stan/booking/Booking.java b/src/main/java/com/stan/booking/Booking.java new file mode 100644 index 0000000..742b5f5 --- /dev/null +++ b/src/main/java/com/stan/booking/Booking.java @@ -0,0 +1,74 @@ +package com.stan.booking; + +import com.stan.car.Car; +import com.stan.user.User; + +import java.time.LocalDateTime; +import java.util.UUID; + +public class Booking { + private UUID bookingId; + private Car car; + private User user; + private LocalDateTime bookingTime; + private boolean isCanceled; + + public Booking(UUID bookingId, Car car, User user, LocalDateTime bookingTime, boolean isCanceled) { + this.bookingId = bookingId; + this.car = car; + this.user = user; + this.bookingTime = bookingTime; + this.isCanceled = isCanceled; + } + + public UUID getBookingId() { + return bookingId; + } + + public void setBookingId(UUID bookingId) { + this.bookingId = bookingId; + } + + public Car getCar() { + return car; + } + + public void setCar(Car car) { + this.car = car; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public LocalDateTime getBookingTime() { + return bookingTime; + } + + public void setBookingTime(LocalDateTime bookingTime) { + this.bookingTime = bookingTime; + } + + public boolean isCanceled() { + return isCanceled; + } + + public void setCanceled(boolean canceled) { + isCanceled = canceled; + } + + @Override + public String toString() { + return "Booking{" + + "bookingId=" + bookingId + + ", car=" + car + + ", user=" + user + + ", bookingTime=" + bookingTime + + ", isCanceled=" + isCanceled + + '}'; + } +} diff --git a/src/main/java/com/stan/booking/BookingDao.java b/src/main/java/com/stan/booking/BookingDao.java new file mode 100644 index 0000000..e80c992 --- /dev/null +++ b/src/main/java/com/stan/booking/BookingDao.java @@ -0,0 +1,29 @@ +package com.stan.booking; + +import com.stan.car.Car; +import com.stan.user.User; + +import java.time.LocalDateTime; +import java.util.UUID; + +public class BookingDao { + private static final int MAX_BOOKINGS = 100; + + private static Booking[] bookings = new Booking[MAX_BOOKINGS] ; + private int curBookingIdx = 0; + + public Booking[] getBookings() { + return bookings; + } + + public int getCurBookingIdx() { + return curBookingIdx; + } + + public Booking createBooking(Car car, User user) { + Booking booking = new Booking(UUID.randomUUID(), car, user, LocalDateTime.now(), false); + bookings[curBookingIdx] = booking; + curBookingIdx++; + return booking; + } +} diff --git a/src/main/java/com/stan/booking/BookingService.java b/src/main/java/com/stan/booking/BookingService.java new file mode 100644 index 0000000..402ee71 --- /dev/null +++ b/src/main/java/com/stan/booking/BookingService.java @@ -0,0 +1,107 @@ +package com.stan.booking; + +import com.stan.car.Car; +import com.stan.car.CarDao; +import com.stan.user.User; +import com.stan.user.UserDao; + +public class BookingService { + private BookingDao bookingDao; + private UserDao userDao; + private CarDao carDao; + + public BookingService(BookingDao bookingDao, UserDao userDao, CarDao carDao) { + this.bookingDao = bookingDao; + this.userDao = userDao; + this.carDao = carDao; + } + + public Booking[] getBookings() { + return this.bookingDao.getBookings(); + } + + public Booking[] getBookingsByUserId(String userId) { + // TODO: use lists but will iterate twice + // 1. in first iteration, get count of bookings that are for user + int userBookingsCount = 0; + Booking[] bookings = getBookings(); + + for (Booking booking : bookings) { + if (booking == null) { + break; + } + if (booking.getUser().getUserId().toString().equals(userId)) { + userBookingsCount++; + } + } + // 2. create user bookings of length of found count + Booking[] userBookings = new Booking[userBookingsCount]; + int curUserBookingIdx = 0; + // 3. iterate second time to populate userBookings + for (Booking booking : bookings) { + if (booking == null) { + break; + } + if (booking.getUser().getUserId().toString().equals(userId)) { + userBookings[curUserBookingIdx] = booking; + curUserBookingIdx++; + } + } + + return userBookings; + } + + public int getCurrentBookingNumber() { + return this.bookingDao.getCurBookingIdx(); + } + + + public Car[] getCarsByUserId(String userId) { + if (bookingDao.getCurBookingIdx() == 0) { + return new Car[0]; + } + + Booking[] userBookings = getBookingsByUserId(userId); + Car[] userCars = new Car[userBookings.length]; + int curUserCarsIdx = 0; + for (Booking booking : userBookings) { + userCars[curUserCarsIdx] = booking.getCar(); + } + return userCars; + } + + public void createBooking(String carRegNumber, String userId) { + // Do I need to robustly handle invalid car reg number and/or user ids for now? + Car[] cars = carDao.getCars(); + boolean isCarFound = false; + Car foundCar = null; + for (Car car : cars) { + if (car.getRegNumber().toString().equals(carRegNumber)) { + isCarFound = true; + foundCar = car; + } + } + if (!isCarFound) { + System.out.println("❌ Unable to book car that doesn't exist"); + return; + } + + User[] users = userDao.getUsers(); + boolean isUserFound = false; + User foundUser = null; + for (User user : users) { + if (user.getUserId().toString().equals(userId)) { + isUserFound = true; + foundUser = user; + } + } + if (!isUserFound) { + System.out.println("❌ Unable to book car for user that doesn't exist"); + return; + } + + Booking booking = bookingDao.createBooking(foundCar, foundUser); + System.out.println("🎉 Successfully booked car with reg number " + carRegNumber + " for user " + foundUser); + System.out.println(String.format("Booking ref: %s", booking.getBookingId().toString())); + } +} diff --git a/src/main/java/com/stan/car/Brand.java b/src/main/java/com/stan/car/Brand.java new file mode 100644 index 0000000..9903574 --- /dev/null +++ b/src/main/java/com/stan/car/Brand.java @@ -0,0 +1,7 @@ +package com.stan.car; + +public enum Brand { + MERCEDES, + TESLA, + AUDI +} diff --git a/src/main/java/com/stan/car/Car.java b/src/main/java/com/stan/car/Car.java new file mode 100644 index 0000000..0f17f39 --- /dev/null +++ b/src/main/java/com/stan/car/Car.java @@ -0,0 +1,61 @@ +package com.stan.car; + +import java.math.BigDecimal; +import java.util.UUID; + +public class Car { + private UUID regNumber; + private BigDecimal rentalPricePerDay; + private Brand brand; + private boolean isElectric; + + public Car(UUID regNumber, BigDecimal rentalPricePerDay, Brand brand, boolean isElectric) { + this.regNumber = regNumber; + this.rentalPricePerDay = rentalPricePerDay; + this.brand = brand; + this.isElectric = isElectric; + } + + public UUID getRegNumber() { + return regNumber; + } + + public void setRegNumber(UUID regNumber) { + this.regNumber = regNumber; + } + + public BigDecimal getRentalPricePerDay() { + return rentalPricePerDay; + } + + public void setRentalPricePerDay(BigDecimal rentalPricePerDay) { + this.rentalPricePerDay = rentalPricePerDay; + } + + public Brand getBrand() { + return brand; + } + + public void setBrand(Brand brand) { + this.brand = brand; + } + + public boolean isElectric() { + return isElectric; + } + + public void setElectric(boolean electric) { + isElectric = electric; + } + + @Override + public String toString() { + return "Car{" + + "regNumber=" + regNumber + + ", rentalPricePerDay=" + rentalPricePerDay + + ", brand=" + brand + + ", isElectric=" + isElectric + + '}'; + } +} + diff --git a/src/main/java/com/stan/car/CarDao.java b/src/main/java/com/stan/car/CarDao.java new file mode 100644 index 0000000..8114937 --- /dev/null +++ b/src/main/java/com/stan/car/CarDao.java @@ -0,0 +1,48 @@ +package com.stan.car; + +import java.math.BigDecimal; +import java.util.UUID; + +import static com.stan.car.Brand.*; + +public class CarDao { + + private static final Car[] cars; + + static { + cars = new Car[]{ + new Car(UUID.fromString("24b15982-69d7-4421-96f3-4c46d48e8cec"), new BigDecimal("89.00"), TESLA,true), + new Car(UUID.fromString("9ff5228a-9c40-434d-a0db-bf2e6fba576d"), new BigDecimal("50.00"), AUDI, false), + new Car(UUID.fromString("f466d410-f3b2-43dc-935c-13e35524d471"), new BigDecimal("77.00"), MERCEDES, false) + }; + } + + public Car[] getCars() { + return cars; + } + + public Car[] getElectricCars() { + // TODO: handle with streams to better filter for electric cars + // Current implementation + // 1. naively iterate through cars, check isElectric property and if it's true, increment count + // 2. create new array of length of that count + // 3. iterate again, updating each index with electric car + int electricCarCount = 0; + for (Car car : cars) { + if (car.isElectric()) { + electricCarCount++; + } + } + + Car[] electricCars = new Car[electricCarCount]; + int curElectricCarIdx = 0; + for (Car car : cars) { + if (car.isElectric()) { + electricCars[curElectricCarIdx] = car; + curElectricCarIdx++; + } + } + + return electricCars; + } +} diff --git a/src/main/java/com/stan/car/CarService.java b/src/main/java/com/stan/car/CarService.java new file mode 100644 index 0000000..8346ec8 --- /dev/null +++ b/src/main/java/com/stan/car/CarService.java @@ -0,0 +1,82 @@ +package com.stan.car; + +import com.stan.booking.Booking; +import com.stan.booking.BookingDao; + +public class CarService { + private CarDao carDao; + private BookingDao bookingDao; + + public CarService(CarDao carDao, BookingDao bookingDao) { + this.carDao = carDao; + this.bookingDao = bookingDao; + } + + public Car[] getCars() { + return this.carDao.getCars(); + } + + public Car[] getAvailableCars() { + Booking[] bookings = bookingDao.getBookings(); + Car[] cars = getCars(); + int availableCarsCount = cars.length; + for (Car car : cars) { + for (Booking booking : bookings) { + if (booking != null && booking.getCar().getRegNumber() == car.getRegNumber()) { + availableCarsCount--; + } + } + } + + Car[] availableCars = new Car[availableCarsCount]; + int curAvailableCarsIdx = 0; + for (Car car : cars) { + boolean isCarAvailable = true; + for (Booking booking : bookings) { + if (booking != null && booking.getCar().getRegNumber() == car.getRegNumber()) { + isCarAvailable = false; + } + } + if (isCarAvailable) { + availableCars[curAvailableCarsIdx] = car; + curAvailableCarsIdx++; + } + } + + return availableCars; + } + + public Car[] getElectricCars() { + return this.carDao.getElectricCars(); + } + + public Car[] getAvailableElectricCars() { + Booking[] bookings = bookingDao.getBookings(); + Car[] electricCars = getElectricCars(); + int availableElectricCarsCount = electricCars.length; + for (Car car : electricCars) { + for (Booking booking : bookings) { + if (booking != null && booking.getCar().getRegNumber() == car.getRegNumber() && car.isElectric()) { + availableElectricCarsCount--; + } + } + } + + Car[] availableElectricCars = new Car[availableElectricCarsCount]; + int curAvailableElectricCarsCount = 0; + for (Car car : electricCars) { + boolean isCarAvailable = true; + for (Booking booking : bookings) { + if (booking != null && booking.getCar().getRegNumber() == car.getRegNumber() && car.isElectric()) { + isCarAvailable = false; + } + } + if (isCarAvailable) { + availableElectricCars[curAvailableElectricCarsCount] = car; + curAvailableElectricCarsCount++; + } + } + + return availableElectricCars; + } +} diff --git a/src/main/java/com/stan/user/User.java b/src/main/java/com/stan/user/User.java new file mode 100644 index 0000000..3773748 --- /dev/null +++ b/src/main/java/com/stan/user/User.java @@ -0,0 +1,37 @@ +package com.stan.user; + +import java.util.UUID; + +public class User { + private UUID userId; + private String name; + + public User(UUID userId, String name) { + this.userId = userId; + this.name = name; + } + + public UUID getUserId() { + return userId; + } + + public void setUserId(UUID userId) { + this.userId = userId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return "User{" + + "userId=" + userId + + ", name='" + name + '\'' + + '}'; + } +} diff --git a/src/main/java/com/stan/user/UserDao.java b/src/main/java/com/stan/user/UserDao.java new file mode 100644 index 0000000..1fae914 --- /dev/null +++ b/src/main/java/com/stan/user/UserDao.java @@ -0,0 +1,19 @@ +package com.stan.user; + +import java.util.UUID; + +public class UserDao { + + private static final User[] users; + + static { + users = new User[]{ + new User(UUID.fromString("8ca51d2b-aaaf-4bf2-834a-e02964e10fc3"), "James"), + new User(UUID.fromString("b10d126a-3608-4980-9f9c-aa179f5cebc3"), "Jamila") + }; + } + + public User[] getUsers() { + return users; + } +} diff --git a/src/main/java/com/stan/user/UserService.java b/src/main/java/com/stan/user/UserService.java new file mode 100644 index 0000000..be90cc6 --- /dev/null +++ b/src/main/java/com/stan/user/UserService.java @@ -0,0 +1,23 @@ +package com.stan.user; + +public class UserService { + private UserDao userDao; + + public UserService(UserDao userDao) { + this.userDao = userDao; + } + + public User[] getUsers() { + return userDao.getUsers(); + } + + public User getUserById(String userId) { + User[] users = getUsers(); + for (User user : users) { + if (user.getUserId().toString().equals(userId)) { + return user; + } + } + return null; + } +}