diff --git a/README.md b/README.md
index 90aa7f092a..4a3d7c4b38 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,373 @@
-# Duke project template
-
-This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.
-
-## Setting up in Intellij
-
-Prerequisites: JDK 17, update Intellij to the most recent version.
-
-1. Open Intellij (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project first)
-1. Open the project into Intellij as follows:
- 1. Click `Open`.
- 1. Select the project directory, and click `OK`.
- 1. If there are any further prompts, accept the defaults.
-1. Configure the project to use **JDK 17** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
- In the same dialog, set the **Project language level** field to the `SDK default` option.
-3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output:
- ```
- Hello from
- ____ _
- | _ \ _ _| | _____
- | | | | | | | |/ / _ \
- | |_| | |_| | < __/
- |____/ \__,_|_|\_\___|
- ```
+# Kafka User Guide
+
+
+
+
+
+
+Kafka is a simple, interactive chatbot with personality designed to help users manage tasks. With Kafka, users can create, manage, and track their tasks, set deadlines, mark tasks as completed, and more. It provides an intuitive command-based interface that helps you keep track of your to-do list efficiently.
+
+
+
+
+
+## Adding deadlines
+
+
+
+Kafka allows users to add tasks with deadlines, helping them stay on top of their important events.
+
+
+
+Usage: To add a deadline, use the following command format:
+
+
+
+Command Format: `deadline /by `
+
+
+
+Example: `deadline submit assignment /by 2024-09-20 1800`
+
+
+
+Expected Outcome: The task with a deadline will be added to the list, and Kafka will confirm the addition by displaying the task and its corresponding deadline.
+
+
+
+```
+
+Got it. I've added this task:
+
+ [D][ ] submit assignment (by: September 20 2024 1800)
+
+Now you have 1 task(s) in the list.
+
+```
+
+
+
+## Adding To-Dos
+
+
+
+To-dos are basic tasks without any specific deadline. Dave allows users to add and manage these tasks.
+
+
+
+Usage: To add a to-do, use the following command format:
+
+
+
+Command Format: `todo `
+
+
+
+Example: `todo read book`
+
+
+
+Expected Outcome: A to-do task will be added to the list, and Kafka will confirm it by displaying the task.
+
+
+
+```
+
+Got it. I've added this task:
+
+ [T][ ] read book
+
+Now you have 4 task(s) in the list.
+
+```
+
+
+
+## Adding Events
+
+
+
+For tasks that are tied to specific events with start and end times, you can use Kafka's event feature.
+
+
+
+Usage: To add an event, use the following command format:
+
+
+
+Command Format: `event /at `
+
+
+
+Example: `event attend meeting /from 2024-09-21 1000 /to 2024-09-21 1200`
+
+
+
+Expected Outcome: An event will be added to the task list with a specified date and time, and Kafka will confirm the addition.
+
+
+
+```
+
+Got it. I've added this task:
+
+ [E][ ] Attend meeting (from: September 21 2024 1000 to: September 21 2024 1200)
+
+Now you have 5 task(s) in the list.
+
+```
+
+## Marking Tasks as Done
+
+
+
+When a task is completed, you can mark it as done to keep your task list up-to-date.
+
+
+
+Usage: To mark a task as done, use the following command format:
+
+
+
+Command Format: `mark `
+
+
+
+Example: `mark 1`
+
+
+
+Expected Outcome: Kafka will mark the specified task as done and update the task list accordingly.
+
+
+
+```
+
+Good work on this task. Want a prize?:
+
+ [T][X] buy groceries
+
+```
+
+
+
+## Unmarking Tasks
+
+
+
+If you need to unmark a task that was previously marked as done, you can easily undo this action.
+
+
+
+Usage: To unmark a task, use the following command format:
+
+
+
+Command Format: `unmark `
+
+
+
+Example: `unmark 1`
+
+
+
+Expected Outcome: Kafka will unmark the specified task and return it to the list of pending tasks.
+
+
+
+```
+
+Hurry up. This task is necessary for Elio's script:
+
+ [T][ ] buy groceries
+
+```
+
+
+
+## Deleting Tasks
+
+
+
+If a task is no longer needed, you can delete it from the task list.
+
+
+
+Usage: To delete a task, use the following command format:
+
+
+
+Command Format: `delete `
+
+
+
+Example: `delete 2`
+
+
+
+Expected Outcome: The task will be removed from the list, and Kafka will confirm the deletion by displaying the updated task list.
+
+
+
+```
+
+I've removed this task:
+
+ [D][ ] Submit assignment (by: September 20 2024 1800)
+
+Now you have 4 task(s) in the list.
+
+```
+
+
+
+## Finding Tasks
+
+
+
+To quickly search for tasks containing a specific keyword, Kafka offers a find command.
+
+
+
+Usage: To find tasks, use the following command format:
+
+
+
+Command Format: `find `
+
+
+
+Example: `find meeting`
+
+
+
+Expected Outcome: Kafka will display a list of tasks that contain the specified keyword.
+
+
+
+
+
+```
+
+Here you go, these are the matching tasks in your list:
+
+ 1.[D][ ] submit assignment (by: September 21 2024 1000)
+
+```
+
+
+
+## Listing All Tasks
+
+
+
+To view all tasks that are currently tracked by Kafka, use the list command.
+
+
+
+Usage: To display the full list of saved tasks, use the following command format:
+
+
+
+Command Format: `list`
+
+
+
+Example: `list`
+
+
+
+Expected Outcome: Kafka will display the full list of tasks, including their status (whether they are marked as done or pending).
+
+
+
+
+
+```
+
+Here are the tasks in your list:
+
+ 1. [T][ ] Buy groceries
+
+ 2. [D][ ] Submit assignment (by: September 21 2024 1000)
+
+ 3. [T][ ] Complete project report
+
+```
+
+
+
+
+
+
+
+
+
+## Snooze tasks
+
+
+
+Kafka allows users to snooze tasks by changing their deadline and event dates.
+
+
+Usage: To snooze a task, use one of the following command formats:
+
+
+
+Command Format:
+
+
+
+`snooze /by ` - Snooze deadline tasks.
+
+
+
+`snooze /from ` - Snooze event tasks and the duration stays the same.
+
+
+
+`snooze /from /to ` - Snooze event tasks and the date and time can be freely changed.
+
+
+
+Example:
+
+
+
+`snooze 3 /by 2024-01-01 1800`
+
+
+
+`snooze 3 /from 2024-01-01 1800`
+
+
+
+`snooze 3 /from 2024-01-01 1800 /to 2024-01-01 2000`
+
+
+
+Expected Outcome:
+
+
+
+When you use the snooze deadline command, Kafka is able to freely change the deadline task date and time.
+
+
+When you use the snooze event command with /from, Kafka is able to freely change the event task date and time, however the /to date and time is automatically updated with the duration staying the same.
+
+
+When you use the snooze deadline command with /from and /to, Kafka is able to freely change the event task date and time.
+
+
+
+For tasks:
+
+
+
+```
+
+Oh, the task is delayed? Do you need any help?
+
+ [D][ ] submit assignment (by: January 01 2024 1800)
+
+```
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000..cd49c6678d
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,59 @@
+plugins {
+ id 'java'
+ id 'application'
+ id 'com.github.johnrengelman.shadow' version '7.1.2'
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ String javaFxVersion = '17.0.1'
+
+ testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.10.0'
+ testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.10.0'
+
+ implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux'
+ implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux'
+ implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux'
+ implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux'
+}
+
+test {
+ useJUnitPlatform()
+
+ testLogging {
+ events "passed", "skipped", "failed"
+
+ showExceptions true
+ exceptionFormat "full"
+ showCauses true
+ showStackTraces true
+ showStandardStreams = false
+ }
+}
+
+application {
+ mainClass.set("kafka.KafkaLauncher")
+}
+
+shadowJar {
+ archiveBaseName = "kafka"
+ mainClassName = "kafka.KafkaLauncher"
+ archiveClassifier = null
+}
+
+run{
+ standardInput = System.in
+}
+
+
diff --git a/data/Kafka.txt b/data/Kafka.txt
new file mode 100644
index 0000000000..844338c198
--- /dev/null
+++ b/data/Kafka.txt
@@ -0,0 +1 @@
+D | false | submit assignment | 2024-01-01T18:00
diff --git a/docs/README.md b/docs/README.md
index 47b9f984f7..2c10c8101c 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,30 +1,372 @@
-# Duke User Guide
+# Kafka User Guide
+
+
+
+
+
+Kafka is a simple, interactive chatbot with personality designed to help users manage tasks. With Kafka, users can create, manage, and track their tasks, set deadlines, mark tasks as completed, and more. It provides an intuitive command-based interface that helps you keep track of your to-do list efficiently.
+
-// Update the title above to match the actual product name
-// Product screenshot goes here
-// Product intro goes here
## Adding deadlines
-// Describe the action and its outcome.
-// Give examples of usage
-Example: `keyword (optional arguments)`
+Kafka allows users to add tasks with deadlines, helping them stay on top of their important events.
+
+
+
+Usage: To add a deadline, use the following command format:
+
+
+
+Command Format: `deadline /by `
+
+
+
+Example: `deadline submit assignment /by 2024-09-20 1800`
+
+
+
+Expected Outcome: The task with a deadline will be added to the list, and Kafka will confirm the addition by displaying the task and its corresponding deadline.
+
+
+
+```
+
+Got it. I've added this task:
+
+ [D][ ] submit assignment (by: September 20 2024 1800)
+
+Now you have 1 task(s) in the list.
+
+```
+
+
+
+## Adding To-Dos
+
+
+
+To-dos are basic tasks without any specific deadline. Dave allows users to add and manage these tasks.
+
+
+
+Usage: To add a to-do, use the following command format:
+
+
+
+Command Format: `todo `
+
+
+
+Example: `todo read book`
+
+
+
+Expected Outcome: A to-do task will be added to the list, and Kafka will confirm it by displaying the task.
+
+
+
+```
+
+Got it. I've added this task:
+
+ [T][ ] read book
+
+Now you have 4 task(s) in the list.
+
+```
+
+
+
+## Adding Events
+
+
+
+For tasks that are tied to specific events with start and end times, you can use Kafka's event feature.
+
+
+
+Usage: To add an event, use the following command format:
+
+
+
+Command Format: `event /at `
+
+
+
+Example: `event attend meeting /from 2024-09-21 1000 /to 2024-09-21 1200`
+
+
+
+Expected Outcome: An event will be added to the task list with a specified date and time, and Kafka will confirm the addition.
+
+
+
+```
+
+Got it. I've added this task:
+
+ [E][ ] Attend meeting (from: September 21 2024 1000 to: September 21 2024 1200)
+
+Now you have 5 task(s) in the list.
+
+```
+
+## Marking Tasks as Done
+
+
+
+When a task is completed, you can mark it as done to keep your task list up-to-date.
+
+
+
+Usage: To mark a task as done, use the following command format:
+
+
+
+Command Format: `mark `
+
+
+
+Example: `mark 1`
+
+
+
+Expected Outcome: Kafka will mark the specified task as done and update the task list accordingly.
+
+
+
+```
+
+Good work on this task. Want a prize?:
+
+ [T][X] buy groceries
+
+```
+
+
+
+## Unmarking Tasks
+
+
+
+If you need to unmark a task that was previously marked as done, you can easily undo this action.
+
+
+
+Usage: To unmark a task, use the following command format:
+
+
+
+Command Format: `unmark `
+
+
+
+Example: `unmark 1`
+
+
+
+Expected Outcome: Kafka will unmark the specified task and return it to the list of pending tasks.
+
+
+
+```
+
+Hurry up. This task is necessary for Elio's script:
+
+ [T][ ] buy groceries
+
+```
+
+
+
+## Deleting Tasks
+
+
+
+If a task is no longer needed, you can delete it from the task list.
+
+
+
+Usage: To delete a task, use the following command format:
+
+
+
+Command Format: `delete `
+
+
+
+Example: `delete 2`
+
+
+
+Expected Outcome: The task will be removed from the list, and Kafka will confirm the deletion by displaying the updated task list.
+
+
+
+```
+
+I've removed this task:
+
+ [D][ ] Submit assignment (by: September 20 2024 1800)
+
+Now you have 4 task(s) in the list.
+
+```
+
+
+
+## Finding Tasks
+
+
+
+To quickly search for tasks containing a specific keyword, Kafka offers a find command.
+
+
+
+Usage: To find tasks, use the following command format:
+
+
+
+Command Format: `find `
+
+
+
+Example: `find meeting`
+
+
+
+Expected Outcome: Kafka will display a list of tasks that contain the specified keyword.
+
+
+
+
+
+```
+
+Here you go, these are the matching tasks in your list:
+
+ 1.[D][ ] submit assignment (by: September 21 2024 1000)
+
+```
+
+
+
+## Listing All Tasks
+
+
+
+To view all tasks that are currently tracked by Kafka, use the list command.
+
+
+
+Usage: To display the full list of saved tasks, use the following command format:
+
+
+
+Command Format: `list`
+
+
+
+Example: `list`
+
+
+
+Expected Outcome: Kafka will display the full list of tasks, including their status (whether they are marked as done or pending).
+
+
+
-// A description of the expected outcome goes here
```
-expected output
+
+Here are the tasks in your list:
+
+ 1. [T][ ] Buy groceries
+
+ 2. [D][ ] Submit assignment (by: September 21 2024 1000)
+
+ 3. [T][ ] Complete project report
+
```
-## Feature ABC
-// Feature details
-## Feature XYZ
-// Feature details
\ No newline at end of file
+
+
+
+
+## Snooze tasks
+
+
+
+Kafka allows users to snooze tasks by changing their deadline and event dates.
+
+
+Usage: To snooze a task, use one of the following command formats:
+
+
+
+Command Format:
+
+
+
+`snooze /by ` - Snooze deadline tasks.
+
+
+
+`snooze /from ` - Snooze event tasks and the duration stays the same.
+
+
+
+`snooze /from /to ` - Snooze event tasks and the date and time can be freely changed.
+
+
+
+Example:
+
+
+
+`snooze 3 /by 2024-01-01 1800`
+
+
+
+`snooze 3 /from 2024-01-01 1800`
+
+
+
+`snooze 3 /from 2024-01-01 1800 /to 2024-01-01 2000`
+
+
+
+Expected Outcome:
+
+
+
+When you use the snooze deadline command, Kafka is able to freely change the deadline task date and time.
+
+
+When you use the snooze event command with /from, Kafka is able to freely change the event task date and time, however the /to date and time is automatically updated with the duration staying the same.
+
+
+When you use the snooze deadline command with /from and /to, Kafka is able to freely change the event task date and time.
+
+
+
+For tasks:
+
+
+
+```
+
+Oh, the task is delayed? Do you need any help?
+
+ [D][ ] submit assignment (by: January 01 2024 1800)
+
+```
\ No newline at end of file
diff --git a/docs/Ui.png b/docs/Ui.png
new file mode 100644
index 0000000000..1367ecb612
Binary files /dev/null and b/docs/Ui.png differ
diff --git a/gradle/.idea/libraries/gradle_wrapper.xml b/gradle/.idea/libraries/gradle_wrapper.xml
new file mode 100644
index 0000000000..d2b3f2743a
--- /dev/null
+++ b/gradle/.idea/libraries/gradle_wrapper.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gradle/.idea/misc.xml b/gradle/.idea/misc.xml
new file mode 100644
index 0000000000..6f29fee2f2
--- /dev/null
+++ b/gradle/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gradle/.idea/modules.xml b/gradle/.idea/modules.xml
new file mode 100644
index 0000000000..be92c07bf6
--- /dev/null
+++ b/gradle/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gradle/.idea/vcs.xml b/gradle/.idea/vcs.xml
new file mode 100644
index 0000000000..6c0b863585
--- /dev/null
+++ b/gradle/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gradle/.idea/workspace.xml b/gradle/.idea/workspace.xml
new file mode 100644
index 0000000000..315dcba541
--- /dev/null
+++ b/gradle/.idea/workspace.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1725596044974
+
+
+ 1725596044974
+
+
+
+
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..033e24c4cd
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..1af9e0930b
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000000..fcb6fca147
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,248 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000000..6689b85bee
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,92 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java
deleted file mode 100644
index 5d313334cc..0000000000
--- 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/kafka/Deadline.java b/src/main/java/kafka/Deadline.java
new file mode 100644
index 0000000000..8a7e580b66
--- /dev/null
+++ b/src/main/java/kafka/Deadline.java
@@ -0,0 +1,22 @@
+package kafka;
+
+import java.time.LocalDateTime;
+
+public class Deadline extends Task {
+
+ public LocalDateTime by;
+
+ public Deadline(String description, LocalDateTime by, boolean isDone) {
+ super(description, isDone);
+ this.by = by;
+ }
+ @Override
+ public void snooze(LocalDateTime newBy) {
+ this.by = newBy;
+ }
+
+ @Override
+ public String toString() {
+ return "[D]" + super.toString() + "(by: " + LocalDateTimeConverter.getDifferentFormat(this.by) + ")";
+ }
+}
diff --git a/src/main/java/kafka/DialogBox.java b/src/main/java/kafka/DialogBox.java
new file mode 100644
index 0000000000..bd1580ac58
--- /dev/null
+++ b/src/main/java/kafka/DialogBox.java
@@ -0,0 +1,60 @@
+package kafka;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.HBox;
+
+import java.io.IOException;
+import java.util.Collections;
+
+/**
+ * Represents a dialog box consisting of an ImageView to represent the speaker's face
+ * and a label containing text from the speaker.
+ */
+public class DialogBox extends HBox {
+ @FXML
+ private Label dialog;
+ @FXML
+ private ImageView displayPicture;
+
+ private DialogBox(String text, Image img) {
+ try {
+ FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource("/view/DialogBox.fxml"));
+ fxmlLoader.setController(this);
+ fxmlLoader.setRoot(this);
+ fxmlLoader.load();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ dialog.setText(text);
+ displayPicture.setImage(img);
+ }
+
+ /**
+ * Flips the dialog box such that the ImageView is on the left and text on the right.
+ */
+ private void flip() {
+ ObservableList tmp = FXCollections.observableArrayList(this.getChildren());
+ Collections.reverse(tmp);
+ getChildren().setAll(tmp);
+ setAlignment(Pos.TOP_LEFT);
+ }
+
+ public static DialogBox getUserDialog(String text, Image img) {
+ return new DialogBox(text, img);
+ }
+
+ public static DialogBox getDukeDialog(String text, Image img) {
+ var db = new DialogBox(text, img);
+ db.flip();
+ return db;
+ }
+}
diff --git a/src/main/java/kafka/Event.java b/src/main/java/kafka/Event.java
new file mode 100644
index 0000000000..4f35c6b53c
--- /dev/null
+++ b/src/main/java/kafka/Event.java
@@ -0,0 +1,34 @@
+package kafka;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+
+public class Event extends Task {
+
+ public LocalDateTime from;
+ public LocalDateTime to;
+
+ public Event(String description, LocalDateTime from, LocalDateTime to, boolean isDone) {
+ super(description, isDone);
+ this.from = from;
+ this.to = to;
+ }
+
+ @Override
+ public void snooze(LocalDateTime newTime) {
+ Duration difference = Duration.between(this.from, this.to);
+ this.from = newTime;
+ this.to = newTime.plus(difference);
+ }
+
+ public void snooze(LocalDateTime newFrom, LocalDateTime newTo) {
+ this.from = newFrom;
+ this.to = newTo;
+ }
+
+ @Override
+ public String toString() {
+ return "[E]" + super.toString() + "(from: " + LocalDateTimeConverter.getDifferentFormat(this.from)
+ + " to: " + LocalDateTimeConverter.getDifferentFormat(this.to) + ")";
+ }
+}
diff --git a/src/main/java/kafka/Kafka.java b/src/main/java/kafka/Kafka.java
new file mode 100644
index 0000000000..7e209523e5
--- /dev/null
+++ b/src/main/java/kafka/Kafka.java
@@ -0,0 +1,39 @@
+package kafka;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.time.format.DateTimeParseException;
+
+
+public class Kafka {
+
+ private Storage storage;
+ private TaskList taskList;
+ private Ui ui;
+
+ public Kafka(String filePath) throws FileNotFoundException {
+ ui = new Ui();
+ storage = new Storage(filePath);
+ try {
+ taskList = new TaskList(storage.load());
+ } catch (IOException e) {
+ ui.showError(e);
+ taskList = new TaskList();
+ }
+ }
+
+ public String getResponse(String input) {
+ String output;
+ try {
+ output = Parser.parseCommand(input, taskList, storage, ui);
+ } catch (KafkaException | IOException e) {
+ output = ui.showError(e);
+ } catch (DateTimeParseException e) {
+ output = ui.incorrectDateDetails();
+ }
+ return output;
+ }
+
+// public static void main(String[] args) {
+// }
+}
diff --git a/src/main/java/kafka/KafkaException.java b/src/main/java/kafka/KafkaException.java
new file mode 100644
index 0000000000..c3f50a92a7
--- /dev/null
+++ b/src/main/java/kafka/KafkaException.java
@@ -0,0 +1,7 @@
+package kafka;
+
+public class KafkaException extends Exception {
+ public KafkaException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/kafka/KafkaLauncher.java b/src/main/java/kafka/KafkaLauncher.java
new file mode 100644
index 0000000000..f9db695516
--- /dev/null
+++ b/src/main/java/kafka/KafkaLauncher.java
@@ -0,0 +1,12 @@
+package kafka;
+
+import javafx.application.Application;
+
+/**
+ * A launcher class to workaround classpath issues.
+ */
+public class KafkaLauncher {
+ public static void main(String[] args) {
+ Application.launch(Main.class, args);
+ }
+}
diff --git a/src/main/java/kafka/LocalDateTimeConverter.java b/src/main/java/kafka/LocalDateTimeConverter.java
new file mode 100644
index 0000000000..9e7b8014d4
--- /dev/null
+++ b/src/main/java/kafka/LocalDateTimeConverter.java
@@ -0,0 +1,32 @@
+package kafka;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * This class provides utility methods for converting LocalDateTime objects to and from different string formats.
+ */
+public class LocalDateTimeConverter {
+
+ /**
+ * Parses a string representing a LocalDateTime in the format "yyyy-MM-dd HHmm" into a LocalDateTime object.
+ *
+ * @param dateTime The string representing the LocalDateTime in the format "yyyy-MM-dd HHmm".
+ * @return The parsed LocalDateTime object.
+ */
+ public static LocalDateTime getLocalDateTime(String dateTime) {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm");
+ return LocalDateTime.parse(dateTime, formatter);
+ }
+
+ /**
+ * Formats a LocalDateTime object into a string in the format "MMMM dd yyyy HHmm".
+ *
+ * @param ldt The LocalDateTime object to be formatted.
+ * @return The formatted string in the format "MMMM dd yyyy HHmm".
+ */
+ public static String getDifferentFormat(LocalDateTime ldt) {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM dd yyyy HHmm");
+ return ldt.format(formatter);
+ }
+}
diff --git a/src/main/java/kafka/Main.java b/src/main/java/kafka/Main.java
new file mode 100644
index 0000000000..6f07905e60
--- /dev/null
+++ b/src/main/java/kafka/Main.java
@@ -0,0 +1,40 @@
+package kafka;
+
+import javafx.application.Application;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Scene;
+import javafx.scene.layout.AnchorPane;
+import javafx.stage.Stage;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * A GUI for Duke using FXML.
+ */
+public class Main extends Application {
+
+ private Kafka kafka;
+
+ {
+ try {
+ kafka = new Kafka("./data/Kafka.txt");
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void start(Stage stage) {
+ try {
+ FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml"));
+ AnchorPane ap = fxmlLoader.load();
+ Scene scene = new Scene(ap);
+ stage.setScene(scene);
+ fxmlLoader.getController().setKafka(kafka);
+ stage.show();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/kafka/MainWindow.java b/src/main/java/kafka/MainWindow.java
new file mode 100644
index 0000000000..3864fa6e18
--- /dev/null
+++ b/src/main/java/kafka/MainWindow.java
@@ -0,0 +1,50 @@
+package kafka;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.control.TextField;
+import javafx.scene.image.Image;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.VBox;
+
+/**
+ * Controller for the main GUI.
+ */
+public class MainWindow extends AnchorPane {
+ @FXML
+ private ScrollPane scrollPane;
+ @FXML
+ private VBox dialogContainer;
+ @FXML
+ private TextField userInput;
+
+ private Kafka kafka;
+
+ private Image userImage = new Image(this.getClass().getResourceAsStream("/images/StarRailMC.png"));
+ private Image kafkaImage = new Image(this.getClass().getResourceAsStream("/images/Kafka.png"));
+
+ @FXML
+ public void initialize() {
+ scrollPane.vvalueProperty().bind(dialogContainer.heightProperty());
+ }
+
+ /** Injects the Kafka instance */
+ public void setKafka(Kafka k) {
+ kafka = k;
+ }
+
+ /**
+ * Creates two dialog boxes, one echoing user input and the other containing Kafka's reply and then appends them to
+ * the dialog container. Clears the user input after processing.
+ */
+ @FXML
+ private void handleUserInput() {
+ String input = userInput.getText();
+ String response = kafka.getResponse(input);
+ dialogContainer.getChildren().addAll(
+ DialogBox.getUserDialog(input, userImage),
+ DialogBox.getDukeDialog(response, kafkaImage)
+ );
+ userInput.clear();
+ }
+}
diff --git a/src/main/java/kafka/Parser.java b/src/main/java/kafka/Parser.java
new file mode 100644
index 0000000000..22b8b949e3
--- /dev/null
+++ b/src/main/java/kafka/Parser.java
@@ -0,0 +1,286 @@
+package kafka;
+
+import java.io.IOException;
+import java.time.format.DateTimeParseException;
+import java.time.LocalDateTime;
+
+/**
+ * This class parses user input commands and executes corresponding actions within the Kafka application.
+ * It interacts with TaskList, Storage, and Ui objects to manage tasks, persist data, and provide user feedback.
+ */
+
+public class Parser {
+
+ private static final String BY_DELIMITER = " /by ";
+ private static final String FROM_TO_DELIMITER = " /from | /to ";
+
+ /**
+ * Parses the given user input and executes the appropriate command.
+ *
+ * @param userInput The user input string.
+ * @param taskList The TaskList object to manage tasks.
+ * @param storage The Storage object for data persistence.
+ * @param ui The Ui object for user interface interactions.
+ * @throws KafkaException If an error occurs during command parsing or execution.
+ * @throws IOException If an error occurs during file operations.
+ * @throws DateTimeParseException If an error occurs while parsing date and time strings.
+ */
+ public static String parseCommand(String userInput, TaskList taskList, Storage storage, Ui ui) throws KafkaException, IOException, DateTimeParseException {
+ assert userInput != null && !userInput.trim().isEmpty() : "User input cannot be null or empty";
+ String[] splitInput = userInput.trim().split(" ", 2);
+
+ if (splitInput[0] == null) {
+ return "";
+ }
+
+ String command = splitInput[0].toLowerCase();
+ String arguments = splitInput.length > 1 ? splitInput[1] : "";
+ String output;
+
+ try {
+ output = switch (command) {
+ case "bye" -> executeByeCommand(ui);
+ case "list" -> executeListCommand(taskList, ui);
+ case "mark" -> executeMarkCommand(arguments, taskList, storage, ui);
+ case "unmark" -> executeUnmarkCommand(arguments, taskList, storage, ui);
+ case "snooze" -> executeSnoozeCommand(arguments, taskList, storage, ui);
+ case "delete" -> executeDeleteCommand(arguments, taskList, storage, ui);
+ case "find" -> executeFindCommand(arguments, taskList, ui);
+ case "todo" -> executeTodoCommand(arguments, taskList, storage, ui);
+ case "deadline" -> executeDeadlineCommand(arguments, taskList, storage, ui);
+ case "event" -> executeEventCommand(arguments, taskList, storage, ui);
+ default ->
+ throw new KafkaException("Hmm... I'm not sure what you're getting at. Care to enlighten me?");
+ };
+ } catch (IOException e) {
+ output = ui.showError(e);
+ } catch (DateTimeParseException e) {
+ output = ui.incorrectDateDetails();
+ }
+ return output;
+ }
+
+ /**
+ * Executes the "bye" command, which triggers the application to exit.
+ *
+ * @param ui The user interface object.
+ * @return A message indicating the application's exit.
+ */
+ private static String executeByeCommand(Ui ui) {
+ return ui.goodbye();
+ }
+
+ /**
+ * Executes the "list" command, which displays all tasks in the task list.
+ *
+ * @param taskList The task list object.
+ * @param ui The user interface object.
+ * @return A string containing the list header and the formatted task list.
+ */
+ private static String executeListCommand(TaskList taskList, Ui ui) {
+ return ui.getList() + "\n" + taskList.printList();
+ }
+
+ /**
+ * Executes the "mark" command, which marks a specified task as completed.
+ *
+ * @param arguments The task number to mark.
+ * @param taskList The task list object.
+ * @param storage The storage object for saving task data.
+ * @param ui The user interface object.
+ * @return A message indicating the task has been marked as completed.
+ * @throws IOException If there's an error writing to the storage.
+ */
+ private static String executeMarkCommand(String arguments, TaskList taskList, Storage storage, Ui ui) throws IOException, KafkaException {
+ checkForEmptyArguments(arguments);
+ int taskNumberMark = Integer.parseInt(arguments);
+ Task taskToMark = taskList.tasks.get(taskNumberMark - 1);
+ taskList.mark(taskToMark);
+ storage.writeToFile(taskList.tasks);
+ return ui.mark(taskToMark);
+ }
+
+ /**
+ * Executes the "unmark" command, which marks a specified task as incomplete.
+ *
+ * @param arguments The task number to unmark.
+ * @param taskList The task list object.
+ * @param storage The storage object for saving task data.
+ * @param ui The user interface object.
+ * @return A message indicating the task has been marked as incomplete.
+ * @throws IOException If there's an error writing to the storage.
+ */
+ private static String executeUnmarkCommand(String arguments, TaskList taskList, Storage storage, Ui ui) throws IOException, KafkaException {
+ checkForEmptyArguments(arguments);
+ int taskNumberUnmark = Integer.parseInt(arguments);
+ Task taskToUnmark = taskList.tasks.get(taskNumberUnmark - 1);
+ taskList.unmark(taskToUnmark);
+ storage.writeToFile(taskList.tasks);
+ return ui.unmark(taskToUnmark);
+ }
+
+ /**
+ * Executes the "snooze" command, which reschedules a specified task to a later time.
+ *
+ * @param arguments The task number and new time for the task (separated by "by" or "from" and "to").
+ * @param taskList The task list object.
+ * @param storage The storage object for saving task data.
+ * @param ui The user interface object.
+ * @return A message indicating the task has been snoozed.
+ * @throws IOException If there's an error writing to the storage.
+ * @throws KafkaException If there's an error in the snoozing process.
+ */
+ private static String executeSnoozeCommand(String arguments, TaskList taskList, Storage storage, Ui ui) throws IOException, KafkaException {
+ checkForEmptyArguments(arguments);
+ if (arguments.contains("/by")) {
+ String[] taskParts = arguments.split(BY_DELIMITER);
+ int taskNumber = Integer.parseInt(taskParts[0]);
+ Task taskToSnooze = taskList.tasks.get(taskNumber - 1);
+ LocalDateTime by = LocalDateTimeConverter.getLocalDateTime(taskParts[1]);
+ if (!(taskToSnooze instanceof Deadline deadline)) {
+ throw new KafkaException(" Looks like this is not a deadline task, mind using /from and /to?");
+ }
+ deadline.snooze(by);
+ storage.writeToFile(taskList.tasks);
+ return ui.snooze(taskToSnooze);
+ } else if (arguments.contains("/from")) {
+ String[] taskParts = arguments.split(FROM_TO_DELIMITER);
+ int taskNumber = Integer.parseInt(taskParts[0]);
+ Task taskToSnooze = taskList.tasks.get(taskNumber - 1);
+ LocalDateTime from = LocalDateTimeConverter.getLocalDateTime(taskParts[1]);
+ if (!(taskToSnooze instanceof Event event)) {
+ throw new KafkaException(" Looks like this is not a event task, mind using /by?");
+ }
+ if (taskParts.length < 3) {
+ event.snooze(from);
+ } else {
+ LocalDateTime to = LocalDateTimeConverter.getLocalDateTime(taskParts[2]);
+ event.snooze(from, to);
+ }
+ storage.writeToFile(taskList.tasks);
+ return ui.snooze(taskToSnooze);
+ } else {
+ throw new KafkaException(" Looks like this is not a task that can be snoozed, mind trying other tasks?");
+ }
+ }
+
+ /**
+ * Executes the "delete" command, which deletes a specified task from the task list.
+ *
+ * @param arguments The task number to delete.
+ * @param taskList The task list object.
+ * @param storage The storage object for saving task data.
+ * @param ui The user interface object.
+ * @return A message indicating the task has been deleted.
+ * @throws IOException If there's an error writing to the storage.
+ */
+ private static String executeDeleteCommand(String arguments, TaskList taskList, Storage storage, Ui ui) throws IOException, KafkaException {
+ checkForEmptyArguments(arguments);
+ if (taskList.tasks.isEmpty()) {
+ return "";
+ }
+ int taskNumberDelete = Integer.parseInt(arguments);
+ Task taskToDelete = taskList.tasks.get(taskNumberDelete - 1);
+ taskList.delete(taskNumberDelete);
+ storage.writeToFile(taskList.tasks);
+ return ui.delete(taskToDelete, taskList);
+ }
+
+ /**
+ * Executes the "find" command, which searches for tasks containing a specified keyword.
+ *
+ * @param arguments The keyword to search for.
+ * @param taskList The task list object.
+ * @param ui The user interface object.
+ * @return A string containing the search results.
+ * @throws KafkaException If there's an error during the search.
+ */
+ private static String executeFindCommand(String arguments, TaskList taskList, Ui ui) throws KafkaException {
+ checkForEmptyArguments(arguments);
+ TaskList temp = taskList.find(arguments.toLowerCase());
+ if (temp.isEmpty()) {
+ throw new KafkaException("Hmm, it seems that no task aligns with that word... mind trying again?");
+ }
+ return ui.find() + "\n" + temp.printList();
+ }
+
+ /**
+ * Executes the "todo" command, which creates a new todo task.
+ *
+ * @param arguments The description of the todo task.
+ * @param taskList The task list object.
+ * @param storage The storage object for saving task data.
+ * @param ui The user interface object.
+ * @return A message indicating the task has been added.
+ * @throws IOException If there's an error writing to the storage.
+ * @throws KafkaException If there's an error in the task creation process.
+ */
+ private static String executeTodoCommand(String arguments, TaskList taskList, Storage storage, Ui ui) throws IOException, KafkaException {
+ checkForEmptyArguments(arguments);
+ Task todo = new Todo(arguments, false);
+ taskList.addTask(todo);
+ storage.writeToFile(taskList.tasks);
+ return ui.addTask(todo, taskList);
+ }
+
+ /**
+ * Executes the "deadline" command, which creates a new deadline task with a specified deadline.
+ *
+ * @param arguments The description and deadline of the task (separated by "by").
+ * @param taskList The task list object.
+ * @param storage The storage object for saving task data.
+ * @param ui The user interface object.
+ * @return A message indicating the task has been added.
+ * @throws IOException If there's an error writing to the storage.
+ * @throws KafkaException If there's an error in the task creation process.
+ */
+ private static String executeDeadlineCommand(String arguments, TaskList taskList, Storage storage, Ui ui) throws IOException, KafkaException {
+ checkForEmptyArguments(arguments);
+ String[] deadlineParts = arguments.split(BY_DELIMITER);
+ if (deadlineParts.length != 2 || deadlineParts[0] == null) {
+ throw new KafkaException("It appears the details for this deadline task are off. Let's try adding descriptions, shall we?");
+ }
+ LocalDateTime by = LocalDateTimeConverter.getLocalDateTime(deadlineParts[1]);
+ Task deadline = new Deadline(deadlineParts[0], by, false);
+ taskList.addTask(deadline);
+ storage.writeToFile(taskList.tasks);
+ return ui.addTask(deadline, taskList);
+ }
+
+ /**
+ * Executes the "event" command, which creates a new event task with specified start and end times.
+ *
+ * @param arguments The description, start time, and end time of the event (separated by "from" and "to").
+ * @param taskList The task list object.
+ * @param storage The storage object for saving task data.
+ * @param ui The user interface object.
+ * @return A message indicating the task has been added.
+ * @throws IOException If there's an error writing to the storage.
+ * @throws KafkaException If there's an error in the task creation process.
+ */
+ private static String executeEventCommand(String arguments, TaskList taskList, Storage storage, Ui ui) throws IOException, KafkaException {
+ checkForEmptyArguments(arguments);
+ String[] eventParts = arguments.split(FROM_TO_DELIMITER);
+ if (eventParts.length != 3 || eventParts[0] == null) {
+ throw new KafkaException("It appears the details for this event task are off. Let's give it another go, shall we?");
+ }
+ LocalDateTime from = LocalDateTimeConverter.getLocalDateTime(eventParts[1]);
+ LocalDateTime to = LocalDateTimeConverter.getLocalDateTime(eventParts[2]);
+ Task event = new Event(eventParts[0], from, to, false);
+ taskList.addTask(event);
+ storage.writeToFile(taskList.tasks);
+ return ui.addTask(event, taskList);
+ }
+
+ /**
+ * Checks if the given arguments are empty.
+ *
+ * @param arguments The arguments to check.
+ * @throws KafkaException If the arguments are empty.
+ */
+ private static void checkForEmptyArguments(String arguments) throws KafkaException {
+ if (arguments.isEmpty()) {
+ throw new KafkaException("It seems you've left the details blank. Even the simplest tasks need some direction, don't you think?");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/kafka/Storage.java b/src/main/java/kafka/Storage.java
new file mode 100644
index 0000000000..66e4cc94d5
--- /dev/null
+++ b/src/main/java/kafka/Storage.java
@@ -0,0 +1,124 @@
+package kafka;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+/**
+ * This class represents a storage for managing tasks. It allows loading tasks from a file and saving tasks back to the file.
+ */
+public class Storage {
+
+ private final String filePath;
+
+ /**
+ * Constructor that takes the file path for storing tasks.
+ *
+ * @param filePath The path to the file where tasks are stored.
+ */
+ public Storage(String filePath) {
+ this.filePath = filePath;
+ }
+
+ /**
+ * Loads tasks from the specified file path.
+ *
+ * @throws FileNotFoundException If the file is not found at the specified path.
+ * @return An ArrayList containing loaded tasks.
+ */
+ public ArrayList load() throws IOException {
+ this.getNewFile(filePath);
+ ArrayList tasks = new ArrayList<>();
+ this.printFileContents(tasks);
+ return tasks;
+ }
+
+ /**
+ * Reads the contents of the file and populates the provided ArrayList with loaded tasks.
+ *
+ * @param tasks The ArrayList to be populated with loaded tasks.
+ * @throws FileNotFoundException If the file is not found at the specified path.
+ */
+ private void printFileContents(ArrayList tasks) throws FileNotFoundException {
+ try {
+ File f = new File(filePath);
+ Scanner s = new Scanner(f);
+ while (s.hasNextLine()) {
+ String[] fileContent = s.nextLine().trim().split(" \\| ");
+ String taskType = fileContent[0];
+ boolean isDone = Boolean.parseBoolean(fileContent[1]);
+ String description = fileContent[2];
+ assert taskType.equals("T") || taskType.equals("D") || taskType.equals("E") : "Invalid task type";
+ switch (taskType) {
+ case "T":
+ Task todo = new Todo(description, isDone);
+ tasks.add(todo);
+ break;
+ case "D":
+ LocalDateTime by = LocalDateTime.parse(fileContent[3]);
+ Task deadline = new Deadline(description, by, isDone);
+ tasks.add(deadline);
+ break;
+ case "E":
+ LocalDateTime from = LocalDateTime.parse(fileContent[3]);
+ LocalDateTime to = LocalDateTime.parse(fileContent[4]);
+ Task event = new Event(description, from, to, isDone);
+ tasks.add(event);
+ break;
+ }
+ }
+ } catch (FileNotFoundException e) {
+ throw new FileNotFoundException("File not found at path: " + filePath);
+ }
+ }
+
+ /**
+ * Writes the provided tasks to the specified file path.
+ *
+ * @param tasks The ArrayList containing tasks to be saved.
+ * @throws IOException If an error occurs while writing to the file.
+ */
+ public void writeToFile(ArrayList tasks) throws IOException {
+ try (FileWriter fw = new FileWriter(filePath)) {
+ for (Task t : tasks) {
+ if (t instanceof Todo todo) {
+ fw.write("T | " + todo.isDone + " | "
+ + todo.description + System.lineSeparator());
+ } else if (t instanceof Deadline deadline) {
+ fw.write("D | " + deadline.isDone + " | "
+ + deadline.description + " | " + deadline.by + System.lineSeparator());
+ } else if (t instanceof Event event) {
+ fw.write("E | " + event.isDone + " | "
+ + event.description + " | " + event.from + " | " + event.to
+ + System.lineSeparator());
+ }
+ }
+ } catch (IOException e) {
+ throw new IOException("Something went wrong: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Creates a new file at the specified path if it doesn't exist, including creating any necessary parent directories.
+ *
+ * @param filePath The path to the file to be created.
+ */
+ private void getNewFile(String filePath) throws IOException{
+ File f = new File(filePath);
+ try {
+ if (!f.getParentFile().exists()) {
+ f.getParentFile().mkdirs();
+ }
+ if (!f.exists()) {
+ f.createNewFile();
+ }
+ } catch (IOException e) {
+ throw new IOException("An error occurred while creating the file: " + filePath, e);
+ }
+ }
+}
+
diff --git a/src/main/java/kafka/Task.java b/src/main/java/kafka/Task.java
new file mode 100644
index 0000000000..7e4098a8a0
--- /dev/null
+++ b/src/main/java/kafka/Task.java
@@ -0,0 +1,67 @@
+package kafka;
+
+import java.time.LocalDateTime;
+
+/**
+ * Represents a task with a description and a completion status.
+ */
+public class Task {
+
+ /** The task description. */
+ public final String description;
+
+ /** The completion status of the task. */
+ public boolean isDone;
+
+ /**
+ * Constructs a Task with a description and its status.
+ *
+ * @param description The description of the task.
+ * @param isDone The completion status of the task.
+ */
+ public Task(String description, boolean isDone) {
+ this.description = description;
+ this.isDone = isDone;
+ }
+
+ /**
+ * Returns the status icon representing whether the task is done.
+ *
+ * @return "X" if done, otherwise a space.
+ */
+ public String getStatusIcon() {
+ return (this.isDone ? "X" : " ");
+ }
+
+ /**
+ * Marks the task as done.
+ */
+ public void markAsDone() {
+ if (this.isDone) {
+ return;
+ }
+ this.isDone = true;
+ }
+
+ /**
+ * Marks the task as not done.
+ */
+ public void markAsNotDone() {
+ if (!this.isDone) {
+ return;
+ }
+ this.isDone = false;
+ }
+
+ public void snooze(LocalDateTime newTime) {}
+
+ /**
+ * Returns a string representation of the task.
+ *
+ * @return A string showing the status icon and description of the task.
+ */
+ @Override
+ public String toString() {
+ return "[" + this.getStatusIcon() + "] " + this.description;
+ }
+}
diff --git a/src/main/java/kafka/TaskList.java b/src/main/java/kafka/TaskList.java
new file mode 100644
index 0000000000..f47b1355c9
--- /dev/null
+++ b/src/main/java/kafka/TaskList.java
@@ -0,0 +1,117 @@
+package kafka;
+
+import java.util.ArrayList;
+
+/**
+ * Represents a list of tasks.
+ */
+public class TaskList {
+
+ /** List storing the tasks */
+ public final ArrayList tasks;
+
+ /**
+ * Constructs a TaskList with a given list of tasks.
+ *
+ * @param tasks List of tasks to initialize the TaskList with.
+ */
+ public TaskList(ArrayList tasks) {
+ this.tasks = tasks;
+ }
+
+ /**
+ * Constructs an empty TaskList.
+ */
+ public TaskList() {
+ this.tasks = new ArrayList<>();
+ }
+
+ /**
+ * Adds a task to the list.
+ *
+ * @param task The task to be added.
+ */
+ public void addTask(Task task) {
+ this.tasks.add(task);
+ }
+
+ /**
+ * Prints all tasks in the list.
+ */
+ public String printList() {
+ assert tasks.isEmpty() : "List is empty, unable to print list.";
+ if (tasks.isEmpty()) {
+ return "";
+ }
+ String listMessage = "";
+ for (int i = 0; i < this.tasks.size(); i++) {
+ Task t = this.tasks.get(i);
+ listMessage += " " + (i + 1) + "." + t + "\n";
+ }
+ return listMessage;
+ }
+
+ /**
+ * Marks a task as done.
+ *
+ * @param t The task to be marked as done.
+ */
+ public void mark(Task t) {
+ t.markAsDone();
+ }
+
+ /**
+ * Unmarks a task as not done.
+ *
+ * @param t The task to be marked as not done.
+ */
+ public void unmark(Task t) {
+ t.markAsNotDone();
+ }
+
+ /**
+ * Deletes a task by its task number.
+ *
+ * @param taskNumber The task number to be deleted (1-based index).
+ */
+ public void delete(int taskNumber) {
+ if (this.tasks.isEmpty()) {
+ return;
+ }
+ this.tasks.remove(taskNumber - 1);
+ }
+
+ /**
+ * Gets the number of tasks in the list.
+ *
+ * @return The number of tasks in the list.
+ */
+ public int getSize() {
+ return this.tasks.size();
+ }
+
+ /**
+ * Checks if the task list is empty.
+ *
+ * @return True if the task list is empty, false otherwise.
+ */
+ public boolean isEmpty() {
+ return this.tasks.isEmpty();
+ }
+
+ /**
+ * Finds tasks in the list that contain the specified keyword in their descriptions.
+ *
+ * @param keyword The keyword to search for.
+ * @return A new TaskList containing the found tasks.
+ */
+ public TaskList find(String keyword) {
+ TaskList temp = new TaskList();
+ for (Task t : tasks) {
+ if (t.description.toLowerCase().contains(keyword)) {
+ temp.addTask(t);
+ }
+ }
+ return temp;
+ }
+}
diff --git a/src/main/java/kafka/Todo.java b/src/main/java/kafka/Todo.java
new file mode 100644
index 0000000000..cec3016b61
--- /dev/null
+++ b/src/main/java/kafka/Todo.java
@@ -0,0 +1,13 @@
+package kafka;
+
+public class Todo extends Task {
+
+ public Todo(String description, boolean isDone) {
+ super(description, isDone);
+ }
+
+ @Override
+ public String toString() {
+ return "[T]" + super.toString();
+ }
+}
diff --git a/src/main/java/kafka/Ui.java b/src/main/java/kafka/Ui.java
new file mode 100644
index 0000000000..caa731dfdb
--- /dev/null
+++ b/src/main/java/kafka/Ui.java
@@ -0,0 +1,66 @@
+package kafka;
+
+public class Ui {
+
+ public static final String LOGO = """
+ __ __ __ _
+ | |/ / ____ _/ /_ | | ____
+ | / / _ | |_ _| | |/ / / _ |
+ | \\ | |_| | | | | < | |_| |
+ |__|\\__\\ \\____| |__| |_|\\ \\ \\____|
+ """;
+
+ public static String greet() {
+ return " Hello from\n" + LOGO + "\n" + """
+ Hello. Kafka here.
+ We meet again.
+ """ + "\n" + " What do you need me for?";
+ }
+
+ public String goodbye() {
+ return " Farewell. I look forward to our next meeting, wherever destiny may lead us.";
+ }
+
+ public String addTask(Task task, TaskList taskList) {
+ return " Got it. I've added this task.\n"
+ + " " + task + "\n"
+ + " Now you have " + taskList.getSize() + " task(s) in the list.";
+ }
+
+ public String getList() {
+ return " Here are the tasks in your list:";
+ }
+
+ public String find() {
+ return " Here you go, these are the matching tasks in your list:";
+ }
+
+ public String mark(Task t) {
+ return " Good work on this task. Want a prize?:\n"
+ + " " + t;
+ }
+
+ public String unmark(Task t) {
+ return " Hurry up. This task is necessary for Elio's script:\n"
+ + " " + t;
+ }
+
+ public String snooze(Task t) {
+ return " Oh, the task is delayed? Do you need any help?\n"
+ + " " + t;
+ }
+
+ public String delete(Task t, TaskList taskList) {
+ return " I've removed this task:\n"
+ + " " + t + "\n"
+ + " Now you have " + taskList.getSize() + " task(s) in the list.";
+ }
+
+ public String incorrectDateDetails() {
+ return " Ah, it seems you have made a mistake with the date. Please align your date with this format: yyyy-mm-dd hhmm (2024-01-01 2300)";
+ }
+
+ public String showError(Exception e) {
+ return " " + e.getMessage();
+ }
+}
diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..a64b7d592d
--- /dev/null
+++ b/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: kafka.Main
+
diff --git a/src/main/resources/images/Kafka.png b/src/main/resources/images/Kafka.png
new file mode 100644
index 0000000000..eb7835fbe8
Binary files /dev/null and b/src/main/resources/images/Kafka.png differ
diff --git a/src/main/resources/images/StarRailMC.png b/src/main/resources/images/StarRailMC.png
new file mode 100644
index 0000000000..8bd43c1d5c
Binary files /dev/null and b/src/main/resources/images/StarRailMC.png differ
diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml
new file mode 100644
index 0000000000..fe672c90ea
--- /dev/null
+++ b/src/main/resources/view/DialogBox.fxml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
new file mode 100644
index 0000000000..13551471c1
--- /dev/null
+++ b/src/main/resources/view/MainWindow.fxml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/seedu/kafka/StorageTest.java b/src/test/java/seedu/kafka/StorageTest.java
new file mode 100644
index 0000000000..1fd92a0e3b
--- /dev/null
+++ b/src/test/java/seedu/kafka/StorageTest.java
@@ -0,0 +1,65 @@
+package seedu.kafka;
+
+import kafka.Deadline;
+import kafka.Storage;
+import kafka.Todo;
+import kafka.Event;
+import kafka.Task;
+import org.junit.jupiter.api.Test;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+public class StorageTest {
+
+ @Test
+ public void testWriteTodoToFile() throws IOException {
+ ArrayList tasks = new ArrayList<>();
+ tasks.add(new Todo("Sample todo", false));
+
+ Path tempFile = Files.createTempFile("test", ".txt");
+ Storage storage = new Storage(tempFile.toString());
+ storage.writeToFile(tasks);
+
+ String expected = "T | false | Sample todo" + System.lineSeparator();
+ String content = Files.readString(tempFile);
+
+ assertEquals(expected, content);
+ }
+
+ @Test
+ public void testWriteDeadlineToFile() throws IOException {
+ ArrayList tasks = new ArrayList<>();
+ tasks.add(new Deadline("Sample deadline", LocalDateTime.of(2024, 12, 31, 23, 59), false));
+
+ Path tempFile = Files.createTempFile("test", ".txt");
+ Storage storage = new Storage(tempFile.toString());
+ storage.writeToFile(tasks);
+
+ String expected = "D | false | Sample deadline | 2024-12-31T23:59" + System.lineSeparator();
+ String content = Files.readString(tempFile);
+
+ assertEquals(expected, content);
+ }
+
+ @Test
+ public void testWriteEventToFile() throws IOException {
+ ArrayList tasks = new ArrayList<>();
+ tasks.add(new Event("Sample event",
+ LocalDateTime.of(2024, 12, 1, 12, 0),
+ LocalDateTime.of(2024, 12, 1, 14, 0), false));
+
+ Path tempFile = Files.createTempFile("test", ".txt");
+ Storage storage = new Storage(tempFile.toString());
+ storage.writeToFile(tasks);
+
+ String expected = "E | false | Sample event | 2024-12-01T12:00 | 2024-12-01T14:00" + System.lineSeparator();
+ String content = Files.readString(tempFile);
+
+ assertEquals(expected, content);
+ }
+}
diff --git a/src/test/java/seedu/kafka/TaskListTest.java b/src/test/java/seedu/kafka/TaskListTest.java
new file mode 100644
index 0000000000..10deb2e8bc
--- /dev/null
+++ b/src/test/java/seedu/kafka/TaskListTest.java
@@ -0,0 +1,56 @@
+package seedu.kafka;
+
+import kafka.Deadline;
+import kafka.Event;
+import kafka.TaskList;
+import kafka.Todo;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class TaskListTest {
+
+ private TaskList taskList;
+ private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ private final PrintStream originalOut = System.out;
+
+ @BeforeEach
+ public void setUp() {
+ taskList = new TaskList();
+ System.setOut(new PrintStream(outputStream));
+ }
+
+ @AfterEach
+ public void restoreSystemOut() {
+ System.setOut(originalOut);
+ }
+
+ @Test
+ public void printList_emptyTaskList_displaysNothing() {
+ outputStream.reset();
+ taskList.printList();
+ assertEquals("", outputStream.toString().trim());
+ }
+
+ //@Test
+ /**public void printList_nonEmptyTaskList_displaysTasks() {
+ outputStream.reset();
+
+ taskList.addTask(new Todo("Todo sample", false));
+ taskList.addTask(new Deadline("Deadline sample", LocalDateTime.of(2024, 1, 1, 12, 0), false));
+ taskList.addTask(new Event("Event sample", LocalDateTime.of(2024, 1, 1, 12, 0), LocalDateTime.of(2024, 1, 1, 14, 0), false));
+
+ taskList.printList();
+
+ String expectedOutput = "1.[T][ ] Todo sample\n"
+ + " 2.[D][ ] Deadline sample(by: January 01 2024 1200)\n"
+ + " 3.[E][ ] Event sample(from: January 01 2024 1200 to: January 01 2024 1400)";
+
+ assertEquals(expectedOutput, outputStream.toString().trim());
+ }**/
+}
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e7..f6a619f4b9 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,84 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
+ Hello from
+ __ __ __ _
+ | |/ / ____ _/ /_ | | ____
+ | / / _ | |_ _| | |/ / / _ |
+ | \ | |_| | | | | < | |_| |
+ |__|\__\ \____| |__| |_|\ \ \____|
+
+ Hello. kafka.Kafka here.
+ We meet again.
+
+ What do you need me for?
+
+ Got it. I've added this task.
+ [T][ ] read book
+ Now you have 1 task(s) in the list.
+
+ Got it. I've added this task.
+ [T][ ] return book
+ Now you have 2 task(s) in the list.
+
+ Got it. I've added this task.
+ [D][ ] finish CS2103T assignments (by: Friday 4pm)
+ Now you have 3 task(s) in the list.
+
+ Got it. I've added this task.
+ [D][ ] do ST2334 notes (by: Sunday)
+ Now you have 4 task(s) in the list.
+
+ Got it. I've added this task.
+ [E][ ] welcome tea (from: Monday 7pm to: 9pm)
+ Now you have 5 task(s) in the list.
+
+ Got it. I've added this task.
+ [E][ ] meeting (from: Wednesday 11pm to: Thursday 12am)
+ Now you have 6 task(s) in the list.
+
+ Here are the tasks in your list:
+ 1.[T][ ] read book
+ 2.[T][ ] return book
+ 3.[D][ ] finish CS2103T assignments (by: Friday 4pm)
+ 4.[D][ ] do ST2334 notes (by: Sunday)
+ 5.[E][ ] welcome tea (from: Monday 7pm to: 9pm)
+ 6.[E][ ] meeting (from: Wednesday 11pm to: Thursday 12am)
+
+ Good work on this task. Want a prize?:
+ [T][X] read book
+
+ Good work on this task. Want a prize?:
+ [D][X] do ST2334 notes (by: Sunday)
+
+ Here are the tasks in your list:
+ 1.[T][X] read book
+ 2.[T][ ] return book
+ 3.[D][ ] finish CS2103T assignments (by: Friday 4pm)
+ 4.[D][X] do ST2334 notes (by: Sunday)
+ 5.[E][ ] welcome tea (from: Monday 7pm to: 9pm)
+ 6.[E][ ] meeting (from: Wednesday 11pm to: Thursday 12am)
+
+ Hurry up. This task is necessary for Elio's script:
+ [D][ ] do ST2334 notes (by: Sunday)
+
+ Here are the tasks in your list:
+ 1.[T][X] read book
+ 2.[T][ ] return book
+ 3.[D][ ] finish CS2103T assignments (by: Friday 4pm)
+ 4.[D][ ] do ST2334 notes (by: Sunday)
+ 5.[E][ ] welcome tea (from: Monday 7pm to: 9pm)
+ 6.[E][ ] meeting (from: Wednesday 11pm to: Thursday 12am)
+
+ Hmm... I'm not sure what you're getting at. Care to enlighten me?
+
+ I've removed this task:
+ [E][ ] meeting (from: Wednesday 11pm to: Thursday 12am)
+ Now you have 5 task(s) in the list.
+
+ Here are the tasks in your list:
+ 1.[T][X] read book
+ 2.[T][ ] return book
+ 3.[D][ ] finish CS2103T assignments (by: Friday 4pm)
+ 4.[D][ ] do ST2334 notes (by: Sunday)
+ 5.[E][ ] welcome tea (from: Monday 7pm to: 9pm)
+
+ Farewell. I look forward to our next meeting, wherever destiny may lead us.
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb2..db1580bfce 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,16 @@
+todo read book
+todo return book
+deadline finish CS2103T assignments /by Friday 4pm
+deadline do ST2334 notes /by Sunday
+event welcome tea /from Monday 7pm /to 9pm
+event meeting /from Wednesday 11pm /to Thursday 12am
+list
+mark 1
+mark 4
+list
+unmark 4
+list
+remove 6
+delete 6
+list
+bye
\ No newline at end of file
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
index 0873744649..a265937309 100644
--- a/text-ui-test/runtest.bat
+++ b/text-ui-test/runtest.bat
@@ -15,7 +15,7 @@ IF ERRORLEVEL 1 (
REM no error here, errorlevel == 0
REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT
-java -classpath ..\bin Duke < input.txt > ACTUAL.TXT
+java -classpath ..\bin kafka.Kafka < input.txt > ACTUAL.TXT
REM compare the output to the expected output
FC ACTUAL.TXT EXPECTED.TXT
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
old mode 100644
new mode 100755
index c9ec870033..f3fd48e7d8
--- a/text-ui-test/runtest.sh
+++ b/text-ui-test/runtest.sh
@@ -20,7 +20,7 @@ then
fi
# run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT
-java -classpath ../bin Duke < input.txt > ACTUAL.TXT
+java -classpath ../bin Kafka < input.txt > ACTUAL.TXT
# convert to UNIX format
cp EXPECTED.TXT EXPECTED-UNIX.TXT