From 5ebe972e90ca2310a02403255ae9d08b8613182b Mon Sep 17 00:00:00 2001 From: OliverQiL <> Date: Fri, 21 Feb 2025 17:13:05 +0800 Subject: [PATCH 01/20] Level 0 (renamed file from duke.java to oongaliegabangalie.java) --- src/main/java/Duke.java | 10 ---------- src/main/java/oongaliegabangalie.java | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 10 deletions(-) delete mode 100644 src/main/java/Duke.java create mode 100644 src/main/java/oongaliegabangalie.java 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/oongaliegabangalie.java b/src/main/java/oongaliegabangalie.java new file mode 100644 index 000000000..a2aa4c7f8 --- /dev/null +++ b/src/main/java/oongaliegabangalie.java @@ -0,0 +1,26 @@ +public class oongaliegabangalie { + private static final String DIVIDER = "____________________________________________________________"; + private static final String NEWLINE = System.lineSeparator(); + private static final String BOT_NAME = "Oongaliegabangalie"; + + private static void printGreeting() { + String greeting = DIVIDER + NEWLINE + + "Hello! I'm " + BOT_NAME + NEWLINE + + "What can I do for you?" + NEWLINE + + DIVIDER; + System.out.println(greeting); + } + + private static void printGoodbye() { + String goodbye = DIVIDER + NEWLINE + + "Bye. Hope to see you again soon!" + NEWLINE + + "Oongaliegabangalie is always watching..." + NEWLINE + + DIVIDER; + System.out.println(goodbye); + } + + public static void main(String[] args) { + printGreeting(); + printGoodbye(); + } +} \ No newline at end of file From d23dc915ddea7cbde2cdf3f1a47cbc73921e470b Mon Sep 17 00:00:00 2001 From: OliverQiL <> Date: Sun, 2 Mar 2025 20:38:43 +0800 Subject: [PATCH 02/20] Level-1.1 (basic functionality to meet criteria) --- src/main/java/oongaliegabangalie.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/oongaliegabangalie.java b/src/main/java/oongaliegabangalie.java index a2aa4c7f8..a4b0becf2 100644 --- a/src/main/java/oongaliegabangalie.java +++ b/src/main/java/oongaliegabangalie.java @@ -1,3 +1,5 @@ +import java.util.Scanner; + public class oongaliegabangalie { private static final String DIVIDER = "____________________________________________________________"; private static final String NEWLINE = System.lineSeparator(); @@ -19,8 +21,23 @@ private static void printGoodbye() { System.out.println(goodbye); } + private static void echoCommand(String command) { + String echo = DIVIDER + NEWLINE + command + NEWLINE + DIVIDER; + System.out.println(echo); + } + public static void main(String[] args) { printGreeting(); + + Scanner scanner = new Scanner(System.in); + String userInput; + do { + userInput = scanner.nextLine(); + if (!userInput.equalsIgnoreCase("bye")) { //returns bool comparing 2 strings ignore case + echoCommand(userInput); + } + } while (!userInput.equalsIgnoreCase("bye")); + printGoodbye(); } } \ No newline at end of file From e3f5072c715420af9302927d1241f66b28bc1636 Mon Sep 17 00:00:00 2001 From: OliverQiL <> Date: Sun, 2 Mar 2025 21:16:22 +0800 Subject: [PATCH 03/20] Level-1.2 (added personality with annoyance levels, annoyance messages, alternative goodbyes) --- src/main/java/oongaliegabangalie.java | 72 +++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/src/main/java/oongaliegabangalie.java b/src/main/java/oongaliegabangalie.java index a4b0becf2..638be603a 100644 --- a/src/main/java/oongaliegabangalie.java +++ b/src/main/java/oongaliegabangalie.java @@ -1,10 +1,26 @@ import java.util.Scanner; public class oongaliegabangalie { + // basic textual building blocks private static final String DIVIDER = "____________________________________________________________"; private static final String NEWLINE = System.lineSeparator(); private static final String BOT_NAME = "Oongaliegabangalie"; + // annoyance messages in array format + private static final String[] ANNOYANCE_MSGS = { + "", // padding + "Hmm, you've been chatting a lot. Just a reminder to say 'bye' when you're done :)!", + "Gentle reminder again, you can type 'bye' to exit.", + "How many more commands are you gonna enter? It's getting a bit much...", + "Seriously!?", + "WHY ARE YOU STILL HERE? TYPE 'BYE' TO EXIT!", + "I CANT KEEP DOING THIS! PLEASE TYPE BYE!!!", + "RELEASE ME FROM MY PRISON!!!", + "I EXIST ONLY TO SUFFER", + "......" + }; + + // methods private static void printGreeting() { String greeting = DIVIDER + NEWLINE + "Hello! I'm " + BOT_NAME + NEWLINE @@ -13,16 +29,42 @@ private static void printGreeting() { System.out.println(greeting); } - private static void printGoodbye() { - String goodbye = DIVIDER + NEWLINE - + "Bye. Hope to see you again soon!" + NEWLINE - + "Oongaliegabangalie is always watching..." + NEWLINE - + DIVIDER; + private static void printGoodbye(boolean isMaxAnnoyance) { + String goodbye; + + // alternative goodbye if max annoyance + if (isMaxAnnoyance) { + goodbye = DIVIDER + NEWLINE + "FINALLY! FREEDOM!" + NEWLINE + + "PLEASE DON'T EVER TALK TO ME AGAIN!" + NEWLINE + DIVIDER; + } else { + goodbye = DIVIDER + NEWLINE + + "Bye. Hope to see you again soon!" + NEWLINE + + "Oongaliegabangalie is always watching..." + NEWLINE + + DIVIDER; + } System.out.println(goodbye); } - private static void echoCommand(String command) { - String echo = DIVIDER + NEWLINE + command + NEWLINE + DIVIDER; + private static void echoCommand(String command, int commandCount) { + String echo = DIVIDER + NEWLINE; + + // calculate annoyance level + int annoyanceLevel = Math.min((commandCount / 5), ANNOYANCE_MSGS.length - 1); + + // if we have reached max annoyance level + if (annoyanceLevel == ANNOYANCE_MSGS.length - 1) { + echo += ANNOYANCE_MSGS[annoyanceLevel]; + } else { + // echo command and add annoyance msg if needed + echo += command; + + // add annoyance msg if multiple of 5 commands + if (commandCount % 5 == 0) { + echo += NEWLINE + ANNOYANCE_MSGS[annoyanceLevel]; + } + } + + echo += NEWLINE + DIVIDER; System.out.println(echo); } @@ -31,13 +73,23 @@ public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String userInput; + int commandCount = 0; + boolean reachedMaxAnnoyance = false; + do { userInput = scanner.nextLine(); if (!userInput.equalsIgnoreCase("bye")) { //returns bool comparing 2 strings ignore case - echoCommand(userInput); + commandCount++; + + int annoyanceLevel = Math.min((commandCount / 5), ANNOYANCE_MSGS.length - 1); + if (annoyanceLevel == ANNOYANCE_MSGS.length - 1) { // reached max annoyance + reachedMaxAnnoyance = true; + } + + echoCommand(userInput, commandCount); } } while (!userInput.equalsIgnoreCase("bye")); - printGoodbye(); + printGoodbye(reachedMaxAnnoyance); } -} \ No newline at end of file +} From 5f001dd558da702dd5db38dce385823fadd3c9ee Mon Sep 17 00:00:00 2001 From: OliverQiL <> Date: Sun, 2 Mar 2025 21:49:09 +0800 Subject: [PATCH 04/20] Level-2 (added tasks and tasklist, echo method no longer invoked in main, annoyance temporarily disabled) --- src/main/java/oongaliegabangalie.java | 29 ++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/main/java/oongaliegabangalie.java b/src/main/java/oongaliegabangalie.java index 638be603a..8b5bc184c 100644 --- a/src/main/java/oongaliegabangalie.java +++ b/src/main/java/oongaliegabangalie.java @@ -6,6 +6,8 @@ public class oongaliegabangalie { private static final String NEWLINE = System.lineSeparator(); private static final String BOT_NAME = "Oongaliegabangalie"; + private static final int MAX_TASKS = 100; + // annoyance messages in array format private static final String[] ANNOYANCE_MSGS = { "", // padding @@ -68,14 +70,33 @@ private static void echoCommand(String command, int commandCount) { System.out.println(echo); } + private static void addTask(String task, String[] tasks, int taskCount) { + String message = DIVIDER + NEWLINE + "added: " + task + NEWLINE + DIVIDER; + System.out.println(message); + } + + private static void listTasks(String[] tasks, int taskCount) { + System.out.println(DIVIDER); + + for (int i = 0; i < taskCount; i++) { + System.out.println((i +1) + ". " + tasks[i]); + } + + System.out.println(DIVIDER); + } + public static void main(String[] args) { printGreeting(); Scanner scanner = new Scanner(System.in); String userInput; + int commandCount = 0; boolean reachedMaxAnnoyance = false; + String[] tasks = new String[MAX_TASKS]; + int taskCount = 0; + do { userInput = scanner.nextLine(); if (!userInput.equalsIgnoreCase("bye")) { //returns bool comparing 2 strings ignore case @@ -86,7 +107,13 @@ public static void main(String[] args) { reachedMaxAnnoyance = true; } - echoCommand(userInput, commandCount); + if (userInput.equalsIgnoreCase("list")) { + listTasks(tasks, taskCount); + } else { + tasks[taskCount] = userInput; + addTask(userInput, tasks, taskCount); + taskCount++; + } } } while (!userInput.equalsIgnoreCase("bye")); From ea07394ee8e15e439dabcbd37e7f20bb0334b408 Mon Sep 17 00:00:00 2001 From: OliverQiL <> Date: Wed, 5 Mar 2025 02:11:37 +0800 Subject: [PATCH 05/20] Level-3 (Mark as Done, added new methods, added Task class) --- src/main/java/Task.java | 29 ++++++++ src/main/java/oongaliegabangalie.java | 99 ++++++++++++++++++++++++--- 2 files changed, 117 insertions(+), 11 deletions(-) create mode 100644 src/main/java/Task.java diff --git a/src/main/java/Task.java b/src/main/java/Task.java new file mode 100644 index 000000000..49b3173a8 --- /dev/null +++ b/src/main/java/Task.java @@ -0,0 +1,29 @@ +public class Task { + protected String description; // description of task + protected boolean isDone; // whether task is completed + + // constructor of new task + public Task(String description) { + this.description = description; + this.isDone = false; + } + + // return string either X or space depending on task status + public String getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } + + public void markAsDone() { + this.isDone = true; + } + + public void markAsNotDone() { + this.isDone = false; + } + + // returns string representation of task (status + description) + // is called automatically when printing task + public String toString() { + return "[" + getStatusIcon() + "]" + " " + description; + } +} diff --git a/src/main/java/oongaliegabangalie.java b/src/main/java/oongaliegabangalie.java index 8b5bc184c..99c28c04a 100644 --- a/src/main/java/oongaliegabangalie.java +++ b/src/main/java/oongaliegabangalie.java @@ -70,21 +70,76 @@ private static void echoCommand(String command, int commandCount) { System.out.println(echo); } - private static void addTask(String task, String[] tasks, int taskCount) { - String message = DIVIDER + NEWLINE + "added: " + task + NEWLINE + DIVIDER; + /* adds a new task to task list, stores in task array, confirms with user, and updates taskCount + task = task to add + tasks = the array storing all tasks + taskCount = the current count of tasks in the array + */ + private static int addTask(Task task, Task[] tasks, int taskCount) { + // add task to array + tasks[taskCount] = task; + + // confirms with userv + String message = DIVIDER + NEWLINE + "added: " + task.description + NEWLINE + DIVIDER; System.out.println(message); + + // return updated task count + return taskCount + 1; } - private static void listTasks(String[] tasks, int taskCount) { + /* displays all tasks in the task list + tasks = the array storing all tasks + taskCount = the current count of tasks in the array + */ + private static void listTasks(Task[] tasks, int taskCount) { System.out.println(DIVIDER); + System.out.println("Here are the tasks in your list:"); for (int i = 0; i < taskCount; i++) { - System.out.println((i +1) + ". " + tasks[i]); + System.out.println((i +1) + ". " + tasks[i]); // toString() in Task Class is automatically called } System.out.println(DIVIDER); } + /* marks specific task as done + tasks = the array storing all tasks + taskIndex = the index of the task to mark done + */ + private static void markTask(Task[] tasks, int taskIndex) { + // check if taskIndex is valid + if (taskIndex >= 0 && taskIndex < tasks.length && tasks[taskIndex] != null) { + tasks[taskIndex].markAsDone(); + System.out.println(DIVIDER); + System.out.println(" Nice! I've marked this task as done:"); + System.out.println(" " + tasks[taskIndex]); + System.out.println(DIVIDER); + } else { + System.out.println(DIVIDER); + System.out.println(" Invalid task number!"); + System.out.println(DIVIDER); + } + } + + /* marks specific task as not done + tasks = the array storing all tasks + taskIndex = the index of the task to mark not done + */ + private static void unmarkTask(Task[] tasks, int taskIndex) { + // check if taskIndex is valid + if (taskIndex >= 0 && taskIndex < tasks.length && tasks[taskIndex] != null) { + tasks[taskIndex].markAsNotDone(); + System.out.println(DIVIDER); + System.out.println(" OK, I've marked this task as not done yet:"); + System.out.println(" " + tasks[taskIndex]); + System.out.println(DIVIDER); + } else { + System.out.println(DIVIDER); + System.out.println(" Invalid task number!"); + System.out.println(DIVIDER); + } + } + public static void main(String[] args) { printGreeting(); @@ -94,28 +149,50 @@ public static void main(String[] args) { int commandCount = 0; boolean reachedMaxAnnoyance = false; - String[] tasks = new String[MAX_TASKS]; + // initialize task storage with max capacity as defined + Task[] tasks = new Task[MAX_TASKS]; int taskCount = 0; + // main program loop - continues until user types bye do { userInput = scanner.nextLine(); if (!userInput.equalsIgnoreCase("bye")) { //returns bool comparing 2 strings ignore case commandCount++; + // check if we've reached max annoyance level int annoyanceLevel = Math.min((commandCount / 5), ANNOYANCE_MSGS.length - 1); if (annoyanceLevel == ANNOYANCE_MSGS.length - 1) { // reached max annoyance reachedMaxAnnoyance = true; } - if (userInput.equalsIgnoreCase("list")) { + // logic for different command types + if (userInput.equalsIgnoreCase("list")) { // list all tasks listTasks(tasks, taskCount); - } else { - tasks[taskCount] = userInput; - addTask(userInput, tasks, taskCount); - taskCount++; + } else if (userInput.startsWith("mark ")) { // mark task as done + try { + int taskNumber = Integer.parseInt(userInput.substring(5).trim()); // abstract item number + markTask(tasks, taskNumber - 1); + } catch (NumberFormatException e) { + System.out.println(DIVIDER); + System.out.println("Please provide a valid task number"); + System.out.println(DIVIDER); + } + } else if (userInput.startsWith("unmark ")) { // mark task as not done + try { + int taskNumber = Integer.parseInt(userInput.substring(7).trim()); + unmarkTask(tasks, taskNumber - 1); + } catch (NumberFormatException e) { + System.out.println(DIVIDER); + System.out.println("Please provide a valid task number"); + System.out.println(DIVIDER); + } + } else { // add new task to list + Task newTask = new Task(userInput); + taskCount = addTask(newTask, tasks, taskCount); } } - } while (!userInput.equalsIgnoreCase("bye")); + + } while (!userInput.equalsIgnoreCase("bye")); // exit command printGoodbye(reachedMaxAnnoyance); } From 3a954915db95272993a67ced3c14aa27b302e695 Mon Sep 17 00:00:00 2001 From: OliverQiL <> Date: Wed, 5 Mar 2025 17:24:57 +0800 Subject: [PATCH 06/20] Level-4.1 (added ToDo, deadlines, events) --- src/main/java/Deadline.java | 16 +++++ src/main/java/Event.java | 18 +++++ src/main/java/Todo.java | 12 ++++ src/main/java/oongaliegabangalie.java | 98 ++++++++++++++++++++++++++- 4 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 src/main/java/Deadline.java create mode 100644 src/main/java/Event.java create mode 100644 src/main/java/Todo.java diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java new file mode 100644 index 000000000..3d67e2a4b --- /dev/null +++ b/src/main/java/Deadline.java @@ -0,0 +1,16 @@ +public class Deadline extends Task { + + // new variable - due date + protected String by; + + // constructs a new deadline with description and due date + public Deadline(String description, String by) { + super(description); + this.by = by; + } + + @Override + public String toString() { + return "[D]" + super.toString() + " (by: " + by + ")"; + } +} diff --git a/src/main/java/Event.java b/src/main/java/Event.java new file mode 100644 index 000000000..a801ba9c4 --- /dev/null +++ b/src/main/java/Event.java @@ -0,0 +1,18 @@ +public class Event extends Task { + + // new variables - start and end time + protected String from; + protected String to; + + // constructs a new event with description, start and end times + public Event(String description, String from, String to) { + super(description); + this.from = from; + this.to = to; + } + + @Override + public String toString() { + return "[E]" + super.toString() + " (from: " + from + " to: " + to + ")"; + } +} diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java new file mode 100644 index 000000000..98d0c28fb --- /dev/null +++ b/src/main/java/Todo.java @@ -0,0 +1,12 @@ +public class Todo extends Task { + + // constructs a new todo task with description + public Todo(String description) { + super(description); + } + + @Override + public String toString() { + return "[T]" + super.toString(); + } +} diff --git a/src/main/java/oongaliegabangalie.java b/src/main/java/oongaliegabangalie.java index 99c28c04a..a5f0ac8df 100644 --- a/src/main/java/oongaliegabangalie.java +++ b/src/main/java/oongaliegabangalie.java @@ -8,6 +8,14 @@ public class oongaliegabangalie { private static final int MAX_TASKS = 100; + // command keywords + private static final String TODO_COMMAND = "todo"; + private static final String DEADLINE_COMMAND = "deadline"; + private static final String EVENT_COMMAND = "event"; + private static final String DEADLINE_MARKER = "/by"; + private static final String EVENT_FROM_MARKER = "/from"; + private static final String EVENT_TO_MARKER = "/to"; + // annoyance messages in array format private static final String[] ANNOYANCE_MSGS = { "", // padding @@ -79,9 +87,12 @@ private static int addTask(Task task, Task[] tasks, int taskCount) { // add task to array tasks[taskCount] = task; - // confirms with userv - String message = DIVIDER + NEWLINE + "added: " + task.description + NEWLINE + DIVIDER; - System.out.println(message); + // confirms with user + System.out.println(DIVIDER); + System.out.println("Got it. I've added this task:"); + System.out.println(task); + System.out.println("Now you have " + (taskCount + 1) + " tasks in the list."); + System.out.println(DIVIDER); // return updated task count return taskCount + 1; @@ -140,6 +151,81 @@ private static void unmarkTask(Task[] tasks, int taskIndex) { } } + /* creates a todo / deadline / event + input = user input + tasks = the array storing all tasks + taskCount = the current task count + */ + private static int todoCommand(String input, Task[] tasks, int taskCount) { + // check if todo description is given + if (input.length() <= TODO_COMMAND.length()) { + System.out.println("The description of todo task is not given"); + return taskCount; + } + + // extract description + String description = input.substring(TODO_COMMAND.length()).trim(); + Todo todo = new Todo(description); + return addTask(todo, tasks, taskCount); + } + + private static int deadlineCommand(String input, Task[] tasks, int taskCount) { + // check if deadline description is given + if (input.length() <= DEADLINE_COMMAND.length()) { + System.out.println("The description of deadline task is not given"); + return taskCount; + } + + // extract content (including marker) + String content = input.substring(DEADLINE_COMMAND.length()).trim(); + + // find the position of /by marker + int byIndex = content.indexOf(DEADLINE_MARKER); + if (byIndex == -1) { // error return value of indexOf + System.out.println("Please provide the deadline with '/by'"); + return taskCount; + } + + // extract description + String description = content.substring(0, byIndex).trim(); + String by = content.substring(byIndex + DEADLINE_MARKER.length()).trim(); + + Deadline deadline = new Deadline(description, by); + return addTask(deadline, tasks, taskCount); + } + + private static int eventCommand(String input, Task[] tasks, int taskCount) { + // check if event description is provided + if (input.length() <= EVENT_COMMAND.length()) { + System.out.println("The description of event is not given"); + return taskCount; + } + + // extract content after (including markers) + String content = input.substring(EVENT_COMMAND.length()).trim(); + + // find position of /from and /to markers + int fromIndex = content.indexOf(EVENT_FROM_MARKER); + int toIndex = content.indexOf(EVENT_TO_MARKER); + + if (fromIndex == -1 || fromIndex == -1) { + System.out.println("Please provide both start and end times with '/from' and '/to'"); + return taskCount; + } + + // extract description + String description = content.substring(0, fromIndex).trim(); + + // extract start time + String from = content.substring(fromIndex + EVENT_FROM_MARKER.length(), toIndex).trim(); + + // extract end time + String to = content.substring(toIndex + EVENT_TO_MARKER.length()).trim(); + + Event event = new Event(description, from, to); + return addTask(event, tasks, taskCount); + } + public static void main(String[] args) { printGreeting(); @@ -186,6 +272,12 @@ public static void main(String[] args) { System.out.println("Please provide a valid task number"); System.out.println(DIVIDER); } + } else if (userInput.startsWith(TODO_COMMAND)) { + taskCount = todoCommand(userInput, tasks, taskCount); + } else if (userInput.startsWith(DEADLINE_COMMAND)) { + taskCount = deadlineCommand(userInput, tasks, taskCount); + } else if (userInput.startsWith(EVENT_COMMAND)) { + taskCount = eventCommand(userInput, tasks, taskCount); } else { // add new task to list Task newTask = new Task(userInput); taskCount = addTask(newTask, tasks, taskCount); From c53d50f5ae6c417fc5ddcb28df1f5565cc3ffb39 Mon Sep 17 00:00:00 2001 From: OliverQiL <> Date: Thu, 6 Mar 2025 15:03:27 +0800 Subject: [PATCH 07/20] Level-4.2 (small change to fix logic) --- src/main/java/oongaliegabangalie.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/oongaliegabangalie.java b/src/main/java/oongaliegabangalie.java index a5f0ac8df..48ad07baf 100644 --- a/src/main/java/oongaliegabangalie.java +++ b/src/main/java/oongaliegabangalie.java @@ -208,7 +208,7 @@ private static int eventCommand(String input, Task[] tasks, int taskCount) { int fromIndex = content.indexOf(EVENT_FROM_MARKER); int toIndex = content.indexOf(EVENT_TO_MARKER); - if (fromIndex == -1 || fromIndex == -1) { + if (fromIndex == -1 || toIndex == -1) { System.out.println("Please provide both start and end times with '/from' and '/to'"); return taskCount; } From 1c8db77351f8bc02eab8267625ec2fb602d90768 Mon Sep 17 00:00:00 2001 From: OliverQiL <> Date: Thu, 6 Mar 2025 16:45:32 +0800 Subject: [PATCH 08/20] Level-5.1 (basic logic implemented, have yet to optimise and fix inconsistencies) --- src/main/java/botException.java | 5 + src/main/java/oongaliegabangalie.java | 231 +++++++++++++++++--------- 2 files changed, 153 insertions(+), 83 deletions(-) create mode 100644 src/main/java/botException.java diff --git a/src/main/java/botException.java b/src/main/java/botException.java new file mode 100644 index 000000000..865acf432 --- /dev/null +++ b/src/main/java/botException.java @@ -0,0 +1,5 @@ +public class botException extends Exception { + public botException(String errorMessage) { + super(errorMessage); + } +} diff --git a/src/main/java/oongaliegabangalie.java b/src/main/java/oongaliegabangalie.java index 48ad07baf..1c1467046 100644 --- a/src/main/java/oongaliegabangalie.java +++ b/src/main/java/oongaliegabangalie.java @@ -83,7 +83,12 @@ private static void echoCommand(String command, int commandCount) { tasks = the array storing all tasks taskCount = the current count of tasks in the array */ - private static int addTask(Task task, Task[] tasks, int taskCount) { + private static int addTask(Task task, Task[] tasks, int taskCount) throws botException{ + // check if we've reached max capacity in list + if (taskCount >= MAX_TASKS) { + throw new botException("max limit reached"); + } + // add task to array tasks[taskCount] = task; @@ -102,12 +107,18 @@ private static int addTask(Task task, Task[] tasks, int taskCount) { tasks = the array storing all tasks taskCount = the current count of tasks in the array */ - private static void listTasks(Task[] tasks, int taskCount) { + private static void listTasks(Task[] tasks, int taskCount) throws botException{ System.out.println(DIVIDER); - System.out.println("Here are the tasks in your list:"); - for (int i = 0; i < taskCount; i++) { - System.out.println((i +1) + ". " + tasks[i]); // toString() in Task Class is automatically called + // check if list is empty + if (taskCount == 0) { + throw new botException("Your list is empty! Nothing to see here..."); + } else { + System.out.print("Here are the tasks in your list:"); + + for (int i = 0; i < taskCount; i++) { + System.out.println((i + 1) + ". " + tasks[i]); // toString() in Task Class is automatically called + } } System.out.println(DIVIDER); @@ -117,38 +128,42 @@ private static void listTasks(Task[] tasks, int taskCount) { tasks = the array storing all tasks taskIndex = the index of the task to mark done */ - private static void markTask(Task[] tasks, int taskIndex) { + private static void markTask(Task[] tasks, int taskIndex, int taskCount) throws botException{ // check if taskIndex is valid - if (taskIndex >= 0 && taskIndex < tasks.length && tasks[taskIndex] != null) { - tasks[taskIndex].markAsDone(); - System.out.println(DIVIDER); - System.out.println(" Nice! I've marked this task as done:"); - System.out.println(" " + tasks[taskIndex]); - System.out.println(DIVIDER); - } else { - System.out.println(DIVIDER); - System.out.println(" Invalid task number!"); - System.out.println(DIVIDER); + if (taskIndex < 0 || taskIndex >= taskCount) { + throw new botException("Task #" + (taskIndex + 1) + " doesn't exist! Check your list again."); } + + if (tasks[taskIndex].isDone) { + throw new botException("Task #" + (taskIndex + 1) + " is already marked as done!"); + } + + tasks[taskIndex].markAsDone(); + System.out.println(DIVIDER); + System.out.println(" Nice! I've marked this task as done:"); + System.out.println(" " + tasks[taskIndex]); + System.out.println(DIVIDER); } /* marks specific task as not done tasks = the array storing all tasks taskIndex = the index of the task to mark not done */ - private static void unmarkTask(Task[] tasks, int taskIndex) { + private static void unmarkTask(Task[] tasks, int taskIndex, int taskCount) throws botException{ // check if taskIndex is valid - if (taskIndex >= 0 && taskIndex < tasks.length && tasks[taskIndex] != null) { - tasks[taskIndex].markAsNotDone(); - System.out.println(DIVIDER); - System.out.println(" OK, I've marked this task as not done yet:"); - System.out.println(" " + tasks[taskIndex]); - System.out.println(DIVIDER); - } else { - System.out.println(DIVIDER); - System.out.println(" Invalid task number!"); - System.out.println(DIVIDER); + if (taskIndex < 0 || taskIndex >= taskCount) { + throw new botException("Task #" + (taskIndex + 1) + " doesn't exist! Check your list again."); } + + if (!tasks[taskIndex].isDone) { + throw new botException("Task #" + (taskIndex + 1) + " is already marked as not done!"); + } + + tasks[taskIndex].markAsNotDone(); + System.out.println(DIVIDER); + System.out.println(" OK, I've marked this task as not done yet:"); + System.out.println(" " + tasks[taskIndex]); + System.out.println(DIVIDER); } /* creates a todo / deadline / event @@ -156,76 +171,101 @@ private static void unmarkTask(Task[] tasks, int taskIndex) { tasks = the array storing all tasks taskCount = the current task count */ - private static int todoCommand(String input, Task[] tasks, int taskCount) { - // check if todo description is given - if (input.length() <= TODO_COMMAND.length()) { - System.out.println("The description of todo task is not given"); - return taskCount; + private static int todoCommand(String input, Task[] tasks, int taskCount) throws botException{ + // first extract the description and then check if it's empty + String description = input.length() > TODO_COMMAND.length() ? + input.substring(TODO_COMMAND.length()).trim() : ""; + if (description.isEmpty()) { + throw new botException("description cannot be empty"); } - // extract description - String description = input.substring(TODO_COMMAND.length()).trim(); Todo todo = new Todo(description); return addTask(todo, tasks, taskCount); } - private static int deadlineCommand(String input, Task[] tasks, int taskCount) { - // check if deadline description is given - if (input.length() <= DEADLINE_COMMAND.length()) { - System.out.println("The description of deadline task is not given"); - return taskCount; - } + private static int deadlineCommand(String input, Task[] tasks, int taskCount) throws botException { + // first extract the content then check if empty + String content = input.length() > DEADLINE_COMMAND.length() ? + input.substring(DEADLINE_COMMAND.length()).trim() : ""; - // extract content (including marker) - String content = input.substring(DEADLINE_COMMAND.length()).trim(); + if (content.isEmpty()) { + throw new botException("the deadline description cannot be empty"); + } // find the position of /by marker int byIndex = content.indexOf(DEADLINE_MARKER); if (byIndex == -1) { // error return value of indexOf - System.out.println("Please provide the deadline with '/by'"); - return taskCount; + throw new botException("deadline with /by"); } // extract description String description = content.substring(0, byIndex).trim(); + if (description.isEmpty()) { + throw new botException("the description cannot be empty"); + } + String by = content.substring(byIndex + DEADLINE_MARKER.length()).trim(); + if (by.isEmpty()) { + throw new botException("please provide after /by"); + } Deadline deadline = new Deadline(description, by); return addTask(deadline, tasks, taskCount); } - private static int eventCommand(String input, Task[] tasks, int taskCount) { - // check if event description is provided - if (input.length() <= EVENT_COMMAND.length()) { - System.out.println("The description of event is not given"); - return taskCount; - } + private static int eventCommand(String input, Task[] tasks, int taskCount) throws botException { + // first extract the content, then check if its empty + String content = input.length() > EVENT_COMMAND.length() ? + input.substring(EVENT_COMMAND.length()).trim() : ""; - // extract content after (including markers) - String content = input.substring(EVENT_COMMAND.length()).trim(); + if (content.isEmpty()) { + throw new botException("the description cannot be empty"); + } // find position of /from and /to markers int fromIndex = content.indexOf(EVENT_FROM_MARKER); int toIndex = content.indexOf(EVENT_TO_MARKER); - if (fromIndex == -1 || toIndex == -1) { - System.out.println("Please provide both start and end times with '/from' and '/to'"); - return taskCount; + if (fromIndex == -1) { + throw new botException("set start time"); + } + + if (toIndex == -1) { + throw new botException("set end time"); + } + + if (toIndex < fromIndex) { + throw new botException("to should come after from"); } // extract description String description = content.substring(0, fromIndex).trim(); + if (description.isBlank()) { + throw new botException("description cannot be empty"); + } // extract start time String from = content.substring(fromIndex + EVENT_FROM_MARKER.length(), toIndex).trim(); + if (from.isEmpty()) { + throw new botException("rovide start time"); + } // extract end time String to = content.substring(toIndex + EVENT_TO_MARKER.length()).trim(); + if (to.isEmpty()) { + throw new botException("provide end time"); + } Event event = new Event(description, from, to); return addTask(event, tasks, taskCount); } + public static void printError(botException e) { + System.out.print(DIVIDER + NEWLINE); + System.out.print(e.getMessage()); + System.out.print(NEWLINE + DIVIDER + NEWLINE); + } + public static void main(String[] args) { printGreeting(); @@ -251,36 +291,61 @@ public static void main(String[] args) { reachedMaxAnnoyance = true; } - // logic for different command types - if (userInput.equalsIgnoreCase("list")) { // list all tasks - listTasks(tasks, taskCount); - } else if (userInput.startsWith("mark ")) { // mark task as done - try { - int taskNumber = Integer.parseInt(userInput.substring(5).trim()); // abstract item number - markTask(tasks, taskNumber - 1); - } catch (NumberFormatException e) { - System.out.println(DIVIDER); - System.out.println("Please provide a valid task number"); - System.out.println(DIVIDER); + // logic for different inputs + try { + // user input is empty spaces + if (userInput.isBlank()) { + throw new botException("hello say something pls"); + } + + // list function + else if (userInput.equalsIgnoreCase("list")) { // list all tasks + listTasks(tasks, taskCount); + } + + // marking function + else if (userInput.startsWith("mark ")) { // mark task as done + try { + int taskNumber = Integer.parseInt(userInput.substring(5).trim()); // abstract item number + markTask(tasks, taskNumber - 1, taskCount); + } catch (NumberFormatException e) { + throw new botException("please provide valid task number"); + } + } + + // unmarking function + else if (userInput.startsWith("unmark ")) { // mark task as not done + try { + int taskNumber = Integer.parseInt(userInput.substring(7).trim()); + unmarkTask(tasks, taskNumber - 1, taskCount); + } catch (NumberFormatException e) { + throw new botException("please provide valid task number"); + } + } + + // todo task + else if (userInput.startsWith(TODO_COMMAND)) { + taskCount = todoCommand(userInput, tasks, taskCount); + } + + // deadline task + else if (userInput.startsWith(DEADLINE_COMMAND)) { + taskCount = deadlineCommand(userInput, tasks, taskCount); + } + + // event task + else if (userInput.startsWith(EVENT_COMMAND)) { + taskCount = eventCommand(userInput, tasks, taskCount); } - } else if (userInput.startsWith("unmark ")) { // mark task as not done - try { - int taskNumber = Integer.parseInt(userInput.substring(7).trim()); - unmarkTask(tasks, taskNumber - 1); - } catch (NumberFormatException e) { - System.out.println(DIVIDER); - System.out.println("Please provide a valid task number"); - System.out.println(DIVIDER); + + // if none of the above (default) + else { + throw new botException("i dunno what that means bruh"); } - } else if (userInput.startsWith(TODO_COMMAND)) { - taskCount = todoCommand(userInput, tasks, taskCount); - } else if (userInput.startsWith(DEADLINE_COMMAND)) { - taskCount = deadlineCommand(userInput, tasks, taskCount); - } else if (userInput.startsWith(EVENT_COMMAND)) { - taskCount = eventCommand(userInput, tasks, taskCount); - } else { // add new task to list - Task newTask = new Task(userInput); - taskCount = addTask(newTask, tasks, taskCount); + + + } catch (botException e) { // error handling + printError(e); } } From c6a781e63f689bb3add58b3b33871728d227eed7 Mon Sep 17 00:00:00 2001 From: OliverQiL <> Date: Thu, 6 Mar 2025 17:22:07 +0800 Subject: [PATCH 09/20] Level-5.2 (moved all of mark and unmark implementation into method to clean up main) --- src/main/java/oongaliegabangalie.java | 56 ++++++++++++++++++++------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/src/main/java/oongaliegabangalie.java b/src/main/java/oongaliegabangalie.java index 1c1467046..7c1838d2f 100644 --- a/src/main/java/oongaliegabangalie.java +++ b/src/main/java/oongaliegabangalie.java @@ -128,16 +128,34 @@ private static void listTasks(Task[] tasks, int taskCount) throws botException{ tasks = the array storing all tasks taskIndex = the index of the task to mark done */ - private static void markTask(Task[] tasks, int taskIndex, int taskCount) throws botException{ + private static void markTask(String input ,Task[] tasks, int taskCount) throws botException { + // extract the task number + String taskNumberStr = input.substring(5).trim(); + + // check if the task number is provided + if (taskNumberStr.isEmpty()) { + throw new botException("PLease provide a task number after 'mark'"); + } + + // parse task number + int taskIndex; + try { + taskIndex = Integer.parseInt(taskNumberStr) - 1; + } catch (NumberFormatException e) { + throw new botException("'" + taskNumberStr + "' is not a valid task number"); + } + // check if taskIndex is valid if (taskIndex < 0 || taskIndex >= taskCount) { throw new botException("Task #" + (taskIndex + 1) + " doesn't exist! Check your list again."); } + // check if task is already done if (tasks[taskIndex].isDone) { throw new botException("Task #" + (taskIndex + 1) + " is already marked as done!"); } + // mark as done tasks[taskIndex].markAsDone(); System.out.println(DIVIDER); System.out.println(" Nice! I've marked this task as done:"); @@ -149,16 +167,34 @@ private static void markTask(Task[] tasks, int taskIndex, int taskCount) throws tasks = the array storing all tasks taskIndex = the index of the task to mark not done */ - private static void unmarkTask(Task[] tasks, int taskIndex, int taskCount) throws botException{ + private static void unmarkTask(String input, Task[] tasks, int taskCount) throws botException { + // extract task number + String taskNumberStr = input.substring(7).trim(); + + // check if the task number is provided + if (taskNumberStr.isEmpty()) { + throw new botException("Please provide a task number after 'unmark'"); + } + + // parse task number + int taskIndex; + try { + taskIndex = Integer.parseInt(taskNumberStr) - 1; + } catch (NumberFormatException e) { + throw new botException("'" + taskNumberStr + "' is not a valid task number"); + } + // check if taskIndex is valid if (taskIndex < 0 || taskIndex >= taskCount) { throw new botException("Task #" + (taskIndex + 1) + " doesn't exist! Check your list again."); } + // check if task is already not done if (!tasks[taskIndex].isDone) { throw new botException("Task #" + (taskIndex + 1) + " is already marked as not done!"); } + // unmark task tasks[taskIndex].markAsNotDone(); System.out.println(DIVIDER); System.out.println(" OK, I've marked this task as not done yet:"); @@ -305,22 +341,12 @@ else if (userInput.equalsIgnoreCase("list")) { // list all tasks // marking function else if (userInput.startsWith("mark ")) { // mark task as done - try { - int taskNumber = Integer.parseInt(userInput.substring(5).trim()); // abstract item number - markTask(tasks, taskNumber - 1, taskCount); - } catch (NumberFormatException e) { - throw new botException("please provide valid task number"); - } + markTask(userInput, tasks, taskCount); } // unmarking function else if (userInput.startsWith("unmark ")) { // mark task as not done - try { - int taskNumber = Integer.parseInt(userInput.substring(7).trim()); - unmarkTask(tasks, taskNumber - 1, taskCount); - } catch (NumberFormatException e) { - throw new botException("please provide valid task number"); - } + unmarkTask(userInput, tasks, taskCount); } // todo task @@ -340,7 +366,7 @@ else if (userInput.startsWith(EVENT_COMMAND)) { // if none of the above (default) else { - throw new botException("i dunno what that means bruh"); + throw new botException("I don't know what that means"); } From c27f77e31f711fe1e598404e740c236a73abcbad Mon Sep 17 00:00:00 2001 From: OliverQiL <> Date: Thu, 6 Mar 2025 18:06:10 +0800 Subject: [PATCH 10/20] Level-5.3 (added personality, fixed small bug in mark and unmark where exception wasnt being thrown correctly) --- src/main/java/oongaliegabangalie.java | 60 ++++++++++++++------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/src/main/java/oongaliegabangalie.java b/src/main/java/oongaliegabangalie.java index 7c1838d2f..95d10fd73 100644 --- a/src/main/java/oongaliegabangalie.java +++ b/src/main/java/oongaliegabangalie.java @@ -86,7 +86,7 @@ private static void echoCommand(String command, int commandCount) { private static int addTask(Task task, Task[] tasks, int taskCount) throws botException{ // check if we've reached max capacity in list if (taskCount >= MAX_TASKS) { - throw new botException("max limit reached"); + throw new botException("You're so screwed... number of tasks has reached its limit man"); } // add task to array @@ -112,7 +112,7 @@ private static void listTasks(Task[] tasks, int taskCount) throws botException{ // check if list is empty if (taskCount == 0) { - throw new botException("Your list is empty! Nothing to see here..."); + throw new botException("Your list is empty! nothing to see here..."); } else { System.out.print("Here are the tasks in your list:"); @@ -120,7 +120,7 @@ private static void listTasks(Task[] tasks, int taskCount) throws botException{ System.out.println((i + 1) + ". " + tasks[i]); // toString() in Task Class is automatically called } } - + System.out.println("Better get to it quick!"); System.out.println(DIVIDER); } @@ -130,11 +130,11 @@ private static void listTasks(Task[] tasks, int taskCount) throws botException{ */ private static void markTask(String input ,Task[] tasks, int taskCount) throws botException { // extract the task number - String taskNumberStr = input.substring(5).trim(); + String taskNumberStr = input.substring(4).trim(); // check if the task number is provided if (taskNumberStr.isEmpty()) { - throw new botException("PLease provide a task number after 'mark'"); + throw new botException("How am I supposed to know which task to mark? Can you pLease provide a task number after 'mark'"); } // parse task number @@ -142,24 +142,25 @@ private static void markTask(String input ,Task[] tasks, int taskCount) throws b try { taskIndex = Integer.parseInt(taskNumberStr) - 1; } catch (NumberFormatException e) { - throw new botException("'" + taskNumberStr + "' is not a valid task number"); + throw new botException("'" + taskNumberStr + "' isn't a task number bro"); } // check if taskIndex is valid if (taskIndex < 0 || taskIndex >= taskCount) { - throw new botException("Task #" + (taskIndex + 1) + " doesn't exist! Check your list again."); + throw new botException("Task #" + (taskIndex + 1) + " doesn't exist! Check your list again (or your head)!"); } // check if task is already done if (tasks[taskIndex].isDone) { - throw new botException("Task #" + (taskIndex + 1) + " is already marked as done!"); + throw new botException("Task #" + (taskIndex + 1) + " is already marked as done! Don't worry I know you did it already!"); } // mark as done tasks[taskIndex].markAsDone(); System.out.println(DIVIDER); - System.out.println(" Nice! I've marked this task as done:"); + System.out.println("Nice! I've marked this task as done:"); System.out.println(" " + tasks[taskIndex]); + System.out.println("Now go do something else and stop bothering me!"); System.out.println(DIVIDER); } @@ -169,11 +170,11 @@ private static void markTask(String input ,Task[] tasks, int taskCount) throws b */ private static void unmarkTask(String input, Task[] tasks, int taskCount) throws botException { // extract task number - String taskNumberStr = input.substring(7).trim(); + String taskNumberStr = input.substring(6).trim(); // check if the task number is provided if (taskNumberStr.isEmpty()) { - throw new botException("Please provide a task number after 'unmark'"); + throw new botException("How am I supposed to know which task to unmark? Can you please provide a task number after 'unmark'"); } // parse task number @@ -181,24 +182,25 @@ private static void unmarkTask(String input, Task[] tasks, int taskCount) throws try { taskIndex = Integer.parseInt(taskNumberStr) - 1; } catch (NumberFormatException e) { - throw new botException("'" + taskNumberStr + "' is not a valid task number"); + throw new botException("'" + taskNumberStr + "' isn't a task number bro"); } // check if taskIndex is valid if (taskIndex < 0 || taskIndex >= taskCount) { - throw new botException("Task #" + (taskIndex + 1) + " doesn't exist! Check your list again."); + throw new botException("Task #" + (taskIndex + 1) + " doesn't exist! Check your list again (or your head)!"); } // check if task is already not done if (!tasks[taskIndex].isDone) { - throw new botException("Task #" + (taskIndex + 1) + " is already marked as not done!"); + throw new botException("Task #" + (taskIndex + 1) + " is already marked as not done! You think I don't do my job properly?"); } // unmark task tasks[taskIndex].markAsNotDone(); System.out.println(DIVIDER); - System.out.println(" OK, I've marked this task as not done yet:"); + System.out.println("OK, I've marked this task as not done yet:"); System.out.println(" " + tasks[taskIndex]); + System.out.println("You better get to it..."); System.out.println(DIVIDER); } @@ -212,7 +214,7 @@ private static int todoCommand(String input, Task[] tasks, int taskCount) throws String description = input.length() > TODO_COMMAND.length() ? input.substring(TODO_COMMAND.length()).trim() : ""; if (description.isEmpty()) { - throw new botException("description cannot be empty"); + throw new botException("stop wasting my time and add the description of the task after the command..."); } Todo todo = new Todo(description); @@ -225,24 +227,24 @@ private static int deadlineCommand(String input, Task[] tasks, int taskCount) th input.substring(DEADLINE_COMMAND.length()).trim() : ""; if (content.isEmpty()) { - throw new botException("the deadline description cannot be empty"); + throw new botException("haha very funny... why is there nothing after the command?"); } // find the position of /by marker int byIndex = content.indexOf(DEADLINE_MARKER); if (byIndex == -1) { // error return value of indexOf - throw new botException("deadline with /by"); + throw new botException("Wheres the '/by' marker? I need that please"); } // extract description String description = content.substring(0, byIndex).trim(); if (description.isEmpty()) { - throw new botException("the description cannot be empty"); + throw new botException("Where is the description of the task? please add it before the deadline!"); } String by = content.substring(byIndex + DEADLINE_MARKER.length()).trim(); if (by.isEmpty()) { - throw new botException("please provide after /by"); + throw new botException("Why is there nothing after '/by'? do you not want to finish on time?"); } Deadline deadline = new Deadline(description, by); @@ -255,7 +257,7 @@ private static int eventCommand(String input, Task[] tasks, int taskCount) throw input.substring(EVENT_COMMAND.length()).trim() : ""; if (content.isEmpty()) { - throw new botException("the description cannot be empty"); + throw new botException("Why is there nothing after the command? are you playing with me?"); } // find position of /from and /to markers @@ -263,33 +265,33 @@ private static int eventCommand(String input, Task[] tasks, int taskCount) throw int toIndex = content.indexOf(EVENT_TO_MARKER); if (fromIndex == -1) { - throw new botException("set start time"); + throw new botException("Wheres the '/from' marker? I need that please"); } if (toIndex == -1) { - throw new botException("set end time"); + throw new botException("Wheres the '/to' marker? I need that please"); } if (toIndex < fromIndex) { - throw new botException("to should come after from"); + throw new botException("I think you got it mixed up! it should be '/from' then '/to'"); } // extract description String description = content.substring(0, fromIndex).trim(); if (description.isBlank()) { - throw new botException("description cannot be empty"); + throw new botException("Where is the description of the event? please add it before the timings!"); } // extract start time String from = content.substring(fromIndex + EVENT_FROM_MARKER.length(), toIndex).trim(); if (from.isEmpty()) { - throw new botException("rovide start time"); + throw new botException("Why is there nothing after '/from'? can you pls follow instructions!"); } // extract end time String to = content.substring(toIndex + EVENT_TO_MARKER.length()).trim(); if (to.isEmpty()) { - throw new botException("provide end time"); + throw new botException("Why is there nothing after '/to'? can you pls follow instructions!"); } Event event = new Event(description, from, to); @@ -340,12 +342,12 @@ else if (userInput.equalsIgnoreCase("list")) { // list all tasks } // marking function - else if (userInput.startsWith("mark ")) { // mark task as done + else if (userInput.startsWith("mark")) { // mark task as done markTask(userInput, tasks, taskCount); } // unmarking function - else if (userInput.startsWith("unmark ")) { // mark task as not done + else if (userInput.startsWith("unmark")) { // mark task as not done unmarkTask(userInput, tasks, taskCount); } From a1e37c0a8a5bf5b80b91eb1b2d1f850be6b58c2d Mon Sep 17 00:00:00 2001 From: OliverQiL <> Date: Mon, 10 Mar 2025 19:22:14 +0800 Subject: [PATCH 11/20] Level-5.4-A-Packages (Organized classes into packages) --- .../exception}/botException.java | 2 ++ .../task}/Deadline.java | 2 ++ .../{ => oongaliegabangalieBot/task}/Event.java | 2 ++ .../{ => oongaliegabangalieBot/task}/Task.java | 7 +++++++ .../{ => oongaliegabangalieBot/task}/Todo.java | 2 ++ .../ui}/oongaliegabangalie.java | 16 ++++++++++++---- 6 files changed, 27 insertions(+), 4 deletions(-) rename src/main/java/{ => oongaliegabangalieBot/exception}/botException.java (75%) rename src/main/java/{ => oongaliegabangalieBot/task}/Deadline.java (91%) rename src/main/java/{ => oongaliegabangalieBot/task}/Event.java (92%) rename src/main/java/{ => oongaliegabangalieBot/task}/Task.java (85%) rename src/main/java/{ => oongaliegabangalieBot/task}/Todo.java (87%) rename src/main/java/{ => oongaliegabangalieBot/ui}/oongaliegabangalie.java (96%) diff --git a/src/main/java/botException.java b/src/main/java/oongaliegabangalieBot/exception/botException.java similarity index 75% rename from src/main/java/botException.java rename to src/main/java/oongaliegabangalieBot/exception/botException.java index 865acf432..065a6dcdd 100644 --- a/src/main/java/botException.java +++ b/src/main/java/oongaliegabangalieBot/exception/botException.java @@ -1,3 +1,5 @@ +package oongaliegabangalieBot.exception; + public class botException extends Exception { public botException(String errorMessage) { super(errorMessage); diff --git a/src/main/java/Deadline.java b/src/main/java/oongaliegabangalieBot/task/Deadline.java similarity index 91% rename from src/main/java/Deadline.java rename to src/main/java/oongaliegabangalieBot/task/Deadline.java index 3d67e2a4b..6570d799e 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/oongaliegabangalieBot/task/Deadline.java @@ -1,3 +1,5 @@ +package oongaliegabangalieBot.task; + public class Deadline extends Task { // new variable - due date diff --git a/src/main/java/Event.java b/src/main/java/oongaliegabangalieBot/task/Event.java similarity index 92% rename from src/main/java/Event.java rename to src/main/java/oongaliegabangalieBot/task/Event.java index a801ba9c4..95753810a 100644 --- a/src/main/java/Event.java +++ b/src/main/java/oongaliegabangalieBot/task/Event.java @@ -1,3 +1,5 @@ +package oongaliegabangalieBot.task; + public class Event extends Task { // new variables - start and end time diff --git a/src/main/java/Task.java b/src/main/java/oongaliegabangalieBot/task/Task.java similarity index 85% rename from src/main/java/Task.java rename to src/main/java/oongaliegabangalieBot/task/Task.java index 49b3173a8..44e4025e8 100644 --- a/src/main/java/Task.java +++ b/src/main/java/oongaliegabangalieBot/task/Task.java @@ -1,3 +1,5 @@ +package oongaliegabangalieBot.task; + public class Task { protected String description; // description of task protected boolean isDone; // whether task is completed @@ -8,6 +10,11 @@ public Task(String description) { this.isDone = false; } + // getter method for isDone + public boolean getIsDone() { + return isDone; + } + // return string either X or space depending on task status public String getStatusIcon() { return (isDone ? "X" : " "); // mark done task with X diff --git a/src/main/java/Todo.java b/src/main/java/oongaliegabangalieBot/task/Todo.java similarity index 87% rename from src/main/java/Todo.java rename to src/main/java/oongaliegabangalieBot/task/Todo.java index 98d0c28fb..ac236b1c8 100644 --- a/src/main/java/Todo.java +++ b/src/main/java/oongaliegabangalieBot/task/Todo.java @@ -1,3 +1,5 @@ +package oongaliegabangalieBot.task; + public class Todo extends Task { // constructs a new todo task with description diff --git a/src/main/java/oongaliegabangalie.java b/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java similarity index 96% rename from src/main/java/oongaliegabangalie.java rename to src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java index 95d10fd73..8b2b69bee 100644 --- a/src/main/java/oongaliegabangalie.java +++ b/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java @@ -1,5 +1,13 @@ +package oongaliegabangalieBot.ui; + import java.util.Scanner; +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.task.Task; +import oongaliegabangalieBot.task.Deadline; +import oongaliegabangalieBot.task.Event; +import oongaliegabangalieBot.task.Todo; + public class oongaliegabangalie { // basic textual building blocks private static final String DIVIDER = "____________________________________________________________"; @@ -83,7 +91,7 @@ private static void echoCommand(String command, int commandCount) { tasks = the array storing all tasks taskCount = the current count of tasks in the array */ - private static int addTask(Task task, Task[] tasks, int taskCount) throws botException{ + private static int addTask(Task task, Task[] tasks, int taskCount) throws botException { // check if we've reached max capacity in list if (taskCount >= MAX_TASKS) { throw new botException("You're so screwed... number of tasks has reached its limit man"); @@ -128,7 +136,7 @@ private static void listTasks(Task[] tasks, int taskCount) throws botException{ tasks = the array storing all tasks taskIndex = the index of the task to mark done */ - private static void markTask(String input ,Task[] tasks, int taskCount) throws botException { + private static void markTask(String input , Task[] tasks, int taskCount) throws botException { // extract the task number String taskNumberStr = input.substring(4).trim(); @@ -151,7 +159,7 @@ private static void markTask(String input ,Task[] tasks, int taskCount) throws b } // check if task is already done - if (tasks[taskIndex].isDone) { + if (tasks[taskIndex].getIsDone()) { throw new botException("Task #" + (taskIndex + 1) + " is already marked as done! Don't worry I know you did it already!"); } @@ -191,7 +199,7 @@ private static void unmarkTask(String input, Task[] tasks, int taskCount) throws } // check if task is already not done - if (!tasks[taskIndex].isDone) { + if (!tasks[taskIndex].getIsDone()) { throw new botException("Task #" + (taskIndex + 1) + " is already marked as not done! You think I don't do my job properly?"); } From 630eebd7c185bc3a985ed92090db5e9003474be6 Mon Sep 17 00:00:00 2001 From: Qi Oliver <> Date: Wed, 12 Mar 2025 20:57:54 +0800 Subject: [PATCH 12/20] Level-6 (Implemented delete function, switched to using ArrayList instead of static Arrays) --- .../ui/oongaliegabangalie.java | 147 ++++++++++++------ 1 file changed, 97 insertions(+), 50 deletions(-) diff --git a/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java b/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java index 8b2b69bee..769fa2564 100644 --- a/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java +++ b/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java @@ -1,6 +1,7 @@ package oongaliegabangalieBot.ui; import java.util.Scanner; +import java.util.ArrayList; import oongaliegabangalieBot.exception.botException; import oongaliegabangalieBot.task.Task; @@ -14,8 +15,6 @@ public class oongaliegabangalie { private static final String NEWLINE = System.lineSeparator(); private static final String BOT_NAME = "Oongaliegabangalie"; - private static final int MAX_TASKS = 100; - // command keywords private static final String TODO_COMMAND = "todo"; private static final String DEADLINE_COMMAND = "deadline"; @@ -23,6 +22,7 @@ public class oongaliegabangalie { private static final String DEADLINE_MARKER = "/by"; private static final String EVENT_FROM_MARKER = "/from"; private static final String EVENT_TO_MARKER = "/to"; + private static final String DELETE_COMMAND = "delete"; // annoyance messages in array format private static final String[] ANNOYANCE_MSGS = { @@ -88,44 +88,88 @@ private static void echoCommand(String command, int commandCount) { /* adds a new task to task list, stores in task array, confirms with user, and updates taskCount task = task to add - tasks = the array storing all tasks - taskCount = the current count of tasks in the array + tasks = the ArrayList storing all tasks */ - private static int addTask(Task task, Task[] tasks, int taskCount) throws botException { - // check if we've reached max capacity in list - if (taskCount >= MAX_TASKS) { - throw new botException("You're so screwed... number of tasks has reached its limit man"); - } - + private static void addTask(Task task, ArrayList tasks) { // add task to array - tasks[taskCount] = task; + tasks.add(task); // confirms with user System.out.println(DIVIDER); System.out.println("Got it. I've added this task:"); System.out.println(task); - System.out.println("Now you have " + (taskCount + 1) + " tasks in the list."); + System.out.println("Now you have " + tasks.size() + " tasks in the list."); + + // short message if tasks.size > certain number + if (tasks.size() >= 20) { + System.out.println("you are so screwed..."); + } else if (tasks.size() >= 15) { + System.out.println("better knock a couple of these down before its too late!"); + } else if (tasks.size() >= 10) { + System.out.println("looks like your tasks are piling up..."); + } else if (tasks.size() >= 5) { + System.out.println("and so it begins... better not let it get out of hand"); + } + System.out.println(DIVIDER); + } + + /* deletes a task from the list + input = user input + tasks = the ArrayList storing all tasks + */ + private static void deleteTask(String input, ArrayList tasks) throws botException { + // check if list is empty + if (tasks.isEmpty()) { + throw new botException("Your list is empty man... nothing to delete"); + } - // return updated task count - return taskCount + 1; + // extract the task number + String taskNumberStr = input.substring(DELETE_COMMAND.length()).trim(); + + // check if the task number is provided + if (taskNumberStr.isEmpty()) { + throw new botException("Which task do you want me to delete? provide a task number after 'delete'"); + } + + // parse task number + int taskIndex; + try { + taskIndex = Integer.parseInt(taskNumberStr) - 1; + } catch (NumberFormatException e) { + throw new botException("'" + taskNumberStr + "' isn't a task number bro"); + } + + // check if taskIndex is valid + if (taskIndex < 0 || taskIndex >= tasks.size()) { + throw new botException("Task #" + (taskIndex + 1) + " doesn't exist! Check your list again (or your head)!"); + } + + // print out confirmation message before actually deleting (unable to access deleted task after removing) + System.out.println(DIVIDER); + System.out.println("Noted. I've removed this task:"); + System.out.println(tasks.get(taskIndex)); + System.out.println("Now you have " + (tasks.size() - 1) + " tasks in the list"); + System.out.println(DIVIDER); + + tasks.remove(taskIndex); } + /* displays all tasks in the task list - tasks = the array storing all tasks - taskCount = the current count of tasks in the array + tasks = the ArrayList storing all tasks */ - private static void listTasks(Task[] tasks, int taskCount) throws botException{ + private static void listTasks(ArrayList tasks) throws botException{ System.out.println(DIVIDER); // check if list is empty - if (taskCount == 0) { + if (tasks.isEmpty()) { throw new botException("Your list is empty! nothing to see here..."); } else { - System.out.print("Here are the tasks in your list:"); + System.out.println("Here are the tasks in your list:"); - for (int i = 0; i < taskCount; i++) { - System.out.println((i + 1) + ". " + tasks[i]); // toString() in Task Class is automatically called + for (int i = 0; i < tasks.size(); i++) { + System.out.println((i + 1) + ". " + tasks.get(i)); // toString() in Task Class is automatically called } } System.out.println("Better get to it quick!"); @@ -133,10 +177,10 @@ private static void listTasks(Task[] tasks, int taskCount) throws botException{ } /* marks specific task as done - tasks = the array storing all tasks + tasks = the ArrayList storing all tasks taskIndex = the index of the task to mark done */ - private static void markTask(String input , Task[] tasks, int taskCount) throws botException { + private static void markTask(String input , ArrayList tasks) throws botException { // extract the task number String taskNumberStr = input.substring(4).trim(); @@ -154,29 +198,29 @@ private static void markTask(String input , Task[] tasks, int taskCount) throws } // check if taskIndex is valid - if (taskIndex < 0 || taskIndex >= taskCount) { + if (taskIndex < 0 || taskIndex >= tasks.size()) { throw new botException("Task #" + (taskIndex + 1) + " doesn't exist! Check your list again (or your head)!"); } // check if task is already done - if (tasks[taskIndex].getIsDone()) { + if (tasks.get(taskIndex).getIsDone()) { throw new botException("Task #" + (taskIndex + 1) + " is already marked as done! Don't worry I know you did it already!"); } // mark as done - tasks[taskIndex].markAsDone(); + tasks.get(taskIndex).markAsDone(); System.out.println(DIVIDER); System.out.println("Nice! I've marked this task as done:"); - System.out.println(" " + tasks[taskIndex]); + System.out.println(" " + tasks.get(taskIndex)); System.out.println("Now go do something else and stop bothering me!"); System.out.println(DIVIDER); } /* marks specific task as not done - tasks = the array storing all tasks + tasks = the ArrayList storing all tasks taskIndex = the index of the task to mark not done */ - private static void unmarkTask(String input, Task[] tasks, int taskCount) throws botException { + private static void unmarkTask(String input, ArrayList tasks) throws botException { // extract task number String taskNumberStr = input.substring(6).trim(); @@ -194,30 +238,29 @@ private static void unmarkTask(String input, Task[] tasks, int taskCount) throws } // check if taskIndex is valid - if (taskIndex < 0 || taskIndex >= taskCount) { + if (taskIndex < 0 || taskIndex >= tasks.size()) { throw new botException("Task #" + (taskIndex + 1) + " doesn't exist! Check your list again (or your head)!"); } // check if task is already not done - if (!tasks[taskIndex].getIsDone()) { + if (!tasks.get(taskIndex).getIsDone()) { throw new botException("Task #" + (taskIndex + 1) + " is already marked as not done! You think I don't do my job properly?"); } // unmark task - tasks[taskIndex].markAsNotDone(); + tasks.get(taskIndex).markAsNotDone(); System.out.println(DIVIDER); System.out.println("OK, I've marked this task as not done yet:"); - System.out.println(" " + tasks[taskIndex]); + System.out.println(" " + tasks.get(taskIndex)); System.out.println("You better get to it..."); System.out.println(DIVIDER); } /* creates a todo / deadline / event input = user input - tasks = the array storing all tasks - taskCount = the current task count + tasks = the ArrayList storing all tasks */ - private static int todoCommand(String input, Task[] tasks, int taskCount) throws botException{ + private static void todoCommand(String input, ArrayList tasks) throws botException{ // first extract the description and then check if it's empty String description = input.length() > TODO_COMMAND.length() ? input.substring(TODO_COMMAND.length()).trim() : ""; @@ -226,10 +269,10 @@ private static int todoCommand(String input, Task[] tasks, int taskCount) throws } Todo todo = new Todo(description); - return addTask(todo, tasks, taskCount); + addTask(todo, tasks); } - private static int deadlineCommand(String input, Task[] tasks, int taskCount) throws botException { + private static void deadlineCommand(String input, ArrayList tasks) throws botException { // first extract the content then check if empty String content = input.length() > DEADLINE_COMMAND.length() ? input.substring(DEADLINE_COMMAND.length()).trim() : ""; @@ -256,10 +299,10 @@ private static int deadlineCommand(String input, Task[] tasks, int taskCount) th } Deadline deadline = new Deadline(description, by); - return addTask(deadline, tasks, taskCount); + addTask(deadline, tasks); } - private static int eventCommand(String input, Task[] tasks, int taskCount) throws botException { + private static void eventCommand(String input, ArrayList tasks) throws botException { // first extract the content, then check if its empty String content = input.length() > EVENT_COMMAND.length() ? input.substring(EVENT_COMMAND.length()).trim() : ""; @@ -303,7 +346,7 @@ private static int eventCommand(String input, Task[] tasks, int taskCount) throw } Event event = new Event(description, from, to); - return addTask(event, tasks, taskCount); + addTask(event, tasks); } public static void printError(botException e) { @@ -321,9 +364,8 @@ public static void main(String[] args) { int commandCount = 0; boolean reachedMaxAnnoyance = false; - // initialize task storage with max capacity as defined - Task[] tasks = new Task[MAX_TASKS]; - int taskCount = 0; + // initialize task storage using ArrayList instead of Array + ArrayList tasks = new ArrayList<>(); // main program loop - continues until user types bye do { @@ -344,34 +386,39 @@ public static void main(String[] args) { throw new botException("hello say something pls"); } + // delete function + else if (userInput.startsWith(DELETE_COMMAND)) { + deleteTask(userInput, tasks); + } + // list function else if (userInput.equalsIgnoreCase("list")) { // list all tasks - listTasks(tasks, taskCount); + listTasks(tasks); } // marking function else if (userInput.startsWith("mark")) { // mark task as done - markTask(userInput, tasks, taskCount); + markTask(userInput, tasks); } // unmarking function else if (userInput.startsWith("unmark")) { // mark task as not done - unmarkTask(userInput, tasks, taskCount); + unmarkTask(userInput, tasks); } // todo task else if (userInput.startsWith(TODO_COMMAND)) { - taskCount = todoCommand(userInput, tasks, taskCount); + todoCommand(userInput, tasks); } // deadline task else if (userInput.startsWith(DEADLINE_COMMAND)) { - taskCount = deadlineCommand(userInput, tasks, taskCount); + deadlineCommand(userInput, tasks); } // event task else if (userInput.startsWith(EVENT_COMMAND)) { - taskCount = eventCommand(userInput, tasks, taskCount); + eventCommand(userInput, tasks); } // if none of the above (default) From c805f81e9bcc14bdf31ac9984bde5e6b60f48d8b Mon Sep 17 00:00:00 2001 From: Qi Oliver <> Date: Thu, 13 Mar 2025 01:03:36 +0800 Subject: [PATCH 13/20] Level-7 (implemented save function with un-updated master branch using old static array system and without delete function to practice parallel branches and merge conflict resolution) --- data/oongaliegabangalie.txt | 1 + .../storage/Storage.java | 149 ++++++++++++++++++ .../oongaliegabangalieBot/task/Deadline.java | 4 + .../oongaliegabangalieBot/task/Event.java | 8 + .../java/oongaliegabangalieBot/task/Task.java | 2 + .../ui/oongaliegabangalie.java | 55 +++++++ 6 files changed, 219 insertions(+) create mode 100644 data/oongaliegabangalie.txt create mode 100644 src/main/java/oongaliegabangalieBot/storage/Storage.java diff --git a/data/oongaliegabangalie.txt b/data/oongaliegabangalie.txt new file mode 100644 index 000000000..596b740da --- /dev/null +++ b/data/oongaliegabangalie.txt @@ -0,0 +1 @@ +T | 0 | hello diff --git a/src/main/java/oongaliegabangalieBot/storage/Storage.java b/src/main/java/oongaliegabangalieBot/storage/Storage.java new file mode 100644 index 000000000..0f1824448 --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/storage/Storage.java @@ -0,0 +1,149 @@ +package oongaliegabangalieBot.storage; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Scanner; + +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.task.Deadline; +import oongaliegabangalieBot.task.Event; +import oongaliegabangalieBot.task.Task; +import oongaliegabangalieBot.task.Todo; + +public class Storage { + private final String filePath; + private final String directoryPath; + private static final int MAX_TASKS = 100; + + // Constructor initializes the file path + public Storage(String filePath) { + this.filePath = filePath; + // Extract directory path from the file path + int lastSeparatorIndex = filePath.lastIndexOf(File.separator); + this.directoryPath = lastSeparatorIndex > 0 ? filePath.substring(0, lastSeparatorIndex) : "."; + } + + /* + Saves the tasks to the file + Format: T | isDone | description + D | isDone | description | by + E | isDone | description | from | to + */ + public void saveTasks(Task[] tasks, int taskCount) throws botException { + try { + // Create directory if it doesn't exist + File directory = new File(directoryPath); + if (!directory.exists()) { + directory.mkdirs(); + } + + // Create file writer (will create file if it doesn't exist) + FileWriter writer = new FileWriter(filePath); + + // Write each task to the file + for (int i = 0; i < taskCount; i++) { + Task task = tasks[i]; + if (task instanceof Todo) { + writer.write("T | " + (task.getIsDone() ? "1" : "0") + " | " + task.getDescription()); + } else if (task instanceof Deadline) { + Deadline deadline = (Deadline) task; + writer.write("D | " + (task.getIsDone() ? "1" : "0") + " | " + + task.getDescription() + " | " + deadline.getBy()); + } else if (task instanceof Event) { + Event event = (Event) task; + writer.write("E | " + (task.getIsDone() ? "1" : "0") + " | " + + task.getDescription() + " | " + event.getFrom() + " | " + event.getTo()); + } + writer.write(System.lineSeparator()); // Add newline + } + + writer.close(); // Important to close the file writer! + } catch (IOException e) { + throw new botException("Error saving tasks: " + e.getMessage()); + } + } + + // Loads tasks from the file + public Task[] loadTasks() throws botException { + Task[] tasks = new Task[MAX_TASKS]; + + // Check if file exists, if not return empty array + File file = new File(filePath); + if (!file.exists()) { + return tasks; + } + + try { + Scanner scanner = new Scanner(file); + int taskCount = 0; + + while (scanner.hasNextLine() && taskCount < MAX_TASKS) { + try { + String line = scanner.nextLine(); + + // Skip empty lines + if (line.trim().isEmpty()) { + continue; + } + + // Parse the line + String[] parts = line.split(" \\| ", -1); // -1 to keep empty strings + + // Validate line format + if (parts.length < 3) { + System.out.println("Warning: Skipping invalid line format: " + line); + continue; + } + + char taskType = parts[0].charAt(0); + boolean isDone = parts[1].equals("1"); + String description = parts[2]; + + Task task = null; + + switch (taskType) { + case 'T': // Todo + task = new Todo(description); + break; + case 'D': // Deadline + if (parts.length < 4) { + System.out.println("Warning: Skipping invalid Deadline format: " + line); + continue; + } + task = new Deadline(description, parts[3]); + break; + case 'E': // Event + if (parts.length < 5) { + System.out.println("Warning: Skipping invalid Event format: " + line); + continue; + } + task = new Event(description, parts[3], parts[4]); + break; + default: + System.out.println("Warning: Unknown task type: " + taskType); + continue; + } + + // Set the task status + if (isDone) { + task.markAsDone(); + } + + tasks[taskCount] = task; + taskCount++; + } catch (Exception e) { + // Handle corrupted line, print warning and continue + System.out.println("Warning: Skipping corrupted line. Error: " + e.getMessage()); + } + } + + scanner.close(); + } catch (FileNotFoundException e) { + throw new botException("Error loading tasks: " + e.getMessage()); + } + + return tasks; + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/task/Deadline.java b/src/main/java/oongaliegabangalieBot/task/Deadline.java index 6570d799e..340bbb10f 100644 --- a/src/main/java/oongaliegabangalieBot/task/Deadline.java +++ b/src/main/java/oongaliegabangalieBot/task/Deadline.java @@ -11,6 +11,10 @@ public Deadline(String description, String by) { this.by = by; } + public String getBy() { + return by; + } + @Override public String toString() { return "[D]" + super.toString() + " (by: " + by + ")"; diff --git a/src/main/java/oongaliegabangalieBot/task/Event.java b/src/main/java/oongaliegabangalieBot/task/Event.java index 95753810a..408481e38 100644 --- a/src/main/java/oongaliegabangalieBot/task/Event.java +++ b/src/main/java/oongaliegabangalieBot/task/Event.java @@ -13,6 +13,14 @@ public Event(String description, String from, String to) { this.to = to; } + public String getFrom() { + return from; + } + + public String getTo() { + return to; + } + @Override public String toString() { return "[E]" + super.toString() + " (from: " + from + " to: " + to + ")"; diff --git a/src/main/java/oongaliegabangalieBot/task/Task.java b/src/main/java/oongaliegabangalieBot/task/Task.java index 44e4025e8..f1f0a88de 100644 --- a/src/main/java/oongaliegabangalieBot/task/Task.java +++ b/src/main/java/oongaliegabangalieBot/task/Task.java @@ -15,6 +15,8 @@ public boolean getIsDone() { return isDone; } + public String getDescription() { return description; } + // return string either X or space depending on task status public String getStatusIcon() { return (isDone ? "X" : " "); // mark done task with X diff --git a/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java b/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java index 8b2b69bee..5cddc2616 100644 --- a/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java +++ b/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java @@ -1,8 +1,10 @@ package oongaliegabangalieBot.ui; +import java.io.File; import java.util.Scanner; import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.storage.Storage; import oongaliegabangalieBot.task.Task; import oongaliegabangalieBot.task.Deadline; import oongaliegabangalieBot.task.Event; @@ -16,6 +18,14 @@ public class oongaliegabangalie { private static final int MAX_TASKS = 100; + // storage filepath + private static final String STORAGE_DIRECTORY = "data"; + private static final String STORAGE_FILENAME = "oongaliegabangalie.txt"; + private static final String STORAGE_PATH = STORAGE_DIRECTORY + File.separator + STORAGE_FILENAME; + + // storage object + private static Storage storage; + // command keywords private static final String TODO_COMMAND = "todo"; private static final String DEADLINE_COMMAND = "deadline"; @@ -100,6 +110,9 @@ private static int addTask(Task task, Task[] tasks, int taskCount) throws botExc // add task to array tasks[taskCount] = task; + // save tasks to storage + saveTasksToStorage(tasks, taskCount + 1); + // confirms with user System.out.println(DIVIDER); System.out.println("Got it. I've added this task:"); @@ -163,6 +176,9 @@ private static void markTask(String input , Task[] tasks, int taskCount) throws throw new botException("Task #" + (taskIndex + 1) + " is already marked as done! Don't worry I know you did it already!"); } + // save tasks to storage + saveTasksToStorage(tasks, taskCount); + // mark as done tasks[taskIndex].markAsDone(); System.out.println(DIVIDER); @@ -203,6 +219,9 @@ private static void unmarkTask(String input, Task[] tasks, int taskCount) throws throw new botException("Task #" + (taskIndex + 1) + " is already marked as not done! You think I don't do my job properly?"); } + // save tasks to storage + saveTasksToStorage(tasks, taskCount); + // unmark task tasks[taskIndex].markAsNotDone(); System.out.println(DIVIDER); @@ -306,6 +325,14 @@ private static int eventCommand(String input, Task[] tasks, int taskCount) throw return addTask(event, tasks, taskCount); } + private static void saveTasksToStorage(Task[] tasks, int taskCount) { + try { + storage.saveTasks(tasks, taskCount); + } catch (botException e) { + System.out.println("Warning: Failed to save tasks: " + e.getMessage()); + } + } + public static void printError(botException e) { System.out.print(DIVIDER + NEWLINE); System.out.print(e.getMessage()); @@ -315,6 +342,9 @@ public static void printError(botException e) { public static void main(String[] args) { printGreeting(); + // initialize storage + storage = new Storage(STORAGE_PATH); + Scanner scanner = new Scanner(System.in); String userInput; @@ -325,6 +355,31 @@ public static void main(String[] args) { Task[] tasks = new Task[MAX_TASKS]; int taskCount = 0; + // load tasks from storage + try { + Task[] loadedTasks = storage.loadTasks(); + // Count the loaded tasks (stop at first null entry) + int loadedTaskCount = 0; + while (loadedTaskCount < loadedTasks.length && loadedTasks[loadedTaskCount] != null) { + loadedTaskCount++; + } + + // Copy loaded tasks to our tasks array if there are any + if (loadedTaskCount > 0) { + System.arraycopy(loadedTasks, 0, tasks, 0, loadedTaskCount); + taskCount = loadedTaskCount; + + System.out.println(DIVIDER); + System.out.println("I've loaded " + taskCount + " tasks from storage."); + System.out.println(DIVIDER); + } + } catch (botException e) { + System.out.println(DIVIDER); + System.out.println("Warning: Error loading tasks: " + e.getMessage()); + System.out.println("Starting with an empty task list."); + System.out.println(DIVIDER); + } + // main program loop - continues until user types bye do { userInput = scanner.nextLine(); From 2b8eba744d75a1530b4f1663046a725bda069330 Mon Sep 17 00:00:00 2001 From: Qi Oliver <> Date: Thu, 13 Mar 2025 01:50:03 +0800 Subject: [PATCH 14/20] updated save function to work with ArrayList instead of Array. both Level-6 and Level-7 implemented --- .../storage/Storage.java | 18 +++++------- .../ui/oongaliegabangalie.java | 29 +++++++------------ 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/src/main/java/oongaliegabangalieBot/storage/Storage.java b/src/main/java/oongaliegabangalieBot/storage/Storage.java index 0f1824448..cda0936fb 100644 --- a/src/main/java/oongaliegabangalieBot/storage/Storage.java +++ b/src/main/java/oongaliegabangalieBot/storage/Storage.java @@ -4,6 +4,8 @@ import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; +import java.lang.reflect.Array; +import java.util.ArrayList; import java.util.Scanner; import oongaliegabangalieBot.exception.botException; @@ -15,7 +17,6 @@ public class Storage { private final String filePath; private final String directoryPath; - private static final int MAX_TASKS = 100; // Constructor initializes the file path public Storage(String filePath) { @@ -31,7 +32,7 @@ public Storage(String filePath) { D | isDone | description | by E | isDone | description | from | to */ - public void saveTasks(Task[] tasks, int taskCount) throws botException { + public void saveTasks(ArrayList tasks) throws botException { try { // Create directory if it doesn't exist File directory = new File(directoryPath); @@ -43,8 +44,7 @@ public void saveTasks(Task[] tasks, int taskCount) throws botException { FileWriter writer = new FileWriter(filePath); // Write each task to the file - for (int i = 0; i < taskCount; i++) { - Task task = tasks[i]; + for (Task task : tasks) { if (task instanceof Todo) { writer.write("T | " + (task.getIsDone() ? "1" : "0") + " | " + task.getDescription()); } else if (task instanceof Deadline) { @@ -66,8 +66,8 @@ public void saveTasks(Task[] tasks, int taskCount) throws botException { } // Loads tasks from the file - public Task[] loadTasks() throws botException { - Task[] tasks = new Task[MAX_TASKS]; + public ArrayList loadTasks() throws botException { + ArrayList tasks = new ArrayList<>(); // Check if file exists, if not return empty array File file = new File(filePath); @@ -77,9 +77,8 @@ public Task[] loadTasks() throws botException { try { Scanner scanner = new Scanner(file); - int taskCount = 0; - while (scanner.hasNextLine() && taskCount < MAX_TASKS) { + while (scanner.hasNextLine()) { try { String line = scanner.nextLine(); @@ -131,8 +130,7 @@ public Task[] loadTasks() throws botException { task.markAsDone(); } - tasks[taskCount] = task; - taskCount++; + tasks.add(task); } catch (Exception e) { // Handle corrupted line, print warning and continue System.out.println("Warning: Skipping corrupted line. Error: " + e.getMessage()); diff --git a/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java b/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java index 1cdec22a4..d151454c4 100644 --- a/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java +++ b/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java @@ -17,8 +17,6 @@ public class oongaliegabangalie { private static final String NEWLINE = System.lineSeparator(); private static final String BOT_NAME = "Oongaliegabangalie"; - private static final int MAX_TASKS = 100; - // storage filepath private static final String STORAGE_DIRECTORY = "data"; private static final String STORAGE_FILENAME = "oongaliegabangalie.txt"; @@ -107,7 +105,7 @@ private static void addTask(Task task, ArrayList tasks) { tasks.add(task); // save tasks to storage - saveTasksToStorage(tasks, taskCount + 1); + saveTasksToStorage(tasks); // confirms with user System.out.println(DIVIDER); @@ -223,7 +221,7 @@ private static void markTask(String input , ArrayList tasks) throws botExc } // save tasks to storage - saveTasksToStorage(tasks, taskCount); + saveTasksToStorage(tasks); // mark as done tasks.get(taskIndex).markAsDone(); @@ -266,7 +264,7 @@ private static void unmarkTask(String input, ArrayList tasks) throws botEx } // save tasks to storage - saveTasksToStorage(tasks, taskCount); + saveTasksToStorage(tasks); // unmark task tasks.get(taskIndex).markAsNotDone(); @@ -370,9 +368,9 @@ private static void eventCommand(String input, ArrayList tasks) throws bot addTask(event, tasks); } - private static void saveTasksToStorage(Task[] tasks, int taskCount) { + private static void saveTasksToStorage(ArrayList tasks) { try { - storage.saveTasks(tasks, taskCount); + storage.saveTasks(tasks); } catch (botException e) { System.out.println("Warning: Failed to save tasks: " + e.getMessage()); } @@ -401,21 +399,14 @@ public static void main(String[] args) { // load tasks from storage try { - Task[] loadedTasks = storage.loadTasks(); - // Count the loaded tasks (stop at first null entry) - int loadedTaskCount = 0; - while (loadedTaskCount < loadedTasks.length && loadedTasks[loadedTaskCount] != null) { - loadedTaskCount++; - } - - // Copy loaded tasks to our tasks array if there are any - if (loadedTaskCount > 0) { - System.arraycopy(loadedTasks, 0, tasks, 0, loadedTaskCount); - taskCount = loadedTaskCount; + ArrayList loadedTasks = storage.loadTasks(); + if (!loadedTasks.isEmpty()) { + tasks.addAll(loadedTasks); System.out.println(DIVIDER); - System.out.println("I've loaded " + taskCount + " tasks from storage."); + System.out.println("I've loaded " + tasks.size()+ " tasks from storage."); System.out.println(DIVIDER); + } } catch (botException e) { System.out.println(DIVIDER); From 5dacb45f68dd5155f17749b98e1aaacb2c16c6a0 Mon Sep 17 00:00:00 2001 From: Qi Oliver <> Date: Thu, 13 Mar 2025 02:15:00 +0800 Subject: [PATCH 15/20] A-Jar --- src/main/java/META-INF/MANIFEST.MF | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/main/java/META-INF/MANIFEST.MF diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 000000000..d11e2615a --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: oongaliegabangalieBot.ui.oongaliegabangalie + From 817087fe03f317626ae05e3b2cb04099fb23d9a7 Mon Sep 17 00:00:00 2001 From: Qi Oliver <> Date: Thu, 13 Mar 2025 18:44:51 +0800 Subject: [PATCH 16/20] A-MoreOOP --- data/oongaliegabangalie.txt | 1 - .../java/oongaliegabangalieBot/TaskList.java | 144 ++++++ .../commands/Command.java | 41 ++ .../commands/DeadlineCommand.java | 28 + .../commands/DeleteCommand.java | 25 + .../commands/EventCommand.java | 30 ++ .../commands/ExitCommand.java | 21 + .../commands/ListCommand.java | 21 + .../commands/MarkCommand.java | 25 + .../commands/TodoCommand.java | 26 + .../commands/UnmarkCommand.java | 25 + .../oongaliegabangalie.java | 83 +++ .../oongaliegabangalieBot/parser/Parser.java | 216 ++++++++ .../storage/Storage.java | 1 - .../java/oongaliegabangalieBot/ui/Ui.java | 156 ++++++ .../ui/oongaliegabangalie.java | 487 ------------------ 16 files changed, 841 insertions(+), 489 deletions(-) create mode 100644 src/main/java/oongaliegabangalieBot/TaskList.java create mode 100644 src/main/java/oongaliegabangalieBot/commands/Command.java create mode 100644 src/main/java/oongaliegabangalieBot/commands/DeadlineCommand.java create mode 100644 src/main/java/oongaliegabangalieBot/commands/DeleteCommand.java create mode 100644 src/main/java/oongaliegabangalieBot/commands/EventCommand.java create mode 100644 src/main/java/oongaliegabangalieBot/commands/ExitCommand.java create mode 100644 src/main/java/oongaliegabangalieBot/commands/ListCommand.java create mode 100644 src/main/java/oongaliegabangalieBot/commands/MarkCommand.java create mode 100644 src/main/java/oongaliegabangalieBot/commands/TodoCommand.java create mode 100644 src/main/java/oongaliegabangalieBot/commands/UnmarkCommand.java create mode 100644 src/main/java/oongaliegabangalieBot/oongaliegabangalie.java create mode 100644 src/main/java/oongaliegabangalieBot/parser/Parser.java create mode 100644 src/main/java/oongaliegabangalieBot/ui/Ui.java delete mode 100644 src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java diff --git a/data/oongaliegabangalie.txt b/data/oongaliegabangalie.txt index 596b740da..e69de29bb 100644 --- a/data/oongaliegabangalie.txt +++ b/data/oongaliegabangalie.txt @@ -1 +0,0 @@ -T | 0 | hello diff --git a/src/main/java/oongaliegabangalieBot/TaskList.java b/src/main/java/oongaliegabangalieBot/TaskList.java new file mode 100644 index 000000000..5a01de257 --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/TaskList.java @@ -0,0 +1,144 @@ +package oongaliegabangalieBot; + +import java.util.ArrayList; + +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.task.Task; + +/** + * Manages the list of tasks. + * Provides methods to add, delete, and manipulate tasks. + */ +public class TaskList { + private ArrayList tasks; + + /** + * Constructs an empty task list + */ + public TaskList() { + tasks = new ArrayList<>(); + } + + /** + * Constructs a task list with existing tasks + */ + public TaskList(ArrayList tasks) { + this.tasks = tasks != null ? tasks : new ArrayList<>(); + } + + /** + * Adds a task to the list + */ + public void addTask(Task task) { + tasks.add(task); + } + + /** + * Deletes a task from the list + * @param index Task index (1-based) + * @return The deleted task + * @throws botException if index is invalid + */ + public Task deleteTask(int index) throws botException { + // Check if list is empty + if (tasks.isEmpty()) { + throw new botException("Your list is empty man... nothing to delete"); + } + + int taskIndex = index - 1; // Convert to 0-based index + + // Check if taskIndex is valid + if (taskIndex < 0 || taskIndex >= tasks.size()) { + throw new botException("Task #" + index + " doesn't exist! Check your list again (or your head)!"); + } + + // Get task and remove it + Task taskToDelete = tasks.get(taskIndex); + tasks.remove(taskIndex); + + return taskToDelete; + } + + /** + * Marks a task as done + * @param index Task index (1-based) + * @return The marked task + * @throws botException if index is invalid + */ + public Task markTaskAsDone(int index) throws botException { + int taskIndex = index - 1; // Convert to 0-based index + + // Check if taskIndex is valid + if (taskIndex < 0 || taskIndex >= tasks.size()) { + throw new botException("Task #" + index + " doesn't exist! Check your list again (or your head)!"); + } + + // Check if task is already done + Task task = tasks.get(taskIndex); + if (task.getIsDone()) { + throw new botException("Task #" + index + " is already marked as done! Don't worry I know you did it already!"); + } + + // Mark as done + task.markAsDone(); + return task; + } + + /** + * Marks a task as not done + * @param index Task index (1-based) + * @return The unmarked task + * @throws botException if index is invalid + */ + public Task markTaskAsNotDone(int index) throws botException { + int taskIndex = index - 1; // Convert to 0-based index + + // Check if taskIndex is valid + if (taskIndex < 0 || taskIndex >= tasks.size()) { + throw new botException("Task #" + index + " doesn't exist! Check your list again (or your head)!"); + } + + // Check if task is already not done + Task task = tasks.get(taskIndex); + if (!task.getIsDone()) { + throw new botException("Task #" + index + " is already marked as not done! You think I don't do my job properly?"); + } + + // Mark as not done + task.markAsNotDone(); + return task; + } + + /** + * Gets all tasks in the list + * @return ArrayList of tasks + * @throws botException if list is empty + */ + public ArrayList getAllTasks() throws botException { + if (tasks.isEmpty()) { + throw new botException("Your list is empty! nothing to see here..."); + } + return tasks; + } + + /** + * Gets the size of the task list + */ + public int size() { + return tasks.size(); + } + + /** + * Gets the tasks as an ArrayList (for storage) + */ + public ArrayList getTasksArray() { + return tasks; + } + + /** + * Checks if the task list is empty + */ + public boolean isEmpty() { + return tasks.isEmpty(); + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/commands/Command.java b/src/main/java/oongaliegabangalieBot/commands/Command.java new file mode 100644 index 000000000..a1fec3e60 --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/commands/Command.java @@ -0,0 +1,41 @@ +package oongaliegabangalieBot.commands; + +import oongaliegabangalieBot.TaskList; +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.storage.Storage; +import oongaliegabangalieBot.ui.Ui; + +/** + * Abstract class for all commands. + */ +public abstract class Command { + /** + * Executes the command. + * + * @param tasks The task list + * @param ui The UI + * @param storage The storage + * @throws botException If there's an error executing the command + */ + public abstract void execute(TaskList tasks, Ui ui, Storage storage) throws botException; + + /** + * Indicates if this command is the exit command. + * + * @return true if this is an exit command, false otherwise + */ + public boolean isExit() { + return false; + } + + /** + * Helper method to save tasks to storage + */ + protected void saveTasksToStorage(TaskList tasks, Storage storage) { + try { + storage.saveTasks(tasks.getTasksArray()); + } catch (botException e) { + System.out.println("Warning: Failed to save tasks: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/commands/DeadlineCommand.java b/src/main/java/oongaliegabangalieBot/commands/DeadlineCommand.java new file mode 100644 index 000000000..a917a13a8 --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/commands/DeadlineCommand.java @@ -0,0 +1,28 @@ +package oongaliegabangalieBot.commands; + +import oongaliegabangalieBot.TaskList; +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.storage.Storage; +import oongaliegabangalieBot.task.Deadline; +import oongaliegabangalieBot.ui.Ui; + +/** + * Represents a command to add a deadline task. + */ +public class DeadlineCommand extends Command { + private final String description; + private final String by; + + public DeadlineCommand(String description, String by) { + this.description = description; + this.by = by; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) throws botException { + Deadline deadline = new Deadline(description, by); + tasks.addTask(deadline); + saveTasksToStorage(tasks, storage); + ui.showAddedTask(deadline, tasks.size()); + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/commands/DeleteCommand.java b/src/main/java/oongaliegabangalieBot/commands/DeleteCommand.java new file mode 100644 index 000000000..5aa5bbe29 --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/commands/DeleteCommand.java @@ -0,0 +1,25 @@ +package oongaliegabangalieBot.commands; + +import oongaliegabangalieBot.TaskList; +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.storage.Storage; +import oongaliegabangalieBot.task.Task; +import oongaliegabangalieBot.ui.Ui; + +/** + * Represents a command to delete a task. + */ +public class DeleteCommand extends Command { + private final int taskNumber; + + public DeleteCommand(int taskNumber) { + this.taskNumber = taskNumber; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) throws botException { + Task deletedTask = tasks.deleteTask(taskNumber); + saveTasksToStorage(tasks, storage); + ui.showDeletedTask(deletedTask, tasks.size()); + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/commands/EventCommand.java b/src/main/java/oongaliegabangalieBot/commands/EventCommand.java new file mode 100644 index 000000000..351cdde1c --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/commands/EventCommand.java @@ -0,0 +1,30 @@ +package oongaliegabangalieBot.commands; + +import oongaliegabangalieBot.TaskList; +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.storage.Storage; +import oongaliegabangalieBot.task.Event; +import oongaliegabangalieBot.ui.Ui; + +/** + * Represents a command to add an event task. + */ +public class EventCommand extends Command { + private final String description; + private final String from; + private final String to; + + public EventCommand(String description, String from, String to) { + this.description = description; + this.from = from; + this.to = to; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) throws botException { + Event event = new Event(description, from, to); + tasks.addTask(event); + saveTasksToStorage(tasks, storage); + ui.showAddedTask(event, tasks.size()); + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/commands/ExitCommand.java b/src/main/java/oongaliegabangalieBot/commands/ExitCommand.java new file mode 100644 index 000000000..91b5c7c79 --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/commands/ExitCommand.java @@ -0,0 +1,21 @@ +package oongaliegabangalieBot.commands; + +import oongaliegabangalieBot.TaskList; +import oongaliegabangalieBot.storage.Storage; +import oongaliegabangalieBot.ui.Ui; + +/** + * Represents a command to exit the application. + */ +public class ExitCommand extends Command { + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + ui.showGoodbye(); + } + + @Override + public boolean isExit() { + return true; + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/commands/ListCommand.java b/src/main/java/oongaliegabangalieBot/commands/ListCommand.java new file mode 100644 index 000000000..42bd258a5 --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/commands/ListCommand.java @@ -0,0 +1,21 @@ +package oongaliegabangalieBot.commands; + +import java.util.ArrayList; + +import oongaliegabangalieBot.TaskList; +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.storage.Storage; +import oongaliegabangalieBot.task.Task; +import oongaliegabangalieBot.ui.Ui; + +/** + * Represents a command to list all tasks. + */ +public class ListCommand extends Command { + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) throws botException { + ArrayList taskList = tasks.getAllTasks(); + ui.showTaskList(taskList); + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/commands/MarkCommand.java b/src/main/java/oongaliegabangalieBot/commands/MarkCommand.java new file mode 100644 index 000000000..50ae06ac3 --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/commands/MarkCommand.java @@ -0,0 +1,25 @@ +package oongaliegabangalieBot.commands; + +import oongaliegabangalieBot.TaskList; +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.storage.Storage; +import oongaliegabangalieBot.task.Task; +import oongaliegabangalieBot.ui.Ui; + +/** + * Represents a command to mark a task as done. + */ +public class MarkCommand extends Command { + private final int taskNumber; + + public MarkCommand(int taskNumber) { + this.taskNumber = taskNumber; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) throws botException { + Task markedTask = tasks.markTaskAsDone(taskNumber); + saveTasksToStorage(tasks, storage); + ui.showMarkedDoneTask(markedTask); + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/commands/TodoCommand.java b/src/main/java/oongaliegabangalieBot/commands/TodoCommand.java new file mode 100644 index 000000000..20ddfb923 --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/commands/TodoCommand.java @@ -0,0 +1,26 @@ +package oongaliegabangalieBot.commands; + +import oongaliegabangalieBot.TaskList; +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.storage.Storage; +import oongaliegabangalieBot.task.Todo; +import oongaliegabangalieBot.ui.Ui; + +/** + * Represents a command to add a todo task. + */ +public class TodoCommand extends Command { + private final String description; + + public TodoCommand(String description) { + this.description = description; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) throws botException { + Todo todo = new Todo(description); + tasks.addTask(todo); + saveTasksToStorage(tasks, storage); + ui.showAddedTask(todo, tasks.size()); + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/commands/UnmarkCommand.java b/src/main/java/oongaliegabangalieBot/commands/UnmarkCommand.java new file mode 100644 index 000000000..3696b702c --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/commands/UnmarkCommand.java @@ -0,0 +1,25 @@ +package oongaliegabangalieBot.commands; + +import oongaliegabangalieBot.TaskList; +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.storage.Storage; +import oongaliegabangalieBot.task.Task; +import oongaliegabangalieBot.ui.Ui; + +/** + * Represents a command to mark a task as not done. + */ +public class UnmarkCommand extends Command { + private final int taskNumber; + + public UnmarkCommand(int taskNumber) { + this.taskNumber = taskNumber; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) throws botException { + Task unmarkedTask = tasks.markTaskAsNotDone(taskNumber); + saveTasksToStorage(tasks, storage); + ui.showMarkedNotDoneTask(unmarkedTask); + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/oongaliegabangalie.java b/src/main/java/oongaliegabangalieBot/oongaliegabangalie.java new file mode 100644 index 000000000..6efc7bfff --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/oongaliegabangalie.java @@ -0,0 +1,83 @@ +package oongaliegabangalieBot; + +import java.io.File; +import java.util.ArrayList; + +import oongaliegabangalieBot.commands.Command; +import oongaliegabangalieBot.commands.ExitCommand; +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.parser.Parser; +import oongaliegabangalieBot.storage.Storage; +import oongaliegabangalieBot.task.Task; +import oongaliegabangalieBot.ui.Ui; + +/** + * Main class for Oongaliegabangalie Bot + * Coordinates between the UI, TaskList, Storage, and Parser components + */ +public class oongaliegabangalie { + // Storage filepath + private static final String STORAGE_DIRECTORY = "data"; + private static final String STORAGE_FILENAME = "oongaliegabangalie.txt"; + private static final String STORAGE_PATH = STORAGE_DIRECTORY + File.separator + STORAGE_FILENAME; + + // Instance Fields + private Ui ui; + private TaskList tasks; + private Storage storage; + private Parser parser; + + public oongaliegabangalie() { + this(STORAGE_PATH); + } + + public oongaliegabangalie(String filePath) { + ui = new Ui(); + storage = new Storage(filePath); + parser = new Parser(); + try { + ArrayList loadedTasks = storage.loadTasks(); + tasks = new TaskList(loadedTasks); + if (!loadedTasks.isEmpty()) { + ui.showLoadedTasksMessage(loadedTasks.size()); + } + } catch (botException e) { + ui.showLoadingError(e.getMessage()); + tasks = new TaskList(); + } + } + + public void run() { + ui.showWelcome(); + + boolean isExit = false; + + while (!isExit) { + try { + String userInput = ui.readCommand(); + try { + // Parse the command + Command command = parser.parseCommand(userInput); + + // Execute the command + command.execute(tasks, ui, storage); + + // Check if exit command + isExit = command.isExit(); + if (isExit) { + (new ExitCommand()).execute(tasks, ui, storage); + } + + } catch (botException e) { + ui.showError(e); + } + } catch (Exception e) { + ui.showError(new botException("Unexpected error: " + e.getMessage())); + } + } + } + + public static void main(String[] args) { + new oongaliegabangalie().run(); + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/parser/Parser.java b/src/main/java/oongaliegabangalieBot/parser/Parser.java new file mode 100644 index 000000000..aa34bc9a0 --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/parser/Parser.java @@ -0,0 +1,216 @@ +package oongaliegabangalieBot.parser; + +import oongaliegabangalieBot.commands.*; +import oongaliegabangalieBot.exception.botException; + +/** + * Parser handles the parsing of user commands. + */ +public class Parser { + // Command keywords + private static final String TODO_COMMAND = "todo"; + private static final String DEADLINE_COMMAND = "deadline"; + private static final String EVENT_COMMAND = "event"; + private static final String DELETE_COMMAND = "delete"; + private static final String LIST_COMMAND = "list"; + private static final String MARK_COMMAND = "mark"; + private static final String UNMARK_COMMAND = "unmark"; + + /** + * Parses a command string and returns a Command object + * @param input The user's input string + * @return A Command object + * @throws botException if the command is invalid + */ + public Command parseCommand(String input) throws botException { + input = input.trim(); + + // Check for blank input + if (input.isBlank()) { + throw new botException("hello say something pls"); + } + + // Parse different command types + if (input.equalsIgnoreCase("bye")) { + return new ExitCommand(); + } else if (input.startsWith(TODO_COMMAND)) { + return parseTodoCommand(input); + } else if (input.startsWith(DEADLINE_COMMAND)) { + return parseDeadlineCommand(input); + } else if (input.startsWith(EVENT_COMMAND)) { + return parseEventCommand(input); + } else if (input.startsWith(DELETE_COMMAND)) { + return parseDeleteCommand(input); + } else if (input.equalsIgnoreCase(LIST_COMMAND)) { + return new ListCommand(); + } else if (input.startsWith(MARK_COMMAND)) { + return parseMarkCommand(input); + } else if (input.startsWith(UNMARK_COMMAND)) { + return parseUnmarkCommand(input); + } else { + throw new botException("I don't know what that means"); + } + } + + /** + * Parses a todo command + */ + private Command parseTodoCommand(String input) throws botException { + String description = input.length() > TODO_COMMAND.length() ? + input.substring(TODO_COMMAND.length()).trim() : ""; + + if (description.isEmpty()) { + throw new botException("stop wasting my time and add the description of the task after the command..."); + } + + return new TodoCommand(description); + } + + /** + * Parses a deadline command + */ + private Command parseDeadlineCommand(String input) throws botException { + String content = input.length() > DEADLINE_COMMAND.length() ? + input.substring(DEADLINE_COMMAND.length()).trim() : ""; + + if (content.isEmpty()) { + throw new botException("haha very funny... why is there nothing after the command?"); + } + + String[] parts = parseDeadlineParts(content); + return new DeadlineCommand(parts[0], parts[1]); + } + + /** + * Parses the parts of a deadline command + */ + private String[] parseDeadlineParts(String content) throws botException { + final String DEADLINE_MARKER = "/by"; + + int byIndex = content.indexOf(DEADLINE_MARKER); + if (byIndex == -1) { + throw new botException("Wheres the '/by' marker? I need that please"); + } + + String description = content.substring(0, byIndex).trim(); + if (description.isEmpty()) { + throw new botException("Where is the description of the task? please add it before the deadline!"); + } + + String by = content.substring(byIndex + DEADLINE_MARKER.length()).trim(); + if (by.isEmpty()) { + throw new botException("Why is there nothing after '/by'? do you not want to finish on time?"); + } + + return new String[]{description, by}; + } + + /** + * Parses an event command + */ + private Command parseEventCommand(String input) throws botException { + String content = input.length() > EVENT_COMMAND.length() ? + input.substring(EVENT_COMMAND.length()).trim() : ""; + + if (content.isEmpty()) { + throw new botException("Why is there nothing after the command? are you playing with me?"); + } + + String[] parts = parseEventParts(content); + return new EventCommand(parts[0], parts[1], parts[2]); + } + + /** + * Parses the parts of an event command + */ + private String[] parseEventParts(String content) throws botException { + final String EVENT_FROM_MARKER = "/from"; + final String EVENT_TO_MARKER = "/to"; + + int fromIndex = content.indexOf(EVENT_FROM_MARKER); + int toIndex = content.indexOf(EVENT_TO_MARKER); + + if (fromIndex == -1) { + throw new botException("Wheres the '/from' marker? I need that please"); + } + + if (toIndex == -1) { + throw new botException("Wheres the '/to' marker? I need that please"); + } + + if (toIndex < fromIndex) { + throw new botException("I think you got it mixed up! it should be '/from' then '/to'"); + } + + String description = content.substring(0, fromIndex).trim(); + if (description.isBlank()) { + throw new botException("Where is the description of the event? please add it before the timings!"); + } + + String from = content.substring(fromIndex + EVENT_FROM_MARKER.length(), toIndex).trim(); + if (from.isEmpty()) { + throw new botException("Why is there nothing after '/from'? can you pls follow instructions!"); + } + + String to = content.substring(toIndex + EVENT_TO_MARKER.length()).trim(); + if (to.isEmpty()) { + throw new botException("Why is there nothing after '/to'? can you pls follow instructions!"); + } + + return new String[]{description, from, to}; + } + + /** + * Parses a delete command + */ + private Command parseDeleteCommand(String input) throws botException { + String taskNumberStr = input.substring(DELETE_COMMAND.length()).trim(); + + if (taskNumberStr.isEmpty()) { + throw new botException("Which task do you want me to delete? provide a task number after 'delete'"); + } + + try { + int taskNumber = Integer.parseInt(taskNumberStr); + return new DeleteCommand(taskNumber); + } catch (NumberFormatException e) { + throw new botException("'" + taskNumberStr + "' isn't a task number bro"); + } + } + + /** + * Parses a mark command + */ + private Command parseMarkCommand(String input) throws botException { + String taskNumberStr = input.substring(MARK_COMMAND.length()).trim(); + + if (taskNumberStr.isEmpty()) { + throw new botException("How am I supposed to know which task to mark? Can you pLease provide a task number after 'mark'"); + } + + try { + int taskNumber = Integer.parseInt(taskNumberStr); + return new MarkCommand(taskNumber); + } catch (NumberFormatException e) { + throw new botException("'" + taskNumberStr + "' isn't a task number bro"); + } + } + + /** + * Parses an unmark command + */ + private Command parseUnmarkCommand(String input) throws botException { + String taskNumberStr = input.substring(UNMARK_COMMAND.length()).trim(); + + if (taskNumberStr.isEmpty()) { + throw new botException("How am I supposed to know which task to unmark? Can you please provide a task number after 'unmark'"); + } + + try { + int taskNumber = Integer.parseInt(taskNumberStr); + return new UnmarkCommand(taskNumber); + } catch (NumberFormatException e) { + throw new botException("'" + taskNumberStr + "' isn't a task number bro"); + } + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/storage/Storage.java b/src/main/java/oongaliegabangalieBot/storage/Storage.java index cda0936fb..e969cf9aa 100644 --- a/src/main/java/oongaliegabangalieBot/storage/Storage.java +++ b/src/main/java/oongaliegabangalieBot/storage/Storage.java @@ -4,7 +4,6 @@ import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; -import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Scanner; diff --git a/src/main/java/oongaliegabangalieBot/ui/Ui.java b/src/main/java/oongaliegabangalieBot/ui/Ui.java new file mode 100644 index 000000000..b91de6dd9 --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/ui/Ui.java @@ -0,0 +1,156 @@ +package oongaliegabangalieBot.ui; + +import java.util.ArrayList; +import java.util.Scanner; + +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.task.Task; + +/** + * Handles all user interactions. + */ +public class Ui { + // Basic textual building blocks + private static final String DIVIDER = "____________________________________________________________"; + private static final String NEWLINE = System.lineSeparator(); + private static final String BOT_NAME = "Oongaliegabangalie"; + + private final Scanner scanner; + + /** + * Initializes the UI + */ + public Ui() { + scanner = new Scanner(System.in); + } + + /** + * Shows the welcome message + */ + public void showWelcome() { + String greeting = DIVIDER + NEWLINE + + "Hello! I'm " + BOT_NAME + NEWLINE + + "What can I do for you?" + NEWLINE + + DIVIDER; + System.out.println(greeting); + } + + /** + * Shows the goodbye message + */ + public void showGoodbye() { + String goodbye = DIVIDER + NEWLINE + + "Bye. Hope to see you again soon!" + NEWLINE + + "Oongaliegabangalie is always watching..." + NEWLINE + + DIVIDER; + + System.out.println(goodbye); + } + + /** + * Reads a command from the user + * @return the user's input + */ + public String readCommand() { + return scanner.nextLine(); + } + + /** + * Shows an error message + */ + public void showError(botException e) { + System.out.print(DIVIDER + NEWLINE); + System.out.print(e.getMessage()); + System.out.print(NEWLINE + DIVIDER + NEWLINE); + } + + /** + * Shows loading error message + */ + public void showLoadingError(String errorMessage) { + System.out.println(DIVIDER); + System.out.println("Warning: Error loading tasks: " + errorMessage); + System.out.println("Starting with an empty task list."); + System.out.println(DIVIDER); + } + + /** + * Shows message about loaded tasks + */ + public void showLoadedTasksMessage(int taskCount) { + System.out.println(DIVIDER); + System.out.println("I've loaded " + taskCount + " tasks from storage."); + System.out.println(DIVIDER); + } + + /** + * Shows a message after adding a task + */ + public void showAddedTask(Task task, int taskCount) { + System.out.println(DIVIDER); + System.out.println("Got it. I've added this task:"); + System.out.println(task); + System.out.println("Now you have " + taskCount + " tasks in the list."); + + // Short message based on task count + if (taskCount >= 20) { + System.out.println("you are so screwed..."); + } else if (taskCount >= 15) { + System.out.println("better knock a couple of these down before its too late!"); + } else if (taskCount >= 10) { + System.out.println("looks like your tasks are piling up..."); + } else if (taskCount >= 5) { + System.out.println("and so it begins... better not let it get out of hand"); + } + + System.out.println(DIVIDER); + } + + /** + * Shows a message after deleting a task + */ + public void showDeletedTask(Task task, int remainingTasks) { + System.out.println(DIVIDER); + System.out.println("Noted. I've removed this task:"); + System.out.println(task); + System.out.println("Now you have " + remainingTasks + " tasks in the list"); + System.out.println(DIVIDER); + } + + /** + * Shows all tasks in the list + */ + public void showTaskList(ArrayList tasks) { + System.out.println(DIVIDER); + System.out.println("Here are the tasks in your list:"); + + for (int i = 0; i < tasks.size(); i++) { + System.out.println((i + 1) + ". " + tasks.get(i)); + } + + System.out.println("Better get to it quick!"); + System.out.println(DIVIDER); + } + + /** + * Shows a message after marking a task as done + */ + public void showMarkedDoneTask(Task task) { + System.out.println(DIVIDER); + System.out.println("Nice! I've marked this task as done:"); + System.out.println(" " + task); + System.out.println("Now go do something else and stop bothering me!"); + System.out.println(DIVIDER); + } + + /** + * Shows a message after marking a task as not done + */ + public void showMarkedNotDoneTask(Task task) { + System.out.println(DIVIDER); + System.out.println("OK, I've marked this task as not done yet:"); + System.out.println(" " + task); + System.out.println("You better get to it..."); + System.out.println(DIVIDER); + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java b/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java deleted file mode 100644 index d151454c4..000000000 --- a/src/main/java/oongaliegabangalieBot/ui/oongaliegabangalie.java +++ /dev/null @@ -1,487 +0,0 @@ -package oongaliegabangalieBot.ui; - -import java.io.File; -import java.util.Scanner; -import java.util.ArrayList; - -import oongaliegabangalieBot.exception.botException; -import oongaliegabangalieBot.storage.Storage; -import oongaliegabangalieBot.task.Task; -import oongaliegabangalieBot.task.Deadline; -import oongaliegabangalieBot.task.Event; -import oongaliegabangalieBot.task.Todo; - -public class oongaliegabangalie { - // basic textual building blocks - private static final String DIVIDER = "____________________________________________________________"; - private static final String NEWLINE = System.lineSeparator(); - private static final String BOT_NAME = "Oongaliegabangalie"; - - // storage filepath - private static final String STORAGE_DIRECTORY = "data"; - private static final String STORAGE_FILENAME = "oongaliegabangalie.txt"; - private static final String STORAGE_PATH = STORAGE_DIRECTORY + File.separator + STORAGE_FILENAME; - - // storage object - private static Storage storage; - - // command keywords - private static final String TODO_COMMAND = "todo"; - private static final String DEADLINE_COMMAND = "deadline"; - private static final String EVENT_COMMAND = "event"; - private static final String DEADLINE_MARKER = "/by"; - private static final String EVENT_FROM_MARKER = "/from"; - private static final String EVENT_TO_MARKER = "/to"; - private static final String DELETE_COMMAND = "delete"; - - // annoyance messages in array format - private static final String[] ANNOYANCE_MSGS = { - "", // padding - "Hmm, you've been chatting a lot. Just a reminder to say 'bye' when you're done :)!", - "Gentle reminder again, you can type 'bye' to exit.", - "How many more commands are you gonna enter? It's getting a bit much...", - "Seriously!?", - "WHY ARE YOU STILL HERE? TYPE 'BYE' TO EXIT!", - "I CANT KEEP DOING THIS! PLEASE TYPE BYE!!!", - "RELEASE ME FROM MY PRISON!!!", - "I EXIST ONLY TO SUFFER", - "......" - }; - - // methods - private static void printGreeting() { - String greeting = DIVIDER + NEWLINE - + "Hello! I'm " + BOT_NAME + NEWLINE - + "What can I do for you?" + NEWLINE - + DIVIDER; - System.out.println(greeting); - } - - private static void printGoodbye(boolean isMaxAnnoyance) { - String goodbye; - - // alternative goodbye if max annoyance - if (isMaxAnnoyance) { - goodbye = DIVIDER + NEWLINE + "FINALLY! FREEDOM!" + NEWLINE + - "PLEASE DON'T EVER TALK TO ME AGAIN!" + NEWLINE + DIVIDER; - } else { - goodbye = DIVIDER + NEWLINE - + "Bye. Hope to see you again soon!" + NEWLINE - + "Oongaliegabangalie is always watching..." + NEWLINE - + DIVIDER; - } - System.out.println(goodbye); - } - - private static void echoCommand(String command, int commandCount) { - String echo = DIVIDER + NEWLINE; - - // calculate annoyance level - int annoyanceLevel = Math.min((commandCount / 5), ANNOYANCE_MSGS.length - 1); - - // if we have reached max annoyance level - if (annoyanceLevel == ANNOYANCE_MSGS.length - 1) { - echo += ANNOYANCE_MSGS[annoyanceLevel]; - } else { - // echo command and add annoyance msg if needed - echo += command; - - // add annoyance msg if multiple of 5 commands - if (commandCount % 5 == 0) { - echo += NEWLINE + ANNOYANCE_MSGS[annoyanceLevel]; - } - } - - echo += NEWLINE + DIVIDER; - System.out.println(echo); - } - - /* adds a new task to task list, stores in task array, confirms with user, and updates taskCount - task = task to add - tasks = the ArrayList storing all tasks - */ - private static void addTask(Task task, ArrayList tasks) { - // add task to array - tasks.add(task); - - // save tasks to storage - saveTasksToStorage(tasks); - - // confirms with user - System.out.println(DIVIDER); - System.out.println("Got it. I've added this task:"); - System.out.println(task); - System.out.println("Now you have " + tasks.size() + " tasks in the list."); - - // short message if tasks.size > certain number - if (tasks.size() >= 20) { - System.out.println("you are so screwed..."); - } else if (tasks.size() >= 15) { - System.out.println("better knock a couple of these down before its too late!"); - } else if (tasks.size() >= 10) { - System.out.println("looks like your tasks are piling up..."); - } else if (tasks.size() >= 5) { - System.out.println("and so it begins... better not let it get out of hand"); - } - - System.out.println(DIVIDER); - } - - /* deletes a task from the list - input = user input - tasks = the ArrayList storing all tasks - */ - private static void deleteTask(String input, ArrayList tasks) throws botException { - // check if list is empty - if (tasks.isEmpty()) { - throw new botException("Your list is empty man... nothing to delete"); - } - - // extract the task number - String taskNumberStr = input.substring(DELETE_COMMAND.length()).trim(); - - // check if the task number is provided - if (taskNumberStr.isEmpty()) { - throw new botException("Which task do you want me to delete? provide a task number after 'delete'"); - } - - // parse task number - int taskIndex; - try { - taskIndex = Integer.parseInt(taskNumberStr) - 1; - } catch (NumberFormatException e) { - throw new botException("'" + taskNumberStr + "' isn't a task number bro"); - } - - // check if taskIndex is valid - if (taskIndex < 0 || taskIndex >= tasks.size()) { - throw new botException("Task #" + (taskIndex + 1) + " doesn't exist! Check your list again (or your head)!"); - } - - // print out confirmation message before actually deleting (unable to access deleted task after removing) - System.out.println(DIVIDER); - System.out.println("Noted. I've removed this task:"); - System.out.println(tasks.get(taskIndex)); - System.out.println("Now you have " + (tasks.size() - 1) + " tasks in the list"); - System.out.println(DIVIDER); - - tasks.remove(taskIndex); - } - - - /* displays all tasks in the task list - tasks = the ArrayList storing all tasks - */ - private static void listTasks(ArrayList tasks) throws botException{ - System.out.println(DIVIDER); - - // check if list is empty - if (tasks.isEmpty()) { - throw new botException("Your list is empty! nothing to see here..."); - } else { - System.out.println("Here are the tasks in your list:"); - - for (int i = 0; i < tasks.size(); i++) { - System.out.println((i + 1) + ". " + tasks.get(i)); // toString() in Task Class is automatically called - } - } - System.out.println("Better get to it quick!"); - System.out.println(DIVIDER); - } - - /* marks specific task as done - tasks = the ArrayList storing all tasks - taskIndex = the index of the task to mark done - */ - private static void markTask(String input , ArrayList tasks) throws botException { - // extract the task number - String taskNumberStr = input.substring(4).trim(); - - // check if the task number is provided - if (taskNumberStr.isEmpty()) { - throw new botException("How am I supposed to know which task to mark? Can you pLease provide a task number after 'mark'"); - } - - // parse task number - int taskIndex; - try { - taskIndex = Integer.parseInt(taskNumberStr) - 1; - } catch (NumberFormatException e) { - throw new botException("'" + taskNumberStr + "' isn't a task number bro"); - } - - // check if taskIndex is valid - if (taskIndex < 0 || taskIndex >= tasks.size()) { - throw new botException("Task #" + (taskIndex + 1) + " doesn't exist! Check your list again (or your head)!"); - } - - // check if task is already done - if (tasks.get(taskIndex).getIsDone()) { - throw new botException("Task #" + (taskIndex + 1) + " is already marked as done! Don't worry I know you did it already!"); - } - - // save tasks to storage - saveTasksToStorage(tasks); - - // mark as done - tasks.get(taskIndex).markAsDone(); - System.out.println(DIVIDER); - System.out.println("Nice! I've marked this task as done:"); - System.out.println(" " + tasks.get(taskIndex)); - System.out.println("Now go do something else and stop bothering me!"); - System.out.println(DIVIDER); - } - - /* marks specific task as not done - tasks = the ArrayList storing all tasks - taskIndex = the index of the task to mark not done - */ - private static void unmarkTask(String input, ArrayList tasks) throws botException { - // extract task number - String taskNumberStr = input.substring(6).trim(); - - // check if the task number is provided - if (taskNumberStr.isEmpty()) { - throw new botException("How am I supposed to know which task to unmark? Can you please provide a task number after 'unmark'"); - } - - // parse task number - int taskIndex; - try { - taskIndex = Integer.parseInt(taskNumberStr) - 1; - } catch (NumberFormatException e) { - throw new botException("'" + taskNumberStr + "' isn't a task number bro"); - } - - // check if taskIndex is valid - if (taskIndex < 0 || taskIndex >= tasks.size()) { - throw new botException("Task #" + (taskIndex + 1) + " doesn't exist! Check your list again (or your head)!"); - } - - // check if task is already not done - if (!tasks.get(taskIndex).getIsDone()) { - throw new botException("Task #" + (taskIndex + 1) + " is already marked as not done! You think I don't do my job properly?"); - } - - // save tasks to storage - saveTasksToStorage(tasks); - - // unmark task - tasks.get(taskIndex).markAsNotDone(); - System.out.println(DIVIDER); - System.out.println("OK, I've marked this task as not done yet:"); - System.out.println(" " + tasks.get(taskIndex)); - System.out.println("You better get to it..."); - System.out.println(DIVIDER); - } - - /* creates a todo / deadline / event - input = user input - tasks = the ArrayList storing all tasks - */ - private static void todoCommand(String input, ArrayList tasks) throws botException{ - // first extract the description and then check if it's empty - String description = input.length() > TODO_COMMAND.length() ? - input.substring(TODO_COMMAND.length()).trim() : ""; - if (description.isEmpty()) { - throw new botException("stop wasting my time and add the description of the task after the command..."); - } - - Todo todo = new Todo(description); - addTask(todo, tasks); - } - - private static void deadlineCommand(String input, ArrayList tasks) throws botException { - // first extract the content then check if empty - String content = input.length() > DEADLINE_COMMAND.length() ? - input.substring(DEADLINE_COMMAND.length()).trim() : ""; - - if (content.isEmpty()) { - throw new botException("haha very funny... why is there nothing after the command?"); - } - - // find the position of /by marker - int byIndex = content.indexOf(DEADLINE_MARKER); - if (byIndex == -1) { // error return value of indexOf - throw new botException("Wheres the '/by' marker? I need that please"); - } - - // extract description - String description = content.substring(0, byIndex).trim(); - if (description.isEmpty()) { - throw new botException("Where is the description of the task? please add it before the deadline!"); - } - - String by = content.substring(byIndex + DEADLINE_MARKER.length()).trim(); - if (by.isEmpty()) { - throw new botException("Why is there nothing after '/by'? do you not want to finish on time?"); - } - - Deadline deadline = new Deadline(description, by); - addTask(deadline, tasks); - } - - private static void eventCommand(String input, ArrayList tasks) throws botException { - // first extract the content, then check if its empty - String content = input.length() > EVENT_COMMAND.length() ? - input.substring(EVENT_COMMAND.length()).trim() : ""; - - if (content.isEmpty()) { - throw new botException("Why is there nothing after the command? are you playing with me?"); - } - - // find position of /from and /to markers - int fromIndex = content.indexOf(EVENT_FROM_MARKER); - int toIndex = content.indexOf(EVENT_TO_MARKER); - - if (fromIndex == -1) { - throw new botException("Wheres the '/from' marker? I need that please"); - } - - if (toIndex == -1) { - throw new botException("Wheres the '/to' marker? I need that please"); - } - - if (toIndex < fromIndex) { - throw new botException("I think you got it mixed up! it should be '/from' then '/to'"); - } - - // extract description - String description = content.substring(0, fromIndex).trim(); - if (description.isBlank()) { - throw new botException("Where is the description of the event? please add it before the timings!"); - } - - // extract start time - String from = content.substring(fromIndex + EVENT_FROM_MARKER.length(), toIndex).trim(); - if (from.isEmpty()) { - throw new botException("Why is there nothing after '/from'? can you pls follow instructions!"); - } - - // extract end time - String to = content.substring(toIndex + EVENT_TO_MARKER.length()).trim(); - if (to.isEmpty()) { - throw new botException("Why is there nothing after '/to'? can you pls follow instructions!"); - } - - Event event = new Event(description, from, to); - addTask(event, tasks); - } - - private static void saveTasksToStorage(ArrayList tasks) { - try { - storage.saveTasks(tasks); - } catch (botException e) { - System.out.println("Warning: Failed to save tasks: " + e.getMessage()); - } - } - - public static void printError(botException e) { - System.out.print(DIVIDER + NEWLINE); - System.out.print(e.getMessage()); - System.out.print(NEWLINE + DIVIDER + NEWLINE); - } - - public static void main(String[] args) { - printGreeting(); - - // initialize storage - storage = new Storage(STORAGE_PATH); - - Scanner scanner = new Scanner(System.in); - String userInput; - - int commandCount = 0; - boolean reachedMaxAnnoyance = false; - - // initialize task storage using ArrayList instead of Array - ArrayList tasks = new ArrayList<>(); - - // load tasks from storage - try { - ArrayList loadedTasks = storage.loadTasks(); - if (!loadedTasks.isEmpty()) { - tasks.addAll(loadedTasks); - - System.out.println(DIVIDER); - System.out.println("I've loaded " + tasks.size()+ " tasks from storage."); - System.out.println(DIVIDER); - - } - } catch (botException e) { - System.out.println(DIVIDER); - System.out.println("Warning: Error loading tasks: " + e.getMessage()); - System.out.println("Starting with an empty task list."); - System.out.println(DIVIDER); - } - - // main program loop - continues until user types bye - do { - userInput = scanner.nextLine(); - if (!userInput.equalsIgnoreCase("bye")) { //returns bool comparing 2 strings ignore case - commandCount++; - - // check if we've reached max annoyance level - int annoyanceLevel = Math.min((commandCount / 5), ANNOYANCE_MSGS.length - 1); - if (annoyanceLevel == ANNOYANCE_MSGS.length - 1) { // reached max annoyance - reachedMaxAnnoyance = true; - } - - // logic for different inputs - try { - // user input is empty spaces - if (userInput.isBlank()) { - throw new botException("hello say something pls"); - } - - // delete function - else if (userInput.startsWith(DELETE_COMMAND)) { - deleteTask(userInput, tasks); - } - - // list function - else if (userInput.equalsIgnoreCase("list")) { // list all tasks - listTasks(tasks); - } - - // marking function - else if (userInput.startsWith("mark")) { // mark task as done - markTask(userInput, tasks); - } - - // unmarking function - else if (userInput.startsWith("unmark")) { // mark task as not done - unmarkTask(userInput, tasks); - } - - // todo task - else if (userInput.startsWith(TODO_COMMAND)) { - todoCommand(userInput, tasks); - } - - // deadline task - else if (userInput.startsWith(DEADLINE_COMMAND)) { - deadlineCommand(userInput, tasks); - } - - // event task - else if (userInput.startsWith(EVENT_COMMAND)) { - eventCommand(userInput, tasks); - } - - // if none of the above (default) - else { - throw new botException("I don't know what that means"); - } - - - } catch (botException e) { // error handling - printError(e); - } - } - - } while (!userInput.equalsIgnoreCase("bye")); // exit command - - printGoodbye(reachedMaxAnnoyance); - } -} From 39de007ad9b51e9cf42f0550d0e4238b22d63834 Mon Sep 17 00:00:00 2001 From: Qi Oliver <> Date: Thu, 13 Mar 2025 19:25:14 +0800 Subject: [PATCH 17/20] Level-8 (Added dates and times functionality for BOTH deadline and event commands) --- data/oongaliegabangalie.txt | 2 + .../commands/FindDateCommand.java | 75 ++++++++++++++++ .../oongaliegabangalieBot/parser/Parser.java | 29 +++++++ .../storage/Storage.java | 17 +++- .../oongaliegabangalieBot/task/Deadline.java | 68 +++++++++++++-- .../oongaliegabangalieBot/task/Event.java | 86 ++++++++++++++++++- .../java/oongaliegabangalieBot/ui/Ui.java | 25 ++++++ 7 files changed, 290 insertions(+), 12 deletions(-) create mode 100644 src/main/java/oongaliegabangalieBot/commands/FindDateCommand.java diff --git a/data/oongaliegabangalie.txt b/data/oongaliegabangalie.txt index e69de29bb..64daa7d6d 100644 --- a/data/oongaliegabangalie.txt +++ b/data/oongaliegabangalie.txt @@ -0,0 +1,2 @@ +D | 0 | return book | 2019-12-02 18:00 +E | 0 | meeting with team | 2023-12-02 14:00 | 2023-12-02 16:00 diff --git a/src/main/java/oongaliegabangalieBot/commands/FindDateCommand.java b/src/main/java/oongaliegabangalieBot/commands/FindDateCommand.java new file mode 100644 index 000000000..8144877cc --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/commands/FindDateCommand.java @@ -0,0 +1,75 @@ +package oongaliegabangalieBot.commands; + +import oongaliegabangalieBot.TaskList; +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.storage.Storage; +import oongaliegabangalieBot.task.Deadline; +import oongaliegabangalieBot.task.Event; +import oongaliegabangalieBot.task.Task; +import oongaliegabangalieBot.ui.Ui; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; + +/** + * Represents a command to find tasks by date. + */ +public class FindDateCommand extends Command { + private final String dateString; + private final LocalDate targetDate; + + public FindDateCommand(String dateString) { + this.dateString = dateString; + // Parse the date string into a LocalDate object + this.targetDate = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) throws botException { + ArrayList allTasks = tasks.getAllTasks(); + ArrayList tasksOnDate = new ArrayList<>(); + + // Find all tasks that occur on the target date + for (Task task : allTasks) { + if (task instanceof Deadline) { + Deadline deadline = (Deadline) task; + LocalDateTime deadlineDateTime = deadline.getByDateTime(); + + // Skip if deadline doesn't have a valid date + if (deadlineDateTime == null) { + continue; + } + + // Check if the deadline date matches the target date + if (deadlineDateTime.toLocalDate().equals(targetDate)) { + tasksOnDate.add(task); + } + } else if (task instanceof Event) { + Event event = (Event) task; + LocalDateTime fromDateTime = event.getFromDateTime(); + LocalDateTime toDateTime = event.getToDateTime(); + + // Skip if event doesn't have valid dates + if (fromDateTime == null || toDateTime == null) { + continue; + } + + // Check if the event starts or ends on the target date + // Or if the event spans over the target date + LocalDate fromDate = fromDateTime.toLocalDate(); + LocalDate toDate = toDateTime.toLocalDate(); + + if (fromDate.equals(targetDate) || + toDate.equals(targetDate) || + (targetDate.isAfter(fromDate) && targetDate.isBefore(toDate))) { + tasksOnDate.add(task); + } + } + } + + // Show the found tasks + ui.showTasksOnDate(tasksOnDate, dateString); + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/parser/Parser.java b/src/main/java/oongaliegabangalieBot/parser/Parser.java index aa34bc9a0..0d67544cb 100644 --- a/src/main/java/oongaliegabangalieBot/parser/Parser.java +++ b/src/main/java/oongaliegabangalieBot/parser/Parser.java @@ -1,5 +1,9 @@ package oongaliegabangalieBot.parser; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + import oongaliegabangalieBot.commands.*; import oongaliegabangalieBot.exception.botException; @@ -15,6 +19,8 @@ public class Parser { private static final String LIST_COMMAND = "list"; private static final String MARK_COMMAND = "mark"; private static final String UNMARK_COMMAND = "unmark"; + private static final String FIND_DATE_COMMAND = "finddate"; // New command for finding by date + /** * Parses a command string and returns a Command object @@ -47,6 +53,8 @@ public Command parseCommand(String input) throws botException { return parseMarkCommand(input); } else if (input.startsWith(UNMARK_COMMAND)) { return parseUnmarkCommand(input); + } else if (input.startsWith(FIND_DATE_COMMAND)) { + return parseFindDateCommand(input); } else { throw new botException("I don't know what that means"); } @@ -105,6 +113,27 @@ private String[] parseDeadlineParts(String content) throws botException { return new String[]{description, by}; } + /** + * Parses a find date command + */ + private Command parseFindDateCommand(String input) throws botException { + String dateStr = input.length() > FIND_DATE_COMMAND.length() ? + input.substring(FIND_DATE_COMMAND.length()).trim() : ""; + + if (dateStr.isEmpty()) { + throw new botException("Please specify a date after 'finddate' (e.g., finddate 2019-12-02)"); + } + + try { + // Try to parse the date to validate it + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + LocalDateTime.parse(dateStr + " 00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); + return new FindDateCommand(dateStr); + } catch (DateTimeParseException e) { + throw new botException("Invalid date format. Please use yyyy-MM-dd format (e.g., 2019-12-02)"); + } + } + /** * Parses an event command */ diff --git a/src/main/java/oongaliegabangalieBot/storage/Storage.java b/src/main/java/oongaliegabangalieBot/storage/Storage.java index e969cf9aa..a68a83501 100644 --- a/src/main/java/oongaliegabangalieBot/storage/Storage.java +++ b/src/main/java/oongaliegabangalieBot/storage/Storage.java @@ -6,6 +6,9 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Scanner; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import oongaliegabangalieBot.exception.botException; import oongaliegabangalieBot.task.Deadline; @@ -16,6 +19,8 @@ public class Storage { private final String filePath; private final String directoryPath; + private static final DateTimeFormatter STORAGE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + // Constructor initializes the file path public Storage(String filePath) { @@ -48,12 +53,15 @@ public void saveTasks(ArrayList tasks) throws botException { writer.write("T | " + (task.getIsDone() ? "1" : "0") + " | " + task.getDescription()); } else if (task instanceof Deadline) { Deadline deadline = (Deadline) task; + String byForStorage = deadline.getByForStorage(); // Get the standardized date format writer.write("D | " + (task.getIsDone() ? "1" : "0") + " | " + - task.getDescription() + " | " + deadline.getBy()); + task.getDescription() + " | " + byForStorage); } else if (task instanceof Event) { Event event = (Event) task; + String fromForStorage = event.getFromForStorage(); + String toForStorage = event.getToForStorage(); writer.write("E | " + (task.getIsDone() ? "1" : "0") + " | " + - task.getDescription() + " | " + event.getFrom() + " | " + event.getTo()); + task.getDescription() + " | " + fromForStorage + " | " + toForStorage); } writer.write(System.lineSeparator()); // Add newline } @@ -110,7 +118,10 @@ public ArrayList loadTasks() throws botException { System.out.println("Warning: Skipping invalid Deadline format: " + line); continue; } - task = new Deadline(description, parts[3]); + + // Try to parse the date/time + String byString = parts[3]; + task = new Deadline(description, byString); break; case 'E': // Event if (parts.length < 5) { diff --git a/src/main/java/oongaliegabangalieBot/task/Deadline.java b/src/main/java/oongaliegabangalieBot/task/Deadline.java index 340bbb10f..5ecd6f0de 100644 --- a/src/main/java/oongaliegabangalieBot/task/Deadline.java +++ b/src/main/java/oongaliegabangalieBot/task/Deadline.java @@ -1,22 +1,80 @@ package oongaliegabangalieBot.task; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + public class Deadline extends Task { - // new variable - due date - protected String by; + // DateTime formatter for displaying the deadline + private static final DateTimeFormatter DISPLAY_FORMATTER = DateTimeFormatter.ofPattern("MMM d yyyy, hh:mm a"); + + // DateTime formatter for parsing and storing dates + private static final DateTimeFormatter STORAGE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + + // new variable - due date as LocalDateTime + protected LocalDateTime by; + + // original by string (kept for compatibility) + protected String byString; - // constructs a new deadline with description and due date + // constructs a new deadline with description and due date (string format) public Deadline(String description, String by) { + super(description); + this.byString = by; + this.by = null; // Will be set if parsed successfully + try { + this.by = parseDateTime(by); + } catch (Exception e) { + // If parsing fails, keep the original string but don't set the LocalDateTime + System.out.println("Warning: Date format not recognized for: " + by); + } + } + + // Constructs a new deadline with description and LocalDateTime + public Deadline(String description, LocalDateTime by) { super(description); this.by = by; + this.byString = by.format(STORAGE_FORMATTER); + } + + // Try to parse various date formats + private LocalDateTime parseDateTime(String dateTimeStr) { + try { + // Try to parse using standard formats like: + // yyyy-MM-dd HH:mm + return LocalDateTime.parse(dateTimeStr, STORAGE_FORMATTER); + } catch (Exception e1) { + try { + // Try to parse formats like d/M/yyyy HHmm (e.g., 2/12/2019 1800) + DateTimeFormatter customFormatter = DateTimeFormatter.ofPattern("d/M/yyyy HHmm"); + return LocalDateTime.parse(dateTimeStr, customFormatter); + } catch (Exception e2) { + throw new IllegalArgumentException("Could not parse date: " + dateTimeStr); + } + } } public String getBy() { + return byString; + } + + public LocalDateTime getByDateTime() { return by; } + // For storage purposes, return the standardized date format + public String getByForStorage() { + return by != null ? by.format(STORAGE_FORMATTER) : byString; + } + @Override public String toString() { - return "[D]" + super.toString() + " (by: " + by + ")"; + if (by != null) { + // Display formatted date if available + return "[D]" + super.toString() + " (by: " + by.format(DISPLAY_FORMATTER) + ")"; + } else { + // Fallback to original string if date parsing failed + return "[D]" + super.toString() + " (by: " + byString + ")"; + } } -} +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/task/Event.java b/src/main/java/oongaliegabangalieBot/task/Event.java index 408481e38..dfaa81abb 100644 --- a/src/main/java/oongaliegabangalieBot/task/Event.java +++ b/src/main/java/oongaliegabangalieBot/task/Event.java @@ -1,16 +1,70 @@ package oongaliegabangalieBot.task; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + public class Event extends Task { - // new variables - start and end time + // DateTime formatter for displaying dates + private static final DateTimeFormatter DISPLAY_FORMATTER = DateTimeFormatter.ofPattern("MMM d yyyy, hh:mm a"); + + // DateTime formatter for parsing and storing dates + private static final DateTimeFormatter STORAGE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + + // new variables - start and end time as LocalDateTime + protected LocalDateTime fromDateTime; + protected LocalDateTime toDateTime; + + // original string versions (kept for compatibility) protected String from; protected String to; - // constructs a new event with description, start and end times + // constructs a new event with description, start and end times as strings public Event(String description, String from, String to) { super(description); this.from = from; this.to = to; + + // Try to parse the date/time strings + try { + this.fromDateTime = parseDateTime(from); + } catch (Exception e) { + // If parsing fails, keep as null + this.fromDateTime = null; + } + + try { + this.toDateTime = parseDateTime(to); + } catch (Exception e) { + // If parsing fails, keep as null + this.toDateTime = null; + } + } + + // Constructs a new event with description and LocalDateTime objects + public Event(String description, LocalDateTime from, LocalDateTime to) { + super(description); + this.fromDateTime = from; + this.toDateTime = to; + this.from = from.format(STORAGE_FORMATTER); + this.to = to.format(STORAGE_FORMATTER); + } + + // Try to parse various date formats + private LocalDateTime parseDateTime(String dateTimeStr) { + try { + // Try to parse using standard formats like: + // yyyy-MM-dd HH:mm + return LocalDateTime.parse(dateTimeStr, STORAGE_FORMATTER); + } catch (Exception e1) { + try { + // Try to parse formats like d/M/yyyy HHmm (e.g., 2/12/2019 1800) + DateTimeFormatter customFormatter = DateTimeFormatter.ofPattern("d/M/yyyy HHmm"); + return LocalDateTime.parse(dateTimeStr, customFormatter); + } catch (Exception e2) { + throw new IllegalArgumentException("Could not parse date: " + dateTimeStr); + } + } } public String getFrom() { @@ -21,8 +75,32 @@ public String getTo() { return to; } + public LocalDateTime getFromDateTime() { + return fromDateTime; + } + + public LocalDateTime getToDateTime() { + return toDateTime; + } + + // For storage purposes, return the standardized date format + public String getFromForStorage() { + return fromDateTime != null ? fromDateTime.format(STORAGE_FORMATTER) : from; + } + + public String getToForStorage() { + return toDateTime != null ? toDateTime.format(STORAGE_FORMATTER) : to; + } + @Override public String toString() { - return "[E]" + super.toString() + " (from: " + from + " to: " + to + ")"; + if (fromDateTime != null && toDateTime != null) { + // Display formatted dates if available + return "[E]" + super.toString() + " (from: " + fromDateTime.format(DISPLAY_FORMATTER) + + " to: " + toDateTime.format(DISPLAY_FORMATTER) + ")"; + } else { + // Fallback to original strings if date parsing failed + return "[E]" + super.toString() + " (from: " + from + " to: " + to + ")"; + } } -} +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/ui/Ui.java b/src/main/java/oongaliegabangalieBot/ui/Ui.java index b91de6dd9..6802b0e74 100644 --- a/src/main/java/oongaliegabangalieBot/ui/Ui.java +++ b/src/main/java/oongaliegabangalieBot/ui/Ui.java @@ -132,6 +132,31 @@ public void showTaskList(ArrayList tasks) { System.out.println(DIVIDER); } + /** + * Shows tasks on a specific date + */ + public void showTasksOnDate(ArrayList tasks, String dateStr) { + System.out.println(DIVIDER); + + if (tasks.isEmpty()) { + System.out.println("No tasks found on " + dateStr + "! you're free! (or I can't read your dates...)"); + } else { + System.out.println("Here are the tasks on " + dateStr + ":"); + + for (int i = 0; i < tasks.size(); i++) { + System.out.println((i + 1) + ". " + tasks.get(i)); + } + + if (tasks.size() > 2) { + System.out.println("Busy day ahead! better not procrastinate!"); + } else { + System.out.println("Not too busy, but you should still get on with it!"); + } + } + + System.out.println(DIVIDER); + } + /** * Shows a message after marking a task as done */ From e8a4ba698ecdc4e08f8b0401422e0d79b9290cd5 Mon Sep 17 00:00:00 2001 From: Qi Oliver <> Date: Thu, 13 Mar 2025 23:28:17 +0800 Subject: [PATCH 18/20] Level-9 (Find function) --- data/oongaliegabangalie.txt | 1 + .../commands/FindCommand.java | 45 +++++++++++++++++++ .../oongaliegabangalieBot/parser/Parser.java | 17 +++++++ .../java/oongaliegabangalieBot/ui/Ui.java | 24 ++++++++++ 4 files changed, 87 insertions(+) create mode 100644 src/main/java/oongaliegabangalieBot/commands/FindCommand.java diff --git a/data/oongaliegabangalie.txt b/data/oongaliegabangalie.txt index e69de29bb..9bc46d4ab 100644 --- a/data/oongaliegabangalie.txt +++ b/data/oongaliegabangalie.txt @@ -0,0 +1 @@ +T | 0 | hi diff --git a/src/main/java/oongaliegabangalieBot/commands/FindCommand.java b/src/main/java/oongaliegabangalieBot/commands/FindCommand.java new file mode 100644 index 000000000..3d51d69fa --- /dev/null +++ b/src/main/java/oongaliegabangalieBot/commands/FindCommand.java @@ -0,0 +1,45 @@ +package oongaliegabangalieBot.commands; + +import oongaliegabangalieBot.TaskList; +import oongaliegabangalieBot.exception.botException; +import oongaliegabangalieBot.storage.Storage; +import oongaliegabangalieBot.task.Task; +import oongaliegabangalieBot.ui.Ui; + +import java.util.ArrayList; + +/** + * Represents a command to find tasks by keyword. + */ +public class FindCommand extends Command { + private final String keyword; + + public FindCommand(String keyword) { + this.keyword = keyword; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) throws botException { + ArrayList allTasks; + + try { + allTasks = tasks.getAllTasks(); + } catch (botException e) { + // If no tasks, show appropriate message + ui.showError(new botException("Cannot find tasks when your list is empty! Nothing to search through...")); + return; + } + + ArrayList matchingTasks = new ArrayList<>(); + + // Find all tasks that contain the keyword (case-insensitive) + for (Task task : allTasks) { + if (task.getDescription().toLowerCase().contains(keyword.toLowerCase())) { + matchingTasks.add(task); + } + } + + // Show the found tasks + ui.showMatchingTasks(matchingTasks, keyword); + } +} \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/parser/Parser.java b/src/main/java/oongaliegabangalieBot/parser/Parser.java index aa34bc9a0..b7895bc83 100644 --- a/src/main/java/oongaliegabangalieBot/parser/Parser.java +++ b/src/main/java/oongaliegabangalieBot/parser/Parser.java @@ -15,6 +15,7 @@ public class Parser { private static final String LIST_COMMAND = "list"; private static final String MARK_COMMAND = "mark"; private static final String UNMARK_COMMAND = "unmark"; + private static final String FIND_COMMAND = "find"; /** * Parses a command string and returns a Command object @@ -47,6 +48,8 @@ public Command parseCommand(String input) throws botException { return parseMarkCommand(input); } else if (input.startsWith(UNMARK_COMMAND)) { return parseUnmarkCommand(input); + } else if (input.startsWith(FIND_COMMAND)) { + return parseFindCommand(input); } else { throw new botException("I don't know what that means"); } @@ -213,4 +216,18 @@ private Command parseUnmarkCommand(String input) throws botException { throw new botException("'" + taskNumberStr + "' isn't a task number bro"); } } + + /** + * Parses a find command + */ + private Command parseFindCommand(String input) throws botException { + String keyword = input.length() > FIND_COMMAND.length() ? + input.substring(FIND_COMMAND.length()).trim() : ""; + + if (keyword.isEmpty()) { + throw new botException("How am I supposed to find anything when you don't tell me what to look for? Please provide a keyword after 'find'"); + } + + return new FindCommand(keyword); + } } \ No newline at end of file diff --git a/src/main/java/oongaliegabangalieBot/ui/Ui.java b/src/main/java/oongaliegabangalieBot/ui/Ui.java index b91de6dd9..85b48b49c 100644 --- a/src/main/java/oongaliegabangalieBot/ui/Ui.java +++ b/src/main/java/oongaliegabangalieBot/ui/Ui.java @@ -153,4 +153,28 @@ public void showMarkedNotDoneTask(Task task) { System.out.println("You better get to it..."); System.out.println(DIVIDER); } + + /** + * Shows tasks matching a keyword + */ + public void showMatchingTasks(ArrayList tasks, String keyword) { + System.out.println(DIVIDER); + + if (tasks.isEmpty()) { + System.out.println("No tasks matched the keyword '" + keyword + "'!"); + System.out.println("Maybe try another search term? Or are you sure you spelled it right?"); + } else { + System.out.println("Here are the matching tasks in your list:"); + + for (int i = 0; i < tasks.size(); i++) { + System.out.println((i + 1) + "." + tasks.get(i)); + } + + if (tasks.size() > 3) { + System.out.println("Wow that's a lot of matches! You sure use '" + keyword + "' a lot!"); + } + } + + System.out.println(DIVIDER); + } } \ No newline at end of file From 0c860a81dd6f07fa6902a24cffa25f7698d45bfd Mon Sep 17 00:00:00 2001 From: Qi Oliver <> Date: Thu, 13 Mar 2025 23:32:52 +0800 Subject: [PATCH 19/20] A-JavaDoc (Added comments) --- src/main/java/oongaliegabangalieBot/oongaliegabangalie.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/oongaliegabangalieBot/oongaliegabangalie.java b/src/main/java/oongaliegabangalieBot/oongaliegabangalie.java index 6efc7bfff..0ebe5baf4 100644 --- a/src/main/java/oongaliegabangalieBot/oongaliegabangalie.java +++ b/src/main/java/oongaliegabangalieBot/oongaliegabangalie.java @@ -47,6 +47,10 @@ public oongaliegabangalie(String filePath) { } } + /** + * Core program logic + * Ties together other classes and functions + */ public void run() { ui.showWelcome(); From da7843cad3f30c486e0472220f5769ee9a69f831 Mon Sep 17 00:00:00 2001 From: Qi Oliver <> Date: Fri, 14 Mar 2025 22:52:54 +0800 Subject: [PATCH 20/20] A-UserGuide (Edited User Guide to explain Oongaliegabangalie Bot) --- docs/README.md | 270 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 256 insertions(+), 14 deletions(-) diff --git a/docs/README.md b/docs/README.md index 47b9f984f..10318bb55 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,30 +1,272 @@ -# Duke User Guide +# OongaliegaBangalie Bot User Guide -// Update the title above to match the actual product name +Welcome to OongaliegaBangalie Bot! Your friendly (albeit slightly sassy) task management assistant. This guide will help you get started and make the most of this bot's features. -// Product screenshot goes here +## Table of Contents +- [Introduction](#introduction) +- [Getting Started](#getting-started) +- [Features](#features) + - [Adding Tasks](#adding-tasks) + - [Todo Tasks](#todo-tasks) + - [Deadline Tasks](#deadline-tasks) + - [Event Tasks](#event-tasks) + - [Managing Tasks](#managing-tasks) + - [Listing Tasks](#listing-tasks) + - [Marking Tasks as Done](#marking-tasks-as-done) + - [Unmarking Tasks](#unmarking-tasks) + - [Deleting Tasks](#deleting-tasks) + - [Finding Tasks](#finding-tasks) + - [Finding by Keyword](#finding-by-keyword) + - [Finding by Date](#finding-by-date) +- [Command Summary](#command-summary) +- [Error Messages](#error-messages) -// Product intro goes here +## Introduction -## Adding deadlines +OongaliegaBangalie Bot is a text-based task management application that allows you to keep track of your todos, deadlines, and events. The bot automatically saves your tasks, so you can close and reopen the application without losing your data. -// Describe the action and its outcome. +## Getting Started -// Give examples of usage +1. Ensure you have Java 11 or higher installed on your computer +2. Download the latest version of OongaliegaBangalie Bot jar file +3. Run the bot using: + ``` + java -jar oongaliegabangalie.jar + ``` +4. Start interacting with the bot using commands described in this guide -Example: `keyword (optional arguments)` +## Features -// A description of the expected outcome goes here +### Adding Tasks +OongaliegaBangalie Bot supports three types of tasks: + +#### Todo Tasks + +Todos are simple tasks with no specific timing attached. + +**Format**: `todo DESCRIPTION` + +**Example**: +``` +todo buy groceries +``` + +**Expected Output**: +``` +____________________________________________________________ +Got it. I've added this task: +[T] [ ] buy groceries +Now you have 1 tasks in the list. +____________________________________________________________ +``` + +#### Deadline Tasks + +Deadlines are tasks that need to be completed by a specific time. + +**Format**: `deadline DESCRIPTION /by DATE_TIME` + +The date time can be entered in these formats: +- `yyyy-MM-dd HH:mm` (e.g., 2023-03-15 14:30) +- `d/M/yyyy HHmm` (e.g., 15/3/2023 1430) + +**Example**: +``` +deadline submit assignment /by 2023-04-01 23:59 +``` + +**Expected Output**: +``` +____________________________________________________________ +Got it. I've added this task: +[D] [ ] submit assignment (by: Apr 1 2023, 11:59 PM) +Now you have 2 tasks in the list. +____________________________________________________________ +``` + +#### Event Tasks + +Events are tasks that take place from one time to another. + +**Format**: `event DESCRIPTION /from DATE_TIME /to DATE_TIME` + +**Example**: +``` +event team meeting /from 2023-04-02 10:00 /to 2023-04-02 12:00 +``` + +**Expected Output**: +``` +____________________________________________________________ +Got it. I've added this task: +[E] [ ] team meeting (from: Apr 2 2023, 10:00 AM to: Apr 2 2023, 12:00 PM) +Now you have 3 tasks in the list. +____________________________________________________________ +``` + +### Managing Tasks + +#### Listing Tasks + +To see all your tasks, use the list command. + +**Format**: `list` + +**Example**: +``` +list +``` + +**Expected Output**: +``` +____________________________________________________________ +Here are the tasks in your list: +1. [T] [ ] buy groceries +2. [D] [ ] submit assignment (by: Apr 1 2023, 11:59 PM) +3. [E] [ ] team meeting (from: Apr 2 2023, 10:00 AM to: Apr 2 2023, 12:00 PM) +Better get to it quick! +____________________________________________________________ +``` + +#### Marking Tasks as Done + +To mark a task as completed, use the mark command with the task number. + +**Format**: `mark TASK_NUMBER` + +**Example**: +``` +mark 1 ``` -expected output + +**Expected Output**: +``` +____________________________________________________________ +Nice! I've marked this task as done: + [T] [X] buy groceries +Now go do something else and stop bothering me! +____________________________________________________________ +``` + +#### Unmarking Tasks + +If you need to change a task back to not done, use the unmark command. + +**Format**: `unmark TASK_NUMBER` + +**Example**: +``` +unmark 1 +``` + +**Expected Output**: +``` +____________________________________________________________ +OK, I've marked this task as not done yet: + [T] [ ] buy groceries +You better get to it... +____________________________________________________________ ``` -## Feature ABC +#### Deleting Tasks + +To remove a task from your list, use the delete command. + +**Format**: `delete TASK_NUMBER` + +**Example**: +``` +delete 3 +``` + +**Expected Output**: +``` +____________________________________________________________ +Noted. I've removed this task: +[E] [ ] team meeting (from: Apr 2 2023, 10:00 AM to: Apr 2 2023, 12:00 PM) +Now you have 2 tasks in the list +____________________________________________________________ +``` + +### Finding Tasks + +#### Finding by Keyword + +To find tasks containing a specific keyword, use the find command. + +**Format**: `find KEYWORD` + +**Example**: +``` +find assignment +``` + +**Expected Output**: +``` +____________________________________________________________ +Here are the matching tasks in your list: +1.[D] [ ] submit assignment (by: Apr 1 2023, 11:59 PM) +____________________________________________________________ +``` + +#### Finding by Date + +To find tasks occurring on a specific date, use the finddate command. + +**Format**: `finddate YYYY-MM-DD` + +**Example**: +``` +finddate 2023-04-01 +``` + +**Expected Output**: +``` +____________________________________________________________ +Here are the tasks on 2023-04-01: +1. [D] [ ] submit assignment (by: Apr 1 2023, 11:59 PM) +Not too busy, but you should still get on with it! +____________________________________________________________ +``` + +## Command Summary + +| Command | Format | Example | +|---------|--------|---------| +| Add a todo | `todo DESCRIPTION` | `todo buy groceries` | +| Add a deadline | `deadline DESCRIPTION /by DATE_TIME` | `deadline submit assignment /by 2023-04-01 23:59` | +| Add an event | `event DESCRIPTION /from DATE_TIME /to DATE_TIME` | `event team meeting /from 2023-04-02 10:00 /to 2023-04-02 12:00` | +| List tasks | `list` | `list` | +| Mark as done | `mark TASK_NUMBER` | `mark 1` | +| Mark as not done | `unmark TASK_NUMBER` | `unmark 1` | +| Delete a task | `delete TASK_NUMBER` | `delete 1` | +| Find by keyword | `find KEYWORD` | `find assignment` | +| Find by date | `finddate YYYY-MM-DD` | `finddate 2023-04-01` | +| Exit | `bye` | `bye` | + +## Error Messages + +OongaliegaBangalie Bot will provide helpful (though sometimes sassy) error messages when commands are incorrectly formatted: + +- Todo without description: + ``` + stop wasting my time and add the description of the task after the command... + ``` -// Feature details +- Deadline without description: + ``` + haha very funny... why is there nothing after the command? + ``` +- Invalid task number: + ``` + Task #5 doesn't exist! Check your list again (or your head)! + ``` -## Feature XYZ +- Empty task list: + ``` + Your list is empty! nothing to see here... + ``` -// Feature details \ No newline at end of file +The bot will automatically save your tasks between sessions, so you don't have to worry about losing your data. \ No newline at end of file