tasks = new ArrayList<>();
+ File f = new File(DEFAULT_FILE_PATH);
+ if (!f.exists()) {
+ return tasks; // no file => no tasks
+ }
+
+ try (Scanner s = new Scanner(f)) {
+ while (s.hasNextLine()) {
+ String line = s.nextLine().trim();
+ Task t = TaskParser.parseLineToTask(line);
+ if (t != null) {
+ tasks.add(t);
+ }
+ }
+ }
+
+ return tasks;
+ }
+
+
+}
diff --git a/src/main/java/thoth/TaskManager.java b/src/main/java/thoth/TaskManager.java
new file mode 100644
index 000000000..364d75ed9
--- /dev/null
+++ b/src/main/java/thoth/TaskManager.java
@@ -0,0 +1,81 @@
+/**
+ * Manages a list of tasks.
+ *
+ * This class provides methods to add tasks, mark them as done or not done, remove tasks,
+ * and retrieve tasks or the task count.
+ */
+package thoth;
+
+import thoth.tasks.Task;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TaskManager {
+
+ private final List taskList = new ArrayList<>();
+
+ /**
+ * Add a new task to the task list.
+ *
+ * @param task is the task to be added
+ */
+ public void addTask(Task task) {
+ taskList.add(task);
+ }
+
+ /**
+ * Marks the task at the specific task index as done
+ *
+ * @param taskId the index of th task that needs to be mark as done
+ */
+ public void markTaskAsDone(int taskId) {
+ taskList.get(taskId).markAsDone();
+ }
+
+ /**
+ * Marks the task at the specific task index as not done
+ *
+ * @param taskId the index of th task that needs to be mark as not done
+ */
+ public void markTaskAsNotDone(int taskId) {
+ taskList.get(taskId).markAsNotDone();
+ }
+
+ /**
+ * Return the number of tasks in the task list
+ *
+ * @return the size of the task list
+ */
+ public int getTaskCount() {
+ return taskList.size();
+ }
+
+ /**
+ * Return the complete list of tasks
+ *
+ * @return the list of tasks
+ */
+ public List getTaskList() {
+ return taskList;
+ }
+
+ /**
+ * Remove the task at the specific task index
+ *
+ * @param taskId the index of tht task to be removed
+ */
+ public void removeTask(int taskId) {
+ taskList.remove(taskId);
+ }
+
+ /**
+ * Return a sublist of tasks from the specified index to the end of the list
+ *
+ * @param taskId the tarting index for the sublist
+ * @return a list of tasks starting from the specified index
+ */
+ public List getTask(int taskId) {
+ return taskList.subList(taskId, taskList.size());
+ }
+}
diff --git a/src/main/java/thoth/Thoth.java b/src/main/java/thoth/Thoth.java
new file mode 100644
index 000000000..e203b2fee
--- /dev/null
+++ b/src/main/java/thoth/Thoth.java
@@ -0,0 +1,56 @@
+package thoth;
+
+import thoth.command.Command;
+import thoth.exceptions.TaskParsingException;
+import thoth.exceptions.ThothException;
+import thoth.parser.Parser;
+import thoth.tasks.Task;
+
+import java.io.IOException;
+import java.util.List;
+
+public class Thoth {
+
+ public static void main(String[] args) {
+ // Create The task Manager and the User interface
+ TaskManager taskManager = new TaskManager();
+ UserInterface ui = new UserInterface();
+
+ // Print Greeting.
+ ui.printGreetingMessage();
+
+ // String for user input
+ String userInput;
+
+ try {
+ Storage.createFile();
+ List loadedTasks = Storage.loadTasks();
+ // Put those tasks into the TaskManager
+ for (Task t : loadedTasks) {
+ taskManager.addTask(t);
+ }
+ } catch (TaskParsingException | IOException e) {
+ System.err.println("Could not load tasks: " + e.getMessage());
+ }
+
+
+ // Create an endless loop for adding list
+ while (true) {
+
+ try {
+ userInput = ui.readInput();
+ // extracts out the command from the user input
+ Command command = Parser.parse(userInput);
+ // Executes the command parsed out
+ command.execute(taskManager, ui);
+
+ if (command.isExit()) {
+ break;
+ }
+ } catch (ThothException e) {
+ ui.showError(e.getMessage());
+ }
+
+ }
+ }
+}
diff --git a/src/main/java/thoth/UserInterface.java b/src/main/java/thoth/UserInterface.java
new file mode 100644
index 000000000..c621d32a2
--- /dev/null
+++ b/src/main/java/thoth/UserInterface.java
@@ -0,0 +1,118 @@
+package thoth;
+
+import thoth.tasks.Task;
+
+import java.util.List;
+import java.util.Scanner;
+
+public class UserInterface {
+ public static final String INDENT = "%4s";
+ private final Scanner scanner;
+
+ /**
+ * Constructs a new UserInterface and initializes the input scanner.
+ */
+ public UserInterface() {
+ scanner = new Scanner(System.in);
+ }
+
+ /**
+ * Prints the specified message to the console.
+ *
+ * @param message the message to be printed.
+ */
+ public static void printMessage(String message) {
+ System.out.println(message);
+ }
+
+ /**
+ * Prints a message indicating that a task has been marked as done.
+ *
+ * @param task the task that has been marked as done.
+ */
+ public static void printMarkAsDone(Task task) {
+ System.out.printf(INDENT + "Nice! I've marked this task as done:%n", "");
+ System.out.printf(INDENT + "%s\n", "", task.getTaskString());
+ }
+
+ /**
+ * Prints a message indicating that a task has been marked as not done.
+ *
+ * @param task the task that has been marked as not done.
+ */
+ public static void printMarkAsUndone(Task task) {
+ System.out.printf(INDENT + "OK, I've marked this task as not done yet:%n", "");
+ System.out.printf(INDENT + "%s\n", "", task.getTaskString());
+ }
+
+ /**
+ * Prints the list of tasks to the console.
+ *
+ * @param task the list of tasks to be printed.
+ * @param taskCount the number of tasks to print.
+ */
+ public static void printTask(List task, int taskCount) {
+ int listIndex = 1;
+ for (int i = 0; i < taskCount; i++) {
+ System.out.printf(INDENT + "%d. %s%n", "", listIndex, task.get(i).getTaskString());
+ listIndex++;
+ }
+ }
+
+ /**
+ * Prints a message indicating that a task has been added.
+ *
+ * @param task the task that has been added.
+ * @param taskCount the total number of tasks after the addition.
+ */
+ public static void printAddedTask(Task task, int taskCount) {
+ System.out.printf(INDENT + "Got it. I've added this task:\n", "");
+ System.out.printf(INDENT + "%s\n", "", task.getTaskString());
+ System.out.printf(INDENT + "Now you have %d tasks in the list.%n", "", taskCount);
+ }
+
+ /**
+ * Prints a message indicating that a task has been deleted.
+ *
+ * @param task the list of tasks from which the deleted task is assumed to be the first element.
+ * @param taskCount the total number of tasks remaining after deletion.
+ */
+ public static void printDeleteTask(List task, int taskCount) {
+ System.out.printf(INDENT + "Noted. I've removed this task:\n", "");
+ System.out.printf(INDENT + "%s\n", "", task.get(0).getTaskString());
+ System.out.printf(INDENT + "Now you have %d tasks in the list.%n", "", taskCount);
+ }
+
+ /**
+ * Reads a line of input from the user.
+ *
+ * @return the input string entered by the user.
+ */
+ public String readInput() {
+ return scanner.nextLine();
+ }
+
+ /**
+ * Prints the greeting message to the console.
+ */
+ public void printGreetingMessage() {
+ System.out.println("Hello! I'm Thoth");
+ System.out.println("What can I do for you?");
+ }
+
+ /**
+ * Prints a goodbye message to the console.
+ */
+ public void printGoodbye() {
+ System.out.println("Bye. Hope to see you again soon!");
+ }
+
+ /**
+ * Prints the error message to the console.
+ *
+ * @param message the error message to be printed.
+ */
+ public void showError(String message) {
+ System.out.println(message);
+ }
+}
diff --git a/src/main/java/thoth/command/Command.java b/src/main/java/thoth/command/Command.java
new file mode 100644
index 000000000..a9b06c8f8
--- /dev/null
+++ b/src/main/java/thoth/command/Command.java
@@ -0,0 +1,12 @@
+package thoth.command;
+
+import thoth.TaskManager;
+import thoth.UserInterface;
+
+public abstract class Command {
+ public abstract void execute(TaskManager taskManager, UserInterface ui);
+
+ public boolean isExit() {
+ return false;
+ }
+}
diff --git a/src/main/java/thoth/command/DeadlineCommand.java b/src/main/java/thoth/command/DeadlineCommand.java
new file mode 100644
index 000000000..bf727af8c
--- /dev/null
+++ b/src/main/java/thoth/command/DeadlineCommand.java
@@ -0,0 +1,31 @@
+package thoth.command;
+
+import thoth.TaskManager;
+import thoth.Storage;
+import thoth.tasks.Deadline;
+import thoth.tasks.Task;
+import thoth.UserInterface;
+
+import java.io.IOException;
+
+public class DeadlineCommand extends Command {
+ String description;
+ String by;
+
+ public DeadlineCommand(String description, String by) {
+ this.description = description;
+ this.by = by;
+ }
+
+ @Override
+ public void execute(TaskManager taskManager, UserInterface ui) {
+ Task newTask = new Deadline(description, by);
+ taskManager.addTask(newTask);
+ try {
+ Storage.writeFile(newTask.getTaskString());
+ } catch (IOException e) {
+ UserInterface.printMessage("Error writing to file: " + e.getMessage());
+ }
+ UserInterface.printAddedTask(newTask, taskManager.getTaskCount());
+ }
+}
diff --git a/src/main/java/thoth/command/DeleteCommand.java b/src/main/java/thoth/command/DeleteCommand.java
new file mode 100644
index 000000000..b6fdde123
--- /dev/null
+++ b/src/main/java/thoth/command/DeleteCommand.java
@@ -0,0 +1,30 @@
+package thoth.command;
+
+import thoth.TaskManager;
+import thoth.Storage;
+import thoth.UserInterface;
+import thoth.exceptions.ThothException;
+
+import java.io.IOException;
+
+public class DeleteCommand extends Command {
+ int taskIndex;
+
+ public DeleteCommand(int taskIndex) {
+ this.taskIndex = taskIndex;
+ }
+
+ @Override
+ public void execute(TaskManager taskManager, UserInterface ui) {
+ if (taskIndex < 0 || taskIndex >= taskManager.getTaskList().size()) {
+ throw new ThothException("Task index out of range");
+ }
+ UserInterface.printDeleteTask(taskManager.getTask(taskIndex), taskManager.getTaskCount() - 1);
+ taskManager.removeTask(taskIndex);
+ try {
+ Storage.saveTasks(taskManager.getTaskList());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/thoth/command/EventCommand.java b/src/main/java/thoth/command/EventCommand.java
new file mode 100644
index 000000000..7a6960b43
--- /dev/null
+++ b/src/main/java/thoth/command/EventCommand.java
@@ -0,0 +1,33 @@
+package thoth.command;
+
+import thoth.TaskManager;
+import thoth.Storage;
+import thoth.tasks.Event;
+import thoth.tasks.Task;
+import thoth.UserInterface;
+
+import java.io.IOException;
+
+public class EventCommand extends Command {
+ String description;
+ String from;
+ String to;
+
+ public EventCommand(String description, String from, String to) {
+ this.description = description;
+ this.from = from;
+ this.to = to;
+ }
+
+ @Override
+ public void execute(TaskManager taskManager, UserInterface ui) {
+ Task newTask = new Event(description, from, to);
+ taskManager.addTask(newTask);
+ try {
+ Storage.writeFile(newTask.getTaskString());
+ } catch (IOException e) {
+ UserInterface.printMessage("Error writing to file: " + e.getMessage());
+ }
+ UserInterface.printAddedTask(newTask, taskManager.getTaskCount());
+ }
+}
diff --git a/src/main/java/thoth/command/ExitCommand.java b/src/main/java/thoth/command/ExitCommand.java
new file mode 100644
index 000000000..d9d98b463
--- /dev/null
+++ b/src/main/java/thoth/command/ExitCommand.java
@@ -0,0 +1,17 @@
+package thoth.command;
+
+import thoth.TaskManager;
+import thoth.UserInterface;
+
+public class ExitCommand extends Command {
+
+ @Override
+ public void execute(TaskManager taskManager, UserInterface ui) {
+ ui.printGoodbye();
+ }
+
+ @Override
+ public boolean isExit() {
+ return true;
+ }
+}
diff --git a/src/main/java/thoth/command/FindCommand.java b/src/main/java/thoth/command/FindCommand.java
new file mode 100644
index 000000000..404047466
--- /dev/null
+++ b/src/main/java/thoth/command/FindCommand.java
@@ -0,0 +1,46 @@
+package thoth.command;
+
+import thoth.TaskManager;
+import thoth.UserInterface;
+import thoth.tasks.Task; // Assuming tasks are represented by a Task class
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FindCommand extends Command {
+ String keyWord;
+
+ public FindCommand(String keyWord) {
+ this.keyWord = keyWord;
+ }
+
+ @Override
+ public void execute(TaskManager taskManager, UserInterface ui) {
+ if (keyWord.trim().isEmpty()) {
+ UserInterface.printMessage("Keyword cannot be empty. Please enter a valid keyword.");
+ return;
+ }
+
+ List matchedTasks = new ArrayList<>();
+
+ // Retrieve the list of tasks from TaskManager
+ List tasks = taskManager.getTaskList();
+
+ // Search for tasks that contain the keyword (case-insensitive)
+ for (Task task : tasks) {
+ if (task.getTaskString().toLowerCase().contains(keyWord.toLowerCase())) {
+ matchedTasks.add(task);
+ }
+ }
+
+ // Display the matching tasks or an appropriate message if none are found
+ if (matchedTasks.isEmpty()) {
+ UserInterface.printMessage("No matching tasks found for keyword: " + keyWord);
+ } else {
+ UserInterface.printMessage("Here are the matching tasks:");
+ for (int i = 0; i < matchedTasks.size(); i++) {
+ UserInterface.printMessage((i + 1) + ". " + matchedTasks.get(i).getTaskString());
+ }
+ }
+ }
+}
diff --git a/src/main/java/thoth/command/ListCommand.java b/src/main/java/thoth/command/ListCommand.java
new file mode 100644
index 000000000..bcb685ddd
--- /dev/null
+++ b/src/main/java/thoth/command/ListCommand.java
@@ -0,0 +1,12 @@
+package thoth.command;
+
+import thoth.TaskManager;
+import thoth.UserInterface;
+
+public class ListCommand extends Command {
+
+ @Override
+ public void execute(TaskManager taskManager, UserInterface ui) {
+ UserInterface.printTask(taskManager.getTaskList(), taskManager.getTaskCount());
+ }
+}
diff --git a/src/main/java/thoth/command/MarkCommand.java b/src/main/java/thoth/command/MarkCommand.java
new file mode 100644
index 000000000..f5eb3f453
--- /dev/null
+++ b/src/main/java/thoth/command/MarkCommand.java
@@ -0,0 +1,32 @@
+package thoth.command;
+
+import thoth.TaskManager;
+import thoth.Storage;
+import thoth.exceptions.ThothException;
+import thoth.tasks.Task;
+import thoth.UserInterface;
+
+import java.io.IOException;
+
+public class MarkCommand extends Command {
+ int taskIndex;
+
+ public MarkCommand(int taskIndex) {
+ this.taskIndex = taskIndex;
+ }
+
+ @Override
+ public void execute(TaskManager taskManager, UserInterface ui) {
+ if (taskIndex < 0 || taskIndex >= taskManager.getTaskList().size()) {
+ throw new ThothException("Task index out of range");
+ }
+ taskManager.markTaskAsDone(taskIndex);
+ Task updatedTask = taskManager.getTaskList().get(taskIndex);
+ UserInterface.printMarkAsDone(updatedTask);
+ try {
+ Storage.saveTasks(taskManager.getTaskList());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/thoth/command/TodoCommand.java b/src/main/java/thoth/command/TodoCommand.java
new file mode 100644
index 000000000..689526e47
--- /dev/null
+++ b/src/main/java/thoth/command/TodoCommand.java
@@ -0,0 +1,29 @@
+package thoth.command;
+
+import thoth.TaskManager;
+import thoth.Storage;
+import thoth.tasks.Task;
+import thoth.tasks.Todo;
+import thoth.UserInterface;
+
+import java.io.IOException;
+
+public class TodoCommand extends Command {
+ String description;
+
+ public TodoCommand(String description) {
+ this.description = description;
+ }
+
+ @Override
+ public void execute(TaskManager taskManager, UserInterface ui) {
+ Task newTask = new Todo(description);
+ taskManager.addTask(newTask);
+ try {
+ Storage.writeFile(newTask.getTaskString());
+ } catch (IOException e) {
+ UserInterface.printMessage("Error writing to file: " + e.getMessage());
+ }
+ UserInterface.printAddedTask(newTask, taskManager.getTaskCount());
+ }
+}
diff --git a/src/main/java/thoth/command/UnknownCommand.java b/src/main/java/thoth/command/UnknownCommand.java
new file mode 100644
index 000000000..97a42e0c3
--- /dev/null
+++ b/src/main/java/thoth/command/UnknownCommand.java
@@ -0,0 +1,17 @@
+package thoth.command;
+
+import thoth.TaskManager;
+import thoth.UserInterface;
+
+public class UnknownCommand extends Command {
+ String message;
+
+ public UnknownCommand(String message) {
+ this.message = message;
+ }
+
+ @Override
+ public void execute(TaskManager taskManager, UserInterface ui) {
+ UserInterface.printMessage(message);
+ }
+}
diff --git a/src/main/java/thoth/command/UnmarkCommand.java b/src/main/java/thoth/command/UnmarkCommand.java
new file mode 100644
index 000000000..0ef73cfde
--- /dev/null
+++ b/src/main/java/thoth/command/UnmarkCommand.java
@@ -0,0 +1,33 @@
+package thoth.command;
+
+import thoth.TaskManager;
+import thoth.Storage;
+import thoth.exceptions.ThothException;
+import thoth.tasks.Task;
+import thoth.UserInterface;
+
+import java.io.IOException;
+
+public class UnmarkCommand extends Command {
+ int taskIndex;
+
+ public UnmarkCommand(int taskIndex) {
+ this.taskIndex = taskIndex;
+ }
+
+ @Override
+ public void execute(TaskManager taskManager, UserInterface ui) {
+ if (taskIndex < 0 || taskIndex >= taskManager.getTaskList().size()) {
+ throw new ThothException("Task index out of range");
+ }
+
+ taskManager.markTaskAsNotDone(taskIndex);
+ Task updatedTask = taskManager.getTaskList().get(taskIndex);
+ UserInterface.printMarkAsUndone(updatedTask);
+ try {
+ Storage.saveTasks(taskManager.getTaskList());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/thoth/exceptions/TaskParsingException.java b/src/main/java/thoth/exceptions/TaskParsingException.java
new file mode 100644
index 000000000..29e3d71ad
--- /dev/null
+++ b/src/main/java/thoth/exceptions/TaskParsingException.java
@@ -0,0 +1,7 @@
+package thoth.exceptions;
+
+public class TaskParsingException extends RuntimeException {
+ public TaskParsingException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/thoth/exceptions/ThothException.java b/src/main/java/thoth/exceptions/ThothException.java
new file mode 100644
index 000000000..af78231ec
--- /dev/null
+++ b/src/main/java/thoth/exceptions/ThothException.java
@@ -0,0 +1,7 @@
+package thoth.exceptions;
+
+public class ThothException extends RuntimeException {
+ public ThothException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/thoth/parser/Parser.java b/src/main/java/thoth/parser/Parser.java
new file mode 100644
index 000000000..a2cbcd3a8
--- /dev/null
+++ b/src/main/java/thoth/parser/Parser.java
@@ -0,0 +1,181 @@
+/**
+ * Provides functionality to parse user input into executable commands.
+ */
+package thoth.parser;
+
+import thoth.command.Command;
+import thoth.command.DeadlineCommand;
+import thoth.command.EventCommand;
+import thoth.command.MarkCommand;
+import thoth.command.UnmarkCommand;
+import thoth.command.ExitCommand;
+import thoth.command.FindCommand;
+import thoth.command.ListCommand;
+import thoth.command.TodoCommand;
+import thoth.command.DeleteCommand;
+
+import thoth.exceptions.ThothException;
+
+public class Parser {
+
+ private static final int INDEX_OFFSET = 1;
+
+ /**
+ * Parses the user input into the corresponding executable command.
+ *
+ * @param userInput the input string provided by the user.
+ * @return the Command object corresponding to the user input.
+ */
+ public static Command parse(String userInput) throws ThothException {
+ String commandWord = userInput.split(" ")[0].trim();
+
+ if (userInput.equals("bye")) {
+ return new ExitCommand();
+ } else if (userInput.equals("list")) {
+ return new ListCommand();
+ } else if (commandWord.equals("mark")) {
+ return parseMarkCommand(userInput);
+ } else if (commandWord.equals("unmark")) {
+ return parseUnmarkCommand(userInput);
+ } else if (commandWord.equals("delete")) {
+ return parseDeleteCommand(userInput);
+ } else if (commandWord.equals("todo")) {
+ return parseTodoCommand(userInput);
+ } else if (commandWord.equals("deadline")) {
+ return parseDeadlineCommand(userInput);
+ } else if (commandWord.equals("event")) {
+ return parseEventCommand(userInput);
+ } else if (commandWord.equals("find")) {
+ return parseFindCommand(userInput);
+ } else {
+ throw new ThothException("Opps, me no understand that command: " + userInput);
+ }
+ }
+
+
+ /**
+ * Parses a command starting with "mark" and returns the corresponding MarkCommand.
+ *
+ * @param input the input string starting with "mark".
+ * @return a MarkCommand if the index is valid; otherwise, an UnknownCommand with an error message.
+ */
+ private static Command parseMarkCommand(String input) throws ThothException {
+ String[] parts = input.split(" ");
+ if (parts.length < 2) {
+ throw new ThothException("Please provide a task number for the mark command.");
+ }
+ try {
+ // parts[1] should contain the number
+ int taskIndex = Integer.parseInt(parts[1].trim()) - Parser.INDEX_OFFSET;
+ return new MarkCommand(taskIndex);
+ } catch (NumberFormatException e) {
+ throw new ThothException("Please enter a valid task index for the mark command.");
+ }
+ }
+
+
+ /**
+ * Parses a command starting with "unmark" and returns the corresponding UnmarkCommand.
+ *
+ * @param input the input string starting with "unmark".
+ * @return an UnmarkCommand if the index is valid; otherwise, an UnknownCommand with an error message.
+ */
+ private static Command parseUnmarkCommand(String input) {
+ String[] parts = input.split(" ");
+ if (parts.length < 2) {
+ throw new ThothException("Please provide a task index for the unmark command.");
+ }
+ try {
+ // parts[1] should contain the number
+ int taskIndex = Integer.parseInt(parts[1].trim()) - Parser.INDEX_OFFSET;
+ return new UnmarkCommand(taskIndex);
+ } catch (NumberFormatException e) {
+ throw new ThothException("Please enter a valid task index for unmark command.");
+ }
+ }
+
+ /**
+ * Parses a command starting with "delete" and returns the corresponding DeleteCommand.
+ *
+ * @param input the input string starting with "delete".
+ * @return a DeleteCommand if the index is valid; otherwise, an UnknownCommand with an error message.
+ */
+ private static Command parseDeleteCommand(String input) {
+ String[] parts = input.split(" ");
+ if (parts.length < 2) {
+ throw new ThothException("Please provide a task index for the delete command.");
+ }
+ try {
+ // parts[1] should contain the number
+ int taskIndex = Integer.parseInt(parts[1].trim()) - Parser.INDEX_OFFSET;
+ return new DeleteCommand(taskIndex);
+ } catch (NumberFormatException e) {
+ throw new ThothException("Please enter a valid task index for delete command.");
+ }
+ }
+
+ /**
+ * Parses a command starting with "todo" and returns the corresponding TodoCommand.
+ *
+ * @param input the input string starting with "todo".
+ * @return a TodoCommand if the description is non-empty; otherwise, an UnknownCommand with an error message.
+ */
+ private static Command parseTodoCommand(String input) {
+ String description = input.replace("todo", "").trim();
+ if (description.isEmpty()) {
+ throw new ThothException("The description for the todo command is empty.");
+ }
+ return new TodoCommand(description);
+ }
+
+ /**
+ * Parses a command starting with "deadline" and returns the corresponding DeadlineCommand.
+ *
+ * @param input the input string starting with "deadline".
+ * @return a DeadlineCommand if both description and deadline are provided; otherwise, an UnknownCommand with an error message.
+ */
+ private static Command parseDeadlineCommand(String input) {
+ String[] parts = input.replace("deadline", "").trim().split(" /by ");
+ String description = parts[0].trim();
+ String by = (parts.length > 1) ? parts[1].trim() : "";
+ if (description.isEmpty() || by.isEmpty()) {
+ throw new ThothException("Oops task description is empty or time range not specified");
+ }
+ return new DeadlineCommand(description, by);
+ }
+
+ /**
+ * Parses a command starting with "event" and returns the corresponding EventCommand.
+ *
+ * @param input the input string starting with "event".
+ * @return an EventCommand if the description and time range are provided; otherwise, an UnknownCommand with an error message.
+ */
+ private static Command parseEventCommand(String input) {
+ String[] parts = input.replace("event", "").trim().split(" /from ");
+ String description = parts[0].trim();
+ String from = "";
+ String to = "";
+ if (parts.length > 1) {
+ String[] timeParts = parts[1].split(" /to ");
+ from = timeParts[0].trim();
+ if (timeParts.length > 1) {
+ to = timeParts[1].trim();
+ }
+ }
+ if (description.isEmpty() || from.isEmpty() || to.isEmpty()) {
+ throw new ThothException("Oops task description is empty or time range not specified");
+ }
+ return new EventCommand(description, from, to);
+ }
+
+ /**
+ * Parses a command starting with "find" and returns the corresponding FindCommand.
+ *
+ * @param input the input string starting with "find".
+ * @return a FindCommand with the provided keyword.
+ */
+ private static Command parseFindCommand(String input) {
+ String keyWord = input.replace("find", "").trim();
+ return new FindCommand(keyWord);
+ }
+}
diff --git a/src/main/java/thoth/parser/TaskParser.java b/src/main/java/thoth/parser/TaskParser.java
new file mode 100644
index 000000000..a52f92aa1
--- /dev/null
+++ b/src/main/java/thoth/parser/TaskParser.java
@@ -0,0 +1,126 @@
+package thoth.parser;
+
+import thoth.tasks.Deadline;
+import thoth.tasks.Event;
+import thoth.tasks.Task;
+import thoth.tasks.Todo;
+import thoth.exceptions.TaskParsingException;
+
+/**
+ * Provides functionality to parse a line from the storage file into a Task object.
+ */
+public class TaskParser {
+ private static final int MIN_HEADER_SIZE = 7;
+ private static final int TYPE_INDEX = 1;
+ private static final int DONE_INDEX = 4;
+
+ /**
+ * Main method to parse a storage file line into a Task.
+ *
+ * @param line the storage file line.
+ * @return the corresponding Task object.
+ * @throws TaskParsingException if the line is not in the expected format.
+ */
+ public static Task parseLineToTask(String line) throws TaskParsingException {
+ if (line.length() < MIN_HEADER_SIZE) {
+ throw new TaskParsingException("Line too short to parse: " + line);
+ }
+
+ char taskType = line.charAt(TYPE_INDEX);
+ char doneChar = line.charAt(DONE_INDEX);
+ boolean isDone = (doneChar == 'X');
+ String content = line.substring(MIN_HEADER_SIZE).trim();
+
+ switch (taskType) {
+ case 'T':
+ return parseTodo(content, isDone);
+ case 'D':
+ return parseDeadline(content, isDone);
+ case 'E':
+ return parseEvent(content, isDone);
+ default:
+ throw new TaskParsingException("Unknown task type: " + taskType + " in line: " + line);
+ }
+ }
+
+ /**
+ * Helper method to parse a Todo task.
+ *
+ * @param content the content of the task.
+ * @param isDone whether the task is marked as done.
+ * @return the Todo task.
+ * @throws TaskParsingException if the content is empty.
+ */
+ private static Task parseTodo(String content, boolean isDone) throws TaskParsingException {
+ if (content.isEmpty()) {
+ throw new TaskParsingException("Todo description is empty.");
+ }
+ Todo todo = new Todo(content);
+ if (isDone) {
+ todo.markAsDone();
+ }
+ return todo;
+ }
+
+ /**
+ * Helper method to parse a Deadline task.
+ *
+ * @param content the content of the task.
+ * @param isDone whether the task is marked as done.
+ * @return the Deadline task.
+ * @throws TaskParsingException if the '(by:' delimiter is missing or parts are empty.
+ */
+ private static Task parseDeadline(String content, boolean isDone) throws TaskParsingException {
+ int byIndex = content.indexOf("(by:");
+ if (byIndex == -1) {
+ throw new TaskParsingException("Deadline task is missing '(by:' section: " + content);
+ }
+ String description = content.substring(0, byIndex).trim();
+ String byPart = content.substring(byIndex + 5).trim(); // skip "(by:"
+ if (byPart.endsWith(")")) {
+ byPart = byPart.substring(0, byPart.length() - 1).trim();
+ }
+ if (description.isEmpty() || byPart.isEmpty()) {
+ throw new TaskParsingException("Deadline description or deadline time is empty: " + content);
+ }
+ Deadline deadline = new Deadline(description, byPart);
+ if (isDone) {
+ deadline.markAsDone();
+ }
+ return deadline;
+ }
+
+ /**
+ * Helper method to parse an Event task.
+ *
+ * @param content the content of the task.
+ * @param isDone whether the task is marked as done.
+ * @return the Event task.
+ * @throws TaskParsingException if the '(from:' or 'to:' delimiters are missing or parts are empty.
+ */
+ private static Task parseEvent(String content, boolean isDone) throws TaskParsingException {
+ int fromIndex = content.indexOf("(from:");
+ if (fromIndex == -1) {
+ throw new TaskParsingException("Event task is missing '(from:' section: " + content);
+ }
+ String description = content.substring(0, fromIndex).trim();
+ String fromPart = content.substring(fromIndex + 6).trim(); // skip "(from:"
+ int toIndex = fromPart.indexOf("to:");
+ if (toIndex == -1) {
+ throw new TaskParsingException("Event task is missing 'to:' section in: " + content);
+ }
+ String fromTime = fromPart.substring(0, toIndex).trim();
+ String toPart = fromPart.substring(toIndex + 3).trim(); // skip "to:"
+ if (toPart.endsWith(")")) {
+ toPart = toPart.substring(0, toPart.length() - 1).trim();
+ }
+ if (description.isEmpty() || fromTime.isEmpty() || toPart.isEmpty()) {
+ throw new TaskParsingException("Event description or time range is empty: " + content);
+ }
+ Event event = new Event(description, fromTime, toPart);
+ if (isDone) {
+ event.markAsDone();
+ }
+ return event;
+ }
+}
diff --git a/src/main/java/thoth/tasks/Deadline.java b/src/main/java/thoth/tasks/Deadline.java
new file mode 100644
index 000000000..716883f4e
--- /dev/null
+++ b/src/main/java/thoth/tasks/Deadline.java
@@ -0,0 +1,28 @@
+package thoth.tasks;
+
+public class Deadline extends Task {
+
+ protected String by;
+
+ /**
+ * Constructs a Deadline task with the specified description and deadline.
+ *
+ * @param description the description for the deadline task
+ * @param by the deadline for the task
+ */
+ public Deadline(String description, String by) {
+ super(description);
+ this.by = by;
+ }
+
+ /**
+ * Return a String to representing the deadline task including it type and deadline
+ *
+ * @return the formatted string
+ */
+ @Override
+ public String getTaskString() {
+ return "[D]" + super.getTaskString() + " (by: " + by + ")";
+ }
+}
+
diff --git a/src/main/java/thoth/tasks/Event.java b/src/main/java/thoth/tasks/Event.java
new file mode 100644
index 000000000..0ce021720
--- /dev/null
+++ b/src/main/java/thoth/tasks/Event.java
@@ -0,0 +1,30 @@
+package thoth.tasks;
+
+public class Event extends Task {
+
+ protected String to;
+ protected String from;
+
+ /**
+ * Constructs the Event Task with specified description, start and end time of the event
+ *
+ * @param description the description of the event
+ * @param from the starting time of the event
+ * @param to the ending time of the event
+ */
+ public Event(String description, String from, String to) {
+ super(description);
+ this.from = from;
+ this.to = to;
+ }
+
+ /**
+ * Return a string representing the event with its type and start and end timeframe
+ *
+ * @return the formatted task string
+ */
+ @Override
+ public String getTaskString() {
+ return "[E]" + super.getTaskString() + " (from: " + from + " to: " + to + ")";
+ }
+}
diff --git a/src/main/java/thoth/tasks/Task.java b/src/main/java/thoth/tasks/Task.java
new file mode 100644
index 000000000..6049c89dc
--- /dev/null
+++ b/src/main/java/thoth/tasks/Task.java
@@ -0,0 +1,44 @@
+package thoth.tasks;
+
+public class Task {
+ //parameters for checking and unchecking tasks
+ public static final String EMPTY_BOX = "[ ]";
+ public static final String MARKED_BOX = "[X]";
+
+ protected String description;
+ protected boolean isDone;
+
+ /**
+ * Constructs a task with the description
+ *
+ * @param description the description for the task
+ */
+ public Task(String description) {
+ this.description = description;
+ this.isDone = false;
+ }
+
+ /**
+ * mark task as done
+ */
+ public void markAsDone() {
+ this.isDone = true;
+ }
+
+ /**
+ * mark task as not done
+ */
+ public void markAsNotDone() {
+ this.isDone = false;
+ }
+
+ /**
+ * Returns a string representation of the task, including its completion status and description.
+ *
+ * @return the formatted task string
+ */
+ public String getTaskString() {
+ String statusIcon = isDone ? MARKED_BOX : EMPTY_BOX;
+ return statusIcon + " " + description;
+ }
+}
diff --git a/src/main/java/thoth/tasks/Todo.java b/src/main/java/thoth/tasks/Todo.java
new file mode 100644
index 000000000..898d733f2
--- /dev/null
+++ b/src/main/java/thoth/tasks/Todo.java
@@ -0,0 +1,26 @@
+package thoth.tasks;
+
+public class Todo extends Task {
+
+ protected String by;
+
+ /**
+ * constructs a todo tak with the specified description
+ *
+ * @param description the description of the todo task
+ */
+ public Todo(String description) {
+ super(description);
+ }
+
+ /**
+ * Returns a string representation of the todo task including its type
+ *
+ * @return a formatted task string with the type
+ */
+ @Override
+ public String getTaskString() {
+ return "[T]" + super.getTaskString();
+ }
+}
+
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
index 087374464..3dac3dfd5 100644
--- a/text-ui-test/runtest.bat
+++ b/text-ui-test/runtest.bat
@@ -15,7 +15,7 @@ IF ERRORLEVEL 1 (
REM no error here, errorlevel == 0
REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT
-java -classpath ..\bin Duke < input.txt > ACTUAL.TXT
+java -classpath ..\bin Thoth < input.txt > ACTUAL.TXT
REM compare the output to the expected output
FC ACTUAL.TXT EXPECTED.TXT