diff --git a/data/conglo.txt b/data/conglo.txt
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs/README.md b/docs/README.md
index 47b9f984f..97d3dc466 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,30 +1,101 @@
-# Duke User Guide
+# Conglo Task Manager Chatbot
-// Update the title above to match the actual product name
+Conglo is a command-line chatbot designed to help you manage tasks efficiently. Whether it's keeping track of todos, deadlines, or events,
+Conglo provides simple commands to organize your tasks, making it easier to stay productive.
-// Product screenshot goes here
+## Features
-// Product intro goes here
+1. Add tasks, deadlines, and events.
+2. Mark tasks as done or unmark them.
+3. Delete tasks you no longer need.
+4. View all tasks or search for tasks using keywords.
+5. Persistent task storage: Tasks are saved locally, allowing the chatbot to reload them automatically the next time the application is launched.
+6. Exit the application smoothly by saying 'bye'.
-## Adding deadlines
+## Commands
-// Describe the action and its outcome.
+1. **Add a todo**
+ ```plaintext
+ todo [description]
+ ```
+ Example: todo Buy groceries
-// Give examples of usage
+2. **Add a deadline**
+ ```plaintext
+ deadline [description] /by [dd-MM-yyyy HHmm]
+ ```
+ Example: deadline Submit report /by 12-10-2024 2359
-Example: `keyword (optional arguments)`
+3. **Add an event**
+ ```plaintext
+ event [description] /from [start time] /to [end time]
+ ```
+ Example: event Team meeting /from 13-10-2024 0900 /to 13-10-2024 1000
-// A description of the expected outcome goes here
+4. **Mark a task as done**
+ ```plaintext
+ mark [task number]
+ ```
+ Example: mark 1
-```
-expected output
-```
+5. **Unmark a task**
+ ```plaintext
+ unmark [task number]
+ ```
+ Example: unmark 1
-## Feature ABC
+6. **Delete a task**
+ ```plaintext
+ delete [task number]
+ ```
+ Example: delete 2
-// Feature details
+7. **List all tasks**
+ ```plaintext
+ list
+ ```
+8. **Find tasks by keyword**
+ ```plaintext
+ find [keyword]
+ ```
+ Example: find groceries
-## Feature XYZ
+9. **Exit the application**
+ ```plaintext
+ bye
+ ```
-// Feature details
\ No newline at end of file
+## Prerequisites
+
+* JDK 17
+* Conglo JAR file (Ensure you have the compiled JAR file to run the application)
+
+## Setup Instructions
+
+1. Download the Conglo JAR file to your local machine.
+2. Open a command prompt or terminal in the directory where the JAR file is located.
+3. Run the application using the following command:
+ ```plaintext
+ java -jar Conglo.jar
+ ```
+4. If the setup is correct, you should see the following output:
+
+ ```plaintext
+ ----------------------------------------------------------
+ Hola! I'm Conglo, the friendly task manager.
+ ----------------------------------------------------------
+ Here's a quick manual to get you started:
+ 1. Add a todo: todo [description]
+ 2. Add a deadline: deadline [description] /by [dd-MM-yyyy HHmm]
+ 3. Add an event: event [description] /from [start time] /to [end time]
+ 4. Mark a task as done: mark [task number]
+ 5. Unmark a task: unmark [task number]
+ 6. Delete a task: delete [task number]
+ 7. List all tasks: list
+ 8. Find matching keyword: find [keyword]
+ 9. Exit the application: bye
+ ----------------------------------------------------------
+ The list is empty!
+ ----------------------------------------------------------
+ ```
diff --git a/src/main/java/Conglo.class b/src/main/java/Conglo.class
new file mode 100644
index 000000000..43955f6cd
Binary files /dev/null and b/src/main/java/Conglo.class 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/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..4faa854c5
--- /dev/null
+++ b/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: conglo.Conglo
+
diff --git a/src/main/java/conglo/Conglo.java b/src/main/java/conglo/Conglo.java
new file mode 100644
index 000000000..2869858fd
--- /dev/null
+++ b/src/main/java/conglo/Conglo.java
@@ -0,0 +1,73 @@
+package conglo;
+
+import conglo.exception.StorageInvalidFormat;
+import conglo.ui.Ui;
+import conglo.exception.CongloException;
+import conglo.storage.Storage;
+import conglo.task.TaskList;
+import conglo.command.Parser;
+
+import java.io.IOException;
+
+/**
+ * Main class for the Conglo chatbot.
+ * Initializes the application, loads tasks, and handles user interactions.
+ */
+public class Conglo {
+
+ private Ui ui;
+ private TaskList taskList;
+ private Storage storage;
+
+ /**
+ * Constructs a Conglo instance with the specified file path for task storage.
+ * Loads existing tasks or initializes a new task list if loading fails.
+ *
+ * @param filePath the file path to load tasks from and save tasks to
+ */
+ public Conglo(String filePath) {
+ ui = new Ui();
+ storage = new Storage(filePath);
+ try {
+ storage.createFileIfNotExists();
+ taskList = new TaskList(storage.loadTasks());
+ } catch (StorageInvalidFormat | IOException e) {
+ ui.displayLoadingError();
+ taskList = new TaskList();
+ }
+ }
+
+ /**
+ * Runs the main loop of the application, processing user input until the 'bye' command is given.
+ */
+ public void run() {
+ ui.greetUser();
+ String input;
+ boolean isQuit = false;
+
+ while (!isQuit) {
+ input = ui.getUserInput();
+ if (input.equals("bye")) {
+ isQuit = true;
+ ui.sayGoodbye();
+ }
+ try {
+ Parser.processCommand(taskList, input);
+ } catch (CongloException e) {
+ System.out.println(e.getMessage());
+ }
+ ui.printLineSeparator();
+ }
+ ui.closeScanner();
+ }
+
+ /**
+ * The main entry point of the Conglo application.
+ * Initializes the application and starts the main run loop.
+ *
+ * @param args command-line arguments
+ */
+ public static void main(String[] args) {
+ new Conglo("./data/conglo.txt").run();
+ }
+}
diff --git a/src/main/java/conglo/command/DateParser.java b/src/main/java/conglo/command/DateParser.java
new file mode 100644
index 000000000..3f4835644
--- /dev/null
+++ b/src/main/java/conglo/command/DateParser.java
@@ -0,0 +1,51 @@
+package conglo.command;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+/**
+ * Utility class for parsing and formatting dates and times.
+ */
+public class DateParser {
+
+ /**
+ * Parses a date and time string into a {@link LocalDateTime} object.
+ * The input string should follow the format "dd-MM-yyyy HHmm", where:
+ *
+ * - dd: Day of the month (e.g., 01 to 31)
+ * - MM: Month of the year (e.g., 01 for January, 12 for December)
+ * - yyyy: Year (e.g., 2023)
+ * - HHmm: Time in 24-hour format (e.g., 2359 for 11:59 PM)
+ *
+ *
+ * @param dateStr The date and time string to be parsed.
+ * @return A {@link LocalDateTime} object representing the parsed date and time.
+ * @throws DateTimeParseException If the input string is not in the correct format.
+ */
+ public static LocalDateTime parseDateTime(String dateStr) throws DateTimeParseException {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HHmm");
+ return LocalDateTime.parse(dateStr, formatter);
+ }
+
+ /**
+ * Formats a {@link LocalDateTime} object into a readable date and time string.
+ * The formatted output will be in the format "d MMM yyyy hh:mm a", where:
+ *
+ * - d MMM yyyy: Day (without leading zero), month abbreviation, and year (e.g., 1 Jan 2023)
+ * - hh:mm a: Time in 12-hour format with AM/PM notation (e.g., 12:30 PM)
+ *
+ *
+ * @param dateTime The {@link LocalDateTime} object to be formatted.
+ * @return A string representing the formatted date and time.
+ */
+ public static String formatDateTime(LocalDateTime dateTime) {
+ DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("d MMM yyyy");
+ DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm a");
+
+ String formattedDate = dateTime.format(dateFormatter);
+ String formattedTime = dateTime.format(timeFormatter);
+
+ return formattedDate + " " + formattedTime;
+ }
+}
diff --git a/src/main/java/conglo/command/Parser.java b/src/main/java/conglo/command/Parser.java
new file mode 100644
index 000000000..6ae8dd592
--- /dev/null
+++ b/src/main/java/conglo/command/Parser.java
@@ -0,0 +1,231 @@
+package conglo.command;
+
+import conglo.exception.CongloException;
+import conglo.exception.InvalidTaskNumber;
+import conglo.exception.InvalidFormat;
+import conglo.exception.MissingDescription;
+import conglo.exception.MissingTaskNumber;
+import conglo.exception.UnknownCommand;
+import conglo.storage.Storage;
+import conglo.task.Deadline;
+import conglo.task.Event;
+import conglo.task.Task;
+import conglo.task.Todo;
+import conglo.task.TaskList;
+import conglo.ui.Ui;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeParseException;
+
+/**
+ * Handles parsing and processing of user commands for task management.
+ */
+public class Parser {
+ private static boolean isDelete = false;
+ private static Ui ui = new Ui();
+
+ private static void saveTasks(TaskList taskList) {
+ Storage.saveTasks(taskList);
+ }
+
+ /**
+ * Displays a message about the added or removed task and the current number of tasks.
+ *
+ * @param taskList The list of tasks.
+ * @param task The task that was added or removed.
+ */
+ public static void echoTask(TaskList taskList, Task task) {
+ int size = taskList.getSize();
+ if (isDelete) {
+ ui.displayRemoved();
+ size--;
+ } else {
+ ui.displayAdded();
+ }
+ String taskSuffix = " task";
+ if (size > 1) {
+ taskSuffix = " tasks";
+ }
+ System.out.println(" " + task.toFileFormat());
+ System.out.println("The list has " + size + taskSuffix + " now.");
+ }
+
+ /**
+ * Displays the current list of tasks.
+ */
+ public static void listTasks() {
+ ui.displayTaskList();
+ }
+
+ /**
+ * Marks a task as done or not done based on user input.
+ *
+ * @param taskList The list of tasks.
+ * @param words The command and task number input by the user.
+ * @throws InvalidTaskNumber If the task number is invalid.
+ */
+ public static void markTask(TaskList taskList, String[] words) throws InvalidTaskNumber {
+ int taskNumber;
+ try {
+ taskNumber = Integer.parseInt(words[1]) - 1;
+ } catch (NumberFormatException e) {
+ System.out.println("Invalid format! Please provide a task number >.<");
+ return;
+ }
+
+ if (taskNumber >= taskList.getSize() || taskNumber < 0) {
+ throw new InvalidTaskNumber();
+ }
+ if (words[0].equals("mark")) {
+ taskList.getTask(taskNumber).markAsDone();
+ System.out.println("Nice! I've marked this task as done:");
+ } else {
+ taskList.getTask(taskNumber).markAsNotDone();
+ System.out.println("OK, I've marked this task as not done yet:");
+ }
+ System.out.println(taskList.getTask(taskNumber).toFileFormat());
+ saveTasks(taskList);
+ }
+
+ /**
+ * Adds a new To-do task to the task list.
+ *
+ * @param taskList The list of tasks.
+ * @param sentence The description of the To-do task.
+ */
+ public static void addTodo(TaskList taskList, String sentence) {
+ Todo todo = new Todo(sentence);
+ taskList.addTask(todo);
+ echoTask(taskList, todo);
+ saveTasks(taskList);
+ }
+
+ /**
+ * Adds a new Deadline task to the task list.
+ *
+ * @param taskList The list of tasks.
+ * @param sentence The description and due date of the Deadline task.
+ * @throws InvalidFormat If the format of the deadline is incorrect.
+ */
+ public static void addDeadline(TaskList taskList, String sentence) throws InvalidFormat {
+ if (!sentence.contains(" /by ")) {
+ throw new InvalidFormat("deadline");
+ }
+ String[] words = sentence.split(" /by ");
+ LocalDateTime dueDate;
+ try {
+ dueDate = DateParser.parseDateTime(words[1]);
+ } catch (DateTimeParseException e) {
+ System.out.println("Invalid date format! Please use the format 'dd-MM-yyyy HHmm'.");
+ return;
+ }
+ String dateTime = DateParser.formatDateTime(dueDate);
+ Deadline deadline = new Deadline(words[0], dateTime);
+ taskList.addTask(deadline);
+ echoTask(taskList, deadline);
+ saveTasks(taskList);
+ }
+
+ /**
+ * Adds a new Event task to the task list.
+ *
+ * @param taskList The list of tasks.
+ * @param sentence The description, start, and end time of the Event task.
+ * @throws InvalidFormat If the format of the event is incorrect.
+ */
+ public static void addEvent(TaskList taskList, String sentence) throws InvalidFormat {
+ if (!sentence.contains(" /from ") || !sentence.contains(" /to ")) {
+ throw new InvalidFormat("event");
+ }
+ String[] words = sentence.split(" /from | /to ");
+ Event event = new Event(words[0], words[1], words[2]);
+ taskList.addTask(event);
+ echoTask(taskList, event);
+ saveTasks(taskList);
+ }
+
+ /**
+ * Deletes a task from the task list based on user input.
+ *
+ * @param taskList The list of tasks.
+ * @param word The task number to delete.
+ * @throws InvalidTaskNumber If the task number is invalid.
+ */
+ public static void deleteTask(TaskList taskList, String word) throws InvalidTaskNumber {
+ int index;
+ try {
+ index = Integer.parseInt(word) - 1;
+ } catch (NumberFormatException e) {
+ System.out.println("Invalid format! Please provide a task number >.<");
+ return;
+ }
+ if (index >= taskList.getSize() || index < 0) {
+ throw new InvalidTaskNumber();
+ }
+ isDelete = true;
+ echoTask(taskList, taskList.getTask(index));
+ taskList.removeTask(index);
+ isDelete = false;
+ saveTasks(taskList);
+ }
+
+ /**
+ * Processes the user command and calls the appropriate methods to handle the command.
+ *
+ * @param taskList The list of tasks.
+ * @param command The user command input.
+ * @throws CongloException If an error occurs while processing the command.
+ */
+ public static void processCommand(TaskList taskList, String command) throws CongloException {
+ String[] words = command.split(" ", 2);
+ switch(words[0]) {
+ case "bye":
+ break;
+ case "list":
+ if (words.length > 1) {
+ throw new InvalidFormat("list");
+ }
+ listTasks();
+ break;
+ case "find":
+ if (words.length == 1 || words[1].isEmpty()) {
+ throw new MissingDescription("find");
+ }
+ ui.displayFoundTasks(words[1]);
+ break;
+ case "unmark":
+ case "mark":
+ if (words.length == 1 || words[1].isEmpty()) {
+ throw new MissingTaskNumber(words[0]);
+ }
+ markTask(taskList, words);
+ break;
+ case "delete":
+ if (words.length == 1 || words[1].isEmpty()) {
+ throw new MissingTaskNumber(words[0]);
+ }
+ deleteTask(taskList, words[1]);
+ break;
+ case "todo":
+ if (words.length == 1 || words[1].isEmpty()) {
+ throw new MissingDescription("Todo");
+ }
+ addTodo(taskList, words[1]);
+ break;
+ case "deadline":
+ if (words.length == 1 || words[1].isEmpty()) {
+ throw new MissingDescription("deadline");
+ }
+ addDeadline(taskList, words[1]);
+ break;
+ case "event":
+ if (words.length == 1 || words[1].isEmpty()) {
+ throw new MissingDescription("event");
+ }
+ addEvent(taskList, words[1]);
+ break;
+ default:
+ throw new UnknownCommand();
+ }
+ }
+}
diff --git a/src/main/java/conglo/exception/CongloException.java b/src/main/java/conglo/exception/CongloException.java
new file mode 100644
index 000000000..90ec73a92
--- /dev/null
+++ b/src/main/java/conglo/exception/CongloException.java
@@ -0,0 +1,14 @@
+package conglo.exception;
+
+/**
+ * Represents a custom exception for errors specific to the Conglo application.
+ */
+public class CongloException extends Exception {
+
+ /**
+ * Constructs a new CongloException with the specified detail message.
+ */
+ public CongloException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/conglo/exception/InvalidFormat.java b/src/main/java/conglo/exception/InvalidFormat.java
new file mode 100644
index 000000000..2873581fc
--- /dev/null
+++ b/src/main/java/conglo/exception/InvalidFormat.java
@@ -0,0 +1,40 @@
+package conglo.exception;
+
+/**
+ * Represents an exception thrown when a user inputs a command in an incorrect format.
+ */
+public class InvalidFormat extends CongloException {
+
+ /**
+ * Constructs a new InvalidFormat exception with a specific error message
+ * based on the type of command that was formatted incorrectly.
+ *
+ * @param type the type of command that was incorrectly formatted
+ */
+ public InvalidFormat(String type) {
+ super(generateMessage(type));
+ }
+
+ /**
+ * Generates a error message based on the type of the incorrectly
+ * formatted command.
+ *
+ * @param type The type of command.
+ * @return a string containing the error message suggesting the correct format.
+ */
+ private static String generateMessage(String type) {
+ switch (type) {
+ case "list":
+ return "Do you mean 'list'?";
+ case "deadline":
+ return "Oh dear, your deadline command is a bit off."
+ + System.lineSeparator() + "Please use: deadline [description] /by [deadline].";
+ case "event":
+ return "Oh no! Your event command needs a bit of tweaking."
+ + System.lineSeparator() + "Try: event [description] /from [start time] /to [end time].";
+ default:
+ return "Oops! Looks like there's a hiccup in your command."
+ + System.lineSeparator() + "Please follow the correct format.";
+ }
+ }
+}
diff --git a/src/main/java/conglo/exception/InvalidTaskNumber.java b/src/main/java/conglo/exception/InvalidTaskNumber.java
new file mode 100644
index 000000000..ce251cdb6
--- /dev/null
+++ b/src/main/java/conglo/exception/InvalidTaskNumber.java
@@ -0,0 +1,16 @@
+package conglo.exception;
+
+/**
+ * Represents an exception thrown when the user provides an invalid task number,
+ * such as when the task number is out of range or improperly formatted.
+ */
+public class InvalidTaskNumber extends CongloException {
+
+ /**
+ * Constructs a new InvalidTaskNumber exception with a default error message
+ * indicating that the task number is invalid.
+ */
+ public InvalidTaskNumber() {
+ super("Invalid task number! Please try again.");
+ }
+}
diff --git a/src/main/java/conglo/exception/MissingDescription.java b/src/main/java/conglo/exception/MissingDescription.java
new file mode 100644
index 000000000..75d0b5f3e
--- /dev/null
+++ b/src/main/java/conglo/exception/MissingDescription.java
@@ -0,0 +1,18 @@
+package conglo.exception;
+
+/**
+ * Represents an exception thrown when a required description is missing
+ * from the user's input, such as when adding a task without specifying details.
+ */
+public class MissingDescription extends CongloException {
+
+ /**
+ * Constructs a new MissingDescription exception with an error message
+ * that indicates the type of task that is missing a description.
+ *
+ * @param type The type of task or command missing a description.
+ */
+ public MissingDescription(String type) {
+ super("Oopsies, please add a description of " + type + ".");
+ }
+}
diff --git a/src/main/java/conglo/exception/MissingTaskNumber.java b/src/main/java/conglo/exception/MissingTaskNumber.java
new file mode 100644
index 000000000..b38a8f766
--- /dev/null
+++ b/src/main/java/conglo/exception/MissingTaskNumber.java
@@ -0,0 +1,18 @@
+package conglo.exception;
+
+/**
+ * Represents an exception thrown when a task number is missing from the user's input,
+ * particularly when attempting to mark, unmark, or delete a task.
+ */
+public class MissingTaskNumber extends CongloException {
+
+ /**
+ * Constructs a new MissingTaskNumber exception with an error message that
+ * indicates the action that requires a task number.
+ *
+ * @param action The action being performed that requires a task number.
+ */
+ public MissingTaskNumber(String action) {
+ super("Please provide task number to " + action + ".");
+ }
+}
diff --git a/src/main/java/conglo/exception/StorageInvalidFormat.java b/src/main/java/conglo/exception/StorageInvalidFormat.java
new file mode 100644
index 000000000..610b018dc
--- /dev/null
+++ b/src/main/java/conglo/exception/StorageInvalidFormat.java
@@ -0,0 +1,16 @@
+package conglo.exception;
+
+/**
+ * Represents an exception thrown when the storage file contains an invalid task format.
+ */
+public class StorageInvalidFormat extends CongloException {
+
+ /**
+ * Constructs a StorageInvalidFormat exception with the specified invalid line.
+ *
+ * @param line The line from the storage file that contains an invalid task format.
+ */
+ public StorageInvalidFormat(String line) {
+ super("Invalid task format: " + line);
+ }
+}
diff --git a/src/main/java/conglo/exception/UnknownCommand.java b/src/main/java/conglo/exception/UnknownCommand.java
new file mode 100644
index 000000000..428d66352
--- /dev/null
+++ b/src/main/java/conglo/exception/UnknownCommand.java
@@ -0,0 +1,14 @@
+package conglo.exception;
+
+/**
+ * Represents an exception thrown when a user inputs an unrecognized command.
+ */
+public class UnknownCommand extends CongloException {
+
+ /**
+ * Constructs an UnknownCommand exception with a message.
+ */
+ public UnknownCommand() {
+ super("Sorry, I'm not smart enough to understand what you mean.");
+ }
+}
diff --git a/src/main/java/conglo/storage/Storage.java b/src/main/java/conglo/storage/Storage.java
new file mode 100644
index 000000000..1ed860aff
--- /dev/null
+++ b/src/main/java/conglo/storage/Storage.java
@@ -0,0 +1,148 @@
+package conglo.storage;
+
+import conglo.task.Task;
+import conglo.task.TaskList;
+import conglo.task.Todo;
+import conglo.task.Deadline;
+import conglo.task.Event;
+import conglo.exception.StorageInvalidFormat;
+
+import java.io.BufferedWriter;
+import java.io.FileNotFoundException;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+/**
+ * Handles loading and saving tasks from a file to provide persistent storage.
+ */
+public class Storage {
+
+ private static String filePath;
+
+ /**
+ * Initializes the storage with the specified file path.
+ *
+ * @param filePath The path of the file to load and save tasks.
+ */
+ public Storage(String filePath) {
+ Storage.filePath = filePath;
+ }
+
+ /**
+ * Loads tasks from the storage file and returns them as an ArrayList.
+ *
+ * @return an ArrayList of tasks loaded from the file.
+ * @throws StorageInvalidFormat If the file format is invalid.
+ * @throws FileNotFoundException If the specified file does not exist.
+ */
+ public ArrayList loadTasks() throws StorageInvalidFormat, FileNotFoundException {
+ ArrayList tasks = new ArrayList<>();
+ try {
+ File file = new File(filePath);
+ if (!file.exists()) {
+ throw new FileNotFoundException(filePath);
+ }
+ Scanner scanner = new Scanner(file);
+ while (scanner.hasNext()) {
+ String line = scanner.nextLine();
+ String[] parts = line.split(" \\| ");
+
+ if (parts.length < 3) {
+ throw new StorageInvalidFormat(line);
+ }
+
+ String type = parts[0];
+ boolean isDone = parts[1].equals("1");
+ String description = parts[2];
+
+ Task task = null;
+ switch (type) {
+ case "T":
+ task = new Todo(description);
+ break;
+ case "D":
+ validatePartsLength(parts, line);
+ String deadlineTime = parts[3].substring(3);
+ task = new Deadline(description, deadlineTime);
+ break;
+ case "E":
+ validatePartsLength(parts, line);
+ String[] details = extractEventDetails(parts[3]);
+ task = new Event(description, details[0], details[1]);
+ break;
+ }
+ if (task != null && isDone) {
+ task.markAsDone();
+ }
+ tasks.add(task);
+ }
+ scanner.close();
+ } catch (IOException e) {
+ System.out.println("Error loading tasks: " + e.getMessage());
+ }
+ return tasks;
+ }
+
+ /**
+ * Validates if the parts array has the required length.
+ * Throws StorageInvalidFormat if invalid.
+ *
+ * @param parts The array of string parts.
+ * @param line The original line for the error message.
+ * @throws StorageInvalidFormat if the length is insufficient.
+ */
+ private void validatePartsLength(String[] parts, String line) throws StorageInvalidFormat {
+ if (parts.length < 4) {
+ throw new StorageInvalidFormat(line);
+ }
+ }
+
+ /**
+ * Extracts the event details (start and end time) from the event part string.
+ *
+ * @param eventPart The string containing the event times (from-to format).
+ * @return A String array containing the start and end times.
+ */
+ private String[] extractEventDetails(String eventPart) {
+ String[] details = eventPart.split(" to ");
+ details[0] = details[0].substring(5); // Clean start time
+ return details;
+ }
+
+ /**
+ * Saves the current list of tasks to the storage file.
+ *
+ * @param taskList The TaskList object containing the tasks to be saved.
+ */
+ public static void saveTasks(TaskList taskList) {
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
+ for (Task task : taskList.getTaskList()) {
+ writer.write(task.toFileFormat());
+ writer.newLine();
+ }
+ } catch (IOException e) {
+ System.out.println("Error saving tasks: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Ensures that a file at the specified path exists.
+ * If the file does not exist, it will be created.
+ * If the parent directory does not exist, it will be created as well.
+ *
+ * @throws IOException if an I/O error occurs while creating the file or directory.
+ */
+ public void createFileIfNotExists() throws IOException {
+ File file = new File(filePath);
+ if (!file.exists()) {
+ File parentDir = file.getParentFile();
+ if (parentDir != null && !parentDir.exists()) {
+ parentDir.mkdirs();
+ }
+ file.createNewFile();
+ }
+ }
+}
diff --git a/src/main/java/conglo/task/Deadline.java b/src/main/java/conglo/task/Deadline.java
new file mode 100644
index 000000000..06b838cf0
--- /dev/null
+++ b/src/main/java/conglo/task/Deadline.java
@@ -0,0 +1,37 @@
+package conglo.task;
+
+/**
+ * Represents a deadline task with a description and a deadline date.
+ */
+public class Deadline extends Task {
+
+ protected String by;
+
+ public Deadline(String description, String by) {
+ super(description);
+ this.by = by;
+ }
+
+ @Override
+ protected String getTaskType() {
+ return "D";
+ }
+
+ /**
+ * Returns a formatted string of the details for this task.
+ *
+ * @return A string representing the deadline for the task.
+ */
+ protected String getFormattedDetails() {
+ return "by " + by;
+ }
+
+ @Override
+ public String toFileFormat() {
+ return String.format("%s | %s | %s | %s",
+ getTaskType(),
+ getStatusIcon(),
+ getDescription(),
+ getFormattedDetails());
+ }
+}
diff --git a/src/main/java/conglo/task/Event.java b/src/main/java/conglo/task/Event.java
new file mode 100644
index 000000000..9e6ab767e
--- /dev/null
+++ b/src/main/java/conglo/task/Event.java
@@ -0,0 +1,57 @@
+package conglo.task;
+
+/**
+ * Represents an event task with a description, start date, and end date.
+ */
+public class Event extends Task {
+
+ protected String start;
+ protected String end;
+
+ /**
+ * Constructs an Event task with the specified description, start date, and end date.
+ *
+ * @param description The description of the event.
+ * @param start The start date of the event.
+ * @param end The end date of the event.
+ */
+ public Event(String description, String start, String end) {
+ super(description);
+ this.start = start;
+ this.end = end;
+ }
+
+ public String getStart() {
+ return start;
+ }
+
+ public String getEnd() {
+ return end;
+ }
+
+ @Override
+ protected String getTaskType() {
+ return "E";
+ }
+
+ /**
+ * Returns a string representation of the Event task.
+ * The format includes a label for events, the task's completion status,
+ * description, and the start and end dates of the event.
+ *
+ * @return A string representation of the Event task.
+ */
+ protected String getFormattedDetails() {
+ return "from " + start + " to " + end;
+ }
+
+ @Override
+ public String toFileFormat() {
+ return String.format("%s | %s | %s | from %s to %s",
+ getTaskType(),
+ getStatusIcon(),
+ getDescription(),
+ getStart(),
+ getEnd());
+ }
+}
diff --git a/src/main/java/conglo/task/Task.java b/src/main/java/conglo/task/Task.java
new file mode 100644
index 000000000..6b2b0cea5
--- /dev/null
+++ b/src/main/java/conglo/task/Task.java
@@ -0,0 +1,70 @@
+package conglo.task;
+
+/**
+ * Represents a task with a description and a completion status.
+ */
+public abstract 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 Description of the task to be created.
+ */
+ public Task(String description) {
+ this.description = description;
+ this.isDone = false;
+ }
+
+ /**
+ * Returns a status icon representing the task's completion status.
+ * "1" indicates that the task is done; "0" indicates it is not done.
+ *
+ * @return A status icon ("1" if done, otherwise "0").
+ */
+ public String getStatusIcon() {
+ if (isDone) {
+ return "1";
+ }
+ return "0";
+ }
+
+ /**
+ * Marks the task as done.
+ */
+ public void markAsDone() {
+ isDone = true;
+ }
+
+ /**
+ * Marks the task as not done.
+ */
+ public void markAsNotDone() {
+ isDone = false;
+ }
+
+ /**
+ * Returns the description of the task.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Returns the string representation of the task in a file format.
+ */
+ public abstract String toFileFormat();
+
+ /**
+ * Returns the type of the task.
+ */
+ protected abstract String getTaskType();
+
+ /**
+ * Returns the formatted details of the task.
+ */
+ protected abstract String getFormattedDetails();
+
+}
diff --git a/src/main/java/conglo/task/TaskList.java b/src/main/java/conglo/task/TaskList.java
new file mode 100644
index 000000000..8fb56a6b1
--- /dev/null
+++ b/src/main/java/conglo/task/TaskList.java
@@ -0,0 +1,95 @@
+package conglo.task;
+
+import java.util.ArrayList;
+
+/**
+ * Represents a list of tasks.
+ */
+public class TaskList {
+ private static ArrayList taskList;
+
+ /**
+ * Constructs a TaskList with the specified list of tasks.
+ *
+ * @param tasks The initial list of tasks.
+ */
+ public TaskList(ArrayList tasks) {
+ taskList = tasks;
+ }
+
+ /**
+ * Default constructor for an empty task list.
+ * Initializes the task list with an empty list.
+ */
+ public TaskList() {
+ taskList = new ArrayList<>();
+ }
+
+ /**
+ * Checks if the task list is empty.
+ */
+ public static boolean isEmpty() {
+ return taskList.isEmpty();
+ }
+
+ /**
+ * Adds a task to the task list.
+ *
+ * @param task The task to be added.
+ */
+ public void addTask(Task task) {
+ taskList.add(task);
+ }
+
+ /**
+ * Removes a task from the task list at the specified index.
+ *
+ * @param index The index of the task to be removed.
+ */
+ public void removeTask(int index) {
+ taskList.remove(index);
+ }
+
+ /**
+ * Retrieves the task at the specified index.
+ *
+ * @param index The index of the task to retrieve.
+ * @return The task at the specified index.
+ */
+ public Task getTask(int index) {
+ return taskList.get(index);
+ }
+
+ /**
+ * Returns the number of tasks in the list.
+ */
+ public int getSize() {
+ return taskList.size();
+ }
+
+ /**
+ * Returns the list of tasks.
+ */
+ public ArrayList getTaskList() {
+ return taskList;
+ }
+
+ /**
+ * Lists all tasks in the task list, printing their details.
+ */
+ public static void listTasks() {
+ for (int i = 0; i < taskList.size(); i++) {
+ System.out.println((i + 1) + ". " + taskList.get(i).toFileFormat());
+ }
+ }
+
+ public static ArrayList findTasks(String keyword) {
+ ArrayList matchingTasks = new ArrayList<>();
+ for (Task task : taskList) {
+ if (task.getDescription().toLowerCase().contains(keyword.toLowerCase())) {
+ matchingTasks.add(task);
+ }
+ }
+ return matchingTasks;
+ }
+}
diff --git a/src/main/java/conglo/task/Todo.java b/src/main/java/conglo/task/Todo.java
new file mode 100644
index 000000000..1cb00f5f5
--- /dev/null
+++ b/src/main/java/conglo/task/Todo.java
@@ -0,0 +1,34 @@
+package conglo.task;
+
+/**
+ * Represents a To-do task with a description.
+ */
+public class Todo extends Task {
+
+ /**
+ * Constructs a To-do task with the specified description.
+ *
+ * @param description The description of the to-do task.
+ */
+ public Todo(String description) {
+ super(description);
+ }
+
+ @Override
+ protected String getTaskType() {
+ return "T";
+ }
+
+ @Override
+ protected String getFormattedDetails() {
+ return "";
+ }
+
+ @Override
+ public String toFileFormat() {
+ return String.format("%s | %s | %s",
+ getTaskType(),
+ getStatusIcon(),
+ getDescription());
+ }
+}
diff --git a/src/main/java/conglo/ui/Manual.java b/src/main/java/conglo/ui/Manual.java
new file mode 100644
index 000000000..604419d77
--- /dev/null
+++ b/src/main/java/conglo/ui/Manual.java
@@ -0,0 +1,29 @@
+package conglo.ui;
+
+/**
+ * Provides a manual with basic instructions for using the Conglo application.
+ */
+public class Manual {
+
+ /**
+ * Prints a quick manual of instructions for the Conglo application.
+ */
+ public static void printManual() {
+ String[] manual = {
+ "Here's a quick manual to get you started:",
+ "1. Add a todo: todo [description]",
+ "2. Add a deadline: deadline [description] /by [dd-MM-yyyy HHmm]",
+ "3. Add an event: event [description] /from [start time] /to [end time]",
+ "4. Mark a task as done: mark [task number]",
+ "5. Unmark a task: unmark [task number]",
+ "6. Delete a task: delete [task number]",
+ "7. List all tasks: list",
+ "8. Find matching keyword: find [keyword]",
+ "9. Exit the application: bye"
+ };
+
+ for (String line : manual) {
+ System.out.println(line);
+ }
+ }
+}
diff --git a/src/main/java/conglo/ui/Ui.java b/src/main/java/conglo/ui/Ui.java
new file mode 100644
index 000000000..930f34743
--- /dev/null
+++ b/src/main/java/conglo/ui/Ui.java
@@ -0,0 +1,132 @@
+package conglo.ui;
+
+import conglo.task.Task;
+import conglo.task.TaskList;
+
+import java.util.ArrayList;
+import java.util.Scanner;
+
+/**
+ * Handles user interactions for task managing.
+ */
+public class Ui {
+
+ private static final String LINE_SEPARATOR = "-----------------------------" +
+ "-----------------------------";
+ private Scanner scanner;
+
+ /**
+ * Constructs a Ui object, initializing the scanner for user input.
+ */
+ public Ui() {
+ this.scanner = new Scanner(System.in);
+ }
+
+ /**
+ * Retrieves user input from the console.
+ *
+ * @return The input string from the user.
+ */
+ public String getUserInput() {
+ return scanner.nextLine();
+ }
+
+ /**
+ * Prints a line separator to the console.
+ */
+ public void printLineSeparator() {
+ printText(LINE_SEPARATOR);
+ }
+
+ /**
+ * Greets the user and displays the manual.
+ */
+ public void greetUser() {
+ printLineSeparator();
+ printText("Hola! I'm Conglo, the friendly task manager.");
+ printLineSeparator();
+ Manual.printManual();
+ printLineSeparator();
+ displayTaskList();
+ printLineSeparator();
+ }
+
+ /**
+ * Displays a message indicating that a task has been removed.
+ */
+ public void displayRemoved() {
+ printText("Okie! Task is removed from list:");
+ }
+
+ /**
+ * Displays a message indicating that a task has been added.
+ */
+ public void displayAdded() {
+ printText("All done! Task added to list:");
+ }
+
+ /**
+ * Displays a message indicating that the task list is empty.
+ */
+ public void displayEmptyList() {
+ printText("The list is empty!");
+ }
+
+ /**
+ * Displays the current task list.
+ * If the list is empty, it shows a corresponding message.
+ */
+ public void displayTaskList() {
+ if (TaskList.isEmpty()) {
+ displayEmptyList();
+ } else {
+ printText("Here are your tasks:");
+ TaskList.listTasks();
+ }
+ }
+
+ /**
+ * Displays tasks with matching keyword that user provided.
+ *
+ * @param keyword Used to match words in descriptions.
+ */
+ public void displayFoundTasks(String keyword) {
+ ArrayList matchingTasks = TaskList.findTasks(keyword);
+ if (matchingTasks.isEmpty()) {
+ System.out.println("No task matches the keyword :(");
+ } else {
+ System.out.println("Tasks matched in your list:");
+ for (int i = 0; i < matchingTasks.size(); i++) {
+ System.out.println((i + 1) + ". " + matchingTasks.get(i).toFileFormat());
+ }
+ }
+ }
+
+ /**
+ * Displays an error message when there is an issue loading tasks.
+ */
+ public void displayLoadingError() {
+ printText("Oops! There was an error loading your tasks. Please try again.");
+ }
+
+ /**
+ * Displays a goodbye message to the user.
+ */
+ public void sayGoodbye() {
+ printText("Goodbye. See you next time!");
+ }
+
+ /**
+ * Prints a specified message to the console.
+ */
+ public void printText(String message) {
+ System.out.println(message);
+ }
+
+ /**
+ * Closes the scanner to prevent resource leaks.
+ */
+ public void closeScanner() {
+ scanner.close();
+ }
+}
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e..e27a53d88 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,103 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
-
+----------------------------------------------------------
+Hola! I'm Conglo, the friendly task manager.
+----------------------------------------------------------
+Here's a quick manual to get you started:
+1. Add a todo: todo [description]
+2. Add a deadline: deadline [description] /by [dd-MM-yyyy HHmm]
+3. Add an event: event [description] /from [start time] /to [end time]
+4. Mark a task as done: mark [task number]
+5. Unmark a task: unmark [task number]
+6. Delete a task: delete [task number]
+7. List all tasks: list
+8. Find matching keyword: find [keyword]
+9. Exit the application: bye
+----------------------------------------------------------
+The list is empty!
+----------------------------------------------------------
+All done! Task added to list:
+ T | 0 | read
+The list has 1 task now.
+----------------------------------------------------------
+All done! Task added to list:
+ D | 0 | assignment | by 20 Jul 2024 02:15 pm
+The list has 2 tasks now.
+----------------------------------------------------------
+Nice! I've marked this task as done:
+T | 1 | read
+----------------------------------------------------------
+All done! Task added to list:
+ E | 0 | presentation | from Thurs 10am to 12pm
+The list has 3 tasks now.
+----------------------------------------------------------
+Here are your tasks:
+1. T | 1 | read
+2. D | 0 | assignment | by 20 Jul 2024 02:15 pm
+3. E | 0 | presentation | from Thurs 10am to 12pm
+----------------------------------------------------------
+Nice! I've marked this task as done:
+D | 1 | assignment | by 20 Jul 2024 02:15 pm
+----------------------------------------------------------
+OK, I've marked this task as not done yet:
+T | 0 | read
+----------------------------------------------------------
+Here are your tasks:
+1. T | 0 | read
+2. D | 1 | assignment | by 20 Jul 2024 02:15 pm
+3. E | 0 | presentation | from Thurs 10am to 12pm
+----------------------------------------------------------
+All done! Task added to list:
+ T | 0 | cs2113 assignment
+The list has 4 tasks now.
+----------------------------------------------------------
+Tasks matched in your list:
+1. D | 1 | assignment | by 20 Jul 2024 02:15 pm
+2. T | 0 | cs2113 assignment
+----------------------------------------------------------
+Tasks matched in your list:
+1. E | 0 | presentation | from Thurs 10am to 12pm
+----------------------------------------------------------
+Okie! Task is removed from list:
+ T | 0 | read
+The list has 3 tasks now.
+----------------------------------------------------------
+Okie! Task is removed from list:
+ T | 0 | cs2113 assignment
+The list has 2 tasks now.
+----------------------------------------------------------
+Okie! Task is removed from list:
+ E | 0 | presentation | from Thurs 10am to 12pm
+The list has 1 task now.
+----------------------------------------------------------
+Okie! Task is removed from list:
+ D | 1 | assignment | by 20 Jul 2024 02:15 pm
+The list has 0 task now.
+----------------------------------------------------------
+The list is empty!
+----------------------------------------------------------
+Oopsies, please add a description of Todo.
+----------------------------------------------------------
+Oopsies, please add a description of event.
+----------------------------------------------------------
+Oopsies, please add a description of deadline.
+----------------------------------------------------------
+Oh dear, your deadline command is a bit off.
+Please use: deadline [description] /by [deadline].
+----------------------------------------------------------
+Oh no! Your event command needs a bit of tweaking.
+Try: event [description] /from [start time] /to [end time].
+----------------------------------------------------------
+Oh no! Your event command needs a bit of tweaking.
+Try: event [description] /from [start time] /to [end time].
+----------------------------------------------------------
+Do you mean 'list'?
+----------------------------------------------------------
+Please provide task number to unmark.
+----------------------------------------------------------
+Please provide task number to mark.
+----------------------------------------------------------
+Please provide task number to delete.
+----------------------------------------------------------
+Sorry, I'm not smart enough to understand what you mean.
+----------------------------------------------------------
+Goodbye. See you next time!
+----------------------------------------------------------
diff --git a/text-ui-test/data/conglo.txt b/text-ui-test/data/conglo.txt
new file mode 100644
index 000000000..e69de29bb
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb..61591e377 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,28 @@
+todo read
+deadline assignment /by 20-07-2024 1415
+mark 1
+event presentation /from Thurs 10am /to 12pm
+list
+mark 2
+unmark 1
+list
+todo cs2113 assignment
+find assignment
+find presentation
+delete 1
+delete 3
+delete 2
+delete 1
+list
+todo
+event
+deadline
+deadline cook
+event career fair
+event exam /from 7 oct
+list all
+unmark
+mark
+delete
+haha
+bye
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
index 087374464..893146605 100644
--- a/text-ui-test/runtest.bat
+++ b/text-ui-test/runtest.bat
@@ -7,7 +7,7 @@ REM delete output from previous run
if exist ACTUAL.TXT del ACTUAL.TXT
REM compile the code into the bin folder
-javac -cp ..\src\main\java -Xlint:none -d ..\bin ..\src\main\java\*.java
+javac -cp ..\src\main\java -Xlint:none -d ..\bin ..\src\main\java\conglo\Conglo.java
IF ERRORLEVEL 1 (
echo ********** BUILD FAILURE **********
exit /b 1
@@ -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 conglo.Conglo < input.txt > ACTUAL.TXT
REM compare the output to the expected output
FC ACTUAL.TXT EXPECTED.TXT