diff --git a/.gitignore b/.gitignore
index 2873e189e..cf1399567 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,5 @@ bin/
/text-ui-test/ACTUAL.TXT
text-ui-test/EXPECTED-UNIX.TXT
+
+data/
diff --git a/README.md b/README.md
index 90aa7f092..7ecd21748 100644
--- a/README.md
+++ b/README.md
@@ -8,9 +8,9 @@ Prerequisites: JDK 17, update Intellij to the most recent version.
1. Open Intellij (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project first)
1. Open the project into Intellij as follows:
- 1. Click `Open`.
- 1. Select the project directory, and click `OK`.
- 1. If there are any further prompts, accept the defaults.
+ 1. Click `Open`.
+ 1. Select the project directory, and click `OK`.
+ 1. If there are any further prompts, accept the defaults.
1. Configure the project to use **JDK 17** (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:
@@ -21,4 +21,4 @@ Prerequisites: JDK 17, update Intellij to the most recent version.
| | | | | | | |/ / _ \
| |_| | |_| | < __/
|____/ \__,_|_|\_\___|
- ```
+ ```
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
index 47b9f984f..f4bdee04d 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,30 +1,209 @@
-# Duke User Guide
+# TulipTask
-// Update the title above to match the actual product name
+## Overview
-// Product screenshot goes here
+TulipTask allows users to manage tasks, including to-dos, events, and deadlines. It provides a command-line interface where users can add, delete, mark task as done, and list tasks. The tasks are saved to a file so they persist across sessions.
-// Product intro goes here
+---
-## Adding deadlines
+## Features
-// Describe the action and its outcome.
+- **Add Tasks**
+ - **To-Do**: A basic task without any time constraints.
+ - **Deadline**: A task with a specific deadline.
+ - **Event**: A task that has a defined start and end time.
-// Give examples of usage
+- **Manage Tasks**
+ - Mark tasks as done or not done.
+ - Delete tasks from the task list.
-Example: `keyword (optional arguments)`
+- **File Storage**
+ - Tasks are saved to and loaded from a file, making them persistent between sessions.
-// A description of the expected outcome goes here
+- **Task Searching**
+ - You can search for tasks based on keywords in the task description.
+
+---
+
+## Commands
+
+### 1. `todo `
+Adds a To-Do task to the task list.
+
+- **Example**:
+ ```
+ todo Read a book
+ ```
+
+### 2. `deadline /by `
+Adds a Deadline task to the task list.
+
+- **Example**:
+ ```
+ deadline Submit assignment /by Sunday
+ ```
+
+### 3. `event /from /to `
+Adds an Event task to the task list.
+
+- **Example**:
+ ```
+ event Project meeting /from Monday 2pm /to Monday 4pm
+ ```
+
+### 4. `list`
+Displays all tasks in the list along with their statuses.
+
+- **Example**:
+ ```
+ list
+ ```
+
+### 5. `mark `
+Marks a specific task as done based on its task number.
+
+- **Example**:
+ ```
+ mark 2
+ ```
+
+### 6. `unmark `
+Marks a specific task as not done based on its task number.
+
+- **Example**:
+ ```
+ unmark 3
+ ```
+
+### 7. `delete `
+Deletes a specific task based on its task number.
+
+- **Example**:
+ ```
+ delete 4
+ ```
+
+### 8. `find `
+Finds and lists tasks that contain the specified keyword in their description.
+
+- **Example**:
+ ```
+ find book
+ ```
+
+### 9. `save`
+Manually saves the current task list to the file.
+
+- **Example**:
+ ```
+ save
+ ```
+
+### 10. `load`
+Loads tasks from the file if they exist.
+
+- **Example**:
+ ```
+ load
+ ```
+
+### 11. `bye`
+Exits the application, automatically saving all tasks to the file.
+
+- **Example**:
+ ```
+ bye
+ ```
+
+---
+
+## Task Types
+
+### 1. **To-Do Task**
+- A basic task with no specific time or deadline.
+- **Format**: `[T][status] description`
+
+### 2. **Deadline Task**
+- A task that must be completed by a specific deadline.
+- **Format**: `[D][status] description (by: deadline)`
+
+### 3. **Event Task**
+- A task that occurs within a specific time range.
+- **Format**: `[E][status] description (from: start time to: end time)`
+
+### Status
+- `X` means the task is done.
+- ` ` means the task is not done.
+
+---
+
+## File Storage
+
+- Tasks are saved in a file located at `./data/data.txt`.
+- Tasks are loaded automatically when the application starts, if the file exists.
+- If the data directory or file does not exist, they will be created automatically.
+
+---
+
+## Running the Application
+
+1. **Compile and Run**:
+ - Ensure all the required classes (`Task`, `ToDo`, `Deadline`, `Event`, `TaskList`, `Ui`, `Storage`, `InputParser`) are compiled.
+ - Run the `Ui` class which provides the main interaction loop for the application.
+
+2. **Interacting with the App**:
+ - Upon starting, you will be greeted with a welcome message, and you can enter commands as described above.
+
+3. **Exiting**:
+ - Use the `bye` command to save all tasks and exit the application.
+
+---
+
+## Example Usage
```
-expected output
-```
+Hello, I'm TulipTask
+What can I do for you today?
+
+> todo Read a book
+Okay! I have added this task:
+[T][ ] Read a book
+You currently have 1 task in your list.
-## Feature ABC
+> deadline Submit assignment /by Sunday
+Okay! I have added this task:
+[D][ ] Submit assignment (by: Sunday)
+You currently have 2 tasks in your list.
+
+> event Project meeting /from Monday 2pm /to Monday 4pm
+Okay! I have added this task:
+[E][ ] Project meeting (from: Monday 2pm to: Monday 4pm)
+You currently have 3 tasks in your list.
+
+> list
+Here are your current tasks:
+1. [T][ ] Read a book
+2. [D][ ] Submit assignment (by: Sunday)
+3. [E][ ] Project meeting (from: Monday 2pm to: Monday 4pm)
+
+> mark 1
+Great job! I have marked this task as done:
+[T][X] Read a book
+
+> find assignment
+Here are the matching tasks in your list:
+[D][ ] Submit assignment (by: Sunday)
+
+> bye
+Bye! Hope to see you again soon :)
+```
-// Feature details
+---
+## Future Enhancements
-## Feature XYZ
+- **Task Editing**: Add functionality to modify existing tasks.
+- **Recurring Tasks**: Implement support for tasks that repeat on a regular schedule.
+- **Priority Levels**: Allow users to assign priority levels to tasks.
-// Feature details
\ No newline at end of file
+---
diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java
new file mode 100644
index 000000000..fb71f9bd4
--- /dev/null
+++ b/src/main/java/Deadline.java
@@ -0,0 +1,28 @@
+/**
+ * The Deadline class represents a task that has a specific deadline.
+ * It extends the Task class by adding a due date (deadline) to the task.
+ */
+public class Deadline extends Task {
+ protected String by;
+
+ /**
+ * Constructs a Deadline task with a description and a deadline date.
+ *
+ * @param description The description of the task.
+ * @param by The deadline for the task.
+ */
+ public Deadline(String description, String by) {
+ super(description);
+ this.by = by;
+ }
+
+ /**
+ * Returns a string representation of the deadline task.
+ * The format is [D] followed by the task description, status, and the deadline.
+ *
+ * @return A string in the format [D][status] description (by: deadline).
+ */
+ public String toString() {
+ return String.format("[D]%s (by: %s)", super.toString(), 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..15cf89dad
--- /dev/null
+++ b/src/main/java/Event.java
@@ -0,0 +1,31 @@
+/**
+ * The Event class represents a task that occurs over a specific time period.
+ * It extends the Task class by adding a start time and an end time.
+ */
+public class Event extends Task {
+ protected String from;
+ protected String to;
+
+ /**
+ * Constructs an Event task with a description, start time, and end time.
+ *
+ * @param description The description of the event.
+ * @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);
+ this.from = from;
+ this.to = to;
+ }
+
+ /**
+ * Returns a string representation of the event task.
+ * The format is [E] followed by the task description, status, and the event's time period.
+ *
+ * @return A string in the format [E][status] description (from: start time to: end time).
+ */
+ public String toString() {
+ return String.format("[E]%s (from: %s to: %s)", super.toString(), this.from, this.to);
+ }
+}
diff --git a/src/main/java/InputParser.java b/src/main/java/InputParser.java
new file mode 100644
index 000000000..6528a13a4
--- /dev/null
+++ b/src/main/java/InputParser.java
@@ -0,0 +1,58 @@
+import java.util.HashMap;
+
+/**
+ * The InputParser class is responsible for parsing user input into commands and arguments.
+ * It takes a raw input string and splits it into meaningful components such as the command and its arguments.
+ */
+public class InputParser {
+ public static final String COMMAND = "command";
+ public static final String ARGUMENT = "argument";
+
+ /**
+ * Parses the user's input into a command and associated arguments.
+ * The first word in the input is considered the command, and the rest is treated as arguments.
+ * Arguments that start with "/" are treated as named arguments.
+ *
+ * @param input The raw input string from the user.
+ * @return A HashMap containing the parsed command and its arguments.
+ */
+ public static HashMap parseCommands(String input) {
+ HashMap commandArguments = new HashMap<>();
+ String[] splitInput = input.split(" ");
+
+ // check if input is empty
+ if (splitInput.length == 0) {
+ commandArguments.put(InputParser.COMMAND, "");
+ return commandArguments;
+ }
+
+ // set first element as command
+ commandArguments.put(InputParser.COMMAND, splitInput[0]);
+
+ String argumentDescription = InputParser.ARGUMENT;
+ StringBuilder argument = new StringBuilder();
+
+ // parse remaining input
+ for (int i = 1; i < splitInput.length; i++) {
+ String arg = splitInput[i];
+
+ if (arg.startsWith("/")) {
+ if (!argumentDescription.isEmpty()) {
+ commandArguments.put(argumentDescription, argument.toString().strip());
+ }
+
+ argumentDescription = arg;
+ argument.setLength(0);
+ } else {
+ argument.append(" ").append(arg);
+ }
+ }
+
+ // add last argument
+ if (!argument.isEmpty()) {
+ commandArguments.put(argumentDescription, argument.toString().strip());
+ }
+
+ return commandArguments;
+ }
+}
diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java
new file mode 100644
index 000000000..492a9fdbc
--- /dev/null
+++ b/src/main/java/Storage.java
@@ -0,0 +1,73 @@
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The Storage class handles saving and loading tasks from a file.
+ * It provides methods to save tasks to a text file and load tasks from it.
+ */
+public class Storage {
+ static Path directoryPath = Path.of("./data");
+ static Path filePath = directoryPath.resolve("data.txt");
+
+ /**
+ * Saves the provided list of tasks to a file.
+ * If the directory or file does not exist, they are created.
+ *
+ * @param taskList The list of tasks to be saved.
+ */
+ public static void saveTasks(ArrayList taskList) {
+ try {
+ if (!Files.exists(directoryPath)) {
+ Files.createDirectories(directoryPath);
+ System.out.println("Directory created: " + directoryPath);
+ }
+
+ if (!Files.exists(filePath)) {
+ Files.createFile(filePath);
+ System.out.println("File created: " + filePath);
+ }
+
+ try (var writer = new FileWriter(filePath.toFile())) {
+ for (var item : taskList) {
+ writer.write(item + System.lineSeparator());
+ }
+ System.out.println("Task list data saved to file: " + filePath);
+ }
+
+ } catch (IOException e) {
+ System.out.println("An error occurred: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Loads the tasks from the file into a list of strings.
+ *
+ * @return A list of strings representing the tasks. Returns null if an error occurs or the file does not exist.
+ */
+ public static List loadTasks() {
+ List taskList;
+
+ if (!Files.exists(directoryPath)) {
+ System.out.println("Data directory does not exist");
+ }
+
+ try {
+ if (Files.exists(filePath)) {
+ taskList = Files.readAllLines(filePath);
+ return taskList;
+ } else {
+ System.out.println("Data file does not exist: " + filePath);
+ }
+ } catch (IOException e) {
+ System.out.println("An error occurred while reading the file: " + e.getMessage());
+ }
+ return null;
+ }
+}
+
+
+
diff --git a/src/main/java/Task.java b/src/main/java/Task.java
new file mode 100644
index 000000000..6eed34ea3
--- /dev/null
+++ b/src/main/java/Task.java
@@ -0,0 +1,61 @@
+/**
+ * The Task class represents a general task with a description and a completion status.
+ * It serves as the base class for different types of tasks such as ToDo, Deadline, and Event.
+ */
+public class Task {
+ protected String description;
+ protected boolean isDone;
+
+ /**
+ * Constructs a new Task with the specified description.
+ * The task is initially marked as not done.
+ *
+ * @param description The description of the task.
+ */
+ public Task(String description) {
+ this.description = description;
+ this.isDone = false;
+ }
+
+ /**
+ * Returns the status icon of the task. "X" if the task is done, otherwise a space (" ").
+ *
+ * @return A string representing the status icon of the task.
+ */
+ public String getStatusIcon() {
+ return (isDone ? "X" : " "); // mark done task with X
+ }
+
+ /**
+ * Marks the task as done by setting its status to true.
+ */
+ public void markAsDone() {
+ this.isDone = true;
+ }
+
+ /**
+ * Marks the task as not done by setting its status to false.
+ */
+ public void markAsNotDone() {
+ this.isDone = false;
+ }
+
+ /**
+ * Returns the description of the task.
+ *
+ * @return The description of the task.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Returns a string representation of the task.
+ * The format is [statusIcon] followed by the task description.
+ *
+ * @return A string representing the task, including its status and description.
+ */
+ public String toString() {
+ return String.format("[%s] %s", this.getStatusIcon(), this.getDescription());
+ }
+}
diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java
new file mode 100644
index 000000000..72cddd4db
--- /dev/null
+++ b/src/main/java/TaskList.java
@@ -0,0 +1,279 @@
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The TaskList class manages a list of tasks. It allows tasks to be added, deleted, marked as done or not done,
+ * and supports operations like loading tasks from a file or saving them to a file.
+ */
+public class TaskList {
+ public ArrayList taskList;
+ protected int taskIndex;
+ public static final int INVALID_INDEX = -1;
+
+ public TaskList() {
+ this.taskList = new ArrayList<>();
+ }
+
+ /**
+ * Adds a new task to the task list.
+ *
+ * @param task The task to be added.
+ */
+ public void addTask(Task task) {
+ System.out.println("--------------------------------------------");
+ this.taskList.add(task);
+ System.out.println("Okay! I have added this task: ");
+ System.out.println(task.toString());
+ System.out.printf("You currently have %d tasks in your list \n", taskList.size());
+ System.out.println("--------------------------------------------");
+ }
+
+ /**
+ * Deletes a task from the task list.
+ *
+ * @param commandArguments A HashMap containing the command arguments, including the task index.
+ */
+ public void deleteTask(HashMap commandArguments) {
+ String argument = commandArguments.get("argument");
+ getTaskIndex(argument);
+ Task task = taskList.get(this.taskIndex);
+ System.out.println("--------------------------------------------");
+ this.taskList.remove(task);
+ System.out.println("Okay! I have removed this task: ");
+ System.out.println(task.toString());
+ System.out.printf("You currently have %d tasks in your list \n", taskList.size());
+ System.out.println("--------------------------------------------");
+ }
+
+ /**
+ * Lists all tasks in the task list.
+ */
+ public void listTasks() {
+ System.out.println("--------------------------------------------");
+ System.out.println("Here are your current tasks: ");
+ for (int i = 0; i < taskList.size(); i++) {
+ System.out.println(i + 1 + "." + this.taskList.get(i));
+ }
+ System.out.println("--------------------------------------------");
+ }
+
+ /**
+ * Adds a new ToDo task to the task list.
+ *
+ * @param commandArguments A HashMap containing the command arguments, including the task description.
+ * @throws TulipTaskException.InvalidTaskDescriptionException if the task description is invalid.
+ */
+ public void addToDo(HashMap commandArguments) throws TulipTaskException.InvalidTaskDescriptionException {
+ String argument = commandArguments.get("argument");
+ if (argument == null) {
+ throw new TulipTaskException.InvalidTaskDescriptionException();
+ }
+
+ ToDo task = new ToDo(commandArguments.get("argument"));
+ addTask(task);
+ }
+
+ /**
+ * Adds a new Deadline task to the task list.
+ *
+ * @param commandArguments A HashMap containing the command arguments, including the task description and deadline.
+ * @throws TulipTaskException.InvalidDeadlineException if the deadline is invalid.
+ * @throws TulipTaskException.InvalidTaskDescriptionException if the task description is invalid.
+ */
+ public void addDeadline(HashMap commandArguments) throws TulipTaskException.InvalidDeadlineException, TulipTaskException.InvalidTaskDescriptionException {
+ String argument = commandArguments.get("argument");
+ String by = commandArguments.get("/by");
+
+ if (argument == null) {
+ throw new TulipTaskException.InvalidTaskDescriptionException();
+ }
+
+ if (by == null) {
+ throw new TulipTaskException.InvalidDeadlineException();
+ }
+
+ Deadline task = new Deadline(argument, by);
+ addTask(task);
+ }
+
+ /**
+ * Adds a new Event task to the task list.
+ *
+ * @param commandArguments A HashMap containing the command arguments, including the task description, start time, and end time.
+ * @throws TulipTaskException.InvalidTaskDescriptionException if the task description is invalid.
+ * @throws TulipTaskException.InvalidStartDateException if the start date is invalid.
+ * @throws TulipTaskException.InvalidEndDateException if the end date is invalid.
+ */
+ public void addEvent(HashMap commandArguments) throws TulipTaskException.InvalidTaskDescriptionException, TulipTaskException.InvalidStartDateException, TulipTaskException.InvalidEndDateException {
+ String argument = commandArguments.get("argument");
+ String from = commandArguments.get("/from");
+ String to = commandArguments.get("/to");
+
+ if (argument == null) {
+ throw new TulipTaskException.InvalidTaskDescriptionException();
+ }
+
+ if (from == null) {
+ throw new TulipTaskException.InvalidStartDateException();
+ }
+
+ if (to == null) {
+ throw new TulipTaskException.InvalidEndDateException();
+ }
+
+ Event task = new Event(argument, from, to);
+ addTask(task);
+ }
+
+ /**
+ * Gets the index of a task based on the provided index string.
+ *
+ * @param indexString The string representing the task index.
+ */
+ public void getTaskIndex(String indexString) {
+ int index = Integer.parseInt(indexString) - 1;
+
+ if (index < 0 || index > taskList.size() - 1) {
+ this.taskIndex = INVALID_INDEX;
+ return;
+ }
+
+ this.taskIndex = index;
+ }
+
+ /**
+ * Marks a task as done.
+ *
+ * @param commandArguments A HashMap containing the command arguments, including the task index.
+ * @throws TulipTaskException.InvalidTaskIndexException if the task index is invalid.
+ */
+ public void markTaskAsDone(HashMap commandArguments) throws TulipTaskException.InvalidTaskIndexException {
+ String argument = commandArguments.get("argument");
+ getTaskIndex(argument);
+
+ if (this.taskIndex == INVALID_INDEX) {
+ throw new TulipTaskException.InvalidTaskIndexException();
+ }
+
+ Task task = taskList.get(this.taskIndex);
+ task.markAsDone();
+ System.out.println("--------------------------------------------");
+ System.out.println("Great job! I have marked this task as done: ");
+ System.out.println(task);
+ System.out.println("--------------------------------------------");
+ }
+
+ /**
+ * Marks a task as not done.
+ *
+ * @param commandArguments A HashMap containing the command arguments, including the task index.
+ * @throws TulipTaskException.InvalidTaskIndexException if the task index is invalid.
+ */
+ public void markTaskAsNotDone(HashMap commandArguments) throws TulipTaskException.InvalidTaskIndexException {
+ String argument = commandArguments.get("argument");
+ getTaskIndex(argument);
+
+ if (this.taskIndex == INVALID_INDEX) {
+ throw new TulipTaskException.InvalidTaskIndexException();
+ }
+
+ Task task = taskList.get(this.taskIndex);
+ task.markAsNotDone();
+ System.out.println("--------------------------------------------");
+ System.out.println("Okay, I have marked this task as not done: ");
+ System.out.println(task);
+ System.out.println("--------------------------------------------");
+ }
+
+ /**
+ * Saves the tasks to a file.
+ */
+ public void saveTaskToFile() {
+ System.out.println("--------------------------------------------");
+ Storage.saveTasks(this.taskList);
+ System.out.println("--------------------------------------------");
+ }
+
+ /**
+ * Loads tasks from a file.
+ */
+ public void loadTaskFromFile() {
+ List list = Storage.loadTasks();
+ for (int i = 0; i < Objects.requireNonNull(list).size(); i++) {
+ parseTask(list.get(i));
+ }
+ System.out.println("--------------------------------------------");
+ System.out.println("Tasks have been successfully loaded!");
+ System.out.println("--------------------------------------------");
+ }
+
+ /**
+ * Parses a task from a string.
+ *
+ * @param line The string containing the task information.
+ */
+ public void parseTask(String line) {
+ String type = line.substring(1, 2);
+ boolean completed = line.charAt(4) == 'X';
+
+ switch (type) {
+ case "T" -> {
+ String description = line.substring(7);
+ ToDo task = new ToDo(description);
+ this.taskList.add(task);
+ if (completed) {
+ task.markAsDone();
+ }
+
+ }
+ case "D" -> {
+ int deadlineIndex = line.indexOf("(by:");
+ String description = line.substring(7, deadlineIndex).trim();
+ String deadline = line.substring(deadlineIndex + 5, line.length() - 1);
+ Deadline task = new Deadline(description, deadline);
+ this.taskList.add(task);
+ if (completed) {
+ task.markAsDone();
+ }
+
+ }
+ case "E" -> {
+ int eventIndex = line.indexOf("(from:");
+ String description = line.substring(7, eventIndex).trim();
+ String timeInfo = line.substring(eventIndex + 6, line.length() - 1); // Extract time info
+
+ String[] timeParts = timeInfo.split(" to: ");
+ String eventStart = timeParts[0].trim();
+ String eventEnd = timeParts[1].trim();
+ Event task = new Event(description, eventStart, eventEnd);
+ this.taskList.add(task);
+ if (completed) {
+ task.markAsDone();
+ }
+ }
+ }
+ }
+
+ /**
+ * Finds tasks that match a given argument.
+ *
+ * @param commandArguments A HashMap containing the command arguments, including the search keyword.
+ */
+ public void findTask(HashMap commandArguments) {
+ String argument = commandArguments.get("argument");
+
+ System.out.println("--------------------------------------------");
+ System.out.println("Here are the matching tasks in your list: ");
+
+ for (Task task : taskList) {
+ if (task.description.contains(argument)) {
+ System.out.println(task);
+ }
+ }
+
+ System.out.println("--------------------------------------------");
+
+ }
+}
diff --git a/src/main/java/ToDo.java b/src/main/java/ToDo.java
new file mode 100644
index 000000000..2086df9a6
--- /dev/null
+++ b/src/main/java/ToDo.java
@@ -0,0 +1,24 @@
+/**
+ * The ToDo class represents a task without any specific time constraints.
+ * It extends the Task class and provides a simple to-do task.
+ */
+public class ToDo extends Task {
+ /**
+ * Constructs a ToDo task with a given description.
+ *
+ * @param description The description of the to-do task.
+ */
+ public ToDo(String description) {
+ super(description);
+ }
+
+ /**
+ * Returns a string representation of the to-do task.
+ * The format is [T] followed by the task's status and description.
+ *
+ * @return A string in the format [T][status] description.
+ */
+ public String toString() {
+ return String.format("[T]%s", super.toString());
+ }
+}
diff --git a/src/main/java/TulipTask.java b/src/main/java/TulipTask.java
new file mode 100644
index 000000000..b4a971347
--- /dev/null
+++ b/src/main/java/TulipTask.java
@@ -0,0 +1,12 @@
+public class TulipTask {
+
+ /**
+ * Runs the TulipTask program
+ * @param args - Unused
+ */
+ public static void main(String[] args) {
+ Ui ui = new Ui();
+ ui.run();
+ }
+}
+
diff --git a/src/main/java/TulipTaskException.java b/src/main/java/TulipTaskException.java
new file mode 100644
index 000000000..ac124010f
--- /dev/null
+++ b/src/main/java/TulipTaskException.java
@@ -0,0 +1,11 @@
+public class TulipTaskException {
+ public static class InvalidDeadlineException extends Exception {}
+
+ public static class InvalidStartDateException extends Exception {}
+
+ public static class InvalidEndDateException extends Exception {}
+
+ public static class InvalidTaskDescriptionException extends Exception {}
+
+ public static class InvalidTaskIndexException extends Exception {}
+}
diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java
new file mode 100644
index 000000000..2b20b2280
--- /dev/null
+++ b/src/main/java/Ui.java
@@ -0,0 +1,184 @@
+import java.util.HashMap;
+import java.util.Scanner;
+
+/**
+ * The Ui class handles user interactions by accepting input commands and managing the task list.
+ * It provides methods for loading, saving, and modifying tasks, and facilitates communication between
+ * the user and the task list.
+ */
+public class Ui {
+ public TaskList taskList;
+
+ public Ui() {
+ taskList = new TaskList();
+
+ try {
+ taskList.loadTaskFromFile();
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ /**
+ * Matches the user's command with the corresponding task list operation.
+ *
+ * @param command The user's command as a string.
+ * @param commandArguments A HashMap containing command arguments for specific tasks.
+ * @return true if the program should continue accepting input, false if the user entered "bye".
+ */
+ public boolean matchCommand(String command, HashMap commandArguments) {
+ final String goodByeMessage = "--------------------------------------------\n" +
+ "Bye! Hope to see you again soon :)\n" +
+ "--------------------------------------------";
+
+ final String unrecognizedCommand = "--------------------------------------------\n" +
+ "Unrecognized command!\n" +
+ "--------------------------------------------\n";
+
+ switch (command) {
+ case "list":
+ taskList.listTasks();
+ break;
+
+ case "mark":
+ try {
+ taskList.markTaskAsDone(commandArguments);
+ } catch (TulipTaskException.InvalidTaskIndexException e) {
+ System.out.println("--------------------------------------------");
+ System.out.printf("Invalid task index! Please input a number between 1 and %d \n", taskList.taskList.size());
+ System.out.println("--------------------------------------------");
+ }
+ break;
+
+ case "unmark":
+ try {
+ taskList.markTaskAsNotDone(commandArguments);
+ } catch (TulipTaskException.InvalidTaskIndexException e) {
+ System.out.println("--------------------------------------------");
+ System.out.printf("Invalid task index! Please input a number between 1 and %d \n", taskList.taskList.size());
+ System.out.println("--------------------------------------------");
+ }
+ break;
+
+ case "todo":
+ try {
+ taskList.addToDo(commandArguments);
+ } catch (TulipTaskException.InvalidTaskDescriptionException e) {
+ System.out.println("--------------------------------------------");
+ System.out.println("Task description was not given :(");
+ System.out.println("--------------------------------------------");
+ }
+ break;
+
+ case "deadline":
+ try {
+ taskList.addDeadline(commandArguments);
+ } catch (TulipTaskException.InvalidTaskDescriptionException e) {
+ System.out.println("--------------------------------------------");
+ System.out.println("Task description was not given :(");
+ System.out.println("--------------------------------------------");
+ } catch (TulipTaskException.InvalidDeadlineException e) {
+ System.out.println("--------------------------------------------");
+ System.out.println("Task deadline was not given, add a deadline by using /by to indicate task end date!");
+ System.out.println("--------------------------------------------");
+ }
+ break;
+
+ case "event":
+ try {
+ taskList.addEvent(commandArguments);
+ } catch (TulipTaskException.InvalidTaskDescriptionException e) {
+ System.out.println("--------------------------------------------");
+ System.out.println("Task description was not given :(");
+ System.out.println("--------------------------------------------");
+ } catch (TulipTaskException.InvalidStartDateException e) {
+ System.out.println("--------------------------------------------");
+ System.out.println("Event start date was not given, add a start date by using /from to indicate task start date!");
+ System.out.println("--------------------------------------------");
+ } catch (TulipTaskException.InvalidEndDateException e) {
+ System.out.println("--------------------------------------------");
+ System.out.println("Event end date was not given, add a end date by using /to to indicate task end date!");
+ System.out.println("--------------------------------------------");
+ }
+ break;
+
+ case "delete":
+ taskList.deleteTask(commandArguments);
+ break;
+
+ case "save":
+ taskList.saveTaskToFile();
+ break;
+
+ case "load":
+ taskList.loadTaskFromFile();
+ break;
+
+ case "find":
+ taskList.findTask(commandArguments);
+ break;
+
+ case "bye":
+ taskList.saveTaskToFile();
+ System.out.println(goodByeMessage);
+ return false;
+
+ default:
+ System.out.println(unrecognizedCommand);
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Accepts and processes commands entered by the user in an interactive loop.
+ * The loop continues until the user enters the "bye" command.
+ */
+ public void commandEntry() {
+ HashMap commandArguments;
+ String input;
+ Scanner scanner = new Scanner(System.in);
+
+ boolean isAcceptingInput = true;
+
+ while (isAcceptingInput) {
+ input = scanner.nextLine();
+ commandArguments = InputParser.parseCommands(input);
+ String command = commandArguments.get(InputParser.COMMAND);
+
+ try {
+ isAcceptingInput = matchCommand(command, commandArguments);
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Displays a welcome message to the user when the program starts.
+ */
+ public void displayWelcome() {
+ String logo = " \n" +
+ "--.-- | o --.-- | \n" +
+ " | . .| .,---. | ,---.,---.|__/ \n" +
+ " | | || || | | ,---|`---.| \\ \n" +
+ " ` `---'`---'`|---' ` `---^`---'` `\n" +
+ " |";
+
+ final String welcomeMessage = "--------------------------------------------\n" +
+ "Hello, I'm TulipTask\n" +
+ "What can I do for you today?\n" +
+ "--------------------------------------------";
+
+ System.out.println(logo);
+ System.out.println(welcomeMessage);
+ }
+
+ /**
+ * Starts the user interface by displaying the welcome message and then accepting commands from the user.
+ */
+ public void run() {
+ displayWelcome();
+ commandEntry();
+ }
+}
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e..9ae68aa1f 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,63 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
-
+
+--.-- | o --.-- |
+ | . .| .,---. | ,---.,---.|__/
+ | | || || | | ,---|`---.| \
+ ` `---'`---'`|---' ` `---^`---'` `
+ |
+--------------------------------------------
+Hello, I'm TulipTask
+What can I do for you today?
+--------------------------------------------
+--------------------------------------------
+Okay! I have added this task:
+[T][ ] borrow book
+You currently have 1 tasks in your list
+--------------------------------------------
+--------------------------------------------
+Here are your current tasks:
+1.[T][ ] borrow book
+--------------------------------------------
+--------------------------------------------
+Okay! I have added this task:
+[D][ ] return book (by: Friday)
+You currently have 2 tasks in your list
+--------------------------------------------
+--------------------------------------------
+Okay! I have added this task:
+[E][ ] project meeting (from: Mon 2pm to: 4pm)
+You currently have 3 tasks in your list
+--------------------------------------------
+Invalid command
+--------------------------------------------
+Here are your current tasks:
+1.[T][ ] borrow book
+2.[D][ ] return book (by: Friday)
+3.[E][ ] project meeting (from: Mon 2pm to: 4pm)
+--------------------------------------------
+--------------------------------------------
+Great job! I have marked this task as done:
+[T][X] borrow book
+--------------------------------------------
+--------------------------------------------
+Here are your current tasks:
+1.[T][X] borrow book
+2.[D][ ] return book (by: Friday)
+3.[E][ ] project meeting (from: Mon 2pm to: 4pm)
+--------------------------------------------
+--------------------------------------------
+Great job! I have marked this task as done:
+[D][X] return book (by: Friday)
+--------------------------------------------
+--------------------------------------------
+Okay, I have marked this task as not done:
+[T][ ] borrow book
+--------------------------------------------
+--------------------------------------------
+Here are your current tasks:
+1.[T][ ] borrow book
+2.[D][X] return book (by: Friday)
+3.[E][ ] project meeting (from: Mon 2pm to: 4pm)
+--------------------------------------------
+--------------------------------------------
+Bye! Hope to see you again soon :)
+--------------------------------------------
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb..62d76c6d1 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,12 @@
+todo borrow book
+list
+deadline return book /by Friday
+event project meeting /from Mon 2pm /to 4pm
+test
+list
+mark 1
+list
+mark 2
+unmark 1
+list
+bye
\ No newline at end of file
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
index 087374464..58d636d61 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 TulipTask < input.txt > ACTUAL.TXT
REM compare the output to the expected output
FC ACTUAL.TXT EXPECTED.TXT
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
index c9ec87003..5739aa622 100644
--- a/text-ui-test/runtest.sh
+++ b/text-ui-test/runtest.sh
@@ -20,7 +20,7 @@ then
fi
# 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 TulipTask < input.txt > ACTUAL.TXT
# convert to UNIX format
cp EXPECTED.TXT EXPECTED-UNIX.TXT