Add Pet Scheduler assignment

This commit is contained in:
2025-10-24 10:20:33 +02:00
parent 714c3d5344
commit 50e97e8a51
4 changed files with 556 additions and 0 deletions

View File

View File

@@ -0,0 +1,67 @@
import java.time.LocalDate;
import java.time.LocalTime;
import static java.util.Objects.requireNonNull;
public final class Appointment {
private Type type;
private LocalDate date;
private LocalTime time;
private String notes;
public Appointment(Type type, LocalDate date, LocalTime time, String notes) {
this.type = requireNonNull(type, "Type must not be null");
this.date = requireNonNull(date, "date must not be null");
this.time = requireNonNull(time, "time must not be null");
this.notes = requireNonNull(notes, "note must not be null");
}
public Type getType() {
return type;
}
public LocalDate getDate() {
return date;
}
public LocalTime getTime() {
return time;
}
public String getNotes() {
return notes;
}
public void setType(Type type) {
this.type = requireNonNull(type, "Type must not be null");
}
public void setDate(LocalDate date) {
this.date = requireNonNull(date, "date must not be null");
}
public void setTime(LocalTime time) {
this.time = requireNonNull(time, "time must not be null");
}
public void setNotes(String notes) {
this.notes = requireNonNull(notes, "note must not be null");
}
@Override
public String toString() {
return "Appointment{" +
"type=" + type +
", date=" + date +
", time=" + time +
", notes='" + notes + '\'' +
'}';
}
public enum Type {
VET_VISIT,
VACCINATION,
GROOMING
}
}

View File

@@ -0,0 +1,110 @@
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static java.util.Objects.requireNonNull;
public final class Pet {
private String id;
private String name;
private String owner;
private String contactInformation;
private String breed;
private int age;
private LocalDate registrationDate;
private final List<Appointment> appointments = new ArrayList<>();
public Pet(String id, String name, String owner, String contactInformation, String breed, int age, LocalDate registrationDate) {
if (age < 0) throw new IllegalArgumentException("Age must be over 0");
this.age = age;
this.id = requireNonNull(id, "id must not be null");
this.name = requireNonNull(name, "Name must not be null");
this.owner = requireNonNull(owner, "Owner must not be null");
this.contactInformation = requireNonNull(contactInformation, "Contact information must not be null");
this.breed = requireNonNull(breed, "Breed must not be null");
this.registrationDate = requireNonNull(registrationDate, "Registration date must not be null");
}
public void addAppointment(Appointment appointment) {
this.appointments.add(requireNonNull(appointment, "Appointment must not be null"));
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getOwner() {
return owner;
}
public String getContactInformation() {
return contactInformation;
}
public String getBreed() {
return breed;
}
public int getAge() {
return age;
}
public LocalDate getRegistrationDate() {
return registrationDate;
}
public List<Appointment> getAppointments() {
return Collections.unmodifiableList(appointments);
}
public void setId(String id) {
this.id = requireNonNull(id, "id must not be null");
}
public void setName(String name) {
this.name = requireNonNull(name, "Name must not be null");
}
public void setOwner(String owner) {
this.owner = requireNonNull(owner, "Owner must not be null");
}
public void setContactInformation(String contactInformation) {
this.contactInformation =requireNonNull(contactInformation, "Contact information must not be null");
}
public void setBreed(String breed) {
this.breed = requireNonNull(breed, "Breed must not be null");
}
public void setAge(int age) {
if (age < 0) throw new IllegalArgumentException("Age must be over 0");
this.age = age;
}
public void setRegistrationDate(LocalDate registrationDate) {
this.registrationDate = requireNonNull(registrationDate, "Registration date must not be null");
}
@Override
public String toString() {
return "Pet{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", owner='" + owner + '\'' +
", contactInformation='" + contactInformation + '\'' +
", breed='" + breed + '\'' +
", age=" + age +
", registrationDate=" + registrationDate +
", appointments=" + appointments +
'}';
}
}

View File

@@ -0,0 +1,379 @@
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;
}
}
}