diff --git a/.gitignore b/.gitignore
index 2873e189e..c396857e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,4 @@ bin/
/text-ui-test/ACTUAL.TXT
text-ui-test/EXPECTED-UNIX.TXT
+
diff --git a/README.md b/README.md
index 8715d4d91..9f37d2ba9 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Duke project template
+# Ma project template
This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.
@@ -13,7 +13,7 @@ Prerequisites: JDK 11, update Intellij to the most recent version.
1. If there are any further prompts, accept the defaults.
1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
In the same dialog, set the **Project language level** field to the `SDK default` option.
-3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output:
+3. After that, locate the `src/main/java/Ma.java` file, right-click it, and choose `Run Ma.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output:
```
Hello from
____ _
@@ -22,3 +22,4 @@ Prerequisites: JDK 11, update Intellij to the most recent version.
| |_| | |_| | < __/
|____/ \__,_|_|\_\___|
```
+The specific instructions for this task manager program is under docs.README.md
diff --git a/data/duke.txt b/data/duke.txt
new file mode 100644
index 000000000..58561111f
--- /dev/null
+++ b/data/duke.txt
@@ -0,0 +1,4 @@
+T | 1 | 2
+T | 1 | read book
+D | 0 | askdfsoief as kjsa lf | SFJ
+T | 1 | readbook
diff --git a/docs/README.md b/docs/README.md
index 8077118eb..205e7a5a2 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,29 +1,144 @@
-# User Guide
+# TaskManager
-## Features
+TaskManager is a simple yet powerful Java application designed to help users manage their tasks efficiently. It allows users to add, delete, mark tasks as done or not done, and find tasks by searching for keywords.
-### Feature-ABC
+## Features
-Description of the feature.
+- **Add Tasks**: Users can add three types of tasks - todos, deadlines, and events.
+- **Delete Tasks**: Users can delete tasks they no longer need.
+- **Mark Tasks**: Users can mark tasks as done or not done.
+- **Find Tasks**: Users can search for tasks by keywords.
+- **List Tasks**: Users can view all their tasks at any time.
-### Feature-XYZ
+## Getting Started
+## Adding a task
+### Type of task
+- Todo
+- Deadline
+- Event
-Description of the feature.
+### Prompt
+- Todo: todo {task description}
-## Usage
+ _e.g. adding task todo `read book`_
+ ```
+ todo read book
+ ```
-### `Keyword` - Describe action
+- Deadline: deadline {task description} /by {date}
-Describe the action and its outcome.
+ _e.g. adding task deadline `return book` before `2021-09-17`_
+ ```
+ deadline return book /by 2021-09-17
+ ```
-Example of usage:
+- Event: event {task description} from {date} to {date}
-`keyword (optional arguments)`
+ _e.g. adding task event `project meeting` from `2021-09-17` to `2021-09-18`_
+ ```
+ event project meeting from 2021-09-17 to 2021-09-18
+ ```
+### Expected output for all adding tasks
+ Got it. I've added this task:
+ [D][ ] return book (by: 2021-09-17)
+> Note: the following e.g. for each command will be using the output of the above prompt
-Expected outcome:
+## Listing all tasks
+### Prompt
+- list
-Description of the outcome.
+ _e.g. listing all tasks_
+ ```
+ list
+ ```
+### Expected output
-```
-expected output
-```
+ Here are the tasks in your list:
+ 1. [T][ ] read book
+ 2. [D][ ] return book (by: Sep 17 2021)
+ 3. [E][ ] project meeting (from: Sep 17 2021 to: Sep 18 2021)
+
+
+## Deleting a task
+### prompt
+- delete {task number}
+
+ _e.g. deleting 3_
+ ```
+ delete 3
+ ```
+### Expected output
+
+ Noted. I've removed this task: {task number}
+ this can be verified by listing all tasks:
+
+ list
+ Here are the tasks in your list:
+ 1. [T][ ] read book
+ 2. [D][ ] return book (by: Sep 17 2021)
+
+
+## Marking a task as done
+### Prompt
+- mark {task name}
+
+ _e.g. marking task 1 as done_
+ ```
+ mark read book
+ ```
+### Expected output
+
+ Nice! I've marked this task as done: {task name}
+ this can be verified by listing or finding tasks:
+ ```
+ list
+ Here are the tasks in your list:
+ 1. [T][X] read book
+ 2. [D][ ] return book (by: Sep 17 2021)
+ 3. [E][ ] project meeting (from: Sep 17 2021 to: Sep 18 2021)
+ ```
+
+- unmark {task name}
+
+ _e.g. unmarking read book_
+ ```
+ unmark read book
+ ```
+### Expected output
+ ```
+ unmarked
+ I've unmarked this task as done: {task name}
+ ```
+this can be verified by listing all tasks:
+ ```
+ list
+ Here are the tasks in your list:
+ 1. [T][ ] read book
+ 2. [D][ ] return book (by: Sep 17 2021)
+ 3. [E][ ] project meeting (from: Sep 17 2021 to: Sep 18 2021)
+ ```
+
+## Finding a task
+### prompt
+- find {keyword}
+
+ e.g. finding tasks related to `book`
+ ```
+ find book
+ ```
+### Expected output
+ Here are the matching tasks in your list:
+ 1. [T][ ] read book
+ 2. [D][ ] return book (by: Sep 17 2021)
+
+## Exit Program
+### prompt
+- bye
+
+### Expected output
+ ```
+ Bye. Hope to see you again soon!
+ ```
+### Prerequisites
+
+- Java 11 or above.
\ No newline at end of file
diff --git a/src/main/java/CommandParser.java b/src/main/java/CommandParser.java
new file mode 100644
index 000000000..eef2d2ae4
--- /dev/null
+++ b/src/main/java/CommandParser.java
@@ -0,0 +1,60 @@
+/**
+ * CommandParser is responsible for interpreting and executing commands
+ * input by the user. It acts as a controller that directs user commands
+ * to appropriate actions on the task list.
+ */
+public class CommandParser {
+ private final TaskList taskList;
+ private final Ui ui;
+
+ /**
+ * Constructs a CommandParser with the specified task list and UI.
+ *
+ * @param taskList the task list to be manipulated based on user commands.
+ * @param ui the UI object for interacting with the user.
+ */
+ public CommandParser(TaskList taskList, Ui ui) {
+ this.taskList = taskList;
+ this.ui = ui;
+ }
+
+ /**
+ * Parses and executes a user input command. Supported commands include
+ * adding, deleting, marking, unmarking tasks, and finding tasks by keywords.
+ * It also handles listing all tasks and exiting the application.
+ *
+ * @param userInput the full user input command to be parsed and executed.
+ */
+ public void parseCommand(String userInput) {
+ try {
+ if (userInput.trim().isEmpty()) {
+ ui.showError("The input cannot be empty!");
+ } else if (userInput.equalsIgnoreCase("list")) {
+ taskList.listTasks();
+ } else if (userInput.startsWith("delete")) {
+ int taskIndex = Integer.parseInt(userInput.split(" ")[1]) - 1; // Get task index
+ taskList.deleteTask(taskIndex);
+ } else if (userInput.startsWith("mark")) {
+ int taskIndex = Integer.parseInt(userInput.split(" ")[1]) - 1; // Get task index
+ taskList.markTaskAsDone(taskIndex);
+ } else if (userInput.startsWith("unmark")) {
+ int taskIndex = Integer.parseInt(userInput.split(" ")[1]) - 1; // Get task index
+ taskList.markTaskAsNotDone(taskIndex);
+ } else if (userInput.startsWith("find")) {
+ String keyword = userInput.substring(5); // Assume "find " is followed by a keyword
+ taskList.findTask(keyword);
+ } else if (!userInput.startsWith("todo") && !userInput.startsWith("deadline")
+ && !userInput.startsWith("event") && !userInput.startsWith("find")) {
+ ui.showError("OOPS!!! I'm sorry, but I don't know what that means :-(");
+ } else {
+ taskList.addTask(userInput);
+ }
+ } catch (HandleException he) {
+ ui.showError(he.getMessage());
+ } catch (NumberFormatException nfe) {
+ ui.showError("OOPS!!! The task number is invalid.");
+ } catch (ArrayIndexOutOfBoundsException aioobe) {
+ ui.showError("OOPS!!! It seems like the command is not complete.");
+ }
+ }
+}
diff --git a/src/main/java/DeadLine.java b/src/main/java/DeadLine.java
new file mode 100644
index 000000000..ddbc36201
--- /dev/null
+++ b/src/main/java/DeadLine.java
@@ -0,0 +1,40 @@
+/**
+ * Represents a deadline task with a specific due date.
+ * A {@code DeadLine} object encapsulates the details of a task that needs to be done before a specific date.
+ */
+public class DeadLine extends Task {
+ protected String by; // The due date of the deadline task.
+
+ /**
+ * Constructs a {@code DeadLine} with the specified task description and due date.
+ *
+ * @param description The description of the deadline task.
+ * @param by The due date of the task.
+ */
+ public DeadLine(String description, String by) {
+ super(description); // Call the superclass constructor to set the task description.
+ this.by = by; // Set the due date of the deadline task.
+ }
+
+ /**
+ * Returns the string representation of the deadline task in a format suitable for file storage.
+ * The format is "D | isDone | description | by", where "D" indicates a deadline task.
+ *
+ * @return A string representation of the deadline task for file storage.
+ */
+ @Override
+ public String toFileFormat() {
+ return String.format("D | %d | %s | %s", isDone ? 1 : 0, description, by);
+ }
+
+ /**
+ * Returns the string representation of the deadline task, including its status (done or not done),
+ * description, and due date.
+ *
+ * @return A string representation of the deadline task, including status, description, and due date.
+ */
+ @Override
+ public String toString() {
+ return "[D]" + super.toString() + " (by: " + this.by + ")";
+ }
+}
diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java
deleted file mode 100644
index 5d313334c..000000000
--- a/src/main/java/Duke.java
+++ /dev/null
@@ -1,10 +0,0 @@
-public class Duke {
- public static void main(String[] args) {
- String logo = " ____ _ \n"
- + "| _ \\ _ _| | _____ \n"
- + "| | | | | | | |/ / _ \\\n"
- + "| |_| | |_| | < __/\n"
- + "|____/ \\__,_|_|\\_\\___|\n";
- System.out.println("Hello from\n" + logo);
- }
-}
diff --git a/src/main/java/Event.java b/src/main/java/Event.java
new file mode 100644
index 000000000..b94f9a61c
--- /dev/null
+++ b/src/main/java/Event.java
@@ -0,0 +1,44 @@
+/**
+ * Represents an event task with a start and end time.
+ * An {@code Event} object encapsulates the details of a task that occurs over a period defined by a start and end time.
+ */
+public class Event extends Task {
+ protected String from; // The start time of the event.
+ protected String to; // The end time of the event.
+
+ /**
+ * Constructs an {@code Event} with the specified task description, start time, and end time.
+ *
+ * @param description The description of the event task.
+ * @param from The start time of the event.
+ * @param to The end time of the event.
+ */
+ public Event(String description, String from, String to) {
+ super(description); // Call the superclass constructor to set the task description.
+ this.from = from; // Set the start time of the event.
+ this.to = to; // Set the end time of the event.
+ }
+
+ /**
+ * Returns the string representation of the event task in a format suitable for file storage.
+ * The format is "E | isDone | description | from to to", where "E" indicates an event task.
+ *
+ * @return A string representation of the event task for file storage.
+ */
+ @Override
+ public String toFileFormat() {
+ return String.format("E | %d | %s | %s to %s", isDone ? 1 : 0, description, from, to);
+ }
+
+ /**
+ * Returns the string representation of the event task, including its status (done or not done),
+ * description, and the period over which it occurs (from start time to end time).
+ *
+ * @return A string representation of the event task, including status, description, and period.
+ */
+ @Override
+ public String toString() {
+ return "[E]" + super.toString() + " (from: " + this.from + " to: " + this.to + ")";
+ }
+}
+
diff --git a/src/main/java/HandleException.java b/src/main/java/HandleException.java
new file mode 100644
index 000000000..325306b2c
--- /dev/null
+++ b/src/main/java/HandleException.java
@@ -0,0 +1,20 @@
+/**
+ * Represents a custom exception class for handling errors specific to the application.
+ * {@code HandleException} is used to encapsulate user-related errors, providing
+ * more context and control over error handling within the application.
+ */
+public class HandleException extends Exception {
+
+ /**
+ * Constructs a new {@code HandleException} with the specified detail message.
+ * The detail message is saved for later retrieval by the {@link #getMessage()} method.
+ *
+ * @param message the detail message. The detail message is saved for later retrieval
+ * by the {@link #getMessage()} method.
+ */
+ public HandleException(String message) {
+ super(message);
+ }
+}
+
+
diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..fda7ec6fa
--- /dev/null
+++ b/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: TaskManager
+
diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java
new file mode 100644
index 000000000..9d7033cc2
--- /dev/null
+++ b/src/main/java/Storage.java
@@ -0,0 +1,100 @@
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+/**
+ * Handles loading and saving tasks to a file.
+ * This class is responsible for reading from and writing to the task storage file,
+ * converting between the file format and Task objects.
+ */
+public class Storage {
+ private final String filePath; // The file path where tasks are stored.
+
+ /**
+ * Constructs a Storage object associated with a specific file path.
+ *
+ * @param filePath the path to the file used for task storage.
+ */
+ public Storage(String filePath) {
+ this.filePath = filePath;
+ }
+
+ /**
+ * Loads tasks from the storage file.
+ * Reads the task file line by line, parsing each line into a Task object,
+ * and returns a list of all tasks loaded from the file.
+ *
+ * @return an ArrayList of Task objects loaded from the file.
+ */
+ public ArrayList load() {
+ ArrayList loadedTasks = new ArrayList<>();
+ File file = new File(filePath);
+ if (file.exists()) {
+ try (Scanner scanner = new Scanner(file)) {
+ while (scanner.hasNextLine()) {
+ String line = scanner.nextLine();
+ Task task = parseLineToTask(line);
+ if (task != null) {
+ loadedTasks.add(task);
+ }
+ }
+ } catch (IOException e) {
+ System.out.println("Unable to read tasks from file: " + e.getMessage());
+ }
+ }
+ return loadedTasks;
+ }
+
+ /**
+ * Saves the current list of tasks to the storage file.
+ * Writes each task to the file in a format suitable for later loading.
+ *
+ * @param tasks the list of Task objects to be saved to the file.
+ * @throws IOException if an I/O error occurs writing to the file.
+ */
+ public void save(ArrayList tasks) throws IOException {
+ try (FileWriter writer = new FileWriter(filePath, false)) {
+ for (Task task : tasks) {
+ writer.write(task.toFileFormat() + System.lineSeparator());
+ }
+ }
+ }
+
+ /**
+ * Parses a single line from the task file into a Task object.
+ * This method is used internally when loading tasks from the file.
+ *
+ * @param line the line from the file to parse into a Task object.
+ * @return the Task object parsed from the line, or null if the line could not be parsed.
+ */
+ private Task parseLineToTask(String line) {
+ String[] parts = line.split(" \\| ");
+ String type = parts[0];
+ Task task = null;
+
+ try {
+ switch (type) {
+ case "T":
+ task = new Todo(parts[2].trim());
+ break;
+ case "D":
+ task = new DeadLine(parts[2].trim(), parts[3].trim());
+ break;
+ case "E":
+ task = new Event(parts[2].trim(), parts[3].trim(), parts[4].trim());
+ break;
+ }
+
+ if (task != null) {
+ boolean isDone = parts[1].trim().equals("1");
+ task.setDone(isDone);
+ }
+ } catch (Exception e) {
+ System.err.println("Failed to parse line into task: " + line);
+ }
+
+ return task;
+ }
+}
diff --git a/src/main/java/Task.java b/src/main/java/Task.java
new file mode 100644
index 000000000..d5b9de8f6
--- /dev/null
+++ b/src/main/java/Task.java
@@ -0,0 +1,79 @@
+/**
+ * Represents a generic task in the task list.
+ * This class serves as a base class for different types of tasks
+ * such as todos, deadlines, and events.
+ */
+public class Task {
+ protected String description; // The task's description
+ protected boolean isDone; // The task's completion status
+
+ /**
+ * Constructs a new Task with the given description. By default, the task is not done.
+ *
+ * @param description The text description of the task.
+ */
+ public Task(String description) {
+ this.description = description;
+ this.isDone = false;
+ }
+
+ /**
+ * Formats the task for file storage, including its done status and description.
+ *
+ * @return A string representation of the task suitable for file storage.
+ */
+ public String toFileFormat() {
+ return String.format("T | %d | %s", isDone ? 1 : 0, description);
+ }
+
+ /**
+ * Marks the task as done.
+ */
+ public void markAsDone() {
+ this.isDone = true;
+ }
+
+ /**
+ * Marks the task as not done.
+ */
+ public void markAsNotDone() {
+ this.isDone = false;
+ }
+
+ /**
+ * Sets the done status of the task.
+ *
+ * @param isDone True if the task is done, false otherwise.
+ */
+ public void setDone(boolean isDone) {
+ this.isDone = isDone;
+ }
+
+ /**
+ * Returns a status icon indicating whether the task is done.
+ *
+ * @return A string representing a check mark if done, or a space if not done.
+ */
+ public String getStatusIcon() {
+ return (isDone ? "X" : " "); // mark done task with X
+ }
+
+ /**
+ * Returns a string representation of the task, including its status icon and description.
+ *
+ * @return A string representation of the task.
+ */
+ @Override
+ public String toString() {
+ return "[" + this.getStatusIcon() + "] " + this.description;
+ }
+
+ /**
+ * Gets the description of the task.
+ *
+ * @return The description of the task.
+ */
+ public String getDescription() {
+ return this.description;
+ }
+}
diff --git a/src/main/java/TaskFactory.java b/src/main/java/TaskFactory.java
new file mode 100644
index 000000000..595ddab3b
--- /dev/null
+++ b/src/main/java/TaskFactory.java
@@ -0,0 +1,60 @@
+/**
+ * TaskFactory is responsible for creating Task objects based on user input.
+ * It interprets the command and parameters provided by the user to instantiate
+ * the appropriate Task subclass (Todo, DeadLine, or Event).
+ */
+public class TaskFactory {
+
+ /**
+ * Creates a Task object based on the user's input.
+ * This method parses the user input to determine the type of task to create
+ * and extracts any necessary parameters (e.g., description, due date).
+ *
+ * @param userInput The complete command input from the user, including the task type
+ * and any parameters.
+ * @return A Task object corresponding to the user's command.
+ * @throws HandleException If the input format is incorrect or insufficient information
+ * is provided to create a task.
+ */
+ public static Task createTask(String userInput) throws HandleException {
+ String[] parts = userInput.split(" ", 2);
+ String type = parts[0];
+ Task task;
+
+ if (parts.length < 2 || parts[1].isEmpty()) {
+ throw new HandleException("OOPS!!! The description of a task cannot be empty.");
+ }
+
+ // Details are declared outside the switch to use across multiple cases.
+ String[] details;
+
+ switch (type.toLowerCase()) {
+ case "todo":
+ task = new Todo(parts[1]);
+ break;
+ case "deadline":
+ details = parts[1].split(" /by ", 2);
+ if (details.length < 2 || details[1].isEmpty()) {
+ throw new HandleException("OOPS!!! The date of a deadline cannot be empty.");
+ }
+ task = new DeadLine(details[0], details[1]);
+ break;
+ case "event":
+ details = parts[1].split(" /from ", 2);
+ if (details.length < 2 || details[1].isEmpty()) {
+ throw new HandleException("OOPS!!! The start time of an event cannot be empty.");
+ }
+ String[] times = details[1].split(" /to ", 2);
+ if (times.length < 2 || times[1].isEmpty()) {
+ throw new HandleException("OOPS!!! The end time of an event cannot be empty.");
+ }
+ task = new Event(details[0], times[0], times[1]);
+ break;
+ default:
+ throw new HandleException("OOPS!!! I'm sorry, but I don't know what that means :-(");
+ }
+
+ return task;
+ }
+}
+
diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java
new file mode 100644
index 000000000..2e16bb2b4
--- /dev/null
+++ b/src/main/java/TaskList.java
@@ -0,0 +1,116 @@
+import java.util.ArrayList;
+
+/**
+ * Represents a list of tasks in the application. This class manages the tasks,
+ * including adding, deleting, marking tasks as done or not done, listing all tasks,
+ * and finding tasks by keywords.
+ */
+public class TaskList {
+ private final ArrayList tasks; // A list of tasks.
+
+ /**
+ * Constructs a TaskList with a specified list of tasks.
+ *
+ * @param tasks An ArrayList of Task objects.
+ */
+ public TaskList(ArrayList tasks) {
+ this.tasks = tasks;
+ }
+
+ /**
+ * Returns the list of tasks.
+ *
+ * @return An ArrayList of Task objects.
+ */
+ public ArrayList getTasks() {
+ return tasks;
+ }
+
+ /**
+ * Adds a task to the task list based on the user input.
+ *
+ * @param userInput The full command input from the user for creating a task.
+ * @throws HandleException If the task cannot be created due to invalid input.
+ */
+ public void addTask(String userInput) throws HandleException {
+ Task task = TaskFactory.createTask(userInput);
+ tasks.add(task);
+ System.out.println("Got it. I've added this task:\n " + task);
+ System.out.println("Now you have " + tasks.size() + " tasks in the list.");
+ }
+
+ /**
+ * Marks a task as done based on its index in the task list.
+ *
+ * @param taskIndex The index of the task to be marked as done.
+ */
+ public void markTaskAsDone(int taskIndex) {
+ if (taskIndex >= 0 && taskIndex < tasks.size()) {
+ Task task = tasks.get(taskIndex);
+ task.markAsDone();
+ System.out.println("Nice! I've marked this task as done:\n " + task);
+ } else {
+ System.out.println("Task with given index does not exist.");
+ }
+ }
+
+ /**
+ * Marks a task as not done based on its index in the task list.
+ *
+ * @param taskIndex The index of the task to be marked as not done.
+ */
+ public void markTaskAsNotDone(int taskIndex) {
+ if (taskIndex >= 0 && taskIndex < tasks.size()) {
+ Task task = tasks.get(taskIndex);
+ task.markAsNotDone();
+ System.out.println("OK, I've marked this task as not done yet:\n " + task);
+ } else {
+ System.out.println("Task with given index does not exist.");
+ }
+ }
+
+ /**
+ * Deletes a task from the task list based on its index.
+ *
+ * @param taskIndex The index of the task to be deleted.
+ * @throws HandleException If the specified index is invalid.
+ */
+ public void deleteTask(int taskIndex) throws HandleException {
+ if (taskIndex < 0 || taskIndex > tasks.size()) {
+ throw new HandleException("OOPS!!! The task number is invalid.");
+ }
+ Task removedTask = tasks.remove(taskIndex);
+ System.out.println("Noted. I've removed this task:\n " + removedTask);
+ System.out.println("Now you have " + tasks.size() + " tasks in the list.");
+ }
+
+ /**
+ * Lists all tasks in the task list.
+ */
+ public void listTasks() {
+ System.out.println("Here are the tasks in your list:");
+ for (int i = 0; i < tasks.size(); i++) {
+ System.out.println((i + 1) + "." + tasks.get(i));
+ }
+ }
+
+ /**
+ * Finds and lists all tasks that contain the specified keyword in their description.
+ *
+ * @param keyword The keyword to search for in task descriptions.
+ */
+ public void findTask(String keyword) {
+ System.out.println("Here are the matching tasks in your list:");
+ int count = 0;
+ for (int i = 0; i < tasks.size(); i++) {
+ Task task = tasks.get(i);
+ if (task.getDescription().contains(keyword)) {
+ System.out.println((i + 1) + "." + task);
+ count++;
+ }
+ }
+ if (count == 0) {
+ System.out.println("No matching tasks found.");
+ }
+ }
+}
diff --git a/src/main/java/TaskManager.java b/src/main/java/TaskManager.java
new file mode 100644
index 000000000..a6374e302
--- /dev/null
+++ b/src/main/java/TaskManager.java
@@ -0,0 +1,42 @@
+import java.io.IOException; // Make sure to import IOException
+import java.util.ArrayList;
+
+/**
+ * The entry point of the application. This class orchestrates the flow of the application,
+ * including initializing components, loading tasks from storage, and processing user commands.
+ */
+public class TaskManager {
+
+ /**
+ * The main method that drives the application. It initializes the necessary components
+ * such as Ui, Storage, and TaskList, and enters a loop to accept and process user commands
+ * until the "bye" command is entered.
+ *
+ * @param args Command line arguments (not used in this application).
+ */
+ public static void main(String[] args) {
+ Ui ui = new Ui(); // Component for user interactions.
+ Storage storage = new Storage("./data/duke.txt"); // Component for handling task storage.
+ ArrayList loadedTasks = storage.load(); // Load tasks from the specified storage.
+ TaskList taskList = new TaskList(loadedTasks); // Initialize the task list with loaded tasks.
+ CommandParser commandParser = new CommandParser(taskList, ui); // Initialize the command parser with the task list and UI.
+
+ ui.showWelcome(); // Display a welcome message to the user.
+
+ boolean isExit = false; // Flag to control the main application loop.
+ while (!isExit) {
+ String userInput = ui.readCommand(); // Read user input.
+ if (userInput.equalsIgnoreCase("bye")) {
+ ui.showGoodbye(); // Display a goodbye message.
+ try {
+ storage.save(taskList.getTasks()); // Attempt to save the current state of tasks.
+ } catch (IOException e) { // Handle potential IO exceptions from saving tasks.
+ ui.showError("An error occurred while saving tasks: " + e.getMessage());
+ }
+ isExit = true; // Set flag to exit the application loop.
+ } else {
+ commandParser.parseCommand(userInput); // Parse and execute the user command.
+ }
+ }
+ }
+}
diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java
new file mode 100644
index 000000000..aaf307d16
--- /dev/null
+++ b/src/main/java/Todo.java
@@ -0,0 +1,38 @@
+/**
+ * Represents a to-do task without a specific deadline.
+ * A {@code Todo} object encapsulates the details of a task that needs to be done.
+ */
+public class Todo extends Task {
+
+ /**
+ * Constructs a {@code Todo} with the specified task description.
+ * Initializes a new to-do task with the provided description.
+ *
+ * @param description The text description of the to-do task.
+ */
+ public Todo(String description) {
+ super(description); // Calls the superclass Task constructor with the description.
+ }
+
+ /**
+ * Returns the string representation of the to-do task in a format suitable for file storage.
+ * This method leverages the {@code toFileFormat} method from the superclass {@code Task}.
+ *
+ * @return A string representation of the to-do task for file storage, maintaining the format defined in {@code Task}.
+ */
+ @Override
+ public String toFileFormat() {
+ return super.toFileFormat(); // Uses the Task class's method for file formatting.
+ }
+
+ /**
+ * Returns the string representation of the to-do task, including its type, status (done or not done),
+ * and description. Overrides the {@code toString} method from the superclass {@code Task}.
+ *
+ * @return A string representation of the to-do task, formatted with its type and status.
+ */
+ @Override
+ public String toString() {
+ return "[T]" + super.toString(); // Adds the to-do type identifier "[T]" before the standard task representation.
+ }
+}
diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java
new file mode 100644
index 000000000..423970c13
--- /dev/null
+++ b/src/main/java/Ui.java
@@ -0,0 +1,59 @@
+import java.util.Scanner;
+
+/**
+ * Handles all user interactions for the application. This class is responsible for
+ * displaying messages to the user and reading user input from the command line.
+ */
+public class Ui {
+ private final Scanner scanner; // Scanner object to read user input.
+
+ /**
+ * Constructs a Ui object, initializing the scanner to read input from the command line.
+ */
+ public Ui() {
+ this.scanner = new Scanner(System.in);
+ }
+
+ /**
+ * Prompts the user for a command and returns the trimmed input.
+ *
+ * @return The user's input as a trimmed string.
+ */
+ public String readCommand() {
+ System.out.println("\nEnter your command:");
+ return scanner.nextLine().trim();
+ }
+
+ /**
+ * Displays a welcome message to the user at the start of the application.
+ */
+ public void showWelcome() {
+ System.out.println("Hello! I'm TaskManager\nWhat can I do for you?");
+ }
+
+ /**
+ * Displays an error message to the user.
+ *
+ * @param message The error message to be displayed.
+ */
+ public void showError(String message) {
+ System.out.println(message);
+ }
+
+ /**
+ * Displays a line of text to the user. Can be used for displaying
+ * informational messages or command results.
+ *
+ * @param message The message to be displayed.
+ */
+ public void showLine(String message) {
+ System.out.println(message);
+ }
+
+ /**
+ * Displays a goodbye message to the user when exiting the application.
+ */
+ public void showGoodbye() {
+ System.out.println("Bye. Hope to see you again soon!");
+ }
+}
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
index 087374464..cdc0b90b2 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 Ma < input.txt > ACTUAL.TXT
REM compare the output to the expected output
FC ACTUAL.TXT EXPECTED.TXT