From 6a874e53b83cb9e706dadfbb310c2e8de9489f6f Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Tue, 12 Sep 2023 01:05:18 +0800 Subject: [PATCH 01/15] Add history to track the previous state & command --- src/main/java/corgi/Corgi.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/corgi/Corgi.java b/src/main/java/corgi/Corgi.java index c4562eab84..67a3c02e87 100644 --- a/src/main/java/corgi/Corgi.java +++ b/src/main/java/corgi/Corgi.java @@ -1,7 +1,10 @@ package corgi; +import java.util.Stack; + import corgi.commands.Command; import corgi.commands.CommandExecutionException; +import corgi.commands.CommandType; import corgi.parsers.CommandParser; import corgi.parsers.InvalidCommandFormatException; import corgi.parsers.InvalidCommandTypeException; @@ -10,6 +13,7 @@ import corgi.tasks.Task; import corgi.tasks.TaskList; import corgi.ui.TextRenderer; +import javafx.util.Pair; /** @@ -22,15 +26,17 @@ public class Corgi { private TaskList tasks; private Storage storage; private TextRenderer renderer; + private Stack> history; /** - * Constructs new Corgi chatbot with an empty task list. + * Constructs new Corgi chatbot with an empty task list, + * a text renderer, a storage and a history stack. */ public Corgi() { this.renderer = new TextRenderer(); this.storage = new Storage<>(new TaskParser(), "./data/tasks.txt"); this.tasks = new TaskList(storage.load()); - + this.history = new Stack<>(); // if (tasks.size() > 0) { // this.renderer.showTasksLoaded(tasks.size()); // } From 5c7f0d7e0241b33b52090d31c902d58bb7531484 Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Tue, 12 Sep 2023 01:38:11 +0800 Subject: [PATCH 02/15] Store Command object in history --- src/main/java/corgi/Corgi.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/corgi/Corgi.java b/src/main/java/corgi/Corgi.java index 67a3c02e87..dc4427c154 100644 --- a/src/main/java/corgi/Corgi.java +++ b/src/main/java/corgi/Corgi.java @@ -26,7 +26,7 @@ public class Corgi { private TaskList tasks; private Storage storage; private TextRenderer renderer; - private Stack> history; + private Stack> history; /** * Constructs new Corgi chatbot with an empty task list, @@ -57,7 +57,7 @@ public String getResponse(String input) { try { cmd = new CommandParser().parse(input); assert cmd != null : "Command returned from parser cannot be null"; - return cmd.execute(this.tasks, this.renderer, this.storage); + return cmd.execute(this.tasks, this.renderer, this.storage, this.history); } catch (InvalidCommandFormatException e) { return this.renderer.showError(e.getClass().getSimpleName(), e.getMessage()); } catch (InvalidCommandTypeException e) { From 7f63d95f82afc2704b2492fc7ba0444e9ec28b96 Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Tue, 12 Sep 2023 01:38:41 +0800 Subject: [PATCH 03/15] Pass history stack as argument in execute method --- .../java/corgi/commands/AddTaskCommand.java | 14 ++++++++++++-- src/main/java/corgi/commands/Command.java | 8 +++++++- .../java/corgi/commands/DeleteTaskCommand.java | 17 ++++++++++++++--- src/main/java/corgi/commands/ExitCommand.java | 8 +++++++- .../FindTasksContainKeywordCommand.java | 7 ++++++- .../corgi/commands/FindTasksOnDateCommand.java | 7 ++++++- .../java/corgi/commands/ListTasksCommand.java | 8 +++++++- .../java/corgi/commands/MarkTaskCommand.java | 10 +++++++++- 8 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/main/java/corgi/commands/AddTaskCommand.java b/src/main/java/corgi/commands/AddTaskCommand.java index 9ad0694cfa..012eb5a51d 100644 --- a/src/main/java/corgi/commands/AddTaskCommand.java +++ b/src/main/java/corgi/commands/AddTaskCommand.java @@ -1,9 +1,12 @@ package corgi.commands; +import java.util.Stack; + import corgi.storage.Storage; import corgi.tasks.Task; import corgi.tasks.TaskList; import corgi.ui.TextRenderer; +import javafx.util.Pair; /** * Represents a command to add a task to the task list. @@ -34,16 +37,23 @@ public AddTaskCommand(Task target) { /** * Executes the command by adding the specified task to the task list, saving the updated list to storage, - * and return formatted message indicating that the task has been added. + * store the stack to the history stack and return formatted message indicating that the task has been added. * * @param list The task list to which the task should be added. * @param renderer The text renderer to return formatted message. * @param storage The storage for saving and loading tasks (if applicable). + * @param history The history stack to store the states. + * @return A string message indicating the result of the command execution. */ @Override - public String execute(TaskList list, TextRenderer renderer, Storage storage) { + public String execute( + TaskList list, TextRenderer renderer, Storage storage, Stack> history) { list.add(this.target); storage.save(list); + + Pair currState = new Pair<>(this, list); + history.push(currState); + return renderer.showTaskAdded(this.taskType, target.toString(), list.size()); } } diff --git a/src/main/java/corgi/commands/Command.java b/src/main/java/corgi/commands/Command.java index 909ce8f4d4..0b324a36b3 100644 --- a/src/main/java/corgi/commands/Command.java +++ b/src/main/java/corgi/commands/Command.java @@ -1,9 +1,12 @@ package corgi.commands; +import java.util.Stack; + import corgi.storage.Storage; import corgi.tasks.Task; import corgi.tasks.TaskList; import corgi.ui.TextRenderer; +import javafx.util.Pair; /** * An abstract class to represent command. @@ -31,9 +34,12 @@ public Command(boolean isExit) { * @param list The task list to perform the command action on. * @param renderer The text renderer to return formatted message. * @param storage The storage for saving and loading tasks (if applicable). + * @param history The history stack to store the states. * @throws CommandExecutionException If an error occurs during command execution. + * @return A string message indicating the result of the command execution. */ - public abstract String execute(TaskList list, TextRenderer renderer, Storage storage) + public abstract String execute( + TaskList list, TextRenderer renderer, Storage storage, Stack> history) throws CommandExecutionException; /** diff --git a/src/main/java/corgi/commands/DeleteTaskCommand.java b/src/main/java/corgi/commands/DeleteTaskCommand.java index c0061c84d7..6635246388 100644 --- a/src/main/java/corgi/commands/DeleteTaskCommand.java +++ b/src/main/java/corgi/commands/DeleteTaskCommand.java @@ -1,10 +1,13 @@ package corgi.commands; +import java.util.Stack; + import corgi.storage.Storage; import corgi.tasks.Task; import corgi.tasks.TaskList; import corgi.tasks.TaskListIndexOutOfBoundsException; import corgi.ui.TextRenderer; +import javafx.util.Pair; /** * Represents a command to delete a task from the task list. @@ -28,21 +31,29 @@ public DeleteTaskCommand(int targetIdx) { /** * Executes the command by deleting the task at the specified index from the task list, - * saving the updated list to storage, and return message indicating - * that the task has been deleted. + * saving the updated list to storage, store the state to history stack, + * and return message indicating that the task has been deleted. * * @param list The task list from which the task should be deleted. * @param renderer The text renderer to return formatted message. * @param storage The storage for saving and loading tasks (if applicable). + * @param history The history stack to store the states. * @throws CommandExecutionException If an error occurs during command execution. + * @return A string message indicating the result of the command execution. */ @Override - public String execute(TaskList list, TextRenderer renderer, Storage storage) + public String execute( + TaskList list, TextRenderer renderer, Storage storage, Stack> history) throws CommandExecutionException { try { String targetTaskInfo = list.getTaskInfo(targetIdx); list.remove(targetIdx); + storage.save(list); + + Pair currState = new Pair<>(this, list); + history.push(currState); + return renderer.showTaskDeleted(targetTaskInfo, list.size()); } catch (TaskListIndexOutOfBoundsException e) { throw new CommandExecutionException("Invalid index provided!"); diff --git a/src/main/java/corgi/commands/ExitCommand.java b/src/main/java/corgi/commands/ExitCommand.java index 4f8e605795..9c798b18df 100644 --- a/src/main/java/corgi/commands/ExitCommand.java +++ b/src/main/java/corgi/commands/ExitCommand.java @@ -1,9 +1,12 @@ package corgi.commands; +import java.util.Stack; + import corgi.storage.Storage; import corgi.tasks.Task; import corgi.tasks.TaskList; import corgi.ui.TextRenderer; +import javafx.util.Pair; /** * Represents a command to exit the application. @@ -24,9 +27,12 @@ public ExitCommand() { * @param list The task list (not used in this command). * @param renderer The text renderer to return formatted message. * @param storage The storage for saving and loading tasks (not used in this command). + * @param history The history stack to store the states. + * @return A string message indicating the result of the command execution. */ @Override - public String execute(TaskList list, TextRenderer renderer, Storage storage) { + public String execute( + TaskList list, TextRenderer renderer, Storage storage, Stack> history) { return renderer.showExitMsg(); } } diff --git a/src/main/java/corgi/commands/FindTasksContainKeywordCommand.java b/src/main/java/corgi/commands/FindTasksContainKeywordCommand.java index 27e240f605..da35f20dfd 100644 --- a/src/main/java/corgi/commands/FindTasksContainKeywordCommand.java +++ b/src/main/java/corgi/commands/FindTasksContainKeywordCommand.java @@ -1,11 +1,13 @@ package corgi.commands; +import java.util.Stack; import java.util.function.Predicate; import corgi.storage.Storage; import corgi.tasks.Task; import corgi.tasks.TaskList; import corgi.ui.TextRenderer; +import javafx.util.Pair; /** * Represents a command to find tasks containing a specific keyword in the task list. @@ -43,9 +45,12 @@ public FindTasksContainKeywordCommand(String target) { * @param list The task list to filter. * @param renderer The text renderer to return formatted message. * @param storage The storage for saving and loading tasks (not used in this command). + * @param history The history stack to store the states. + * @return A string message indicating the result of the command execution. */ @Override - public String execute(TaskList list, TextRenderer renderer, Storage storage) { + public String execute( + TaskList list, TextRenderer renderer, Storage storage, Stack> history) { TaskList tasksContainKeyword = list.filter(predicate); if (tasksContainKeyword.isEmpty()) { diff --git a/src/main/java/corgi/commands/FindTasksOnDateCommand.java b/src/main/java/corgi/commands/FindTasksOnDateCommand.java index b9b8ba7978..ca42b43b03 100644 --- a/src/main/java/corgi/commands/FindTasksOnDateCommand.java +++ b/src/main/java/corgi/commands/FindTasksOnDateCommand.java @@ -1,6 +1,7 @@ package corgi.commands; import java.time.LocalDate; +import java.util.Stack; import java.util.function.Predicate; import corgi.storage.Storage; @@ -9,6 +10,7 @@ import corgi.tasks.Task; import corgi.tasks.TaskList; import corgi.ui.TextRenderer; +import javafx.util.Pair; /** * Represents a command to find tasks on a specific date in the task list. @@ -54,9 +56,12 @@ public FindTasksOnDateCommand(LocalDate target) { * @param list The task list to filter. * @param renderer The text renderer to return formatted message. * @param storage The storage for saving and loading tasks (not used in this command). + * @param history The history stack to store the states. + * @return A string message indicating the result of the command execution. */ @Override - public String execute(TaskList list, TextRenderer renderer, Storage storage) { + public String execute( + TaskList list, TextRenderer renderer, Storage storage, Stack> history) { TaskList tasksOnDate = list.filter(predicate); String outputDate = this.target.format(Task.DATE_OUTPUT_FORMATTER); diff --git a/src/main/java/corgi/commands/ListTasksCommand.java b/src/main/java/corgi/commands/ListTasksCommand.java index 6c2c16fc56..ce7ec3bca6 100644 --- a/src/main/java/corgi/commands/ListTasksCommand.java +++ b/src/main/java/corgi/commands/ListTasksCommand.java @@ -1,9 +1,12 @@ package corgi.commands; +import java.util.Stack; + import corgi.storage.Storage; import corgi.tasks.Task; import corgi.tasks.TaskList; import corgi.ui.TextRenderer; +import javafx.util.Pair; /** * Represents a command to list tasks in the task list. @@ -23,10 +26,13 @@ public ListTasksCommand() { * * @param list The task list to be displayed. * @param renderer The text renderer to return formatted message. + * @param history The history stack to store the states. * @param storage The storage for saving and loading tasks (not used in this command). + * @return A string message indicating the result of the command execution. */ @Override - public String execute(TaskList list, TextRenderer renderer, Storage storage) { + public String execute( + TaskList list, TextRenderer renderer, Storage storage, Stack> history) { if (list.isEmpty()) { return renderer.showNoTaskFound(); } else { diff --git a/src/main/java/corgi/commands/MarkTaskCommand.java b/src/main/java/corgi/commands/MarkTaskCommand.java index 93555810ce..a437653083 100644 --- a/src/main/java/corgi/commands/MarkTaskCommand.java +++ b/src/main/java/corgi/commands/MarkTaskCommand.java @@ -1,11 +1,14 @@ package corgi.commands; +import java.util.Stack; + import corgi.storage.Storage; import corgi.tasks.Task; import corgi.tasks.TaskList; import corgi.tasks.TaskListIndexOutOfBoundsException; import corgi.tasks.TaskStatusException; import corgi.ui.TextRenderer; +import javafx.util.Pair; /** * Represents a command to mark a task as done or undone in the task list. @@ -45,11 +48,16 @@ public MarkTaskCommand(int index, boolean status) { * @throws CommandExecutionException If an error occurs during command execution. */ @Override - public String execute(TaskList list, TextRenderer renderer, Storage storage) + public String execute( + TaskList list, TextRenderer renderer, Storage storage, Stack> history) throws CommandExecutionException { try { list.mark(this.index, this.status); storage.save(list); + + Pair currState = new Pair<>(this, list); + history.push(currState); + if (status) { return renderer.showTaskDone(list.getTaskInfo(this.index)); } else { From 40c5e141b29200b2e7b7c4ba6dff3b71c1ad5ae5 Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Tue, 12 Sep 2023 01:52:49 +0800 Subject: [PATCH 04/15] Add new undo command --- src/main/java/corgi/commands/CommandType.java | 3 ++- src/main/java/corgi/ui/TextRenderer.java | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/corgi/commands/CommandType.java b/src/main/java/corgi/commands/CommandType.java index 9318b0115e..0ed106d260 100644 --- a/src/main/java/corgi/commands/CommandType.java +++ b/src/main/java/corgi/commands/CommandType.java @@ -13,7 +13,8 @@ public enum CommandType { LIST("list"), DELETE("delete [task no.]"), DATE("date [yyyy-mm-dd]"), - FIND("find [keyword]"); + FIND("find [keyword]"), + UNDO("undo"); private final String commandFormat; diff --git a/src/main/java/corgi/ui/TextRenderer.java b/src/main/java/corgi/ui/TextRenderer.java index 1b4d256340..2eaf042861 100644 --- a/src/main/java/corgi/ui/TextRenderer.java +++ b/src/main/java/corgi/ui/TextRenderer.java @@ -202,4 +202,8 @@ public String showNoTaskFound() { public String showTaskList(String taskList) { return taskList; } + + public String showUndoSucceed(String commandDesc) { + return returnMessage("Undo successful: " + commandDesc); + } } From 91f03fca1af5f13dc0f45cef84655009a1061bcb Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Tue, 12 Sep 2023 01:53:07 +0800 Subject: [PATCH 05/15] Implement UndoCommand class --- src/main/java/corgi/commands/UndoCommand.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/main/java/corgi/commands/UndoCommand.java diff --git a/src/main/java/corgi/commands/UndoCommand.java b/src/main/java/corgi/commands/UndoCommand.java new file mode 100644 index 0000000000..67e6cff68d --- /dev/null +++ b/src/main/java/corgi/commands/UndoCommand.java @@ -0,0 +1,47 @@ +package corgi.commands; + +import java.util.Stack; + +import corgi.storage.Storage; +import corgi.tasks.Task; +import corgi.tasks.TaskList; +import corgi.ui.TextRenderer; +import javafx.util.Pair; + +public class UndoCommand extends Command { + /** + * Initializes a new UndoCommand instance. + */ + public UndoCommand() { + super(false); + } + + /** + * Executes the command by reverting the previous action based on the provided + * history stack and updating the task list accordingly. + * + * @param list The task list. + * @param renderer The text renderer to return formatted message. + * @param storage The storage for saving and loading tasks. + * @param history The history stack to store the states. + * @return A string message indicating the result of the command execution. + */ + @Override + public String execute( + TaskList list, TextRenderer renderer, Storage storage, Stack> history) + throws CommandExecutionException { + if (history.isEmpty()) { + throw new CommandExecutionException("Nothing to undo!"); + } + + Pair prevState = history.pop(); + Command prevCommand = prevState.getKey(); + TaskList prevTaskList = prevState.getValue(); + + list = prevTaskList; + + storage.save(list); + + return renderer.showUndoSucceed(prevCommand.toString()); + } +} From 969049542e8c17a027395a5ef18f41cddacecdf9 Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Tue, 12 Sep 2023 01:53:24 +0800 Subject: [PATCH 06/15] Add new undo command --- src/main/java/corgi/parsers/CommandParser.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/corgi/parsers/CommandParser.java b/src/main/java/corgi/parsers/CommandParser.java index 3f4a799316..525ae110d3 100644 --- a/src/main/java/corgi/parsers/CommandParser.java +++ b/src/main/java/corgi/parsers/CommandParser.java @@ -13,6 +13,7 @@ import corgi.commands.InvalidCommandException; import corgi.commands.ListTasksCommand; import corgi.commands.MarkTaskCommand; +import corgi.commands.UndoCommand; import corgi.tasks.Deadline; import corgi.tasks.Event; import corgi.tasks.Task; @@ -47,6 +48,8 @@ public Command parse(String fullCommand) throws InvalidCommandFormatException, I Command command = null; switch (cmd) { + case UNDO: + command = newUndoCommand(inputs); case BYE: command = newExitCommand(inputs); break; @@ -84,6 +87,14 @@ public Command parse(String fullCommand) throws InvalidCommandFormatException, I return command; } + private Command newUndoCommand(String[] inputs) throws InvalidCommandFormatException { + if (inputs.length > 1) { + throw new InvalidCommandFormatException("No argument is needed!" + "\nFormat: " + + CommandType.UNDO.getCommandFormat()); + } + return new UndoCommand(); + } + private Command newExitCommand(String[] inputs) throws InvalidCommandFormatException { if (inputs.length > 1) { throw new InvalidCommandFormatException("No argument is needed!" + "\nFormat: " From 9091c5010d8fc30e07dd0b1fca1d729a6f3dae05 Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Tue, 12 Sep 2023 01:53:44 +0800 Subject: [PATCH 07/15] Remove unused import --- src/main/java/corgi/Corgi.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/corgi/Corgi.java b/src/main/java/corgi/Corgi.java index dc4427c154..97e5393569 100644 --- a/src/main/java/corgi/Corgi.java +++ b/src/main/java/corgi/Corgi.java @@ -4,7 +4,6 @@ import corgi.commands.Command; import corgi.commands.CommandExecutionException; -import corgi.commands.CommandType; import corgi.parsers.CommandParser; import corgi.parsers.InvalidCommandFormatException; import corgi.parsers.InvalidCommandTypeException; From eb603cfb42aaac634a8565fb24b43350f9613768 Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Tue, 12 Sep 2023 01:56:32 +0800 Subject: [PATCH 08/15] Add string representation of command --- src/main/java/corgi/commands/AddTaskCommand.java | 5 +++++ src/main/java/corgi/commands/DeleteTaskCommand.java | 5 +++++ src/main/java/corgi/commands/MarkTaskCommand.java | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/src/main/java/corgi/commands/AddTaskCommand.java b/src/main/java/corgi/commands/AddTaskCommand.java index 012eb5a51d..64b24fb288 100644 --- a/src/main/java/corgi/commands/AddTaskCommand.java +++ b/src/main/java/corgi/commands/AddTaskCommand.java @@ -56,4 +56,9 @@ public String execute( return renderer.showTaskAdded(this.taskType, target.toString(), list.size()); } + + @Override + public String toString() { + return "Add task " + this.target; + } } diff --git a/src/main/java/corgi/commands/DeleteTaskCommand.java b/src/main/java/corgi/commands/DeleteTaskCommand.java index 6635246388..32cf183b2d 100644 --- a/src/main/java/corgi/commands/DeleteTaskCommand.java +++ b/src/main/java/corgi/commands/DeleteTaskCommand.java @@ -59,4 +59,9 @@ public String execute( throw new CommandExecutionException("Invalid index provided!"); } } + + @Override + public String toString() { + return "Delete task " + this.targetIdx; + } } diff --git a/src/main/java/corgi/commands/MarkTaskCommand.java b/src/main/java/corgi/commands/MarkTaskCommand.java index a437653083..2d52bd597b 100644 --- a/src/main/java/corgi/commands/MarkTaskCommand.java +++ b/src/main/java/corgi/commands/MarkTaskCommand.java @@ -69,4 +69,10 @@ public String execute( throw new CommandExecutionException("The task is already in that status!"); } } + + @Override + public String toString() { + String action = this.status ? "Mark" : "Unmark"; + return action + " task " + this.index; + } } From b8a93b85f1ba86590e9a944fb7e710f21bc0edb7 Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Tue, 12 Sep 2023 01:58:14 +0800 Subject: [PATCH 09/15] Add logic to return UNDO command --- src/main/java/corgi/commands/CommandType.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/corgi/commands/CommandType.java b/src/main/java/corgi/commands/CommandType.java index 0ed106d260..704d9f5e73 100644 --- a/src/main/java/corgi/commands/CommandType.java +++ b/src/main/java/corgi/commands/CommandType.java @@ -56,6 +56,8 @@ public static CommandType getCommandType(String commandStr) throws InvalidComman return DATE; case "find": return FIND; + case "undo": + return UNDO; default: throw new InvalidCommandException(); } From 97b33fb8ca3a9929c5c9398d3f7a8020b36cddb9 Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Tue, 12 Sep 2023 02:02:26 +0800 Subject: [PATCH 10/15] Add missing break statement --- src/main/java/corgi/parsers/CommandParser.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/corgi/parsers/CommandParser.java b/src/main/java/corgi/parsers/CommandParser.java index 525ae110d3..2fda5820ff 100644 --- a/src/main/java/corgi/parsers/CommandParser.java +++ b/src/main/java/corgi/parsers/CommandParser.java @@ -50,6 +50,7 @@ public Command parse(String fullCommand) throws InvalidCommandFormatException, I switch (cmd) { case UNDO: command = newUndoCommand(inputs); + break; case BYE: command = newExitCommand(inputs); break; From 538cd56d6607295e7d6aee02e9c86b1c9c4e7e68 Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Tue, 12 Sep 2023 22:03:06 +0800 Subject: [PATCH 11/15] Store chatbot state in an immutable class --- src/main/java/corgi/Corgi.java | 25 +++++++------- src/main/java/corgi/State.java | 62 ++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 src/main/java/corgi/State.java diff --git a/src/main/java/corgi/Corgi.java b/src/main/java/corgi/Corgi.java index 97e5393569..ed856f4f6c 100644 --- a/src/main/java/corgi/Corgi.java +++ b/src/main/java/corgi/Corgi.java @@ -22,19 +22,18 @@ * This class initializes the chatbot and handles user input and commands. */ public class Corgi { - private TaskList tasks; - private Storage storage; - private TextRenderer renderer; - private Stack> history; + private State state; + private Stack> history; /** * Constructs new Corgi chatbot with an empty task list, * a text renderer, a storage and a history stack. */ public Corgi() { - this.renderer = new TextRenderer(); - this.storage = new Storage<>(new TaskParser(), "./data/tasks.txt"); - this.tasks = new TaskList(storage.load()); + TextRenderer newRenderer = new TextRenderer(); + Storage newStorage = new Storage<>(new TaskParser(), "./data/tasks.txt"); + TaskList newList = new TaskList(newStorage.load()); + this.state = new State(newList, newStorage, newRenderer); this.history = new Stack<>(); // if (tasks.size() > 0) { // this.renderer.showTasksLoaded(tasks.size()); @@ -42,7 +41,7 @@ public Corgi() { } public String getIntro() { - return renderer.showIntro(); + return this.state.getTextRenderer().showIntro(); } /** @@ -56,14 +55,16 @@ public String getResponse(String input) { try { cmd = new CommandParser().parse(input); assert cmd != null : "Command returned from parser cannot be null"; - return cmd.execute(this.tasks, this.renderer, this.storage, this.history); + Pair result = cmd.execute(this.state, this.history); + this.state = result.getKey(); + return result.getValue(); } catch (InvalidCommandFormatException e) { - return this.renderer.showError(e.getClass().getSimpleName(), e.getMessage()); + return this.state.getTextRenderer().showError(e.getClass().getSimpleName(), e.getMessage()); } catch (InvalidCommandTypeException e) { // Todo: Print all valid commands - return this.renderer.showError(e.getClass().getSimpleName(), e.getMessage()); + return this.state.getTextRenderer().showError(e.getClass().getSimpleName(), e.getMessage()); } catch (CommandExecutionException e) { - return this.renderer.showError(e.getClass().getSimpleName(), e.getMessage()); + return this.state.getTextRenderer().showError(e.getClass().getSimpleName(), e.getMessage()); } } } diff --git a/src/main/java/corgi/State.java b/src/main/java/corgi/State.java new file mode 100644 index 0000000000..f4e7a7ca03 --- /dev/null +++ b/src/main/java/corgi/State.java @@ -0,0 +1,62 @@ +package corgi; + +import corgi.storage.Storage; +import corgi.tasks.Task; +import corgi.tasks.TaskList; +import corgi.tasks.TaskListIndexOutOfBoundsException; +import corgi.tasks.TaskStatusException; +import corgi.ui.TextRenderer; + +public final class State { + private final TaskList tasks; + private final Storage storage; + private final TextRenderer renderer; + + public State( + TaskList tasks, Storage storage, TextRenderer renderer) { + this.tasks = tasks; + this.storage = storage; + this.renderer = renderer; + } + + public TaskList getTaskList() { + return this.tasks; + } + + public Storage getStorage() { + return this.storage; + } + + public TextRenderer getTextRenderer() { + return this.renderer; + } + + public State addTask(Task task) { + TaskList newTaskList = this.tasks.add(task); + + this.storage.save(newTaskList); + + return new State(newTaskList, storage, renderer); + } + + public State removeTask(int index) throws TaskListIndexOutOfBoundsException { + TaskList newTaskList = this.tasks.remove(index); + + this.storage.save(newTaskList); + + return new State(newTaskList, storage, renderer); + } + + public State markTask(int index, boolean status) + throws TaskListIndexOutOfBoundsException, TaskStatusException { + TaskList newTaskList = this.tasks.mark(index, status); + + this.storage.save(newTaskList); + + return new State(newTaskList, storage, renderer); + } + + public void save() { + this.storage.save(this.tasks); + } +} From 43d1cf3994b44b46dcc55599cd6928207eb95895 Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Tue, 12 Sep 2023 22:06:26 +0800 Subject: [PATCH 12/15] Convert to immutable class --- src/main/java/corgi/storage/Storage.java | 6 ++-- src/main/java/corgi/tasks/Deadline.java | 20 +++++++++-- src/main/java/corgi/tasks/Event.java | 23 ++++++++++-- src/main/java/corgi/tasks/Task.java | 28 +++++++-------- src/main/java/corgi/tasks/TaskList.java | 46 ++++++++++++++---------- src/main/java/corgi/tasks/ToDo.java | 18 +++++++++- src/main/java/corgi/ui/TextRenderer.java | 2 +- 7 files changed, 99 insertions(+), 44 deletions(-) diff --git a/src/main/java/corgi/storage/Storage.java b/src/main/java/corgi/storage/Storage.java index 0de082efdd..28bd188640 100644 --- a/src/main/java/corgi/storage/Storage.java +++ b/src/main/java/corgi/storage/Storage.java @@ -17,9 +17,9 @@ * * @param The type of object being stored and loaded. */ -public class Storage> { - private Parser parser; - private String filePath; +public final class Storage> { + private final Parser parser; + private final String filePath; /** * Constructs a Storage instance with the given parser and file path. diff --git a/src/main/java/corgi/tasks/Deadline.java b/src/main/java/corgi/tasks/Deadline.java index 04e06671a5..eb46c38c08 100644 --- a/src/main/java/corgi/tasks/Deadline.java +++ b/src/main/java/corgi/tasks/Deadline.java @@ -7,8 +7,8 @@ /** * Deadline task, a type of task that need to be done before a specific date/time. */ -public class Deadline extends Task { - private LocalDate by; +public final class Deadline extends Task { + private final LocalDate by; /** * Initializes a new deadline task with the given description and deadline. @@ -33,6 +33,22 @@ public Deadline(boolean status, String desc, LocalDate by) { this.by = by; } + @Override + public Deadline markAsDone() throws TaskStatusException{ + if (status) { + throw new TaskStatusException("The task is already marked as done."); + } + return new Deadline(true, desc, by); + } + + @Override + public Deadline markAsNotDone() throws TaskStatusException{ + if (!status) { + throw new TaskStatusException("The task is already marked as not done."); + } + return new Deadline(false, desc, by); + } + /** * Checks if the deadline task is happening on the specified target date. * diff --git a/src/main/java/corgi/tasks/Event.java b/src/main/java/corgi/tasks/Event.java index 6a63d8b5a4..d7f303a85d 100644 --- a/src/main/java/corgi/tasks/Event.java +++ b/src/main/java/corgi/tasks/Event.java @@ -7,9 +7,9 @@ /** * Event task, a type of task that start at a specific date/time and ends at a specific date/time. */ -public class Event extends Task { - private LocalDate from; - private LocalDate to; +public final class Event extends Task { + private final LocalDate from; + private final LocalDate to; /** * Initializes a new event with the given description and duration. @@ -24,6 +24,7 @@ public Event(String desc, LocalDate from, LocalDate to) { this.to = to; } + /** * Initializes a new event task with the given status, description, start date, and end date. * @@ -37,7 +38,23 @@ public Event(boolean status, String desc, LocalDate from, LocalDate to) { this.from = from; this.to = to; } + + @Override + public Event markAsDone() throws TaskStatusException{ + if (status) { + throw new TaskStatusException("The task is already marked as done."); + } + return new Event(true, desc, from, to); + } + @Override + public Event markAsNotDone() throws TaskStatusException{ + if (!status) { + throw new TaskStatusException("The task is already marked as not done."); + } + return new Event(false, desc, from, to); + } + /** * Checks if the event task is happening on the specified target date. * diff --git a/src/main/java/corgi/tasks/Task.java b/src/main/java/corgi/tasks/Task.java index 45ca365c21..57c15d214d 100644 --- a/src/main/java/corgi/tasks/Task.java +++ b/src/main/java/corgi/tasks/Task.java @@ -9,8 +9,8 @@ public abstract class Task implements Storable { public static final DateTimeFormatter DATE_INPUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); public static final DateTimeFormatter DATE_OUTPUT_FORMATTER = DateTimeFormatter.ofPattern("MMM dd yyyy"); - protected String desc; - protected boolean status; + protected final String desc; + protected final boolean status; /** * Initializes a new task with its description. The task's initial status is set to not done. @@ -24,24 +24,20 @@ public Task(boolean status, String desc) { } /** - * Mark task as done. + * Marks the task as done. + * + * @return A new Task instance with the "done" status set to true, while keeping the original task unchanged. + * @throws TaskStatusException If an error occurs while marking the task as done. */ - public void markAsDone() throws TaskStatusException { - if (this.status == true) { - throw new TaskStatusException("The task is already marked as done."); - } - this.status = true; - } + public abstract Task markAsDone() throws TaskStatusException; /** - * Mark task as not done. + * Marks the task as not done. + * + * @return A new Task instance with the "done" status set to false, while keeping the original task unchanged. + * @throws TaskStatusException If an error occurs while marking the task as not done. */ - public void markAsNotDone() throws TaskStatusException { - if (this.status == false) { - throw new TaskStatusException("The task is already marked as not done."); - } - this.status = false; - } + public abstract Task markAsNotDone() throws TaskStatusException; /** * Returns an icon representing the status of the task. diff --git a/src/main/java/corgi/tasks/TaskList.java b/src/main/java/corgi/tasks/TaskList.java index 0c897d959e..5e25610411 100644 --- a/src/main/java/corgi/tasks/TaskList.java +++ b/src/main/java/corgi/tasks/TaskList.java @@ -13,7 +13,7 @@ * This class implements the StorableList interface to provide methods for tasks storing. */ public class TaskList implements StorableList { - private List tasks; + private final List tasks; /** * Constructs an empty TaskList. @@ -28,51 +28,61 @@ public TaskList() { * @param tasks The list of tasks to initialize the TaskList. */ public TaskList(List tasks) { - this.tasks = new ArrayList<>(tasks); + this.tasks = tasks; } /** - * Adds a task to the TaskList. + * Adds a new task to the TaskList and returns a new immutable TaskList with the added task. * - * @param t The task to be added. + * @param t The task to add to the TaskList. + * @return A new TaskList containing all previous tasks and the added task. */ - public void add(Task t) { - this.tasks.add(t); + public TaskList add(Task t) { + List newList = new ArrayList<>(this.tasks); + newList.add(t); + return new TaskList(newList); } /** - * Removes a task at the specified index from the TaskList. + * Removes a task at the specified index from the TaskList and returns a new immutable TaskList + * without the removed task. * * @param index The index of the task to be removed. * @throws TaskListIndexOutOfBoundsException If the index is invalid. + * @return A new TaskList with the specified task removed. */ - public void remove(int index) throws TaskListIndexOutOfBoundsException { + public TaskList remove(int index) throws TaskListIndexOutOfBoundsException { if (!isValidIndex(index)) { throw new TaskListIndexOutOfBoundsException(index); } - this.tasks.remove(index); + List newList = new ArrayList<>(this.tasks); + newList.remove(index); + return new TaskList(newList); } /** - * Marks a task's status as done or not done. + * Marks a task's status as done or not done and returns a new immutable TaskList with the updated task. * * @param index The index of the task to be marked. * @param status The new status of the task. * @throws TaskListIndexOutOfBoundsException If the index is invalid. - * @throws TaskStatusException If task was already marked as the given status. + * @throws TaskStatusException If the task was already marked with the given status. + * @return A new TaskList with the specified task's status updated. */ - public void mark(int index, boolean status) throws TaskListIndexOutOfBoundsException, TaskStatusException { + public TaskList mark(int index, boolean status) throws TaskListIndexOutOfBoundsException, TaskStatusException { if (!isValidIndex(index)) { throw new TaskListIndexOutOfBoundsException(index); } - Task task = this.tasks.get(index); + List updatedTasks = new ArrayList<>(this.tasks); - if (status) { - task.markAsDone(); - } else { - task.markAsNotDone(); - } + Task targetTask = updatedTasks.get(index); + + Task modifiedTask = (status) ? targetTask.markAsDone() : targetTask.markAsNotDone(); + + updatedTasks.set(index, modifiedTask); + + return new TaskList(updatedTasks); } /** diff --git a/src/main/java/corgi/tasks/ToDo.java b/src/main/java/corgi/tasks/ToDo.java index 95572ac334..22c6cfc652 100644 --- a/src/main/java/corgi/tasks/ToDo.java +++ b/src/main/java/corgi/tasks/ToDo.java @@ -4,7 +4,7 @@ /** * Todo task, a type of task without any date/time attached to it. */ -public class ToDo extends Task { +public final class ToDo extends Task { /** * Initializes a new todo task with the given description. The task's initial status is set to not done. * @@ -24,6 +24,22 @@ public ToDo(boolean status, String desc) { super(status, desc); } + @Override + public ToDo markAsDone() throws TaskStatusException{ + if (status) { + throw new TaskStatusException("The task is already marked as done."); + } + return new ToDo(true, desc); + } + + @Override + public ToDo markAsNotDone() throws TaskStatusException{ + if (!status) { + throw new TaskStatusException("The task is already marked as not done."); + } + return new ToDo(false, desc); + } + /** * Converts the todo task to a storable string representation. * diff --git a/src/main/java/corgi/ui/TextRenderer.java b/src/main/java/corgi/ui/TextRenderer.java index 2eaf042861..9840906555 100644 --- a/src/main/java/corgi/ui/TextRenderer.java +++ b/src/main/java/corgi/ui/TextRenderer.java @@ -7,7 +7,7 @@ /** * The TextRenderer class is responsible to return message after each command. */ -public class TextRenderer { +public final class TextRenderer { private static final String LOGO = " ____ ___ ____ ____ ___\n" + " / ___/ _ \\| _ \\ / ___|_ _|\n" + "| | | | | | |_) | | _ | |\n" From b9f36d526c33490eaabe6af81ef8251a7d99e26d Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Tue, 12 Sep 2023 23:14:52 +0800 Subject: [PATCH 13/15] Refactor execute method to accept immutable State --- .../java/corgi/commands/AddTaskCommand.java | 28 +++++++-------- src/main/java/corgi/commands/Command.java | 16 +++------ .../corgi/commands/DeleteTaskCommand.java | 33 +++++++++-------- src/main/java/corgi/commands/ExitCommand.java | 21 ++++++----- .../FindTasksContainKeywordCommand.java | 28 +++++++-------- .../commands/FindTasksOnDateCommand.java | 26 +++++++------- .../java/corgi/commands/ListTasksCommand.java | 24 ++++++------- .../java/corgi/commands/MarkTaskCommand.java | 35 +++++++++---------- src/main/java/corgi/commands/UndoCommand.java | 27 +++++++------- 9 files changed, 112 insertions(+), 126 deletions(-) diff --git a/src/main/java/corgi/commands/AddTaskCommand.java b/src/main/java/corgi/commands/AddTaskCommand.java index 64b24fb288..5c9e856eb7 100644 --- a/src/main/java/corgi/commands/AddTaskCommand.java +++ b/src/main/java/corgi/commands/AddTaskCommand.java @@ -2,7 +2,7 @@ import java.util.Stack; -import corgi.storage.Storage; +import corgi.State; import corgi.tasks.Task; import corgi.tasks.TaskList; import corgi.ui.TextRenderer; @@ -28,7 +28,7 @@ public class AddTaskCommand extends Command { * Initializes a new AddTaskCommand instance with the specified task and command type. * * @param target The task to be added. - * @param type The type of command (CommandType.TODO, CommandType.DEADLINE, or CommandType.EVENT). + * @param type The type of command. */ public AddTaskCommand(Task target) { super(false); @@ -37,24 +37,24 @@ public AddTaskCommand(Task target) { /** * Executes the command by adding the specified task to the task list, saving the updated list to storage, - * store the stack to the history stack and return formatted message indicating that the task has been added. + * and storing the state to the history stack. * - * @param list The task list to which the task should be added. - * @param renderer The text renderer to return formatted message. - * @param storage The storage for saving and loading tasks (if applicable). + * @param currState The current state of the application. * @param history The history stack to store the states. - * @return A string message indicating the result of the command execution. + * @return A pair containing the new state and a string message indicating the result of the command execution. */ @Override - public String execute( - TaskList list, TextRenderer renderer, Storage storage, Stack> history) { - list.add(this.target); - storage.save(list); + public Pair execute(State currState, Stack> history) { + history.push(new Pair<>(currState, this)); - Pair currState = new Pair<>(this, list); - history.push(currState); + State newState = currState.addTask(this.target); - return renderer.showTaskAdded(this.taskType, target.toString(), list.size()); + TextRenderer renderer = newState.getTextRenderer(); + TaskList list = newState.getTaskList(); + + String returnMsg = renderer.showTaskAdded(this.taskType, target.toString(), list.size()); + + return new Pair<>(newState, returnMsg); } @Override diff --git a/src/main/java/corgi/commands/Command.java b/src/main/java/corgi/commands/Command.java index 0b324a36b3..245b625200 100644 --- a/src/main/java/corgi/commands/Command.java +++ b/src/main/java/corgi/commands/Command.java @@ -2,10 +2,7 @@ import java.util.Stack; -import corgi.storage.Storage; -import corgi.tasks.Task; -import corgi.tasks.TaskList; -import corgi.ui.TextRenderer; +import corgi.State; import javafx.util.Pair; /** @@ -29,17 +26,14 @@ public Command(boolean isExit) { /** * Executes the command, performing its intended action on the provided task list, - * text renderer, and storage. + * text renderer, and storage. Returns new state and string message * - * @param list The task list to perform the command action on. - * @param renderer The text renderer to return formatted message. - * @param storage The storage for saving and loading tasks (if applicable). + * @param currState The current state of the application. * @param history The history stack to store the states. + * @return A pair containing the new state and a string message indicating the result of the command execution. * @throws CommandExecutionException If an error occurs during command execution. - * @return A string message indicating the result of the command execution. */ - public abstract String execute( - TaskList list, TextRenderer renderer, Storage storage, Stack> history) + public abstract Pair execute(State currState, Stack> history) throws CommandExecutionException; /** diff --git a/src/main/java/corgi/commands/DeleteTaskCommand.java b/src/main/java/corgi/commands/DeleteTaskCommand.java index 32cf183b2d..84c7c77e79 100644 --- a/src/main/java/corgi/commands/DeleteTaskCommand.java +++ b/src/main/java/corgi/commands/DeleteTaskCommand.java @@ -2,8 +2,7 @@ import java.util.Stack; -import corgi.storage.Storage; -import corgi.tasks.Task; +import corgi.State; import corgi.tasks.TaskList; import corgi.tasks.TaskListIndexOutOfBoundsException; import corgi.ui.TextRenderer; @@ -31,30 +30,30 @@ public DeleteTaskCommand(int targetIdx) { /** * Executes the command by deleting the task at the specified index from the task list, - * saving the updated list to storage, store the state to history stack, - * and return message indicating that the task has been deleted. + * saving the updated list to storage, store the state to history stack. * - * @param list The task list from which the task should be deleted. - * @param renderer The text renderer to return formatted message. - * @param storage The storage for saving and loading tasks (if applicable). + * @param currState The current state of the application. * @param history The history stack to store the states. + * @return A pair containing the new state and a string message indicating the result of the command execution. * @throws CommandExecutionException If an error occurs during command execution. - * @return A string message indicating the result of the command execution. */ @Override - public String execute( - TaskList list, TextRenderer renderer, Storage storage, Stack> history) + public Pair execute(State currState, Stack> history) throws CommandExecutionException { try { - String targetTaskInfo = list.getTaskInfo(targetIdx); - list.remove(targetIdx); + history.push(new Pair<>(currState, this)); - storage.save(list); + TaskList currList = currState.getTaskList(); + String targetTaskInfo = currList.getTaskInfo(targetIdx); - Pair currState = new Pair<>(this, list); - history.push(currState); + State newState = currState.removeTask(targetIdx); - return renderer.showTaskDeleted(targetTaskInfo, list.size()); + TextRenderer renderer = newState.getTextRenderer(); + TaskList list = newState.getTaskList(); + + String returnMsg = renderer.showTaskDeleted(targetTaskInfo, list.size()); + + return new Pair<>(newState, returnMsg); } catch (TaskListIndexOutOfBoundsException e) { throw new CommandExecutionException("Invalid index provided!"); } @@ -62,6 +61,6 @@ public String execute( @Override public String toString() { - return "Delete task " + this.targetIdx; + return "Delete task " + (this.targetIdx + 1); } } diff --git a/src/main/java/corgi/commands/ExitCommand.java b/src/main/java/corgi/commands/ExitCommand.java index 9c798b18df..a205de7499 100644 --- a/src/main/java/corgi/commands/ExitCommand.java +++ b/src/main/java/corgi/commands/ExitCommand.java @@ -2,9 +2,7 @@ import java.util.Stack; -import corgi.storage.Storage; -import corgi.tasks.Task; -import corgi.tasks.TaskList; +import corgi.State; import corgi.ui.TextRenderer; import javafx.util.Pair; @@ -22,17 +20,18 @@ public ExitCommand() { } /** - * Executes the command by return an exit message to the user, indicating that the application is terminating. + * Executes the command by return an exit message, indicating that the application is terminating. * - * @param list The task list (not used in this command). - * @param renderer The text renderer to return formatted message. - * @param storage The storage for saving and loading tasks (not used in this command). + * @param currState The current state of the application. * @param history The history stack to store the states. - * @return A string message indicating the result of the command execution. + * @return A pair containing the new state and a string message indicating the result of the command execution. */ @Override - public String execute( - TaskList list, TextRenderer renderer, Storage storage, Stack> history) { - return renderer.showExitMsg(); + public Pair execute(State currState, Stack> history) { + TextRenderer renderer = currState.getTextRenderer(); + + String returnMsg = renderer.showExitMsg(); + + return new Pair<>(currState, returnMsg); } } diff --git a/src/main/java/corgi/commands/FindTasksContainKeywordCommand.java b/src/main/java/corgi/commands/FindTasksContainKeywordCommand.java index da35f20dfd..01558d4d60 100644 --- a/src/main/java/corgi/commands/FindTasksContainKeywordCommand.java +++ b/src/main/java/corgi/commands/FindTasksContainKeywordCommand.java @@ -3,7 +3,7 @@ import java.util.Stack; import java.util.function.Predicate; -import corgi.storage.Storage; +import corgi.State; import corgi.tasks.Task; import corgi.tasks.TaskList; import corgi.ui.TextRenderer; @@ -42,21 +42,21 @@ public FindTasksContainKeywordCommand(String target) { * It then return the filtered tasks to the user or a message indicating * that no matching tasks were found. * - * @param list The task list to filter. - * @param renderer The text renderer to return formatted message. - * @param storage The storage for saving and loading tasks (not used in this command). + * @param currState The current state of the application. * @param history The history stack to store the states. - * @return A string message indicating the result of the command execution. + * @return A pair containing the new state and a string message indicating the result of the command execution. */ @Override - public String execute( - TaskList list, TextRenderer renderer, Storage storage, Stack> history) { - TaskList tasksContainKeyword = list.filter(predicate); - - if (tasksContainKeyword.isEmpty()) { - return renderer.showKeywordNotFound(this.target); - } else { - return renderer.showTasksWithKeyword(this.target, tasksContainKeyword.toString()); - } + public Pair execute(State currState, Stack> history) { + TaskList currList = currState.getTaskList(); + TextRenderer currTextRenderer = currState.getTextRenderer(); + + TaskList tasksContainKeyword = currList.filter(predicate); + + String returnMsg = tasksContainKeyword.isEmpty() + ? currTextRenderer.showKeywordNotFound(this.target) + : currTextRenderer.showTasksWithKeyword(this.target, tasksContainKeyword.toString()); + + return new Pair<>(currState, returnMsg); } } diff --git a/src/main/java/corgi/commands/FindTasksOnDateCommand.java b/src/main/java/corgi/commands/FindTasksOnDateCommand.java index ca42b43b03..68971b8d2e 100644 --- a/src/main/java/corgi/commands/FindTasksOnDateCommand.java +++ b/src/main/java/corgi/commands/FindTasksOnDateCommand.java @@ -4,7 +4,7 @@ import java.util.Stack; import java.util.function.Predicate; -import corgi.storage.Storage; +import corgi.State; import corgi.tasks.Deadline; import corgi.tasks.Event; import corgi.tasks.Task; @@ -53,23 +53,23 @@ public FindTasksOnDateCommand(LocalDate target) { * Executes the command by filtering the task list based on the given predicate to find tasks on the specified date. * It then returns the filtered tasks to the user or a message indicating that no tasks were found on the date. * - * @param list The task list to filter. - * @param renderer The text renderer to return formatted message. - * @param storage The storage for saving and loading tasks (not used in this command). + * @param currState The current state of the application. * @param history The history stack to store the states. - * @return A string message indicating the result of the command execution. + * @return A pair containing the new state and a string message indicating the result of the command execution. */ @Override - public String execute( - TaskList list, TextRenderer renderer, Storage storage, Stack> history) { - TaskList tasksOnDate = list.filter(predicate); + public Pair execute(State currState, Stack> history) { + TaskList currList = currState.getTaskList(); + TextRenderer currTextRenderer = currState.getTextRenderer(); + + TaskList tasksOnDate = currList.filter(predicate); String outputDate = this.target.format(Task.DATE_OUTPUT_FORMATTER); - if (tasksOnDate.isEmpty()) { - return renderer.showNoTaskOnDate(outputDate); - } else { - return renderer.showTasksOnDate(outputDate, tasksOnDate.toString()); - } + String returnMsg = tasksOnDate.isEmpty() + ? currTextRenderer.showNoTaskOnDate(outputDate) + : currTextRenderer.showTasksOnDate(outputDate, tasksOnDate.toString()); + + return new Pair<>(currState, returnMsg); } } diff --git a/src/main/java/corgi/commands/ListTasksCommand.java b/src/main/java/corgi/commands/ListTasksCommand.java index ce7ec3bca6..3dabf7a7dc 100644 --- a/src/main/java/corgi/commands/ListTasksCommand.java +++ b/src/main/java/corgi/commands/ListTasksCommand.java @@ -2,8 +2,7 @@ import java.util.Stack; -import corgi.storage.Storage; -import corgi.tasks.Task; +import corgi.State; import corgi.tasks.TaskList; import corgi.ui.TextRenderer; import javafx.util.Pair; @@ -24,20 +23,19 @@ public ListTasksCommand() { * Executes the command by retrieving and displaying the list of tasks to the user. * It returns either the list of tasks or a message indicating that no tasks are in the list. * - * @param list The task list to be displayed. - * @param renderer The text renderer to return formatted message. + * @param currState The current state of the application. * @param history The history stack to store the states. - * @param storage The storage for saving and loading tasks (not used in this command). - * @return A string message indicating the result of the command execution. + * @return A pair containing the new state and a string message indicating the result of the command execution. */ @Override - public String execute( - TaskList list, TextRenderer renderer, Storage storage, Stack> history) { - if (list.isEmpty()) { - return renderer.showNoTaskFound(); - } else { - return renderer.showTaskList(list.toString()); - } + public Pair execute(State currState, Stack> history) { + TaskList currList = currState.getTaskList(); + TextRenderer currRenderer = currState.getTextRenderer(); + String returnMsg = currList.isEmpty() + ? currRenderer.showNoTaskFound() + : currRenderer.showTaskList(currList.toString()); + + return new Pair<>(currState, returnMsg); } } diff --git a/src/main/java/corgi/commands/MarkTaskCommand.java b/src/main/java/corgi/commands/MarkTaskCommand.java index 2d52bd597b..5c8c34ca34 100644 --- a/src/main/java/corgi/commands/MarkTaskCommand.java +++ b/src/main/java/corgi/commands/MarkTaskCommand.java @@ -2,8 +2,7 @@ import java.util.Stack; -import corgi.storage.Storage; -import corgi.tasks.Task; +import corgi.State; import corgi.tasks.TaskList; import corgi.tasks.TaskListIndexOutOfBoundsException; import corgi.tasks.TaskStatusException; @@ -40,29 +39,29 @@ public MarkTaskCommand(int index, boolean status) { /** * Executes the command by marking the task at the specified index with the new status, - * saving the updated list to storage, and return a message indicating the task's status change. + * saving the updated list to storage. * - * @param list The task list to be updated. - * @param renderer The text renderer to return formatted message. - * @param storage The storage for saving and loading tasks (if applicable). + * @param currState The current state of the application. + * @param history The history stack to store the states. + * @return A pair containing the new state and a string message indicating the result of the command execution. * @throws CommandExecutionException If an error occurs during command execution. */ @Override - public String execute( - TaskList list, TextRenderer renderer, Storage storage, Stack> history) + public Pair execute(State currState, Stack> history) throws CommandExecutionException { try { - list.mark(this.index, this.status); - storage.save(list); + history.push(new Pair<>(currState, this)); - Pair currState = new Pair<>(this, list); - history.push(currState); + State newState = currState.markTask(this.index, this.status); - if (status) { - return renderer.showTaskDone(list.getTaskInfo(this.index)); - } else { - return renderer.showTaskUndone(list.getTaskInfo(this.index)); - } + TextRenderer renderer = newState.getTextRenderer(); + TaskList list = newState.getTaskList(); + + String returnMsg = (status) + ? renderer.showTaskDone(list.getTaskInfo(this.index)) + : renderer.showTaskUndone(list.getTaskInfo(this.index)); + + return new Pair<>(newState, returnMsg); } catch (TaskListIndexOutOfBoundsException e) { throw new CommandExecutionException("Invalid index provided!"); } catch (TaskStatusException e) { @@ -73,6 +72,6 @@ public String execute( @Override public String toString() { String action = this.status ? "Mark" : "Unmark"; - return action + " task " + this.index; + return action + " task " + (this.index + 1); } } diff --git a/src/main/java/corgi/commands/UndoCommand.java b/src/main/java/corgi/commands/UndoCommand.java index 67e6cff68d..1ee3d90744 100644 --- a/src/main/java/corgi/commands/UndoCommand.java +++ b/src/main/java/corgi/commands/UndoCommand.java @@ -2,9 +2,7 @@ import java.util.Stack; -import corgi.storage.Storage; -import corgi.tasks.Task; -import corgi.tasks.TaskList; +import corgi.State; import corgi.ui.TextRenderer; import javafx.util.Pair; @@ -20,28 +18,27 @@ public UndoCommand() { * Executes the command by reverting the previous action based on the provided * history stack and updating the task list accordingly. * - * @param list The task list. - * @param renderer The text renderer to return formatted message. - * @param storage The storage for saving and loading tasks. + * @param currState The current state of the application. * @param history The history stack to store the states. - * @return A string message indicating the result of the command execution. + * @return A pair containing the new state and a string message indicating the result of the command execution. */ @Override - public String execute( - TaskList list, TextRenderer renderer, Storage storage, Stack> history) + public Pair execute(State currState, Stack> history) throws CommandExecutionException { if (history.isEmpty()) { throw new CommandExecutionException("Nothing to undo!"); } - Pair prevState = history.pop(); - Command prevCommand = prevState.getKey(); - TaskList prevTaskList = prevState.getValue(); + Pair previous = history.pop(); + State prevState = previous.getKey(); + Command prevCommand = previous.getValue(); - list = prevTaskList; + prevState.save(); - storage.save(list); + TextRenderer renderer = prevState.getTextRenderer(); - return renderer.showUndoSucceed(prevCommand.toString()); + String returnMsg = renderer.showUndoSucceed(prevCommand.toString()); + + return new Pair<>(prevState, returnMsg); } } From 44ed2182d50767256e05c0c423dd7a2e6ab18f78 Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Wed, 13 Sep 2023 00:12:53 +0800 Subject: [PATCH 14/15] Add JavaDoc comment --- src/main/java/corgi/State.java | 50 ++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/main/java/corgi/State.java b/src/main/java/corgi/State.java index f4e7a7ca03..11d4a0b51a 100644 --- a/src/main/java/corgi/State.java +++ b/src/main/java/corgi/State.java @@ -7,11 +7,21 @@ import corgi.tasks.TaskStatusException; import corgi.ui.TextRenderer; +/** + * An immutable State class to store the state of the chatbot. + */ public final class State { private final TaskList tasks; private final Storage storage; private final TextRenderer renderer; + /** + * Construct new state object with given task list, storage and text renderer. + * + * @param tasks The given task list. + * @param storage The given storage. + * @param renderer The given text renderer. + */ public State( TaskList tasks, Storage storage, TextRenderer renderer) { this.tasks = tasks; @@ -19,18 +29,39 @@ public State( this.renderer = renderer; } + /** + * Getter for task list. + * + * @return The task list. + */ public TaskList getTaskList() { return this.tasks; } + /** + * Getter for storage. + * + * @return The storage. + */ public Storage getStorage() { return this.storage; } + /** + * Getter for text renderer. + * + * @return The text renderer. + */ public TextRenderer getTextRenderer() { return this.renderer; } + /** + * Add target task to the task list. + * + * @param task The target task. + * @return New state with the updated task list. + */ public State addTask(Task task) { TaskList newTaskList = this.tasks.add(task); @@ -39,6 +70,13 @@ public State addTask(Task task) { return new State(newTaskList, storage, renderer); } + /** + * Remove task at the target index in the task list. + * + * @param index The target index. + * @return New state with the updated task list. + * @throws TaskListIndexOutOfBoundsException + */ public State removeTask(int index) throws TaskListIndexOutOfBoundsException { TaskList newTaskList = this.tasks.remove(index); @@ -47,6 +85,15 @@ public State removeTask(int index) throws TaskListIndexOutOfBoundsException { return new State(newTaskList, storage, renderer); } + /** + * Mark task at the target index to a given status. + * + * @param index The target index. + * @param status The expected status. + * @return New state with the updated task list. + * @throws TaskListIndexOutOfBoundsException + * @throws TaskStatusException + */ public State markTask(int index, boolean status) throws TaskListIndexOutOfBoundsException, TaskStatusException { TaskList newTaskList = this.tasks.mark(index, status); @@ -56,6 +103,9 @@ public State markTask(int index, boolean status) return new State(newTaskList, storage, renderer); } + /** + * Store the current task list to local. + */ public void save() { this.storage.save(this.tasks); } From 8dff373ce7edfd404b66e7efc1f67dc2ee3e63d7 Mon Sep 17 00:00:00 2001 From: Nereus Ng Wei Bin Date: Wed, 13 Sep 2023 00:23:04 +0800 Subject: [PATCH 15/15] Fix checkstyle error --- src/main/java/corgi/Corgi.java | 2 +- src/main/java/corgi/State.java | 16 ++++++++-------- src/main/java/corgi/commands/Command.java | 2 +- .../corgi/commands/FindTasksOnDateCommand.java | 4 ++-- .../java/corgi/commands/MarkTaskCommand.java | 2 +- src/main/java/corgi/commands/UndoCommand.java | 9 ++++++--- src/main/java/corgi/tasks/Deadline.java | 4 ++-- src/main/java/corgi/tasks/Event.java | 10 +++++----- src/main/java/corgi/tasks/TaskList.java | 4 ++-- src/main/java/corgi/tasks/ToDo.java | 4 ++-- 10 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/main/java/corgi/Corgi.java b/src/main/java/corgi/Corgi.java index ed856f4f6c..79a4ca852b 100644 --- a/src/main/java/corgi/Corgi.java +++ b/src/main/java/corgi/Corgi.java @@ -26,7 +26,7 @@ public class Corgi { private Stack> history; /** - * Constructs new Corgi chatbot with an empty task list, + * Constructs new Corgi chatbot with an empty task list, * a text renderer, a storage and a history stack. */ public Corgi() { diff --git a/src/main/java/corgi/State.java b/src/main/java/corgi/State.java index 11d4a0b51a..cbc0f72250 100644 --- a/src/main/java/corgi/State.java +++ b/src/main/java/corgi/State.java @@ -17,7 +17,7 @@ public final class State { /** * Construct new state object with given task list, storage and text renderer. - * + * * @param tasks The given task list. * @param storage The given storage. * @param renderer The given text renderer. @@ -31,7 +31,7 @@ public State( /** * Getter for task list. - * + * * @return The task list. */ public TaskList getTaskList() { @@ -40,7 +40,7 @@ public TaskList getTaskList() { /** * Getter for storage. - * + * * @return The storage. */ public Storage getStorage() { @@ -49,7 +49,7 @@ public Storage getStorage() { /** * Getter for text renderer. - * + * * @return The text renderer. */ public TextRenderer getTextRenderer() { @@ -58,7 +58,7 @@ public TextRenderer getTextRenderer() { /** * Add target task to the task list. - * + * * @param task The target task. * @return New state with the updated task list. */ @@ -72,7 +72,7 @@ public State addTask(Task task) { /** * Remove task at the target index in the task list. - * + * * @param index The target index. * @return New state with the updated task list. * @throws TaskListIndexOutOfBoundsException @@ -87,14 +87,14 @@ public State removeTask(int index) throws TaskListIndexOutOfBoundsException { /** * Mark task at the target index to a given status. - * + * * @param index The target index. * @param status The expected status. * @return New state with the updated task list. * @throws TaskListIndexOutOfBoundsException * @throws TaskStatusException */ - public State markTask(int index, boolean status) + public State markTask(int index, boolean status) throws TaskListIndexOutOfBoundsException, TaskStatusException { TaskList newTaskList = this.tasks.mark(index, status); diff --git a/src/main/java/corgi/commands/Command.java b/src/main/java/corgi/commands/Command.java index 245b625200..2a71c7f193 100644 --- a/src/main/java/corgi/commands/Command.java +++ b/src/main/java/corgi/commands/Command.java @@ -26,7 +26,7 @@ public Command(boolean isExit) { /** * Executes the command, performing its intended action on the provided task list, - * text renderer, and storage. Returns new state and string message + * text renderer, and storage. Returns new state and string message * * @param currState The current state of the application. * @param history The history stack to store the states. diff --git a/src/main/java/corgi/commands/FindTasksOnDateCommand.java b/src/main/java/corgi/commands/FindTasksOnDateCommand.java index 68971b8d2e..61aa3ea076 100644 --- a/src/main/java/corgi/commands/FindTasksOnDateCommand.java +++ b/src/main/java/corgi/commands/FindTasksOnDateCommand.java @@ -66,10 +66,10 @@ public Pair execute(State currState, Stack> String outputDate = this.target.format(Task.DATE_OUTPUT_FORMATTER); - String returnMsg = tasksOnDate.isEmpty() + String returnMsg = tasksOnDate.isEmpty() ? currTextRenderer.showNoTaskOnDate(outputDate) : currTextRenderer.showTasksOnDate(outputDate, tasksOnDate.toString()); - + return new Pair<>(currState, returnMsg); } } diff --git a/src/main/java/corgi/commands/MarkTaskCommand.java b/src/main/java/corgi/commands/MarkTaskCommand.java index 5c8c34ca34..4620355422 100644 --- a/src/main/java/corgi/commands/MarkTaskCommand.java +++ b/src/main/java/corgi/commands/MarkTaskCommand.java @@ -60,7 +60,7 @@ public Pair execute(State currState, Stack> String returnMsg = (status) ? renderer.showTaskDone(list.getTaskInfo(this.index)) : renderer.showTaskUndone(list.getTaskInfo(this.index)); - + return new Pair<>(newState, returnMsg); } catch (TaskListIndexOutOfBoundsException e) { throw new CommandExecutionException("Invalid index provided!"); diff --git a/src/main/java/corgi/commands/UndoCommand.java b/src/main/java/corgi/commands/UndoCommand.java index 1ee3d90744..0d53abf6d8 100644 --- a/src/main/java/corgi/commands/UndoCommand.java +++ b/src/main/java/corgi/commands/UndoCommand.java @@ -6,6 +6,9 @@ import corgi.ui.TextRenderer; import javafx.util.Pair; +/** + * Represents a command to undo previous command action. + */ public class UndoCommand extends Command { /** * Initializes a new UndoCommand instance. @@ -15,7 +18,7 @@ public UndoCommand() { } /** - * Executes the command by reverting the previous action based on the provided + * Executes the command by reverting the previous action based on the provided * history stack and updating the task list accordingly. * * @param currState The current state of the application. @@ -23,8 +26,8 @@ public UndoCommand() { * @return A pair containing the new state and a string message indicating the result of the command execution. */ @Override - public Pair execute(State currState, Stack> history) - throws CommandExecutionException { + public Pair execute(State currState, Stack> history) + throws CommandExecutionException { if (history.isEmpty()) { throw new CommandExecutionException("Nothing to undo!"); } diff --git a/src/main/java/corgi/tasks/Deadline.java b/src/main/java/corgi/tasks/Deadline.java index eb46c38c08..9704292c93 100644 --- a/src/main/java/corgi/tasks/Deadline.java +++ b/src/main/java/corgi/tasks/Deadline.java @@ -34,7 +34,7 @@ public Deadline(boolean status, String desc, LocalDate by) { } @Override - public Deadline markAsDone() throws TaskStatusException{ + public Deadline markAsDone() throws TaskStatusException { if (status) { throw new TaskStatusException("The task is already marked as done."); } @@ -42,7 +42,7 @@ public Deadline markAsDone() throws TaskStatusException{ } @Override - public Deadline markAsNotDone() throws TaskStatusException{ + public Deadline markAsNotDone() throws TaskStatusException { if (!status) { throw new TaskStatusException("The task is already marked as not done."); } diff --git a/src/main/java/corgi/tasks/Event.java b/src/main/java/corgi/tasks/Event.java index d7f303a85d..28b44eaae0 100644 --- a/src/main/java/corgi/tasks/Event.java +++ b/src/main/java/corgi/tasks/Event.java @@ -24,7 +24,7 @@ public Event(String desc, LocalDate from, LocalDate to) { this.to = to; } - + /** * Initializes a new event task with the given status, description, start date, and end date. * @@ -38,9 +38,9 @@ public Event(boolean status, String desc, LocalDate from, LocalDate to) { this.from = from; this.to = to; } - + @Override - public Event markAsDone() throws TaskStatusException{ + public Event markAsDone() throws TaskStatusException { if (status) { throw new TaskStatusException("The task is already marked as done."); } @@ -48,13 +48,13 @@ public Event markAsDone() throws TaskStatusException{ } @Override - public Event markAsNotDone() throws TaskStatusException{ + public Event markAsNotDone() throws TaskStatusException { if (!status) { throw new TaskStatusException("The task is already marked as not done."); } return new Event(false, desc, from, to); } - + /** * Checks if the event task is happening on the specified target date. * diff --git a/src/main/java/corgi/tasks/TaskList.java b/src/main/java/corgi/tasks/TaskList.java index 5e25610411..802c278eec 100644 --- a/src/main/java/corgi/tasks/TaskList.java +++ b/src/main/java/corgi/tasks/TaskList.java @@ -48,8 +48,8 @@ public TaskList add(Task t) { * without the removed task. * * @param index The index of the task to be removed. - * @throws TaskListIndexOutOfBoundsException If the index is invalid. * @return A new TaskList with the specified task removed. + * @throws TaskListIndexOutOfBoundsException If the index is invalid. */ public TaskList remove(int index) throws TaskListIndexOutOfBoundsException { if (!isValidIndex(index)) { @@ -65,9 +65,9 @@ public TaskList remove(int index) throws TaskListIndexOutOfBoundsException { * * @param index The index of the task to be marked. * @param status The new status of the task. + * @return A new TaskList with the specified task's status updated. * @throws TaskListIndexOutOfBoundsException If the index is invalid. * @throws TaskStatusException If the task was already marked with the given status. - * @return A new TaskList with the specified task's status updated. */ public TaskList mark(int index, boolean status) throws TaskListIndexOutOfBoundsException, TaskStatusException { if (!isValidIndex(index)) { diff --git a/src/main/java/corgi/tasks/ToDo.java b/src/main/java/corgi/tasks/ToDo.java index 22c6cfc652..80c23ed367 100644 --- a/src/main/java/corgi/tasks/ToDo.java +++ b/src/main/java/corgi/tasks/ToDo.java @@ -25,7 +25,7 @@ public ToDo(boolean status, String desc) { } @Override - public ToDo markAsDone() throws TaskStatusException{ + public ToDo markAsDone() throws TaskStatusException { if (status) { throw new TaskStatusException("The task is already marked as done."); } @@ -33,7 +33,7 @@ public ToDo markAsDone() throws TaskStatusException{ } @Override - public ToDo markAsNotDone() throws TaskStatusException{ + public ToDo markAsNotDone() throws TaskStatusException { if (!status) { throw new TaskStatusException("The task is already marked as not done."); }