diff --git a/.gitignore b/.gitignore
index 2873e189e..98ef5c9c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,4 +14,5 @@ src/main/resources/docs/
bin/
/text-ui-test/ACTUAL.TXT
-text-ui-test/EXPECTED-UNIX.TXT
+/text-ui-test/EXPECTED-UNIX.TXT
+/data/Mel.txt
diff --git a/docs/README.md b/docs/README.md
index 47b9f984f..975474d52 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,30 +1,162 @@
-# Duke User Guide
+# Mel User Guide
-// Update the title above to match the actual product name
-// Product screenshot goes here
+![img.png](img.png)
-// Product intro goes here
+Mel is a console-based chatbot designed to help you manage tasks efficiently, including todos, deadlines, and events. The chatbot understands a variety of commands to add, remove, and track your tasks, as well as search and manage them interactively. With Mel, you can keep track of your schedule, deadlines, and daily tasks seamlessly.
-## Adding deadlines
+## Key Features:
-// Describe the action and its outcome.
+- Supports **todo** tasks for general items.
+- Adds **deadline** tasks with a specified date and optional time.
+- Manages **event** tasks with both start and end dates/times.
+- Allows marking/unmarking of task completion, and finding tasks by description.
+- Keeps a running list of your tasks and saves them automatically.
-// Give examples of usage
+## Quick Start:
-Example: `keyword (optional arguments)`
+1. Ensure you have Java `17` or above installed in your Computer.
+2. Download the latest `.jar` file from [here](https://github.com/yeekian/ip/releases/tag/A-Release).
+3. Copy the file to the folder you want to use as the home folder for your Task Tracker.
+4. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar Mel.jar` command to run the application.
-// A description of the expected outcome goes here
+Your command terminal similar to below should appear in a few seconds.
+
![img_1.png](img_1.png)
-```
-expected output
-```
+## List tasks: `list`
-## Feature ABC
+Displays the current list of tasks, showing their index, type, description, and whether they are completed or not.
-// Feature details
+Format: `list`
+## Adding a todo task: `todo`
-## Feature XYZ
+Adds tasks without any date/time attached to it e.g., explore the new garden
-// Feature details
\ No newline at end of file
+Format: `todo DESCRIPTION`
+- Adds the todo task with the specified DESCRIPTION. The DESCRIPTION refers to the name of the task that will be shown in the task list.
+- The DESCRIPTION is a string and must not be empty.
+
+Examples:
+
+ todo read book
+
+
+## Adding a deadline task: `deadline`
+
+Adds tasks that need to be done before a specific date/time e.g., return book by 04/11/2024 8pm
+
+Format: `deadline DESCRIPTION /by DATE`
+- Adds the deadline task with the specified `DESCRIPTION`. The `DESCRIPTION` refers to the name of the task that will be shown in the task list.
+- The `DESCRIPTION` is a string and must not be empty.
+- Adds deadline date and/or time to the task with the specified `DATE`. The `DATE` is input as a string and must not be empty.
+- The `DATE` has to be specified in one of the following formats:
+ - yyyy-MM-dd HH:mm
+ - yyyy-MM-dd
+ - dd/MM/yyyy HH:mm
+ - dd/MM/yyyy
+- Adding deadline time to `DATE` is optional, if not given, it will be automatically filled with 23:59
+
+
+Examples:
+
+ //Add a deadline task with a description and deadline of return book and Nov 04 2024, 08:00 pm, respectively
+ deadline return book /by 2024-11-04 20:00
+
+ //Add a deadline task with a description and deadline of submit quiz and Nov 05 2024, 11:59 pm, respectively
+ deadline submit quiz /by 2024-11-05
+
+ //Add a deadline task with a description and deadline of return book and Nov 07 2024, 09:00 pm, respectively
+ deadline order cake /by 07/11/2024 21:00
+
+ //Add a deadline task with a description and deadline of submit form and Nov 09 2024, 11:59 pm, respectively
+ deadline submit form /by 09/11/2024
+
+## Adding a event task: `event`
+
+Adds tasks that start at a specific date/time and ends at a specific date/time e.g., team project meeting on 2/10/2019 from 2pm to 4pm
+
+Format: `event DESCRIPTION /from START_TIME /to END_TIME`
+- Adds the event task with the specified `DESCRIPTION`. The `DESCRIPTION` refers to the name of the task that will be shown in the task list.
+- The `DESCRIPTION` is a string and must not be empty.
+- Adds event start and end date/time to the task with the specified `START_TIME` and `END_TIME`, respectively. The `START_TIME` and `END_TIME` are input as strings and must not be empty.
+- The `START_TIME` and `END_TIME` can be specified as a string in any format.
+
+
+Examples:
+
+ //Add an event task with a description, start time and end time of dinner with friends, 5pm and 6pm, respectively
+ event dinner with friends /from 5pm /to 6pm
+
+## Deleting a task: `delete`
+
+Deletes the specified task from the task list.
+
+Format: `delete INDEX`
+- Deletes the task at the specified `INDEX`.
+- The index refers to the index number shown in the displayed task list.
+- The index **must be a positive integer** 1, 2, 3, ...
+
+Examples:
+
+ //Delete the 2nd task in the task list
+ delete 2
+
+## Mark/Unmark Task Completion: `mark`/ `unmark`
+
+Marks/unmarks the specified task from the task list.
+
+Format: `mark INDEX`/ `unmark INDEX`
+- Marks/unmarks the task at the specified `INDEX` to completed/uncompleted.
+- The index refers to the index number shown in the displayed task list.
+- The index **must be a positive integer** 1, 2, 3, ...
+
+Examples:
+
+ //Mark the 2nd task in the task list as completed
+ mark 2
+
+ //Unmark the 2nd task in the task list so that is becomes uncompleted
+ unmark 2
+
+## Finding tasks by description keywords: `find`
+
+Finds persons whose names contain any of the given keywords.
+
+Format: `find KEYWORD_STRING`
+- The search is case-insensitive. e.g. book will match Book
+- The entire keyword string must be found within the task description. e.g. read a large book will not match with read a small book
+- Parts of words will be matched e.g. Pen will match Pencil
+- Only the task description is searched.
+
+Examples:
+
+ //Return submit quiz and submit form
+ find submit
+
+ //Return read magazine, book reservation
+ find read book
+
+## End Chatbot: `bye`
+
+Exits the program.
+
+Format: `bye`
+
+## Saving the data
+
+The task list data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+
+## Command Summary
+
+| Action | Format, Examples |
+|--------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|
+| **List tasks** | `list` |
+| **Add a todo task** | `todo DESCRIPTION`
e.g., `todo read book` |
+| **Add a deadline task** | `deadline DESCRIPTION /by DATE`
e.g., `deadline return book /by 2024-11-04 20:00`
e.g., `deadline submit form /by 2024-11-05` |
+| **Add an event task** | `event DESCRIPTION /from START_TIME /to END_TIME`
e.g., `event dinner with friends /from 5pm /to 6pm` |
+| **Delete a task** | `delete INDEX`
e.g., `delete 2` |
+| **Mark task as completed** | `mark INDEX`
e.g., `mark 2` |
+| **Unmark task as uncompleted** | `unmark INDEX`
e.g., `unmark 2` |
+| **Find tasks** | `find KEYWORD_STRING`
e.g., `find read book` |
+| **End the chatbot** | `bye` |
diff --git a/docs/img.png b/docs/img.png
new file mode 100644
index 000000000..b1fe8dcc9
Binary files /dev/null and b/docs/img.png differ
diff --git a/docs/img_1.png b/docs/img_1.png
new file mode 100644
index 000000000..c034ff061
Binary files /dev/null and b/docs/img_1.png differ
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/Mel.java b/src/main/java/Mel.java
new file mode 100644
index 000000000..e718d8220
--- /dev/null
+++ b/src/main/java/Mel.java
@@ -0,0 +1,44 @@
+import main.TaskList;
+import main.Parser;
+import main.Storage;
+import main.Ui;
+
+import java.util.Scanner;
+import java.io.IOException;
+import java.io.File;
+
+public class Mel {
+
+ private static final String LIST_FILE_PATH = "data" + File.separator + "Mel.txt"; // Use File.separator for cross-platform compatibility
+
+ private Storage storage;
+ private TaskList userList;
+ private Ui ui;
+ private Scanner in;
+
+ public Mel(String filePath) {
+ ui = new Ui();
+ storage = new Storage(filePath);
+
+ // Set up scanner for user input
+ in = new Scanner(System.in);
+ userList = new TaskList(ui);
+ }
+
+ public void run() {
+ ui.printIntroMessage();
+
+ try {
+ storage.writerSetUp();
+ storage.loadDataFromFile(userList); // Load saved tasks
+ } catch (IOException e) {
+ System.out.println("An error occurred when setting up writer.");
+ }
+
+ Parser.getUserInput(in, storage, ui, userList);
+ }
+
+ public static void main(String[] args) throws IOException {
+ new Mel(LIST_FILE_PATH).run();
+ }
+}
diff --git a/src/main/java/exception/EmptyDateFieldException.java b/src/main/java/exception/EmptyDateFieldException.java
new file mode 100644
index 000000000..b459b09ae
--- /dev/null
+++ b/src/main/java/exception/EmptyDateFieldException.java
@@ -0,0 +1,5 @@
+package exception;
+
+public class EmptyDateFieldException extends RuntimeException {
+ //no other code needed
+}
diff --git a/src/main/java/exception/EmptyDescriptionException.java b/src/main/java/exception/EmptyDescriptionException.java
new file mode 100644
index 000000000..5d50407c4
--- /dev/null
+++ b/src/main/java/exception/EmptyDescriptionException.java
@@ -0,0 +1,5 @@
+package exception;
+
+public class EmptyDescriptionException extends Exception {
+ //no other code needed
+}
diff --git a/src/main/java/main/List.java b/src/main/java/main/List.java
new file mode 100644
index 000000000..4caeeccf5
--- /dev/null
+++ b/src/main/java/main/List.java
@@ -0,0 +1,169 @@
+package main;
+
+import exception.EmptyDateFieldException;
+import exception.EmptyDescriptionException;
+import task.Deadline;
+import task.Event;
+import task.Task;
+import task.Todo;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.time.DateTimeException;
+
+/**
+ * Manages the list of tasks. This class provides functionality to
+ * add tasks (events, todos, deadlines) and mark or delete tasks
+ * in the task list.
+ */
+public class List {
+
+ /**
+ * Adds an event task to the provided task list.
+ * The event contains a description, start date, and end date.
+ *
+ * @param itemArrayList The list of tasks to add the event to.
+ * @param ui
+ * @param line The user input containing the event description, start date, and end date.
+ * @throws EmptyDescriptionException If the event description is missing.
+ * @throws EmptyDateFieldException If the event start or end date is missing.
+ */
+ public static void addEvent(ArrayList itemArrayList, Ui ui, String line) {
+ try {
+ String eventDescription = Parser.extractEventDescription(line);
+ String eventStartDate = Parser.extractEventStartDate(line);
+ String eventEndDate = Parser.extractEventEndDate(line);
+ Event newEvent = new Event(eventDescription, eventStartDate, eventEndDate);
+ itemArrayList.add(newEvent);
+ ui.printAddedMessage(itemArrayList, newEvent);
+ } catch (EmptyDescriptionException e) {
+ ui.printTaskDescriptionEmptyMessage();
+ } catch (EmptyDateFieldException e) {
+ ui.printDateFieldEmptyMessage();
+ }
+ }
+
+ /**
+ * Adds a todo task to the provided task list.
+ * The todo contains only a description.
+ *
+ * @param itemArrayList The list of tasks to add the todo to.
+ * @param ui
+ * @param line The user input containing the todo description.
+ * @throws EmptyDescriptionException If the todo description is missing.
+ */
+ public static void addTodo(ArrayList itemArrayList, Ui ui, String line) {
+ try {
+ String todoDescription = Parser.extractTodoDescription(line);
+ Todo newTodo = new Todo(todoDescription);
+ itemArrayList.add(newTodo);
+ ui.printAddedMessage(itemArrayList, newTodo);
+ } catch (EmptyDescriptionException e) {
+ ui.printTaskDescriptionEmptyMessage();
+ }
+ }
+
+ /**
+ * Adds a deadline task to the provided task list.
+ * The deadline contains a description and a due date.
+ *
+ * @param itemArrayList The list of tasks to add the deadline to.
+ * @param ui
+ * @param line The user input containing the deadline description and date.
+ * @throws EmptyDescriptionException If the deadline description is missing.
+ * @throws EmptyDateFieldException If the deadline date is missing.
+ */
+ public static void addDeadline(ArrayList itemArrayList, Ui ui, String line) {
+ try {
+ String deadlineDescription = Parser.extractDeadlineDescription(line);
+ LocalDateTime deadlineDate = Parser.extractDeadlineDate(line);
+ Deadline newDeadline = new Deadline(deadlineDescription, deadlineDate);
+ itemArrayList.add(newDeadline);
+ ui.printAddedMessage(itemArrayList, newDeadline);
+ } catch (EmptyDescriptionException e) {
+ ui.printTaskDescriptionEmptyMessage();
+ } catch (EmptyDateFieldException e) {
+ ui.printDateFieldEmptyMessage();
+ } catch (DateTimeException e) {
+ ui.printInvalidDateFormatMessage();
+ }
+ }
+
+ /**
+ * Marks a task in the task list as done.
+ *
+ * @param itemArrayList The list of tasks.
+ * @param itemNum The task number to be marked as done.
+ */
+ public static void markListItemAsDone(ArrayList itemArrayList, int itemNum) {
+ itemArrayList.get(itemNum - 1).markAsDone();
+ }
+
+ /**
+ * Marks a task in the task list as not done.
+ *
+ * @param itemArrayList The list of tasks.
+ * @param itemNum The task number to be marked as not done.
+ */
+ public static void markListItemAsUnDone(ArrayList itemArrayList, int itemNum) {
+ itemArrayList.get(itemNum - 1).markAsUnDone();
+ }
+
+ /**
+ * Deletes a task from the task list.
+ *
+ * @param itemArrayList The list of tasks.
+ * @param itemNum The task number to be deleted.
+ */
+ public static void deleteListItem(ArrayList itemArrayList, int itemNum) {
+ itemArrayList.remove(itemNum - 1);
+ }
+
+ public static LocalDateTime convertDeadlineDateAsLocalDateTime(String deadlineDate) {
+ // Define multiple format patterns to support different date and date-time formats
+ DateTimeFormatter[] formatters = {
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"), // With time
+ DateTimeFormatter.ofPattern("yyyy-MM-dd"), // Date only
+ DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"), // With time, different format
+ DateTimeFormatter.ofPattern("dd/MM/yyyy"), // Date only, different format
+ };
+
+ // Try to parse as LocalDateTime (with time)
+ for (DateTimeFormatter formatter : formatters) {
+ try {
+ return LocalDateTime.parse(deadlineDate, formatter);
+ } catch (DateTimeException ignored) {
+ // Ignore and try the next formatter
+ }
+ }
+
+ // Try to parse as LocalDate (without time) and convert to LocalDateTime
+ for (DateTimeFormatter formatter : formatters) {
+ try {
+ LocalDate date = LocalDate.parse(deadlineDate, formatter);
+ return date.atTime(23, 59, 59); // Return LocalDateTime with time set to 23:59
+ } catch (DateTimeException ignored) {
+ // Ignore and try the next formatter
+ }
+ }
+
+ // If parsing fails for all formats, throw an exception
+ throw new DateTimeException("Invalid date format: " + deadlineDate);
+ }
+
+
+ public static LocalDateTime getDeadlineDateAsLocalDateTimeFromFile(String deadlineDate) {
+ DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("MMM dd yyyy, h:mm a");
+ return LocalDateTime.parse(deadlineDate, inputFormatter);
+ }
+
+ public static String convertDeadlineDateAsString(LocalDateTime dateTime) {
+ DateTimeFormatter outputformatter = DateTimeFormatter.ofPattern("MMM dd yyyy, h:mm a");
+ String formattedDateTime = dateTime.format(outputformatter);
+
+ return formattedDateTime;
+ }
+}
+
diff --git a/src/main/java/main/Parser.java b/src/main/java/main/Parser.java
new file mode 100644
index 000000000..33477e1b8
--- /dev/null
+++ b/src/main/java/main/Parser.java
@@ -0,0 +1,299 @@
+package main;
+
+import exception.EmptyDateFieldException;
+import exception.EmptyDescriptionException;
+
+import java.time.LocalDateTime;
+import java.util.Scanner;
+
+/**
+ * The Parser class is responsible for interpreting user inputs and extracting the relevant information
+ * to perform the appropriate actions on the task list.
+ */
+public class Parser {
+ public static final String DEADLINE_BY_KEYWORD = "/by";
+ public static final String EVENT_FROM_KEYWORD = "/from";
+ public static final String EVENT_TO_KEYWORD = "/to";
+
+ public static void getUserInput(Scanner in, Storage storage, Ui ui, TaskList userList) {
+ String line;
+ while (true) {
+ line = getLine(ui, in);
+ String commandType = getCommandType(line); // Get command type using the new method
+
+ switch (commandType) {
+ case "bye":
+ ui.printByeMessage();
+ ui.printHorizontalLine();
+ return;
+
+ case "list":
+ userList.printList();
+ ui.printHorizontalLine();
+ break;
+
+ case "mark":
+ userList.markItem(line);
+ ui.printHorizontalLine();
+ storage.saveListToFile(userList);
+ break;
+
+ case "unmark":
+ userList.unmarkItem(line);
+ ui.printHorizontalLine();
+ storage.saveListToFile(userList);
+ break;
+
+ case "delete":
+ userList.deleteItem(line);
+ ui.printHorizontalLine();
+ storage.saveListToFile(userList);
+ break;
+
+ case "find":
+ userList.findItem(line);
+ ui.printHorizontalLine();
+ break;
+
+ default:
+ userList.addItem(line);
+ ui.printHorizontalLine();
+ storage.saveListToFile(userList);
+ break;
+ }
+ }
+ }
+
+
+ /**
+ * Reads a line of input from the user and prints a horizontal line after the input.
+ * @param in Scanner to read user input.
+ * @param ui
+ * @return The user input line as a string.
+ */
+ private static String getLine(Ui ui, Scanner in) {
+ String line;
+ System.out.print(System.lineSeparator());
+ line = in.nextLine();
+ ui.printHorizontalLine();
+ return line;
+ }
+
+ /**
+ * Checks if the input command matches any of the predefined commands, ignoring extraneous parameters
+ * for commands that do not take parameters (e.g., list, bye, help).
+ *
+ * @param line The input string.
+ * @return The command type if it matches, or "unknown" if not recognized.
+ */
+ private static String getCommandType(String line) {
+ String trimmedLine = line.split(" ")[0]; // Extract the first word (command) only
+
+ switch (trimmedLine) {
+ case "list":
+ return "list";
+ case "bye":
+ return "bye";
+ case "mark":
+ return "mark";
+ case "unmark":
+ return "unmark";
+ case "delete":
+ return "delete";
+ case "find":
+ return "find";
+ default:
+ return "unknown"; // Return "unknown" for unrecognized commands
+ }
+ }
+
+ /**
+ * Determines the type of task based on the input line.
+ *
+ * @param line The user input containing task information.
+ * @return The task type as a string ("event", "deadline", "todo", or "unknown").
+ */
+ public static String getTaskType(String line) {
+ if (isValidEvent(line)) {
+ return "event";
+ } else if (isValidDeadline(line)) {
+ return "deadline";
+ } else if (isTodo(line)) {
+ return "todo";
+ } else {
+ return "unknown"; // Return "unknown" for unrecognized task types
+ }
+ }
+
+
+ /**
+ * Checks if the input string is a valid event format.
+ * @param line The input string.
+ * @return True if the command contains an event with the proper format.
+ */
+ public static boolean isValidEvent(String line) {
+ return line.startsWith("event ") &&
+ line.contains(EVENT_FROM_KEYWORD) &&
+ line.contains(EVENT_TO_KEYWORD);
+ }
+
+ /**
+ * Checks if the input string is a valid deadline format.
+ * @param line The input string.
+ * @return True if the command contains a deadline with the "/by" keyword.
+ */
+ public static boolean isValidDeadline(String line) {
+ return line.startsWith("deadline ") && line.contains(DEADLINE_BY_KEYWORD);
+ }
+
+ /**
+ * Checks if the input string is a valid todo task.
+ * @param line The input string.
+ * @return True if the command starts with "todo".
+ */
+ public static boolean isTodo(String line) {
+ return line.startsWith("todo ");
+ }
+
+ /**
+ * Extracts the description from a todo command.
+ * @param line The input string.
+ * @return The description of the todo task.
+ * @throws EmptyDescriptionException if the description is empty.
+ */
+ public static String extractTodoDescription(String line) throws EmptyDescriptionException {
+ String todoDescription;
+ todoDescription = line.replaceFirst("todo", "").trim();
+
+ taskDescriptionNotEmpty(todoDescription);
+
+ return todoDescription;
+ }
+
+ public static String extractFindDescription(String line) throws EmptyDescriptionException {
+ String findDescription;
+ findDescription = line.replaceFirst("find", "").trim();
+
+ taskDescriptionNotEmpty(findDescription);
+
+ return findDescription;
+ }
+
+ /**
+ * Extracts the description from a deadline command.
+ * @param line The input string.
+ * @return The description of the deadline task.
+ * @throws EmptyDescriptionException if the description is empty.
+ */
+ public static String extractDeadlineDescription(String line) throws EmptyDescriptionException {
+ String deadlineDescription;
+ final int indexOfDeadlinePrefix = line.indexOf("/by");
+ deadlineDescription = line.substring(0, indexOfDeadlinePrefix).replaceFirst("deadline", "").trim();
+
+ taskDescriptionNotEmpty(deadlineDescription);
+
+ return deadlineDescription;
+ }
+
+ /**
+ * Checks if a task description is not empty.
+ * @param taskDescription The task description to be checked.
+ * @throws EmptyDescriptionException if the description is empty.
+ */
+ private static void taskDescriptionNotEmpty(String taskDescription) throws EmptyDescriptionException {
+ if (taskDescription.isEmpty()) {
+ throw new EmptyDescriptionException();
+ }
+ }
+
+ /**
+ * Extracts the date from a deadline command.
+ * @param line The input string.
+ * @return The date of the deadline.
+ * @throws EmptyDateFieldException if the date field is empty.
+ */
+ public static LocalDateTime extractDeadlineDate(String line) {
+ LocalDateTime deadlineDate;
+ final int indexOfDeadlinePrefix = line.indexOf("/by");
+ String deadlineDateString = line.substring(indexOfDeadlinePrefix).replaceFirst("/by", "").trim();
+
+ dateFieldNotEmpty(deadlineDateString);
+ deadlineDate = List.convertDeadlineDateAsLocalDateTime(deadlineDateString);
+
+ return deadlineDate;
+ }
+
+ /**
+ * Checks if a date field is not empty.
+ * @param dateField The date field to be checked.
+ * @throws EmptyDateFieldException if the date field is empty.
+ */
+ private static void dateFieldNotEmpty(String dateField) throws EmptyDateFieldException {
+ if (dateField.isEmpty()) {
+ throw new EmptyDateFieldException();
+ }
+ }
+
+ /**
+ * Extracts the description from an event command.
+ * @param line The input string.
+ * @return The description of the event.
+ * @throws EmptyDescriptionException if the description is empty.
+ */
+ public static String extractEventDescription(String line) throws EmptyDescriptionException {
+ String eventDescription;
+ final int indexOfStartDatePrefix = line.indexOf("/from");
+ final int indexOfEndDatePrefix = line.indexOf("/to");
+ if (indexOfEndDatePrefix > indexOfStartDatePrefix) {
+ eventDescription = line.substring(0, indexOfStartDatePrefix).replaceFirst("event", "").trim();
+ } else {
+ eventDescription = line.substring(0, indexOfEndDatePrefix).replaceFirst("event", "").trim();
+ }
+
+ taskDescriptionNotEmpty(eventDescription);
+
+ return eventDescription;
+ }
+
+ /**
+ * Extracts the end date from an event command.
+ * @param line The input string.
+ * @return The end date of the event.
+ * @throws EmptyDateFieldException if the date field is empty.
+ */
+ public static String extractEventEndDate(String line) {
+ String eventEndDate;
+ final int indexOfStartDatePrefix = line.indexOf("/from");
+ final int indexOfEndDatePrefix = line.indexOf("/to");
+ if (indexOfEndDatePrefix > indexOfStartDatePrefix) {
+ eventEndDate = line.substring(indexOfEndDatePrefix).replaceFirst("/to", "").trim();
+ } else {
+ eventEndDate = line.substring(indexOfEndDatePrefix, indexOfStartDatePrefix).replaceFirst("/to", "").trim();
+ }
+
+ dateFieldNotEmpty(eventEndDate);
+
+ return eventEndDate;
+ }
+
+ /**
+ * Extracts the start date from an event command.
+ * @param line The input string.
+ * @return The start date of the event.
+ * @throws EmptyDateFieldException if the date field is empty.
+ */
+ public static String extractEventStartDate(String line) {
+ String eventStartDate;
+ final int indexOfStartDatePrefix = line.indexOf("/from");
+ final int indexOfEndDatePrefix = line.indexOf("/to");
+ if (indexOfStartDatePrefix > indexOfEndDatePrefix) {
+ eventStartDate = line.substring(indexOfStartDatePrefix).replaceFirst("/from", "").trim();
+ } else {
+ eventStartDate = line.substring(indexOfStartDatePrefix, indexOfEndDatePrefix).replaceFirst("/from", "").trim();
+ }
+
+ dateFieldNotEmpty(eventStartDate);
+
+ return eventStartDate;
+ }
+}
diff --git a/src/main/java/main/Storage.java b/src/main/java/main/Storage.java
new file mode 100644
index 000000000..d9b20097c
--- /dev/null
+++ b/src/main/java/main/Storage.java
@@ -0,0 +1,153 @@
+package main;
+
+import task.Deadline;
+import task.Event;
+import task.Todo;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.time.DateTimeException;
+import java.time.LocalDateTime;
+import java.util.Scanner;
+
+/**
+ * The Storage class handles loading and saving task data to and from a file.
+ */
+public class Storage {
+
+ protected String filePath;
+
+ public Storage(String filePath) {
+ this.filePath = filePath;
+ }
+
+ /**
+ * Writes the given text to a specified file.
+ * @param textToAdd The text to add to the file.
+ * @throws IOException If an I/O error occurs while writing to the file.
+ */
+ public void writeToFile(String textToAdd) throws IOException {
+ FileWriter fw = new FileWriter(filePath);
+ fw.write(textToAdd);
+ fw.close();
+ }
+
+ /**
+ * Sets up the file by creating a new file if it does not exist.
+ * Also creates the parent directory if it doesn't exist.
+ * @throws IOException If an I/O error occurs while setting up the file.
+ */
+ public void writerSetUp() throws IOException {
+ File listFile = new File(filePath);
+ if (!listFile.exists()) {
+ File directory = listFile.getParentFile();
+ if (directory != null && !directory.exists()) { // Null check for directory
+ directory.mkdirs(); // Create directory if it doesn't exist
+ }
+ listFile.createNewFile(); // Create file if it doesn't exist
+ }
+ }
+
+ /**
+ * Loads task data from a file and adds it to the provided user list.
+ * @param userList The list where the tasks will be added.
+ */
+ public void loadDataFromFile(TaskList userList) {
+ File file = new File(filePath);
+ try {
+ Scanner scanner = new Scanner(file);
+ while (scanner.hasNextLine()) {
+ String line = scanner.nextLine();
+ parseAndAddItem(line, userList);
+ }
+ scanner.close();
+ } catch (FileNotFoundException e) {
+ System.out.println("\tFile not found: " + filePath);
+ }
+ Ui.printHorizontalLine();
+ }
+
+ /**
+ * Parses a line from the file and adds the corresponding task to the user list.
+ * @param line The line to parse.
+ * @param userList The list where the task will be added.
+ */
+ private static void parseAndAddItem(String line, TaskList userList) {
+ String[] parts = line.split(" \\| ");
+
+ try {
+ String taskType = parts[0]; // T, D, E
+ boolean isDone = parts[1].equals("X");
+ String taskDescription = parts[2];
+
+ // Check for valid task types and number of fields
+ switch (taskType) {
+ case "T":
+ if (parts.length != 3) {
+ System.out.println("\tInvalid format for Todo task: " + line);
+ return; // Skip this line
+ }
+ Todo todoTask = new Todo(taskDescription);
+ if (isDone) {
+ todoTask.markAsDone();
+ }
+ userList.itemArrayList.add(todoTask);
+ break;
+
+ case "D":
+ if (parts.length != 4) {
+ System.out.println("\tSkipping line as invalid format for Deadline task: " + line);
+ return; // Skip this line
+ }
+ try {
+ LocalDateTime deadlineDate = List.getDeadlineDateAsLocalDateTimeFromFile(parts[3]);
+ Deadline deadlineTask = new Deadline(taskDescription, deadlineDate);
+ if (isDone) {
+ deadlineTask.markAsDone();
+ }
+ userList.itemArrayList.add(deadlineTask);
+ } catch (DateTimeException e) {
+ System.out.println("\tSkipping line as invalid date format in Deadline task: " + parts[3]);
+ System.out.println("\t\tInvalid date format, expected: \n\t\t\tyyyy-mm-dd HH:mm \n\t\t\tyyyy-MM-dd \n\t\t\tdd/MM/yyyy HH:mm \n\t\t\tdd/MM/yyyy");
+ }
+ break;
+
+ case "E":
+ if (parts.length != 5) {
+ System.out.println("\tSkipping line as invalid format for Event task: " + line);
+ return; // Skip this line
+ }
+ String eventStart = parts[3]; // Start date/time
+ String eventEnd = parts[4]; // End date/time
+ Event eventTask = new Event(taskDescription, eventStart, eventEnd);
+ if (isDone) {
+ eventTask.markAsDone();
+ }
+ userList.itemArrayList.add(eventTask);
+ break;
+
+ default:
+ System.out.println("\tSkipping line as invalid task type in file: " + line);
+ break;
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ System.out.println("\tSkipping line as error detected in line: " + line);
+ }
+ }
+
+
+ /**
+ * Saves the current task list to the specified file.
+ * @param userList The list containing tasks to save.
+ */
+ public void saveListToFile(TaskList userList) {
+ try {
+ writeToFile(userList.getFormattedTasks()); // getFormattedTasks returns a formatted String
+ } catch (IOException e) {
+ System.out.println("\tAn error occurred while saving the list.");
+ }
+ }
+}
+
diff --git a/src/main/java/main/TaskList.java b/src/main/java/main/TaskList.java
new file mode 100644
index 000000000..8b1b46332
--- /dev/null
+++ b/src/main/java/main/TaskList.java
@@ -0,0 +1,190 @@
+package main;
+
+import exception.EmptyDescriptionException;
+import task.Task;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Manages the list of tasks. Provides functionality to add, mark, unmark, delete,
+ * and print tasks. Also provides formatted task output.
+ */
+public class TaskList {
+
+ private Ui ui;
+ private Task[] itemList = new Task[0];
+ ArrayList itemArrayList = new ArrayList<>(Arrays.asList(itemList));
+
+ /**
+ * Constructs an empty task list with no items.
+ */
+ public TaskList(Ui ui) {
+ this.ui = ui;
+ }
+
+
+ /**
+ * Returns the number of tasks in the list.
+ *
+ * @return The number of tasks in the list.
+ */
+ public int getNumItems() {
+ return itemArrayList.size();
+ }
+
+ /**
+ * Adds a new task to the list based on the user input.
+ * It checks whether the task is an event, deadline, or todo,
+ * and adds it accordingly. If the task is invalid, an error message is printed.
+ *
+ * @param line The user input containing task information.
+ */
+ public void addItem(String line) {
+ String commandType = Parser.getTaskType(line); // Assuming a method to determine task type
+
+ switch (commandType) {
+ case "event":
+ List.addEvent(itemArrayList, ui, line);
+ break;
+ case "deadline":
+ List.addDeadline(itemArrayList, ui, line);
+ break;
+ case "todo":
+ List.addTodo(itemArrayList, ui, line);
+ break;
+ default:
+ ui.printInvalidTaskMessage();
+ break;
+ }
+ }
+
+ /**
+ * Marks a task in the list as done based on the user input.
+ * If the task number is invalid or out of range, an error message is printed.
+ *
+ * @param line The user input containing the task number to mark.
+ */
+ public void markItem(String line) {
+ try {
+ int itemNum = Integer.parseInt(line.substring(5));
+
+ if (itemNum > this.getNumItems() || itemNum <= 0) {
+ ui.printInputIndexOutOfRangeMessage();
+ } else {
+ List.markListItemAsDone(itemArrayList, itemNum);
+ ui.printTaskMarkedMessage(itemArrayList, itemNum);
+ }
+ } catch (NumberFormatException e) {
+ ui.printInputIndexNotAnIntegerMessage();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ ui.printIndexOutOfBoundsMessage();
+ } catch (Exception e) {
+ ui.printInvalidTaskMessage();
+ }
+ }
+
+ /**
+ * Unmarks a task in the list as not done based on the user input.
+ * If the task number is invalid or out of range, an error message is printed.
+ *
+ * @param line The user input containing the task number to unmark.
+ */
+ public void unmarkItem(String line) {
+ try {
+ int itemNum = Integer.parseInt(line.substring(7));
+
+ if (itemNum > this.getNumItems() || itemNum <= 0) {
+ ui.printInputIndexOutOfRangeMessage();
+ } else {
+ List.markListItemAsUnDone(itemArrayList, itemNum);
+ ui.printTaskUnmarkedMessage(itemArrayList, itemNum);
+ }
+ } catch (NumberFormatException e) {
+ ui.printInputIndexNotAnIntegerMessage();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ ui.printIndexOutOfBoundsMessage();
+ } catch (Exception e) {
+ ui.printInvalidTaskMessage();
+ }
+ }
+
+ /**
+ * Deletes a task from the list based on the user input.
+ * If the task number is invalid or out of range, an error message is printed.
+ *
+ * @param line The user input containing the task number to delete.
+ */
+ public void deleteItem(String line) {
+ try {
+ int itemNum = Integer.parseInt(line.substring(7));
+
+ if (itemNum > this.getNumItems() || itemNum <= 0) {
+ ui.printInputIndexOutOfRangeMessage();
+ } else {
+ Task deletedTask = itemArrayList.get(itemNum - 1);
+ List.deleteListItem(itemArrayList, itemNum);
+ ui.printTaskDeletedMessage(itemArrayList, deletedTask);
+ }
+ } catch (NumberFormatException e) {
+ ui.printInputIndexNotAnIntegerMessage();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ ui.printIndexOutOfBoundsMessage();
+ } catch (Exception e) {
+ ui.printInvalidTaskMessage();
+ }
+ }
+
+ /**
+ * Prints the current list of tasks to the console.
+ */
+ public void printList() {
+ System.out.println("\tHere are the tasks in your list:");
+ int i = 0;
+ for (Task a: itemArrayList) {
+ System.out.println("\t" + (i + 1) + "." + a);
+ i += 1;
+ }
+ }
+
+ /**
+ * Returns the formatted string representation of all tasks in the list.
+ * Each task is formatted based on its type and details.
+ *
+ * @return A string representing the formatted tasks.
+ */
+ public String getFormattedTasks() {
+ String outputString = "";
+ for (Task a: itemArrayList) {
+ outputString += a.formattedTask() + System.lineSeparator();
+ }
+ return outputString;
+ }
+
+ public void findItem(String line) {
+ try {
+ String findDescription = Parser.extractFindDescription(line);
+ ArrayList matchedArrayList = new ArrayList<>(itemArrayList); // Safe copy of the original list
+
+ int i = 0;
+ while (i < matchedArrayList.size()) {
+ Task t = matchedArrayList.get(i);
+
+ if (!t.getDescription().toLowerCase().contains(findDescription.toLowerCase())) {
+ matchedArrayList.remove(t);
+ } else {
+ i += 1;
+ }
+ }
+
+ System.out.println("\tHere are the matching tasks in your list:");
+ int j = 0;
+ for (Task a: matchedArrayList) {
+ System.out.println("\t" + (j + 1) + "." + a);
+ j += 1;
+ }
+ } catch (EmptyDescriptionException e) {
+ ui.printFindDescriptionEmptyMessage();
+ }
+ }
+}
diff --git a/src/main/java/main/Ui.java b/src/main/java/main/Ui.java
new file mode 100644
index 000000000..9949956c7
--- /dev/null
+++ b/src/main/java/main/Ui.java
@@ -0,0 +1,155 @@
+package main;
+
+import task.Task;
+
+import java.util.ArrayList;
+
+/**
+ * The Ui class handles all the user interface interactions by displaying messages to the user.
+ * It provides methods to print responses, error messages, and updates about the tasks list.
+ */
+public class Ui {
+
+ public static final String DRAW_HORIZONTAL_LINE = "\t________________________________________";
+ public static final String INVALID_EVENT_INPUT_MESSAGE = "event /from /end ";
+ public static final String INVALID_DEADLINE_INPUT_MESSAGE = "deadline /by ";
+ public static final String INVALID_TODO_INPUT_MESSAGE = "todo ";
+ private static final String INVALID_MARK_MESSAGE = "mark ";
+ private static final String INVALID_UNMARK_MESSAGE = "unmark ";
+ private static final String INVALID_DELETE_MESSAGE = "delete ";
+ private static final String INVALID_FIND_MESSAGE = "find ";
+ private static final String INVALID_LIST_MESSAGE = "list";
+ private static final String INVALID_BYE_MESSAGE = "bye";
+
+
+ /**
+ * Prints a horizontal line for separating sections in the user interface.
+ */
+ public static void printHorizontalLine() {
+ System.out.println(DRAW_HORIZONTAL_LINE);
+ }
+
+ /**
+ * Prints the introduction message when the program starts, including the bot's name and greeting.
+ */
+ public void printIntroMessage() {
+ printHorizontalLine();
+ System.out.println("\tHello! I'm");
+ System.out.println("\t.___ ___. _______ __ \n" +
+ "\t| \\/ | | ____|| | \n" +
+ "\t| \\ / | | |__ | | \n" +
+ "\t| |\\/| | | __| | | \n" +
+ "\t| | | | | |____ | `----.\n" +
+ "\t|__| |__| |_______||_______|\n" +
+ "\t ");
+ System.out.println("\tWhat can I do for you?");
+ printHorizontalLine();
+ }
+
+ /**
+ * Prints the goodbye message when the user exits the program.
+ */
+ public void printByeMessage() {
+ System.out.println("\tBye. Hope to see you again soon!");
+ }
+
+ /**
+ * Prints an error message indicating an invalid task format input from the user,
+ * along with the correct formats for each type of task.
+ */
+ public void printInvalidTaskMessage() {
+ System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + INVALID_TODO_INPUT_MESSAGE
+ + System.lineSeparator() + "\t\t" + INVALID_DEADLINE_INPUT_MESSAGE + System.lineSeparator() + "\t\t"
+ + INVALID_EVENT_INPUT_MESSAGE + System.lineSeparator() + "\t\t"
+ + INVALID_MARK_MESSAGE + System.lineSeparator() + "\t\t"
+ + INVALID_UNMARK_MESSAGE + System.lineSeparator() + "\t\t"
+ + INVALID_DELETE_MESSAGE + System.lineSeparator() + "\t\t"
+ + INVALID_FIND_MESSAGE + System.lineSeparator() + "\t\t"
+ + INVALID_LIST_MESSAGE + System.lineSeparator() + "\t\t"
+ + INVALID_BYE_MESSAGE);
+ }
+
+ /**
+ * Prints an error message when a task description is empty.
+ */
+ public void printTaskDescriptionEmptyMessage() {
+ System.out.println("\tError: The task description cannot be empty.");
+ }
+
+ public void printFindDescriptionEmptyMessage() {
+ System.out.println("\tError: The find description cannot be empty.");
+ }
+
+ /**
+ * Prints a message confirming that a task has been added to the list.
+ * @param itemArrayList The current list of tasks.
+ * @param task The task that was added.
+ */
+ public void printAddedMessage(ArrayList itemArrayList, Task task) {
+ System.out.println("\tGot it. I've added this task:");
+ System.out.println("\t " + task);
+ System.out.println("\tNow you have " + (itemArrayList.size()) + " tasks in the list.");
+ }
+
+ /**
+ * Prints a generic error message for unknown issues.
+ */
+ public void printIndexOutOfBoundsMessage() {
+ System.out.println("Index given was out of bounds of the list");
+ }
+
+ /**
+ * Prints a message confirming that a task has been marked as done.
+ * @param itemArrayList The current list of tasks.
+ * @param itemNum The task index that was marked as done.
+ */
+ public void printTaskMarkedMessage(ArrayList itemArrayList, int itemNum) {
+ System.out.println("\tNice! I've marked this task as done:");
+ System.out.println("\t " + itemArrayList.get(itemNum - 1));
+ }
+
+ /**
+ * Prints a message confirming that a task has been unmarked (marked as not done).
+ * @param itemArrayList The current list of tasks.
+ * @param itemNum The task index that was unmarked.
+ */
+ public void printTaskUnmarkedMessage(ArrayList itemArrayList, int itemNum) {
+ System.out.println("\tOK, I've marked this task as not done yet:");
+ System.out.println("\t " + itemArrayList.get(itemNum - 1));
+ }
+
+ /**
+ * Prints an error message when the user provides an index that is out of range
+ * for marking, unmarking, or deleting tasks.
+ */
+ public void printInputIndexOutOfRangeMessage() {
+ System.out.println("\tInput index number out of range.");
+ }
+
+ /**
+ * Prints an error message when the user provides a non-integer index for task operations.
+ */
+ public void printInputIndexNotAnIntegerMessage() {
+ System.out.println("\tInput index was not a integer.");
+ }
+
+ /**
+ * Prints a message confirming that a task has been deleted from the list.
+ * @param itemArrayList The current list of tasks.
+ * @param task The task that was deleted.
+ */
+ public void printTaskDeletedMessage(ArrayList itemArrayList, Task task) {
+ System.out.println("\tNoted. I've removed this task:");
+ System.out.println("\t " + task);
+ System.out.println("\tNow you have " + itemArrayList.size() + " tasks in the list.");
+ }
+
+ public void printInvalidDateFormatMessage() {
+ System.out.println("\tInvalid date format, expected: \n\t\tyyyy-mm-dd HH:mm \n\t\tyyyy-MM-dd \n\t\tdd/MM/yyyy HH:mm \n\t\tdd/MM/yyyy");
+ }
+
+ public void printDateFieldEmptyMessage() {
+ System.out.println("\tError: Date field(s) cannot be empty");
+ }
+}
+
diff --git a/src/main/java/task/Deadline.java b/src/main/java/task/Deadline.java
new file mode 100644
index 000000000..ebf6ba72e
--- /dev/null
+++ b/src/main/java/task/Deadline.java
@@ -0,0 +1,45 @@
+package task;
+
+import java.time.LocalDateTime;
+import main.List;
+
+/**
+ * Represents a deadline task with a description and a due date.
+ */
+public class Deadline extends Task {
+
+ protected LocalDateTime byDate;
+
+ /**
+ * Constructs a Deadline with the specified description and due date.
+ *
+ * @param description The description of the deadline task.
+ * @param byDate The due date of the deadline task.
+ */
+ public Deadline(String description, LocalDateTime byDate) {
+ super(description);
+ this.byDate = byDate;
+ }
+
+ /**
+ * Returns a string representation of the deadline task, including its completion status
+ * and description with the due date.
+ *
+ * @return A formatted string representation of the deadline task.
+ */
+ @Override
+ public String toString() {
+ return ("[D][" + getDoneStatusIcon() + "] " + description + " (by: " + List.convertDeadlineDateAsString(byDate) + ")");
+ }
+
+ /**
+ * Returns a formatted string representation of the deadline task for storage.
+ *
+ * @return A formatted string representing the deadline task suitable for saving to a file.
+ */
+ @Override
+ public String formattedTask() {
+ return ("D | " + getDoneStatusIcon() + " | " + description + " | " + List.convertDeadlineDateAsString(byDate));
+ }
+
+}
diff --git a/src/main/java/task/Event.java b/src/main/java/task/Event.java
new file mode 100644
index 000000000..f0ecb7a44
--- /dev/null
+++ b/src/main/java/task/Event.java
@@ -0,0 +1,44 @@
+package task;
+
+/**
+ * Represents an event task with a description, start date, and end date.
+ */
+public class Event extends Task {
+ protected String startDate;
+ protected String endDate;
+
+ /**
+ * Constructs an Event with the specified description, start date, and end date.
+ *
+ * @param description The description of the event.
+ * @param startDate The starting date/time of the event.
+ * @param endDate The ending date/time of the event.
+ */
+ public Event(String description, String startDate, String endDate) {
+ super(description);
+ this.startDate = startDate;
+ this.endDate = endDate;
+ }
+
+ /**
+ * Returns a string representation of the event task, including its completion status,
+ * description, start date, and end date.
+ *
+ * @return A formatted string representation of the event task.
+ */
+ @Override
+ public String toString() {
+ return ("[E][" + getDoneStatusIcon() + "] " + description + " (from: " + startDate + " to: " + endDate + ")");
+ }
+
+ /**
+ * Returns a formatted string representation of the event task for storage.
+ *
+ * @return A formatted string representing the event task suitable for saving to a file.
+ */
+ @Override
+ public String formattedTask() {
+ return ("E | " + getDoneStatusIcon() + " | " + description + " | " + startDate + " | " + endDate);
+ }
+}
+
diff --git a/src/main/java/task/Task.java b/src/main/java/task/Task.java
new file mode 100644
index 000000000..5039fc577
--- /dev/null
+++ b/src/main/java/task/Task.java
@@ -0,0 +1,62 @@
+package task;
+
+/**
+ * Represents a task with a description and a completion status.
+ */
+public class Task {
+ protected String description;
+ protected boolean isDone;
+
+ /**
+ * Constructs a 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 description of the task.
+ *
+ * @return The description of the task.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Returns a string representation of the task's completion status.
+ * An "X" indicates that the task is done; a space indicates it is not done.
+ *
+ * @return A string icon representing the task's done status.
+ */
+ public String getDoneStatusIcon() {
+ return (isDone ? "X" : " "); // mark done task with X
+ }
+
+ /**
+ * Marks the task as done.
+ */
+ public void markAsDone() {
+ isDone = true;
+ }
+
+ /**
+ * Marks the task as not done.
+ */
+ public void markAsUnDone() {
+ isDone = false;
+ }
+
+ /**
+ * Returns a formatted string representation of the task.
+ *
+ * @return A formatted string representing the task. By default, it returns "NULL".
+ */
+ public String formattedTask() {
+ return "NULL";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/task/Todo.java b/src/main/java/task/Todo.java
new file mode 100644
index 000000000..574f5d61c
--- /dev/null
+++ b/src/main/java/task/Todo.java
@@ -0,0 +1,38 @@
+package task;
+
+/**
+ * Represents a todo task with a description.
+ */
+public class Todo extends Task {
+
+ /**
+ * Constructs a Todo 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 completion status
+ * and description.
+ *
+ * @return A formatted string representation of the todo task.
+ */
+ @Override
+ public String toString() {
+ return ("[T][" + getDoneStatusIcon() + "] " + description);
+ }
+
+ /**
+ * Returns a formatted string representation of the todo task for storage.
+ *
+ * @return A formatted string representing the todo task suitable for saving to a file.
+ */
+ @Override
+ public String formattedTask() {
+ return ("T | " + getDoneStatusIcon() + " | " + description);
+ }
+}
+
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e..7c828317e 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,287 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
+ ________________________________________
+ Hello! I'm
+ .___ ___. _______ __
+ | \/ | | ____|| |
+ | \ / | | |__ | |
+ | |\/| | | __| | |
+ | | | | | |____ | `----.
+ |__| |__| |_______||_______|
+
+ What can I do for you?
+ ________________________________________
+ ________________________________________
+ ________________________________________
+ Got it. I've added this task:
+ [T][ ] borrow book
+ Now you have 1 tasks in the list.
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ 1.[T][ ] borrow book
+ ________________________________________
+
+ ________________________________________
+ Invalid date format, expected:
+ yyyy-mm-dd HH:mm
+ yyyy-MM-dd
+ dd/MM/yyyy HH:mm
+ dd/MM/yyyy
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ 1.[T][ ] borrow book
+ ________________________________________
+
+ ________________________________________
+ Got it. I've added this task:
+ [E][ ] project meeting (from: Mon 2pm to: 4pm)
+ Now you have 2 tasks in the list.
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ 1.[T][ ] borrow book
+ 2.[E][ ] project meeting (from: Mon 2pm to: 4pm)
+ ________________________________________
+
+ ________________________________________
+ Nice! I've marked this task as done:
+ [T][X] borrow book
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ 1.[T][X] borrow book
+ 2.[E][ ] project meeting (from: Mon 2pm to: 4pm)
+ ________________________________________
+
+ ________________________________________
+ OK, I've marked this task as not done yet:
+ [T][ ] borrow book
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ 1.[T][ ] borrow book
+ 2.[E][ ] project meeting (from: Mon 2pm to: 4pm)
+ ________________________________________
+
+ ________________________________________
+ Input index was not a integer.
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ 1.[T][ ] borrow book
+ 2.[E][ ] project meeting (from: Mon 2pm to: 4pm)
+ ________________________________________
+
+ ________________________________________
+ Input index was not a integer.
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ 1.[T][ ] borrow book
+ 2.[E][ ] project meeting (from: Mon 2pm to: 4pm)
+ ________________________________________
+
+ ________________________________________
+ Invalid command format:
+ todo
+ deadline /by
+ event /from /end
+ mark
+ unmark
+ delete
+ find
+ list
+ bye
+ ________________________________________
+
+ ________________________________________
+ Invalid command format:
+ todo
+ deadline /by
+ event /from /end
+ mark
+ unmark
+ delete
+ find
+ list
+ bye
+ ________________________________________
+
+ ________________________________________
+ Error: The task description cannot be empty.
+ ________________________________________
+
+ ________________________________________
+ Error: The task description cannot be empty.
+ ________________________________________
+
+ ________________________________________
+ Invalid command format:
+ todo
+ deadline /by
+ event /from /end
+ mark
+ unmark
+ delete
+ find
+ list
+ bye
+ ________________________________________
+
+ ________________________________________
+ Error: Date field(s) cannot be empty
+ ________________________________________
+
+ ________________________________________
+ Error: The task description cannot be empty.
+ ________________________________________
+
+ ________________________________________
+ Error: Date field(s) cannot be empty
+ ________________________________________
+
+ ________________________________________
+ Error: Date field(s) cannot be empty
+ ________________________________________
+
+ ________________________________________
+ Got it. I've added this task:
+ [T][ ] todo todo
+ Now you have 3 tasks in the list.
+ ________________________________________
+
+ ________________________________________
+ Invalid date format, expected:
+ yyyy-mm-dd HH:mm
+ yyyy-MM-dd
+ dd/MM/yyyy HH:mm
+ dd/MM/yyyy
+ ________________________________________
+
+ ________________________________________
+ Got it. I've added this task:
+ [E][ ] event event (from: /from /from to: /to /to)
+ Now you have 4 tasks in the list.
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ 1.[T][ ] borrow book
+ 2.[E][ ] project meeting (from: Mon 2pm to: 4pm)
+ 3.[T][ ] todo todo
+ 4.[E][ ] event event (from: /from /from to: /to /to)
+ ________________________________________
+
+ ________________________________________
+ Nice! I've marked this task as done:
+ [T][X] todo todo
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ 1.[T][ ] borrow book
+ 2.[E][ ] project meeting (from: Mon 2pm to: 4pm)
+ 3.[T][X] todo todo
+ 4.[E][ ] event event (from: /from /from to: /to /to)
+ ________________________________________
+
+ ________________________________________
+ Noted. I've removed this task:
+ [E][ ] event event (from: /from /from to: /to /to)
+ Now you have 3 tasks in the list.
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ 1.[T][ ] borrow book
+ 2.[E][ ] project meeting (from: Mon 2pm to: 4pm)
+ 3.[T][X] todo todo
+ ________________________________________
+
+ ________________________________________
+ Input index number out of range.
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ 1.[T][ ] borrow book
+ 2.[E][ ] project meeting (from: Mon 2pm to: 4pm)
+ 3.[T][X] todo todo
+ ________________________________________
+
+ ________________________________________
+ Noted. I've removed this task:
+ [T][X] todo todo
+ Now you have 2 tasks in the list.
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ 1.[T][ ] borrow book
+ 2.[E][ ] project meeting (from: Mon 2pm to: 4pm)
+ ________________________________________
+
+ ________________________________________
+ Noted. I've removed this task:
+ [E][ ] project meeting (from: Mon 2pm to: 4pm)
+ Now you have 1 tasks in the list.
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ 1.[T][ ] borrow book
+ ________________________________________
+
+ ________________________________________
+ Noted. I've removed this task:
+ [T][ ] borrow book
+ Now you have 0 tasks in the list.
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ ________________________________________
+
+ ________________________________________
+ Input index number out of range.
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ ________________________________________
+
+ ________________________________________
+ Input index number out of range.
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ ________________________________________
+
+ ________________________________________
+ Input index number out of range.
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ ________________________________________
+
+ ________________________________________
+ Input index number out of range.
+ ________________________________________
+
+ ________________________________________
+ Here are the tasks in your list:
+ ________________________________________
+
+ ________________________________________
+ Bye. Hope to see you again soon!
+ ________________________________________
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb..1b8fc29da 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,48 @@
+todo borrow book
+list
+deadline return book /by Sunday
+list
+event project meeting /from Mon 2pm /to 4pm
+list
+mark 1
+list
+unmark 1
+list
+mark
+list
+unmark
+list
+
+todo
+deadline /by
+event /from /to
+
+deadline /by
+event /from /to
+event /from /to
+event /from /to
+todo todo todo
+deadline deadline deadline /by /by /by
+event event event /from /from /from /to /to /to
+list
+mark 3
+list
+delete 4
+list
+delete 0
+list
+delete 3
+list
+delete 2
+list
+delete 1
+list
+delete 0
+list
+delete 1
+list
+delete 1
+list
+delete 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..9d12d8b65 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 Mel < 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
old mode 100644
new mode 100755