getArguments() {
+ return arguments;
+ }
+}
diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java
new file mode 100644
index 000000000..b98e84b27
--- /dev/null
+++ b/src/main/java/Storage.java
@@ -0,0 +1,103 @@
+import java.io.File;
+import java.io.FileWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+public class Storage {
+ private final String filePath;
+ private final char DONE_SYMBOL = 'X';
+ private final char NOT_DONE_SYMBOL = 'O';
+
+ public Storage(String filePath) {
+ this.filePath = filePath;
+ }
+
+ /**
+ * Loads the task data from the file at the specified file path.
+ * The tasks are represented as lines in the file, with each line
+ * containing the task type, its completion status, and relevant task details.
+ *
+ * If the file does not exist or an error occurs, an empty list is returned.
+ *
+ * @return a list of tasks loaded from the file
+ */
+ public List loadData() {
+ List data = new ArrayList<>();
+ try {
+ File file = new File(filePath);
+ if (!file.exists()) {
+ return data;
+ }
+ Scanner s = new Scanner(file);
+ while (s.hasNextLine()) {
+ String line = s.nextLine();
+ if (line.charAt(1) == 'T') {
+ Todo todo = new Todo(line.substring(2));
+ if (line.charAt(0) == DONE_SYMBOL) todo.mark();
+ data.add(todo);
+ } else if (line.charAt(1) == 'D') {
+ Deadline deadline = new Deadline(line.substring(2), s.nextLine());
+ if (line.charAt(0) == DONE_SYMBOL) deadline.mark();
+ data.add(deadline);
+ } else if (line.charAt(1) == 'E') {
+ Event event = new Event(line.substring(2), s.nextLine(), s.nextLine());
+ if (line.charAt(0) == DONE_SYMBOL) event.mark();
+ data.add(event);
+ }
+ }
+ return data;
+ } catch (Exception e) {
+ return new ArrayList<>();
+ }
+ }
+
+ /**
+ * Saves the given list of tasks to the file at the specified file path.
+ * Each task is saved with its type, completion status, and relevant task details.
+ *
+ * If the file does not exist, it will be created along with any necessary directories.
+ * Returns true if the data is successfully saved, or false if an error occurs.
+ *
+ * @param taskList the list of tasks to save
+ * @return true if the data is saved successfully, false otherwise
+ */
+ public boolean saveData(List taskList) {
+ try {
+ File file = new File(filePath);
+ file.getParentFile().mkdirs();
+
+ FileWriter fw = new FileWriter(file);
+ StringBuilder sb = new StringBuilder();
+
+ for (Task task : taskList) {
+ sb.append(task.isDone() ? DONE_SYMBOL : NOT_DONE_SYMBOL);
+ if (task instanceof Deadline) {
+ sb.append('D');
+ sb.append(task.getTask());
+ sb.append(System.lineSeparator());
+ sb.append(((Deadline) task).getBy());
+ sb.append(System.lineSeparator());
+ } else if (task instanceof Event) {
+ sb.append('E');
+ sb.append(task.getTask());
+ sb.append(System.lineSeparator());
+ sb.append(((Event) task).getFrom());
+ sb.append(System.lineSeparator());
+ sb.append(((Event) task).getTo());
+ sb.append(System.lineSeparator());
+ } else if (task instanceof Todo) {
+ sb.append('T');
+ sb.append(task.getTask());
+ sb.append(System.lineSeparator());
+ }
+ }
+
+ fw.write(sb.toString());
+ fw.close();
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/Task.java b/src/main/java/Task.java
new file mode 100644
index 000000000..f9f6fe6cd
--- /dev/null
+++ b/src/main/java/Task.java
@@ -0,0 +1,73 @@
+public class Task {
+ protected boolean isDone;
+ protected String task;
+
+ /**
+ * Represents a task with a description and a completion status.
+ * The task can be marked as done or not done.
+ *
+ * @param task the description of the task
+ */
+ public Task(String task) {
+ this(task, false);
+ }
+
+ /**
+ * Represents a task with a description and a specified completion status.
+ * The task can be marked as done or not done.
+ *
+ * @param task the description of the task
+ * @param isDone the initial completion status of the task
+ */
+ public Task(String task, boolean isDone) {
+ this.task = task.trim();
+ this.isDone = isDone;
+ }
+
+ /**
+ * Returns the description of the task.
+ *
+ * @return the task description as a string
+ */
+ public String getTask() {
+ return task;
+ }
+
+ /**
+ * Returns the completion status of the task.
+ *
+ * @return true if the task is done, false otherwise
+ */
+ public boolean isDone() {
+ return isDone;
+ }
+
+ /**
+ * Marks the task as done.
+ */
+ public void mark() {
+ isDone = true;
+ }
+
+ /**
+ * Marks the task as not done.
+ */
+ public void unmark() {
+ isDone = false;
+ }
+
+ /**
+ * Returns a string representation of the task, including its completion status
+ * (marked with "X" for done and " " for not done) and its description.
+ *
+ * @return a formatted string representing the task
+ */
+ @Override
+ public String toString() {
+ return "[" +
+ (isDone ? "X" : " ") +
+ "] " +
+ task;
+ }
+
+}
diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java
new file mode 100644
index 000000000..77b5df327
--- /dev/null
+++ b/src/main/java/TaskList.java
@@ -0,0 +1,80 @@
+import java.util.ArrayList;
+import java.util.List;
+
+public class TaskList {
+ private final List tasks;
+
+ /**
+ * Represents a list of tasks. Provides methods to manage tasks, such as adding,
+ * removing, retrieving, and searching tasks.
+ *
+ * @param tasks the initial list of tasks
+ */
+ public TaskList(List tasks) {
+ this.tasks = tasks;
+ }
+
+ /**
+ * Returns the number of tasks in the task list.
+ *
+ * @return the size of the task list
+ */
+ public int getSize() {
+ return tasks.size();
+ }
+
+ /**
+ * Adds a new task to the task list.
+ *
+ * @param task the task to be added
+ */
+ public void addTask(Task task) {
+ tasks.add(task);
+ }
+
+ /**
+ * Searches for tasks that contain the specified keyword in their descriptions.
+ * The search is case-insensitive and trims leading and trailing spaces.
+ *
+ * @param keyword the keyword to search for
+ * @return a list of tasks that contain the keyword
+ */
+ public List find(String keyword) {
+ List result = new ArrayList<>();
+ for (Task task : tasks) {
+ if (task.task.toLowerCase().contains(keyword.trim().toLowerCase())) {
+ result.add(task);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the task at the specified index in the task list.
+ *
+ * @param index the index of the task to retrieve
+ * @return the task at the specified index
+ */
+ public Task getTask(int index) {
+ return tasks.get(index);
+ }
+
+ /**
+ * Removes and returns the task at the specified index in the task list.
+ *
+ * @param index the index of the task to remove
+ * @return the removed task
+ */
+ public Task removeTask(int index) {
+ return tasks.remove(index);
+ }
+
+ /**
+ * Returns the entire list of tasks.
+ *
+ * @return the list of tasks
+ */
+ public List getTaskList() {
+ return tasks;
+ }
+}
diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java
new file mode 100644
index 000000000..66231c3f5
--- /dev/null
+++ b/src/main/java/Todo.java
@@ -0,0 +1,22 @@
+public class Todo extends Task {
+ /**
+ * Represents a to-do task, which is a simple task without any date or time constraints.
+ * Extends the Task class to inherit task-related properties and behaviors.
+ *
+ * @param task the description of the to-do task
+ */
+ public Todo(String task) {
+ super(task);
+ }
+
+ /**
+ * Returns a string representation of the to-do task in the format "[T] task description",
+ * including the task description and its completion status.
+ *
+ * @return a formatted string representing the to-do task
+ */
+ @Override
+ public String toString() {
+ return "[T]" + super.toString();
+ }
+}
diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java
new file mode 100644
index 000000000..ec0247c2c
--- /dev/null
+++ b/src/main/java/Ui.java
@@ -0,0 +1,97 @@
+import java.util.List;
+import java.util.Scanner;
+
+public class Ui {
+ private final String BREAK_LINE = "____________________";
+ private final String GREETING_LINE = BREAK_LINE + "\nHello! I'm DBot\nWhat can I do for you?\n" + BREAK_LINE;
+ Scanner in;
+
+ /**
+ * Displays a greeting message when the Ui object is initialized.
+ * Initializes the Scanner to read input from the user.
+ */
+ public Ui() {
+ in = new Scanner(System.in);
+ System.out.println(GREETING_LINE);
+ }
+
+ /**
+ * Prints a short message surrounded by a break line to format the output.
+ *
+ * @param message the message to be printed
+ */
+ public void printShortMessage(String message) {
+ System.out.println(BREAK_LINE + " Result " + BREAK_LINE);
+ System.out.println(message);
+ System.out.println(BREAK_LINE + BREAK_LINE + "\n");
+ }
+
+ /**
+ * Prints a long message or a list of objects surrounded by a break line
+ * to format the output. Each object is printed on a new line.
+ *
+ * @param list an array of objects to be printed
+ */
+ public void printLongMessage(Object[] list) {
+ System.out.println(BREAK_LINE + " Result " + BREAK_LINE);
+ for (Object o : list) {
+ System.out.println(o);
+ }
+ System.out.println(BREAK_LINE + BREAK_LINE + "\n");
+ }
+
+ private void printError(String message) {
+ System.out.println(BREAK_LINE + " Error " + BREAK_LINE);
+ System.out.println(message);
+ System.out.println(BREAK_LINE + BREAK_LINE + "\n");
+ }
+
+ /**
+ * Prints an error specific to DBot using the details from a DBotException.
+ * The error includes the type of the error and its cause.
+ *
+ * @param error the DBotException containing the error type and message
+ */
+ public void printDBotError(DBotException error) {
+ printError("Error: " + error.getErrorType() + "\nDue to: " + error.getMessage());
+ }
+
+ /**
+ * Prints a generic error message for undocumented exceptions.
+ * This is used to handle any unexpected or unhandled exceptions.
+ *
+ * @param e the Exception containing the error message
+ */
+ public void printGenericError(Exception e) {
+ printError("Undocumented error occurred\nDue to: " + e.getMessage());
+ }
+
+ /**
+ * Returns a formatted string representation of the list of tasks.
+ * Each task is numbered and printed on a new line.
+ *
+ * @param tasks the list of tasks to be printed
+ * @return a string containing the formatted list of tasks
+ */
+ public String listTasks(List tasks) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < tasks.size(); i++) {
+ sb.append(i + 1);
+ sb.append(". ");
+ sb.append(tasks.get(i).toString());
+ sb.append('\n');
+ }
+ return sb.toString().trim();
+ }
+
+ /**
+ * Reads a line of input from the user after printing a "Command:" prompt.
+ *
+ * @return the user's input as a string, with leading and trailing whitespace removed
+ */
+ public String readLine() {
+ System.out.print("Command: ");
+ return in.nextLine().strip();
+ }
+
+}