Files
coursera-ibm-java-developer…/PetCareScheduler/src/main/java/PetCareScheduler.java

379 lines
15 KiB
Java

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;
/**
* Pet Care Scheduler
*
* @author John Ahlroos / 2025
*
* Allows the user to manage Pet care appointments
*/
public class PetCareScheduler {
private final List<Pet> pets;
private final String dataFileName;
private final Scanner scanner;
public PetCareScheduler(Scanner scanner, String dataFileName) {
this.dataFileName = dataFileName;
this.scanner = scanner;
this.pets = new ArrayList<>();
}
public static void main(String[] args) {
System.out.println("PET CARE SCHEDULER v1.0");
System.out.println("=================================================================");
System.out.println();
try (Scanner scanner = new Scanner(System.in)) {
PetCareScheduler scheduler = new PetCareScheduler(scanner, "data.txt");
boolean loaded = scheduler.loadPetsFromFile();
if (!loaded) {
System.err.println("Failed to load data file.");
return;
}
System.out.println();
boolean exited = false;
while (!exited) {
System.out.println("Actions:");
System.out.println("\t1: Register Pet");
System.out.println("\t2: Schedule Appointment");
System.out.println("\t3: List Pets");
System.out.println("\t4: Print Report");
System.out.println("\t5: Save & Exit");
System.out.println();
System.out.print("Action: ");
try {
int action = Integer.parseInt(scanner.nextLine());
switch (action) {
case 1:
scheduler.registerPet();
break;
case 2:
scheduler.addAppointment();
break;
case 3:
scheduler.list();
break;
case 4:
scheduler.report();
break;
case 5:
boolean saved = scheduler.savePetsToFile();
if (!saved) {
System.err.println("Failed to save data file! Latest changes were lost.");
System.out.print("Exit anyway (yes/no)?");
String option = scanner.nextLine();
exited = option.equals("yes");
} else {
exited = true;
}
break;
default:
System.out.println("Not a valid option!");
}
} catch (NumberFormatException nfe) {
System.err.println("Action must be a number!");
}
}
} catch (RuntimeException re) {
System.err.println(re.getMessage());
}
}
/**
* Register a new pet with the system
*/
public void registerPet() {
System.out.println("=================================================================");
String id = UUID.randomUUID().toString();
LocalDate registration = LocalDate.now();
System.out.print("Name: ");
String name = scanner.nextLine();
if (name.isBlank()) {
System.err.println("Name must not be blank!");
return;
}
System.out.print("Owner: ");
String owner = scanner.nextLine();
if (owner.isBlank()) {
System.err.println("Owner must not be blank!");
return;
}
System.out.print("Contact Information: ");
String contact = scanner.nextLine();
System.out.print("Breed: ");
String breed = scanner.nextLine();
System.out.print("Age: ");
int age;
try{
age = Integer.parseInt(scanner.nextLine());
} catch (NumberFormatException nfe) {
System.err.println("Not a valid number!");
return;
}
Pet pet = new Pet(id,name,owner,contact,breed,age,registration);
pets.add(pet);
System.out.printf("New pet %s registered with id %s%n", pet.getName(), pet.getId());
System.out.println("=================================================================");
System.out.println();
}
/**
* Add a new appointment for a pet
*/
public void addAppointment() {
System.out.println("=================================================================");
System.out.print("Pet ID: ");
String petId = scanner.nextLine();
Optional<Pet> pet = pets.stream().filter(p -> p.getId().equals(petId)).findFirst();
if (pet.isEmpty()) {
System.err.printf("No Pet with id %s%n", petId);
return;
}
System.out.printf("Type (%s): ", Arrays.stream(Appointment.Type.values()).map(Enum::name).collect(Collectors.joining("|")));
String typeStr = scanner.nextLine().toUpperCase();
if (Arrays.stream(Appointment.Type.values()).map(Enum::name).noneMatch(t -> t.equals(typeStr))) {
System.err.printf("%s is not a valid appointment type%n", typeStr);
return;
}
System.out.print("Date (dd/mm/yyyy): ");
String dateStr = scanner.nextLine();
LocalDate date;
try {
date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("dd/MM/yyyy"));
} catch (DateTimeParseException dtpe) {
System.err.printf("%s is not a valid date%n", dateStr);
return;
}
System.out.print("Time (hh:mm): ");
String timeStr = scanner.nextLine();
LocalTime time;
try {
time = LocalTime.parse(timeStr, DateTimeFormatter.ofPattern("HH:mm"));
} catch (DateTimeParseException dtpe) {
System.err.printf("%s is not a valid time%n", timeStr);
return;
}
System.out.print("Notes: ");
String notes = scanner.nextLine();
Appointment appointment = new Appointment(Appointment.Type.valueOf(typeStr), date, time, notes);
pet.get().addAppointment(appointment);
System.out.printf("Appointment added for pet %s at %s%n", pet.get().getName(), appointment.getDate().atTime(appointment.getTime()));
System.out.println("=================================================================");
System.out.println();
}
/**
* List all pets in the system
*/
public void list() {
System.out.println("=================================================================");
System.out.println();
for (Pet pet: pets) {
System.out.printf("Id:\t\t\t%s%n", pet.getId());
System.out.printf("Name:\t\t%s%n", pet.getName());
System.out.printf("Owner:\t\t%s%n", pet.getOwner());
System.out.printf("Contact:\t%s%n", pet.getContactInformation());
System.out.printf("Breed:\t\t%s%n", pet.getBreed());
System.out.printf("Age:\t\t%d%n", pet.getAge());
System.out.printf("Registered:\t%s%n", pet.getRegistrationDate());
System.out.println("Upcoming Appointments:");
for (Appointment appointment : pet.getAppointments()) {
if (appointment.getDate().atTime(appointment.getTime()).isAfter(LocalDateTime.now())) {
System.out.printf("\t- %s %s %s%n",
appointment.getDate().atTime(appointment.getTime()),
appointment.getType(),
appointment.getNotes());
}
}
System.out.println("Past Appointments:");
for (Appointment appointment : pet.getAppointments()) {
if (appointment.getDate().atTime(appointment.getTime()).isBefore(LocalDateTime.now())) {
System.out.printf("\t- %s %s %s%n",
appointment.getDate().atTime(appointment.getTime()),
appointment.getType(),
appointment.getNotes());
}
}
System.out.println();
}
System.out.println("=================================================================");
System.out.println();
}
/**
* Generate a report of future and past appointments
*/
public void report() {
System.out.println("=================================================================");
System.out.println("Next Week: ");
LocalDateTime nextMonday = LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.MONDAY)).atTime(LocalTime.MIDNIGHT);
LocalDateTime nextSunday = nextMonday.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
for (Pet pet : pets) {
for (Appointment appointment : pet.getAppointments()) {
LocalDateTime dt = appointment.getDate().atTime(appointment.getTime());
if (dt.isAfter(nextMonday) && dt.isBefore(nextSunday)) {
System.out.printf("%s: %s %s %s%n", pet.getId(), dt, pet.getName(), pet.getOwner());
}
}
}
System.out.println();
System.out.println("Due Visits: ");
LocalDateTime dueDate = LocalDate.now().minusMonths(6).atTime(LocalTime.MIDNIGHT);
for (Pet pet : pets) {
for (Appointment appointment : pet.getAppointments()) {
LocalDateTime dt = appointment.getDate().atTime(appointment.getTime());
if (dt.isBefore(dueDate)) {
System.out.printf("%s: %s %s %s%n", pet.getId(), dt, pet.getName(), pet.getOwner());
}
}
}
System.out.println("=================================================================");
System.out.println();
}
/**
* Load pets from file
*/
private boolean loadPetsFromFile() {
File dataFile = new File(".", dataFileName);
if (!dataFile.exists()) {
System.out.println("No data file exists, loading empty pet database");
return true;
}
try (BufferedReader reader = Files.newBufferedReader(dataFile.toPath())) {
String line;
while((line = reader.readLine()) != null) {
StringTokenizer petDeserializer = new StringTokenizer(line, "|");
Pet pet = new Pet(
petDeserializer.nextToken(), // id
petDeserializer.nextToken(), // name
petDeserializer.nextToken(), // owner
petDeserializer.nextToken(), // contactInformation
petDeserializer.nextToken(), // breed
Integer.parseInt(petDeserializer.nextToken()), //age
LocalDate.parse(petDeserializer.nextToken(), DateTimeFormatter.ISO_DATE) // registrationDate
);
while((line = reader.readLine()) != null) {
if (line.isEmpty()) {
break;
}
StringTokenizer appointmentDeserializer = new StringTokenizer(line, "|");
Appointment appointment = new Appointment(
Appointment.Type.valueOf(appointmentDeserializer.nextToken()), // type
LocalDate.parse(appointmentDeserializer.nextToken(), DateTimeFormatter.ISO_DATE), // date
LocalTime.parse(appointmentDeserializer.nextToken(), DateTimeFormatter.ISO_TIME), // time
appointmentDeserializer.hasMoreTokens() ? appointmentDeserializer.nextToken() : "" // notes
);
pet.addAppointment(appointment);
}
pets.add(pet);
}
System.out.printf("%d pets loaded successfully from data file %s.%n", pets.size(), dataFileName);
return true;
} catch (IOException | RuntimeException e) {
System.err.printf("Failed to read data file. %s%n", e.getMessage());
return false;
}
}
/**
* Save pets to file
*/
private boolean savePetsToFile() {
if (pets == null || pets.isEmpty()) {
System.out.println("No pets to save");
return true;
}
File dataFile = new File(".", dataFileName);
try {
Path parent = dataFile.toPath().getParent();
if (parent != null) {
Files.createDirectories(parent);
}
} catch (IOException e) {
System.err.println("Failed to create data directory");
return false;
}
OpenOption[] fileOptions = new OpenOption[]{ StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING };
try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(dataFile.toPath(), fileOptions))) {
for (Pet pet : pets) {
StringJoiner petSerializer = new StringJoiner("|");
petSerializer.add(Objects.toString(pet.getId(), UUID.randomUUID().toString()));
petSerializer.add(Objects.toString(pet.getName()," "));
petSerializer.add(Objects.toString(pet.getOwner(), " "));
petSerializer.add(Objects.toString(pet.getContactInformation(), "None"));
petSerializer.add(Objects.toString(pet.getBreed(), "Unknown"));
petSerializer.add(String.valueOf(pet.getAge()));
petSerializer.add(Optional.ofNullable(pet.getRegistrationDate()).orElse(LocalDate.now()).format(DateTimeFormatter.ISO_DATE));
writer.println(petSerializer);
for (Appointment appointment : pet.getAppointments()) {
StringJoiner appointmentSerializer = new StringJoiner("|");
appointmentSerializer.add(appointment.getType().name());
appointmentSerializer.add(appointment.getDate().format(DateTimeFormatter.ISO_DATE));
appointmentSerializer.add(appointment.getTime().format(DateTimeFormatter.ISO_TIME));
appointmentSerializer.add(appointment.getNotes());
writer.println(appointmentSerializer);
}
writer.println();
}
System.out.printf("%d pets saved successfully to fata file %s.%n", pets.size(), dataFileName);
return true;
} catch (IOException | RuntimeException e) {
System.err.printf("Failed to write to file. %s%n", e.getMessage());
return false;
}
}
}