Skip to content

Commit

Permalink
Implement Auto-Archive feature and Sort Command (#155)
Browse files Browse the repository at this point in the history
* Implement Auto-Archive feature and Sort Command

* Fix checkstyle

* Add stashed changes

* Fix test cases
  • Loading branch information
joshenx authored Oct 27, 2021
1 parent 79dc783 commit 007c354
Show file tree
Hide file tree
Showing 21 changed files with 211 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ public class AddAppointmentCommand extends AppointmentCommand {
public static final String COMMAND_WORD = "add";

public static final String MESSAGE_USAGE =
"appt " + COMMAND_WORD + ": Adds an appointment to the appointment book. "
"apmt " + COMMAND_WORD + ": Adds an appointment to the appointment book. "
+ "Parameters: " + CliSyntax.PREFIX_INDEX + "INDEX "
+ CliSyntax.PREFIX_DATETIME + "DATETIME \n"
+ "Example: appt " + COMMAND_WORD + " " + CliSyntax.PREFIX_INDEX + "1 "
+ "Example: apmt " + COMMAND_WORD + " " + CliSyntax.PREFIX_INDEX + "1 "
+ CliSyntax.PREFIX_DATETIME + "2021-12-31 1600";

public static final String MESSAGE_SUCCESS = "New appointment added: %1$s";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ public class ArchiveAppointmentCommand extends AppointmentCommand {

public static final String COMMAND_WORD = "archive";

public static final String MESSAGE_USAGE = "appt " + COMMAND_WORD
public static final String MESSAGE_USAGE = "apmt " + COMMAND_WORD
+ ": Archives the appointment identified by the index number used in the displayed appointment list.\n"
+ "Parameters: INDEX (must be a positive integer)\n" + "Example: appt " + COMMAND_WORD + " 1";
+ "Parameters: INDEX (must be a positive integer)\n" + "Example: apmt " + COMMAND_WORD + " 1";

public static final String MESSAGE_ARCHIVE_APPOINTMENT_SUCCESS = "Archived Appointment: %1$s";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class DeleteAppointmentCommand extends AppointmentCommand {

public static final String MESSAGE_USAGE = COMMAND_WORD
+ ": Deletes the appointment identified by the index number used in the displayed appointment list.\n"
+ "Parameters: INDEX (must be a positive integer)\n" + "Example: appt " + COMMAND_WORD + " 1";
+ "Parameters: INDEX (must be a positive integer)\n" + "Example: apmt " + COMMAND_WORD + " 1";

public static final String MESSAGE_DELETE_APPOINTMENT_SUCCESS = "Deleted Appointment: %1$s";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package seedu.docit.logic.commands;

import static java.util.Objects.requireNonNull;

import java.util.List;

import seedu.docit.logic.commands.exceptions.CommandException;
import seedu.docit.model.Model;
import seedu.docit.model.appointment.Appointment;

/**
* Archives an appointment identified using it's displayed index from the appointment book.
*/
public class SortAppointmentsCommand extends AppointmentCommand {

public static final String COMMAND_WORD = "sort";

public static final String MESSAGE_USAGE = "apmt " + COMMAND_WORD
+ ": Sorts appointments based on their urgency and name.\n"
+ "Parameters: [parameter to sort by..]\n" + "Example: apmt " + COMMAND_WORD + ""; // TODO

public static final String MESSAGE_SORT_APPOINTMENT_SUCCESS = "Sorted Appointments based on "
+ "default settings.";

public SortAppointmentsCommand() {

}

@Override public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
List<Appointment> lastShownList = model.getFilteredAppointmentList();

model.sortAppointments();
return new CommandResult(String.format(MESSAGE_SORT_APPOINTMENT_SUCCESS));
}

@Override public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof SortAppointmentsCommand);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class DeletePrescriptionCommand extends AppointmentCommand {
+ "Parameters: \n"
+ CliSyntax.PREFIX_INDEX + "ID OF APPOINTMENT \n"
+ CliSyntax.PREFIX_NAME + "MEDICINE \n"
+ "Example: appt " + COMMAND_WORD + " "
+ "Example: apmt " + COMMAND_WORD + " "
+ CliSyntax.PREFIX_INDEX + "1 "
+ CliSyntax.PREFIX_NAME + "Penicillin ";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class ListPrescriptionsCommand extends AppointmentCommand {
+ COMMAND_WORD + ": List all prescriptions of an appointment "
+ "Parameters: \n"
+ CliSyntax.PREFIX_INDEX + "ID OF APPOINTMENT \n"
+ "Example: appt " + COMMAND_WORD + " "
+ "Example: apmt " + COMMAND_WORD + " "
+ CliSyntax.PREFIX_INDEX + "1 ";

public static final String MESSAGE_SUCCESS = "Listed all prescriptions of appointment";
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/seedu/docit/logic/parser/AddressBookParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class AddressBookParser {
private static final Pattern APPT_COMMAND_FORMAT = Pattern.compile("(apmt) (?<commandWord>\\S+)(?<arguments>.*)");

private final PatientBookParser patientParser = new PatientBookParser();
private final AppointmentBookParser apptParser = new AppointmentBookParser();
private final AppointmentBookParser apmtParser = new AppointmentBookParser();
private final BasicAddressBookParser basicParser = new BasicAddressBookParser();

/**
Expand All @@ -38,7 +38,7 @@ public Command parseCommand(String userInput) throws ParseException {
// Patient Command Matching
final Matcher patientMatcher = PTNT_COMMAND_FORMAT.matcher(userInput.trim());
final Matcher basicMatcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
final Matcher apptMatcher = APPT_COMMAND_FORMAT.matcher(userInput.trim());
final Matcher apmtMatcher = APPT_COMMAND_FORMAT.matcher(userInput.trim());

// empty inputs
if (userInput.equals("")) {
Expand All @@ -50,11 +50,11 @@ public Command parseCommand(String userInput) throws ParseException {
final String commandWord = basicMatcher.group("commandWord");
final String arguments = basicMatcher.group("arguments"); // ignore any arguments
return basicParser.parseBasicCommand(commandWord);
} else if (apptMatcher.matches()) {
} else if (apmtMatcher.matches()) {
// Appointment Command Matching
final String commandWord = apptMatcher.group("commandWord");
final String arguments = apptMatcher.group("arguments");
return apptParser.parseAppointmentCommand(commandWord, arguments);
final String commandWord = apmtMatcher.group("commandWord");
final String arguments = apmtMatcher.group("arguments");
return apmtParser.parseAppointmentCommand(commandWord, arguments);
} else if (patientMatcher.matches()) {
// Patient Command Matching
final String commandWord = patientMatcher.group("commandWord");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import seedu.docit.logic.commands.DeleteAppointmentCommand;
import seedu.docit.logic.commands.EditAppointmentCommand;
import seedu.docit.logic.commands.ListAppointmentsCommand;
import seedu.docit.logic.commands.SortAppointmentsCommand;
import seedu.docit.logic.commands.prescription.AddPrescriptionCommand;
import seedu.docit.logic.commands.prescription.DeletePrescriptionCommand;
import seedu.docit.logic.commands.prescription.ListPrescriptionsCommand;
Expand Down Expand Up @@ -39,6 +40,8 @@ public AppointmentCommand parseAppointmentCommand(String commandWord, String arg
return new ArchiveAppointmentCommandParser().parseAppointmentCommand(arguments);
case ListAppointmentsCommand.COMMAND_WORD:
return new ListAppointmentsCommand();
case SortAppointmentsCommand.COMMAND_WORD:
return new SortAppointmentsCommand();
case AddPrescriptionCommand.COMMAND_WORD:
return new AddPrescriptionCommandParser().parse(arguments);
case DeletePrescriptionCommand.COMMAND_WORD:
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/seedu/docit/model/AppointmentBook.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ public void setAppointment(Appointment target, Appointment editedAppointment) {
appointments.setAppointment(target, editedAppointment);
}

public void sortAppointments() {
appointments.sort();
}

/**
* Updates appointments in the list with {@code target} when there are changes to the patient's details.
* The appointment identity of {@code editedAppointment} must not be the same as another
Expand Down Expand Up @@ -153,5 +157,4 @@ public void removeAppointment(Appointment key) {
@Override public int hashCode() {
return appointments.hashCode();
}

}
17 changes: 17 additions & 0 deletions src/main/java/seedu/docit/model/AutoArchiveApmts.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package seedu.docit.model;

/**
* Runnable task to auto archive appointments that are 1-day past.
*/
public class AutoArchiveApmts implements Runnable {
private final Model model;

AutoArchiveApmts(Model model) {
this.model = model;
}

@Override
public void run() {
model.archivePastAppointments();
}
}
10 changes: 10 additions & 0 deletions src/main/java/seedu/docit/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ public interface Model {
*/
void setAppointment(Appointment target, Appointment editedAppointment);

/**
* Sorts appointments in order of whether its today, followed by dateTime, and patient name.
*/
void sortAppointments();

String getAppointments();

String getArchivedAppointments();
Expand All @@ -173,4 +178,9 @@ public interface Model {
* @throws NullPointerException if {@code predicate} is null.
*/
void updateFilteredAppointmentList(Predicate<Appointment> predicate);

/**
* Archives all appointments 1-day past their scheduled date.
*/
void archivePastAppointments();
}
58 changes: 58 additions & 0 deletions src/main/java/seedu/docit/model/ModelManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
import static seedu.docit.commons.util.CollectionUtil.requireAllNonNull;

import java.nio.file.Path;
import java.time.Clock;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.logging.Logger;

Expand All @@ -19,6 +27,7 @@
*/
public class ModelManager implements Model {
private static final Logger logger = LogsCenter.getLogger(ModelManager.class);
private static final int UPDATE_HOUR = 5;

private final AddressBook addressBook;
private final AppointmentBook appointmentBook;
Expand All @@ -45,6 +54,25 @@ public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyAppointmentBook app

filteredPatients = new FilteredList<>(this.addressBook.getPatientList());
filteredAppointments = new FilteredList<>(this.appointmentBook.getAppointmentList());


// Setup scheduler to auto-archive past appointments
archivePastAppointments();

ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Asia/Singapore"));
ZonedDateTime nextRun = now.withHour(UPDATE_HOUR).withMinute(0).withSecond(0);
if (now.compareTo(nextRun) > 0) {
nextRun = nextRun.plusDays(1);
}

Duration duration = Duration.between(now, nextRun);
long initalDelay = duration.getSeconds();

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(new AutoArchiveApmts(this),
initalDelay,
TimeUnit.DAYS.toSeconds(1),
TimeUnit.SECONDS);
}

public ModelManager() {
Expand Down Expand Up @@ -206,15 +234,45 @@ public void archiveAppointment(Appointment target) {
archivedAppointmentBook.addAppointment(target);
}

@Override
public void archivePastAppointments() {
for (Appointment appointment : appointmentBook.getAppointmentList()) {
if (isExpired(appointment)) {
archiveAppointment(appointment);
}
}
}

@Override
public void setAppointment(Appointment target, Appointment editedAppointment) {
requireAllNonNull(target, editedAppointment);

appointmentBook.setAppointment(target, editedAppointment);
}

@Override
public void sortAppointments() {
appointmentBook.sortAppointments();
updateFilteredAppointmentList(PREDICATE_SHOW_ALL_APPOINTMENTS);
}

//=========== ArchivedAppointmentBook =======================================================================

/**
* Checks if Appointment is 24-hours/1-day past its scheduled time.
*
* @param appointment
* @return true if appointment is past its scheduled time.
*/
public boolean isExpired(Appointment appointment) {
Clock cl = Clock.systemUTC();
LocalDateTime now = LocalDateTime.now(cl);
LocalDateTime apptTime = appointment.getDatetime();
Duration duration = Duration.between(apptTime, now);

return duration.toDays() >= 1;
}

/**
* Temporarily returns appointment list to be printed in CommandResult.
*/
Expand Down
20 changes: 17 additions & 3 deletions src/main/java/seedu/docit/model/appointment/Appointment.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import static seedu.docit.commons.util.CollectionUtil.requireAllNonNull;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.Objects;
import java.util.function.Predicate;

Expand All @@ -19,7 +21,7 @@
* Represents an Appointment in the appointment book. Guarantees: details are present and not null, field values are
* validated, immutable.
*/
public class Appointment {
public class Appointment implements Comparable<Appointment> {

public static final DateTimeFormatter UI_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("d MMM yyyy HHmm");
public static final DateTimeFormatter UI_DATE_FORMATTER = DateTimeFormatter.ofPattern("d MMM yyyy");
Expand Down Expand Up @@ -93,6 +95,14 @@ public String getInputFormattedDatetimeString() {
return getDatetime().format(INPUT_DATE_TIME_FORMATTER);
}

public boolean containsPrescription(Prescription p) {
return prescriptions.contains(p);
}

public boolean isToday() {
return getDatetime().toLocalDate().equals(LocalDate.now());
}

/**
* Returns true if both appointments have the same name and datetime. This defines a weaker notion of equality
* between two appointments.
Expand Down Expand Up @@ -145,7 +155,11 @@ public String toString() {
+ getPrescriptions() + "\n";
}

public boolean containsPrescription(Prescription p) {
return prescriptions.contains(p);
@Override
public int compareTo(Appointment o) {
return Comparator.comparing(Appointment::isToday).reversed()
.thenComparing(Appointment::getDatetime)
.thenComparing(Appointment::getPatient)
.compare(this, o);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ public void setAppointments(List<Appointment> appointments) {
internalList.setAll(appointments);
}

/**
* Sorts the contents of this list.
*/
public void sort() {
internalList.sort(Appointment::compareTo);
}

/**
* Returns the backing list as an unmodifiable {@code ObservableList}.
*/
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/seedu/docit/model/patient/Patient.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* Represents a Patient in the address book.
* Guarantees: details are present and not null, field values are validated, immutable.
*/
public class Patient {
public class Patient implements Comparable<Patient> {

// Identity fields
private final Name name;
Expand Down Expand Up @@ -170,4 +170,9 @@ public String toString() {

return builder.toString();
}

@Override
public int compareTo(Patient o) {
return this.name.fullName.compareTo(o.name.fullName);
}
}
Loading

0 comments on commit 007c354

Please sign in to comment.