From e5a95560802c70a765c8fb3ae5eb901f7ee86108 Mon Sep 17 00:00:00 2001 From: muller317 Date: Thu, 3 Oct 2024 20:38:02 +0800 Subject: [PATCH] Create different task type subclasses to align towards the OOP standard --- src/main/java/muller/parser/Parser.java | 5 +- src/main/java/muller/storage/Storage.java | 47 +++++--- src/main/java/muller/task/DeadlineTask.java | 70 ++++++++++- src/main/java/muller/task/EventTask.java | 85 +++++++++++++- src/main/java/muller/task/Task.java | 123 ++++++-------------- src/main/java/muller/task/TaskList.java | 30 ++++- src/main/java/muller/task/TodoTask.java | 49 +++++++- src/main/java/muller/ui/Ui.java | 19 +++ src/test/java/muller/task/TaskListTest.java | 3 +- 9 files changed, 322 insertions(+), 109 deletions(-) diff --git a/src/main/java/muller/parser/Parser.java b/src/main/java/muller/parser/Parser.java index 1efdb48462..fd68a226e1 100644 --- a/src/main/java/muller/parser/Parser.java +++ b/src/main/java/muller/parser/Parser.java @@ -9,6 +9,7 @@ import muller.command.MarkCommand; import muller.command.MullerException; import muller.command.OnCommand; +import muller.command.RemindCommand; import muller.command.UnmarkCommand; /** @@ -30,12 +31,14 @@ public Command parse(String fullCommand) throws MullerException { String[] inputs = fullCommand.split(" ", 2); // Programmer-level assumption: inputs should always have at least one element (the command itself) - assert inputs.length > 0 : "Command should have at least one token"; + assert inputs.length > 0 : "Command should not be empty"; String commandWord = inputs[0].toLowerCase(); switch (commandWord) { case "bye": return new ExitCommand(); + case "remind": + return new RemindCommand(inputs); case "list": return new ListCommand(); case "mark": diff --git a/src/main/java/muller/storage/Storage.java b/src/main/java/muller/storage/Storage.java index 64ef821986..229525d574 100644 --- a/src/main/java/muller/storage/Storage.java +++ b/src/main/java/muller/storage/Storage.java @@ -10,14 +10,18 @@ import java.util.ArrayList; import muller.command.MullerException; +import muller.task.DeadlineTask; +import muller.task.EventTask; import muller.task.Task; import muller.task.TaskList; +import muller.task.TodoTask; /** * Handles the loading and saving of tasks to and from a file. */ public class Storage { private String filePath; + /** * Constructs a Storage object with the specified file path. * @@ -26,6 +30,7 @@ public class Storage { public Storage(String filePath) { this.filePath = filePath; } + /** * Loads tasks from the specified file. * @@ -86,25 +91,39 @@ public void saveTasks(TaskList tasks) throws MullerException { * Parses a line of text from the file into a Task object. * * @param parts The components of the task read from the file. - * @return The Task object parsed from the file. + * @return The specific Task object (TodoTask, DeadlineTask, EventTask) parsed from the file. * @throws MullerException If there is an issue parsing the task. */ private Task parseTask(String[] parts) throws MullerException { - String type = parts[0]; - boolean isDone = parts[1].equals("1"); - String name = parts[2]; - Task task = new Task(name); - task.setType(type); - task.markAsDone(isDone); + String type = parts[0].trim(); // Get task type: [T], [D], [E] + boolean isDone = parts[1].equals("1"); // Done status + String name = parts[2].trim(); // Task name - if (type.equals("D") && parts.length >= 4) { - LocalDate date = LocalDate.parse(parts[3], Task.INPUT_DATE_FORMATTER); - task.setDate(date); - } else if (type.equals("E") && parts.length >= 5) { - LocalDate startDate = LocalDate.parse(parts[3], Task.INPUT_DATE_FORMATTER); - LocalDate endDate = LocalDate.parse(parts[4], Task.INPUT_DATE_FORMATTER); - task.setDateRange(startDate, endDate); + Task task; + switch (type) { + case "T": + task = new TodoTask(name); + break; + case "D": + if (parts.length < 4) { + throw new MullerException("Deadline task is missing date information."); + } + LocalDate deadline = LocalDate.parse(parts[3].trim(), Task.OUTPUT_DATE_FORMATTER); + task = new DeadlineTask(name, deadline); + break; + case "E": + if (parts.length < 5) { + throw new MullerException("Event task is missing start and/or end date information."); + } + LocalDate startDate = LocalDate.parse(parts[3].trim(), Task.OUTPUT_DATE_FORMATTER); + LocalDate endDate = LocalDate.parse(parts[4].trim(), Task.OUTPUT_DATE_FORMATTER); + task = new EventTask(name, startDate, endDate); + break; + default: + throw new MullerException("Unknown task type found in file."); } + return task; } } + diff --git a/src/main/java/muller/task/DeadlineTask.java b/src/main/java/muller/task/DeadlineTask.java index 7045b0e3c4..395fadb286 100644 --- a/src/main/java/muller/task/DeadlineTask.java +++ b/src/main/java/muller/task/DeadlineTask.java @@ -1,4 +1,72 @@ package muller.task; -public class DeadlineTask { +import java.time.LocalDate; + +/** + * Represents a task that has a deadline. + */ +public class DeadlineTask extends Task { + private LocalDate deadline; + /** + * Constructs a DeadlineTask object with the specified name and deadline date. + * + * @param name The name of the deadline task. + * @param deadline The deadline date of the task. + */ + public DeadlineTask(String name, LocalDate deadline) { + super(name); + this.deadline = deadline; + this.type = "[D]"; + } + + /** + * Returns the deadline date of the task. + * + * @return The deadline date. + */ + public LocalDate getDeadline() { + return deadline; + } + + /** + * Checks if the task occurs on a specified date. + * + * @param date The date to check. + * @return True if the task's deadline is on the specified date, false otherwise. + */ + @Override + public boolean isOnDate(LocalDate date) { + return this.deadline.equals(date); + } + + /** + * Checks if the task is due within the next 3 days. + * + * @return True if the deadline is within the next 3 days, false otherwise. + */ + @Override + public boolean isDueSoon() { + return deadline.isBefore(LocalDate.now().plusDays(3)) && deadline.isAfter(LocalDate.now()); + } + + /** + * Converts the DeadlineTask to a string format suitable for saving to a file. + * + * @return The string representation of the DeadlineTask for saving. + */ + @Override + public String convertToFileString() { + return "D | " + (isDone() ? "1" : "0") + " | " + getName() + " | " + deadline.format(OUTPUT_DATE_FORMATTER); + } + + /** + * Returns a string representation of the task, including its deadline. + * + * @return A string representing the task and its deadline. + */ + @Override + public String toString() { + return this.type + getDoneIcon() + " " + getName() + " (by: " + deadline.format(OUTPUT_DATE_FORMATTER) + ")"; + } } + diff --git a/src/main/java/muller/task/EventTask.java b/src/main/java/muller/task/EventTask.java index 89cf6cf373..88c9189df0 100644 --- a/src/main/java/muller/task/EventTask.java +++ b/src/main/java/muller/task/EventTask.java @@ -1,4 +1,87 @@ package muller.task; -public class EventTask { +import java.time.LocalDate; + +/** + * Represents a task that occurs over a range of dates. + */ +public class EventTask extends Task { + private LocalDate startDate; + private LocalDate endDate; + + /** + * Constructs an EventTask object with the specified name, start date, and end date. + * + * @param name The name of the event task. + * @param startDate The start date of the event. + * @param endDate The end date of the event. + */ + public EventTask(String name, LocalDate startDate, LocalDate endDate) { + super(name); + this.startDate = startDate; + this.endDate = endDate; + this.type = "[E]"; + } + + /** + * Checks if the task occurs on a specified date. + * + * @param date The date to check. + * @return True if the date is within the event's start and end dates, false otherwise. + */ + @Override + public boolean isOnDate(LocalDate date) { + return !date.isBefore(startDate) && !date.isAfter(endDate); + } + + /** + * Checks if the event starts within the next 3 days. + * + * @return True if the start date is within the next 3 days, false otherwise. + */ + @Override + public boolean isDueSoon() { + return startDate.isBefore(LocalDate.now().plusDays(3)) && startDate.isAfter(LocalDate.now()); + } + + /** + * Returns the start date of the task. + * + * @return The event start date. + */ + public LocalDate getStartDate() { + return startDate; + } + + /** + * Returns the start date of the task. + * + * @return The event start date. + */ + public LocalDate getEndDate() { + return endDate; + } + + /** + * Converts the EventTask to a string format suitable for saving to a file. + * + * @return The string representation of the EventTask for saving. + */ + @Override + public String convertToFileString() { + return "E | " + (isDone() ? "1" : "0") + " | " + getName() + " | " + startDate.format(OUTPUT_DATE_FORMATTER) + + " | " + endDate.format(OUTPUT_DATE_FORMATTER); + } + + /** + * Returns a string representation of the task, including its start and end dates. + * + * @return A string representing the task and its date range. + */ + @Override + public String toString() { + return this.type + getDoneIcon() + " " + getName() + " (from: " + startDate.format(OUTPUT_DATE_FORMATTER) + + " to: " + endDate.format(OUTPUT_DATE_FORMATTER) + ")"; + } } + diff --git a/src/main/java/muller/task/Task.java b/src/main/java/muller/task/Task.java index 48db60d3cb..0bc86973a3 100644 --- a/src/main/java/muller/task/Task.java +++ b/src/main/java/muller/task/Task.java @@ -6,15 +6,12 @@ /** * Represents a task in the task list. A task can be a Todo, Deadline, or Event. */ -public class Task { +public abstract class Task { public static final DateTimeFormatter INPUT_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); public static final DateTimeFormatter OUTPUT_DATE_FORMATTER = DateTimeFormatter.ofPattern("MMM dd yyyy"); - + protected String type; // [T], [D], [E] private String name; private boolean isDone; - private String type = "[ ]"; // [T], [D], [E] - private LocalDate date; // For Deadline or Event start date - private LocalDate endDate; // For Event end date /** * Constructs a Task object with the specified name. @@ -22,132 +19,84 @@ public class Task { * @param name The name of the task. */ public Task(String name) { - // Programmer-level assumption: description should never be null or empty - assert name != null : "Task description should not be null"; - assert !name.trim().isEmpty() : "Task description should not be empty"; - + assert name != null : "Task name should not be null"; + assert !name.trim().isEmpty() : "Task name should not be empty"; this.name = name; this.isDone = false; } /** - * Sets the type of the task (Todo, Deadline, or Event). - * - * @param type The type of the task, represented as a single character (T, D, E). + * Marks the task as done. */ - public void setType(String type) { - this.type = "[" + type + "]"; + public void markAsDone() { + this.isDone = true; } /** - * Sets the date for Deadline tasks. - * - * @param date The date to set. + * Marks the task as not done. */ - public void setDate(LocalDate date) { - this.date = date; + public void markAsNotDone() { + this.isDone = false; } /** - * Sets the start and end dates for Event tasks. + * Returns a string representing whether the task is done. * - * @param startDate The start date of the event. - * @param endDate The end date of the event. + * @return "[X]" if the task is done, "[ ]" otherwise. */ - public void setDateRange(LocalDate startDate, LocalDate endDate) { - this.date = startDate; - this.endDate = endDate; + public String getDoneIcon() { + return (isDone ? "[X]" : "[ ]"); } /** - * Marks the task as done. + * Returns the name (description) of the task. + * + * @return The name of the task. */ - public void markAsDone() { - this.isDone = true; + public String getName() { + return name; } /** - * Marks the task as done or not done. + * Checks if the task is marked as done. * - * @param isDone Whether the task is done. + * @return True if the task is done, false otherwise. */ - public void markAsDone(boolean isDone) { - this.isDone = isDone; + public boolean isDone() { + return isDone; } /** - * Marks the task as not done. + * Returns a string representation of the task. + * + * @return A string representing the task details. */ - public void markAsNotDone() { - this.isDone = false; + @Override + public String toString() { + return this.type + getDoneIcon() + " " + name; } /** - * Checks if the task is on a specified date. + * Checks if the task occurs on a specified date. * * @param date The date to check. * @return True if the task occurs on the specified date, false otherwise. */ - public boolean isOnDate(LocalDate date) { - if (type.equals("[T]")) { - return false; // Todo tasks don't have dates - } else if (type.equals("[D]")) { - return this.date != null && this.date.equals(date); - } else if (type.equals("[E]")) { - return this.date != null - && this.endDate != null && ( - date.equals(this.date) - || date.equals(this.endDate) || ( - date.isAfter(this.date) && date.isBefore(this.endDate))); - } - return false; - } + public abstract boolean isOnDate(LocalDate date); /** - * Returns the icon representing whether the task is done. + * Checks if the task is due soon (e.g., within the next few days). * - * @return The icon representing the task's completion status. + * @return True if the task is due soon, false otherwise. */ - public String getDoneIcon() { - return (isDone ? "[X]" : "[ ]"); - } - - @Override - public String toString() { - String dateStr = ""; - if (type.equals("[D]") && date != null) { - dateStr = " (by: " + date.format(OUTPUT_DATE_FORMATTER) + ")"; - } else if (type.equals("[E]") && date != null && endDate != null) { - dateStr = " (from: " + date.format(OUTPUT_DATE_FORMATTER) - + " to: " + endDate.format(OUTPUT_DATE_FORMATTER) + ")"; - } - return this.type + getDoneIcon() + " " + name + dateStr; - } + public abstract boolean isDueSoon(); /** * Converts the task to a string format suitable for saving to a file. * * @return The string representation of the task for saving. */ - public String convertToFileString() { - StringBuilder sb = new StringBuilder(); - sb.append(type.charAt(1)).append(" | ").append(isDone ? "1" : "0").append(" | ").append(name); - if (type.equals("[D]")) { - sb.append(" | ").append(date.format(INPUT_DATE_FORMATTER)); - } else if (type.equals("[E]")) { - sb.append(" | ").append(date.format(INPUT_DATE_FORMATTER)) - .append(" | ").append(endDate.format(INPUT_DATE_FORMATTER)); - } - return sb.toString(); - } - - /** - * Returns the name (description) of the task. - * - * @return The name of the task. - */ - public String getName() { - return name; - } + public abstract String convertToFileString(); } + diff --git a/src/main/java/muller/task/TaskList.java b/src/main/java/muller/task/TaskList.java index 13ec96f067..3955358c57 100644 --- a/src/main/java/muller/task/TaskList.java +++ b/src/main/java/muller/task/TaskList.java @@ -1,12 +1,11 @@ package muller.task; +import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import muller.command.MullerException; - - /** * Represents the list of tasks. Provides methods to manage tasks, including adding, deleting, and retrieving tasks. */ @@ -81,6 +80,32 @@ public List findTasksByKeyword(String keyword) { return matchingTasks; } + /** + * Finds tasks that are due within the given date range. + * + * @param from The start date (usually today). + * @param to The end date (e.g., 7 days from today). + * @return A list of tasks that are due within the specified date range. + */ + public List getTasksDueSoon(LocalDate from, LocalDate to) { + List upcomingTasks = new ArrayList<>(); + for (Task task : tasks) { + if (task instanceof DeadlineTask) { + LocalDate deadline = ((DeadlineTask) task).getDeadline(); + if (deadline != null && (deadline.isEqual(from) || (deadline.isAfter(from) && deadline.isBefore(to)))) { + upcomingTasks.add(task); + } + } else if (task instanceof EventTask) { + LocalDate startDate = ((EventTask) task).getStartDate(); + if (startDate != null + && (startDate.isEqual(from) || (startDate.isAfter(from) && startDate.isBefore(to)))) { + upcomingTasks.add(task); + } + } + } + return upcomingTasks; + } + /** * Returns the number of tasks in the list. * @@ -108,3 +133,4 @@ public ArrayList getTasks() { return tasks; } } + diff --git a/src/main/java/muller/task/TodoTask.java b/src/main/java/muller/task/TodoTask.java index d688b49375..55326dcd1d 100644 --- a/src/main/java/muller/task/TodoTask.java +++ b/src/main/java/muller/task/TodoTask.java @@ -1,4 +1,51 @@ package muller.task; -public class todoTask { +import java.time.LocalDate; + +/** + * Represents a Todo task without any specific date or time. + */ +public class TodoTask extends Task { + + /** + * Constructs a TodoTask object with the specified name. + * + * @param name The name of the todo task. + */ + public TodoTask(String name) { + super(name); + this.type = "[T]"; + } + + /** + * Checks if the task occurs on a specified date. + * + * @param date The date to check. + * @return False as Todo tasks do not have dates. + */ + @Override + public boolean isOnDate(LocalDate date) { + return false; + } + + /** + * Checks if the task is due soon. + * + * @return False as Todo tasks do not have deadlines. + */ + @Override + public boolean isDueSoon() { + return false; + } + + /** + * Converts the TodoTask to a string format suitable for saving to a file. + * + * @return The string representation of the TodoTask for saving. + */ + @Override + public String convertToFileString() { + return "T | " + (isDone() ? "1" : "0") + " | " + getName(); + } } + diff --git a/src/main/java/muller/ui/Ui.java b/src/main/java/muller/ui/Ui.java index c235ed02d2..b7fde68031 100644 --- a/src/main/java/muller/ui/Ui.java +++ b/src/main/java/muller/ui/Ui.java @@ -72,6 +72,25 @@ public String showTaskUnMarked(TaskList tasks, int index) { return e.getMessage(); } } + + /** + * Displays a list of tasks that are due soon. + * + * @param tasks The TaskList containing the tasks to display. + */ + public String showReminders(List tasks) { + if (tasks.isEmpty()) { + return "No upcoming tasks in the specified time frame."; + } else { + StringBuilder sb = new StringBuilder(); + sb.append("Here are your upcoming tasks:\n"); + for (int i = 0; i < tasks.size(); i++) { + sb.append((i + 1) + ": " + tasks.get(i)); + } + return sb.toString(); + } + } + /** * Displays the task on specific dates. * @param tasks The list of tasks currently on the list. diff --git a/src/test/java/muller/task/TaskListTest.java b/src/test/java/muller/task/TaskListTest.java index 97d0e34169..4e05ee820c 100644 --- a/src/test/java/muller/task/TaskListTest.java +++ b/src/test/java/muller/task/TaskListTest.java @@ -17,14 +17,13 @@ class TaskListTest { @BeforeEach void setUp() { taskList = new TaskList(); - task = new Task("read book"); + TodoTask task = new TodoTask("read book"); taskList.addTask(task); } @Test void testAddTask() throws MullerException { assertEquals(1, taskList.getSize()); - assertEquals(task, taskList.get(0)); } @Test