diff --git a/README.md b/README.md
index 8715d4d915..26602f04fc 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,33 @@
-# Duke project template
+# DukeBot
+
+> "You miss 100% of the shots you dont take." - My friend advising people on medical forums.
+
+DukeBot helps you to keep organised. How?
+
+- Text-based
+- Easy to grasp
+- ~~Very~~ Extremely easy to learn!
+
+All you need to do is:
+
+1. Download it from [here](https://github.com/Effixion/ip/releases/tag/v1.0)
+2. Double click the jar file
+3. Add your tasks
+4. Let it help you to keep organised!
+
+AND IT'S **_FREE_** :wink:
+
+Features:
+- [x] Adding tasks
+- [x] Deleting tasks
+- [ ] GUI (Coming soon)
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 11, 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 11** (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
- ____ _
- | _ \ _ _| | _____
- | | | | | | | |/ / _ \
- | |_| | |_| | < __/
- |____/ \__,_|_|\_\___|
- ```
+Here's how the main method looks like in the Duke class:
+
+```
+public static void main(String[] args) {
+ new Duke("tasks.txt").run();
+}
+```
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000..e6f5582f25
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,62 @@
+plugins {
+ id 'java'
+ id 'application'
+ id 'checkstyle'
+ id 'com.github.johnrengelman.shadow' version '5.1.0'
+}
+
+checkstyle {
+ toolVersion = '10.2'
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0'
+ testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0'
+
+ String javaFxVersion = '11'
+
+ 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 {
+ mainClassName = "duke.Launcher"
+}
+
+shadowJar {
+ archiveBaseName = "duke"
+ archiveClassifier = null
+}
+
+run {
+ standardInput = System.in
+ enableAssertions = true
+}
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
new file mode 100644
index 0000000000..e8ee76467b
--- /dev/null
+++ b/config/checkstyle/checkstyle.xml
@@ -0,0 +1,429 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml
new file mode 100644
index 0000000000..135ea49ee0
--- /dev/null
+++ b/config/checkstyle/suppressions.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
index 8077118ebe..867f425f83 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,29 +1,348 @@
# User Guide
+- User Guide
+ - [Overview](#overview)
+ - [Features](#features)
+ - [Addition of tasks](#addition-of-tasks)
+ - [Deleting of tasks](#deleting-of-tasks)
+ - [Marking and unmarking of tasks](#marking-and-unmarking-of-tasks)
+ - [Finding of tasks or tags](#finding-of-tasks-or-tags)
+ - [Viewing of tasks](#viewing-of-tasks)
+ - [Usage](#usage)
+ - [list](#list---an-overview-of-all-your-tasks)
+ - [todo](#todo---add-a-todo-task)
+ - [event](#event---add-a-event-task)
+ - [deadline](#deadline---add-a-deadline-task)
+ - [find](#find---find-a-task)
+ - [delete](#delete---delete-a-task)
+ - [cdf(changedateformat)](#cdf---changing-of-the-date-format)
+ - [findtag](#findtag---find-a-tag)
+ - [mark](#mark---mark-a-task)
+ - [unmark](#unmark---unmark-a-task)
+ - [bye](#bye---exits-the-program)
+
+## Overview
+This is Seaward, your friendly neighborhood chatbot!
+Seaward helps you to take charge of organizing the tasks that you have to complete by allowing you to add, tag, mark and list them all out in one convenient place.
+Potential users will be glad to have trusty Seaward bt their side!
## Features
-### Feature-ABC
+### Addition of tasks
+
+Seaward categorizes your tasks into three main tasks:
+- ```Todo```
+- ```Deadline```
+- ```Event```
+
+A ```Task``` has a description can it can have a associated tag included.
+A ```Todo``` is like a normal task, it just has a description.
+A ```Deadline``` has a description, but it also has an associated date which represents its deadline.
+A ``` Event``` is similar to a ```Deadline```, but its associated date represents when it will happen instead.
+
+### Deleting of tasks
+
+Seaward allows you to delete your tasks after you no longer want to keep track of them.
+Or you simply want to edit your tasks.
+
+### Marking and unmarking of tasks
+
+Seaward allows you to keep track of your progress with your tasks by marking or unmarking your tasks .
+
+### Finding of tasks or tags
+
+Seaward can easily help you to find a keyword in the description or the tag of a task in a pinch. Thus, you can easily retrieve the information that you want with this feature.
+
+### Viewing of tasks
-Description of the feature.
+Seaward allows you can see all of your tasks in one place so that you can see how many pending tasks you have.
-### Feature-XYZ
+### Storing of your tasks in your computer
-Description of the feature.
+Seaward will create a text file so that it will __remember__ what your tasks were! When you exit and start Seaward again, you will see that your tasks were right where you left off.
## Usage
-### `Keyword` - Describe action
+### `list` - An overview of all your tasks
+
+Displays the current tasks that you have. The description, tag and type of task will be shown, along with its completion and date _(if applicable)_
+
+Format:
+`list`
+
+Example of usage: `list`
+
+Expected outcome:
+```
+1. [D][X] Watch lecture #urgent (by: 2022-09-12)
+2. [E][ ] TF2 i69 lan #hype (at: 2022-08-25)
+3. [T][ ] Borrow a broom
+```
+
+### `todo` - Add a Todo task
+
+Creates a ```Todo``` task with the provided associated description and/or tag.
+
+Format:
-Describe the action and its outcome.
+`todo {DESCRIPTION}`
+
+`todo {DESCRIPTION} /tag {TAG}`
Example of usage:
-`keyword (optional arguments)`
+`todo read book`
+
+`todo read book /tag Hunger Games`
Expected outcome:
+```
+Noted. I have added:
+[T][ ] read book
+Now you have 1 task(s) in your list.
+```
+```
+Noted. I have added:
+[T][ ] read book #Hunger Games
+Now you have 1 task(s) in your list.
+```
+
+### `event` - Add a Event task
+
+Creates an ```Event``` task with its associated description, tag and date. Date must be in YYYY-MM-DD format.
+
+Format:
+
+`event {DESCRIPTION} /at {YYYY-MM-DD}`
-Description of the outcome.
+`event {DESCRIPTION} /tag {TAG} /at {YYYY-MM-DD}`
+
+Example of usage:
+
+`event TF2 i69 lan /at 2022-08-25`
+
+`event TF2 i69 lan /tag hype /at 2022-08-25`
+
+Expected outcome:
+```
+Noted. I have added:
+[E][ ] TF2 i69 lan (at: 2022-08-25)
+Now you have 1 task(s) in your list.
+```
+```
+Noted. I have added:
+[E][ ] TF2 i69 lan #hype (at: 2022-08-25)
+Now you have 1 task(s) in your list.
+```
+### `deadline` - Add a Deadline task
+
+Creates an ```Deadline``` task with its associated description, tag and date. Date must be in YYYY-MM-DD format.
+
+Format:
+
+`deadline {DESCRIPTION} /by {YYYY-MM-DD}`
+
+`deadline {DESCRIPTION} /tag {TAG} /by {YYYY-MM-DD}`
+
+Example of usage:
+
+`deadline functional expressionism /by 2022-08-24`
+
+`deadline functional expressionism /tag no pls /by 2022-08-24`
+
+Expected outcome:
+```
+Noted. I have added:
+[D][ ] functional expressionism (by: 2022-08-24)
+Now you have 1 task(s) in your list.
+```
+```
+Noted. I have added:
+[D][ ] functional expressionism #no pls (by: 2022-08-24)
+Now you have 1 task(s) in your list.
+```
+
+### `find` - Find a task
+
+Finds the tasks that contain a key word provided by the user. Note that the find feature is case sensitive.
+
+Format:
+
+`find {KEYWORD}`
+
+Example of usage:
+
+`find book`
+
+Expected outcome:
+
+If your list consists of
+```
+1. [T][ ] return book #urgent
+```
+then
+```
+Here are the matching tasks in your list:
+1. [T][ ] return book #urgent
+```
+
+If your list consists of
+```
+1. [T][ ] return Book #urgent
+```
+then
+```
+Sorry! There are no matching tasks that contains
+book
+```
+
+### `delete` - Delete a task
+
+Delete a task in your list. The task index that you provide will delete the task at that index.
+
+Format:
+
+`delete {INDEX}`
+
+Example of usage:
+
+`delete 2`
+
+Expected outcome:
+
+If your list consists of
+```
+1. [T][ ] return book #urgent
+2. [T][ ] Borrow a broom
+```
+then
+```
+Noted. I have removed this task:
+[T][ ] Borrow a broom
+Now you have 1 task(s) in your list.
+```
+
+### `cdf` - Changing of the date format
+
+Changes the date format for an ```Event``` or a ```Deadline```. However, the changes are temporary. The index is provided by the user.
+
+Format:
+
+`cdf {INDEX}`
+
+Example of usage:
+
+`cdf 1`
+
+Expected outcome:
+
+If your list consists of
+```
+1. [D][ ] functional expressionism (by: 2022-08-24)
+```
+then
+```
+Here is a different date format for this task!
+[D][ ] functional expressionism (by: 24 Aug 2022)
+```
+
+### `findtag` - Find a tag
+
+Finds the tasks with tags that contain a key word provided by the user. Note that the findtag feature is case sensitive.
+
+Format:
+
+`findtag {KEYWORD}`
+
+Example of usage:
+
+`findtag urgent`
+
+Expected outcome:
+
+If your list consists of
+```
+1. [T][ ] return book #urgent
+```
+then
+```
+Here are the tasks with the matching tags in your list:
+1. [T][ ] return book #urgent
+```
+
+If your list consists of
+```
+1. [T][ ] return book #Urgent
+```
+then
+```
+Sorry! There are no matching tasks with a tag that contains
+urgent
+```
+
+### `mark` - Mark a task
+
+Marks a task as complete. The index of the task will be provided by the user.
+
+Format:
+
+`mark {INDEX}`
+
+Example of usage:
+
+`mark 2`
+
+Expected outcome:
+
+If your list consists of
+```
+1. [T][ ] return book #urgent
+2. [T][ ] Borrow a broom
+```
+then
+```
+I have marked this task as done:
+[T][X] Borrow a broom
+```
+
+### `unmark` - Unmark a task
+
+Marks a task as incomplete. The index of the task will be provided by the user.
+
+Format:
+
+`unmark {INDEX}`
+
+Example of usage:
+
+`unmark 1`
+
+Expected outcome:
+
+If your list consists of
+```
+1. [T][X] return book #urgent
+2. [T][ ] Borrow a broom
+```
+then
+```
+I have marked this task as undone:
+[T][ ] return book #urgent
+```
+
+### `bye` - Exits the program
+
+When exiting, your tasks will be saved into a file on your computer so that the next time you boot up Seaward, you will have your tasks there.
+
+Format:
+
+`bye`
+
+Example of usage:
+
+`bye`
+
+Expected outcome:
```
-expected output
+Seaward out! See you next time buddy!
```
diff --git a/docs/Ui.png b/docs/Ui.png
new file mode 100644
index 0000000000..43329b74b6
Binary files /dev/null and b/docs/Ui.png differ
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..f3d88b1c2f
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..b7c8c5dbf5
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000000..2fe81a7d95
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,183 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or 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 UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# 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"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# 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
+ ;;
+ 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"
+ which java >/dev/null 2>&1 || 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
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000000..62bd9b9cce
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,103 @@
+@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=.
+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%" == "0" goto init
+
+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 init
+
+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
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+: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 %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="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!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+: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/duke/DialogBox.java b/src/main/java/duke/DialogBox.java
new file mode 100644
index 0000000000..ed7af69123
--- /dev/null
+++ b/src/main/java/duke/DialogBox.java
@@ -0,0 +1,60 @@
+package duke;
+
+import java.io.IOException;
+import java.util.Collections;
+
+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;
+
+/**
+ * An example of a custom control using FXML.
+ * This control 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/duke/Duke.java b/src/main/java/duke/Duke.java
new file mode 100644
index 0000000000..fa9cb35d79
--- /dev/null
+++ b/src/main/java/duke/Duke.java
@@ -0,0 +1,71 @@
+package duke;
+
+import java.io.IOException;
+
+import duke.exception.InvalidCommandException;
+import duke.exception.InvalidDescriptionException;
+import duke.parser.Parser;
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+/**
+ * Represents the chatbot and how it facilitates the interactions between
+ * the user and the chatbot.
+ */
+public class Duke {
+
+ private static String welcome = "Hello! I'm Seaward,\n"
+ + "your friendly neighbourhood chatbot.\n"
+ + "Refer to the user guide for all the available commands!";
+ private Storage storage;
+ private TaskList tasks;
+ private Ui ui;
+ private Parser parser;
+
+ /**
+ * Returns a Duke object which takes in a string that represents the file path that contains the
+ * tasks of the user which is then passed into the storage object.
+ * @param filePath A string representing the file path that stores the tasks.
+ */
+ public Duke(String filePath) {
+ // Deals with interactions with the user
+ // Most likely will be using Scanner
+ // Returns messages/error messages to the user
+ ui = new Ui();
+
+ // Deals with loading tasks from the file and
+ // saving them in the file
+ storage = new Storage(filePath);
+
+ // Loading the tasks in the file to the taskList
+ tasks = new TaskList(storage.loadFromFile());
+
+ // Initialises the parser to read user commands
+ parser = new Parser(tasks, storage, ui);
+ }
+
+ /**
+ * Returns a welcome message that greets the user when the user runs the chatbot.
+ * @return A welcome message.
+ */
+ public static String getWelcome() {
+ return welcome;
+ }
+
+ /**
+ * Returns an appropriate response from the parser according to the user input.
+ * @param input A string that represents the user input.
+ * @return A string that contains a success or failure message.
+ */
+ public String getResponse(String input) {
+ try {
+ String response = parser.readInputString(input);
+ return response;
+ } catch (InvalidDescriptionException | InvalidCommandException | IOException e) {
+ return e.getMessage();
+ } catch (NumberFormatException e) {
+ return "Please type in a valid integer!";
+ }
+ }
+}
diff --git a/src/main/java/duke/Launcher.java b/src/main/java/duke/Launcher.java
new file mode 100644
index 0000000000..e74700c6ae
--- /dev/null
+++ b/src/main/java/duke/Launcher.java
@@ -0,0 +1,16 @@
+package duke;
+
+import javafx.application.Application;
+
+/**
+ * Represents a launcher that starts the GUI for Seaward the chatbot.
+ */
+public class Launcher {
+ /**
+ * Launches the GUI for Seaward the chatbot.
+ * @param args Main args
+ */
+ public static void main(String[] args) {
+ Application.launch(Main.class, args);
+ }
+}
diff --git a/src/main/java/duke/Main.java b/src/main/java/duke/Main.java
new file mode 100644
index 0000000000..86c9a00bea
--- /dev/null
+++ b/src/main/java/duke/Main.java
@@ -0,0 +1,32 @@
+package duke;
+
+import java.io.IOException;
+
+import javafx.application.Application;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Scene;
+import javafx.scene.layout.AnchorPane;
+import javafx.stage.Stage;
+
+/**
+ * A GUI for Duke using FXML.
+ */
+public class Main extends Application {
+
+ private Duke duke = new Duke("tasks.txt");
+
+ @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.setTitle("Seaward: Friendly neighbourhood chatbot");
+ stage.setScene(scene);
+ fxmlLoader.getController().setDuke(duke);
+ stage.show();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/duke/MainWindow.java b/src/main/java/duke/MainWindow.java
new file mode 100644
index 0000000000..e2eed312ce
--- /dev/null
+++ b/src/main/java/duke/MainWindow.java
@@ -0,0 +1,57 @@
+package duke;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+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 MainWindow. Provides the layout for the other controls.
+ */
+public class MainWindow extends AnchorPane {
+ @FXML
+ private ScrollPane scrollPane;
+ @FXML
+ private VBox dialogContainer;
+ @FXML
+ private TextField userInput;
+ @FXML
+ private Button sendButton;
+
+ private Duke duke;
+
+ private Image userImage = new Image(this.getClass().getResourceAsStream("/images/DaUser.png"));
+ private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png"));
+
+ /**
+ * Returns a welcome message on the GUI.
+ */
+ @FXML
+ public void initialize() {
+ scrollPane.vvalueProperty().bind(dialogContainer.heightProperty());
+ dialogContainer.getChildren().addAll(
+ DialogBox.getDukeDialog(Duke.getWelcome(), dukeImage)
+ );
+ }
+
+ public void setDuke(Duke d) {
+ duke = d;
+ }
+
+ /**
+ * Creates two dialog boxes, one echoing user input and the other containing Duke'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 = duke.getResponse(input);
+ dialogContainer.getChildren().addAll(
+ DialogBox.getUserDialog(input, userImage),
+ DialogBox.getDukeDialog(response, dukeImage)
+ );
+ userInput.clear();
+ }
+}
diff --git a/src/main/java/duke/command/ByeCommand.java b/src/main/java/duke/command/ByeCommand.java
new file mode 100644
index 0000000000..c4fd3c1176
--- /dev/null
+++ b/src/main/java/duke/command/ByeCommand.java
@@ -0,0 +1,47 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+
+public class ByeCommand extends Command {
+
+ public ByeCommand() {
+ super();
+ }
+
+ @Override
+ public String read(TaskList taskList, Ui ui, Storage storage) throws IOException {
+ storage.clearFile();
+ for (int i = 0; i < taskList.getNumOfTasks(); i++) {
+ char taskType = taskList.readTask(i).charAt(1);
+ String status = taskList.readStatus(i);
+ String tag = taskList.getTag(i);
+ switch (taskType) {
+ case 'T': {
+ String taskToAppend = taskList.storeIntoFileFormat("T", taskList.convertStatus(status),
+ taskList.getDescription(i), tag, "");
+ storage.appendToFile(taskToAppend);
+ break;
+ }
+ case 'D': {
+ String taskToAppend = taskList.storeIntoFileFormat("D", taskList.convertStatus(status),
+ taskList.getDescription(i), tag, taskList.getDate(i));
+ storage.appendToFile(taskToAppend);
+ break;
+ }
+ case 'E': {
+ String taskToAppend = taskList.storeIntoFileFormat("E", taskList.convertStatus(status),
+ taskList.getDescription(i), tag, taskList.getDate(i));
+ storage.appendToFile(taskToAppend);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return ui.getGoodbyeMessage();
+ }
+}
diff --git a/src/main/java/duke/command/ChangeDateFormatCommand.java b/src/main/java/duke/command/ChangeDateFormatCommand.java
new file mode 100644
index 0000000000..b8dedf2233
--- /dev/null
+++ b/src/main/java/duke/command/ChangeDateFormatCommand.java
@@ -0,0 +1,23 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+public class ChangeDateFormatCommand extends Command {
+ private int index;
+
+ public ChangeDateFormatCommand(int index) {
+ super();
+ this.index = index;
+ }
+
+ @Override
+ public String read(TaskList taskList, Ui ui, Storage storage) {
+ if (taskList.changeDateFormat(index).equals("")) {
+ return ui.getNoDateMessage();
+ } else {
+ return ui.getDateChangedMessage() + "\n" + taskList.changeDateFormat(index);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/command/Command.java b/src/main/java/duke/command/Command.java
new file mode 100644
index 0000000000..3387a4f58c
--- /dev/null
+++ b/src/main/java/duke/command/Command.java
@@ -0,0 +1,16 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+
+public abstract class Command {
+ public Command() {
+
+ }
+
+ public abstract String read(TaskList tasks, Ui ui, Storage storage) throws IOException;
+
+}
diff --git a/src/main/java/duke/command/DeadlineCommand.java b/src/main/java/duke/command/DeadlineCommand.java
new file mode 100644
index 0000000000..fe24ecc541
--- /dev/null
+++ b/src/main/java/duke/command/DeadlineCommand.java
@@ -0,0 +1,21 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+public class DeadlineCommand extends Command {
+ private String description;
+
+ public DeadlineCommand(String description) {
+ super();
+ this.description = description;
+ }
+
+ @Override
+ public String read(TaskList taskList, Ui ui, Storage storage) {
+ taskList.addDeadline(description);
+ int numOfTasks = taskList.getNumOfTasks();
+ return ui.getAddTaskMessage(taskList.readTask(numOfTasks - 1), numOfTasks);
+ }
+}
diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java
new file mode 100644
index 0000000000..360aeaa9db
--- /dev/null
+++ b/src/main/java/duke/command/DeleteCommand.java
@@ -0,0 +1,22 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+public class DeleteCommand extends Command {
+ private int index;
+
+ public DeleteCommand(int index) {
+ super();
+ this.index = index;
+ }
+
+ @Override
+ public String read(TaskList taskList, Ui ui, Storage storage) {
+ int numOfTasks = taskList.getNumOfTasks();
+ String result = ui.getDeleteMessage(taskList.readTask(index), numOfTasks - 1);
+ taskList.deleteTask(index);
+ return result;
+ }
+}
diff --git a/src/main/java/duke/command/EventCommand.java b/src/main/java/duke/command/EventCommand.java
new file mode 100644
index 0000000000..ed39d4c81f
--- /dev/null
+++ b/src/main/java/duke/command/EventCommand.java
@@ -0,0 +1,21 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+public class EventCommand extends Command {
+ private String description;
+
+ public EventCommand(String description) {
+ super();
+ this.description = description;
+ }
+
+ @Override
+ public String read(TaskList taskList, Ui ui, Storage storage) {
+ taskList.addEvent(description);
+ int numOfTasks = taskList.getNumOfTasks();
+ return ui.getAddTaskMessage(taskList.readTask(numOfTasks - 1), numOfTasks);
+ }
+}
diff --git a/src/main/java/duke/command/FindCommand.java b/src/main/java/duke/command/FindCommand.java
new file mode 100644
index 0000000000..a7856eeff1
--- /dev/null
+++ b/src/main/java/duke/command/FindCommand.java
@@ -0,0 +1,31 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+public class FindCommand extends Command {
+ private String searchTerm;
+
+ public FindCommand(String searchTerm) {
+ super();
+ this.searchTerm = searchTerm;
+ }
+
+ @Override
+ public String read(TaskList taskList, Ui ui, Storage storage) {
+ StringBuilder result = new StringBuilder();
+ int index = 1;
+ for (int i = 0; i < taskList.getNumOfTasks(); i++) {
+ if (taskList.getDescription(i).contains(searchTerm)) {
+ result.append("\n").append(index).append(".").append(taskList.readTask(i));
+ index++;
+ }
+ }
+ if (result.toString().equals("")) {
+ return ui.getNoMatchingTaskMessage() + searchTerm;
+ } else {
+ return ui.getMatchingTaskMessage() + result;
+ }
+ }
+}
diff --git a/src/main/java/duke/command/FindTagCommand.java b/src/main/java/duke/command/FindTagCommand.java
new file mode 100644
index 0000000000..aac3e6a9c8
--- /dev/null
+++ b/src/main/java/duke/command/FindTagCommand.java
@@ -0,0 +1,32 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+public class FindTagCommand extends Command {
+ private String searchTerm;
+
+ public FindTagCommand(String searchTerm) {
+ super();
+ this.searchTerm = searchTerm;
+ }
+
+ @Override
+ public String read(TaskList taskList, Ui ui, Storage storage) {
+ StringBuilder result = new StringBuilder();
+ int index = 1;
+ for (int i = 0; i < taskList.getNumOfTasks(); i++) {
+ if (taskList.getTag(i).contains(searchTerm)) {
+ result.append("\n").append(index).append(".").append(taskList.readTask(i));
+ index++;
+ }
+ }
+ if (result.toString().equals("")) {
+ return ui.getNoMatchingTagMessage() + searchTerm;
+ } else {
+ return ui.getMatchingTagMessage() + result;
+ }
+ }
+
+}
diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java
new file mode 100644
index 0000000000..7feb5d6728
--- /dev/null
+++ b/src/main/java/duke/command/ListCommand.java
@@ -0,0 +1,21 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+public class ListCommand extends Command {
+ public ListCommand() {
+ super();
+ }
+
+ @Override
+ public String read(TaskList taskList, Ui ui, Storage storage) {
+ int numOfTasks = taskList.getNumOfTasks();
+ if (numOfTasks == 0) {
+ return ui.getEmptyTaskMessage();
+ } else {
+ return ui.getList(taskList);
+ }
+ }
+}
diff --git a/src/main/java/duke/command/MarkCommand.java b/src/main/java/duke/command/MarkCommand.java
new file mode 100644
index 0000000000..ee01424ee3
--- /dev/null
+++ b/src/main/java/duke/command/MarkCommand.java
@@ -0,0 +1,20 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+public class MarkCommand extends Command {
+ private int index;
+
+ public MarkCommand(int index) {
+ super();
+ this.index = index;
+ }
+
+ @Override
+ public String read(TaskList taskList, Ui ui, Storage storage) {
+ taskList.setCompleted(index);
+ return ui.getMarkedTaskMessage() + taskList.readTask(index);
+ }
+}
diff --git a/src/main/java/duke/command/TodoCommand.java b/src/main/java/duke/command/TodoCommand.java
new file mode 100644
index 0000000000..7e9b4d267c
--- /dev/null
+++ b/src/main/java/duke/command/TodoCommand.java
@@ -0,0 +1,21 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+public class TodoCommand extends Command {
+ private String description;
+
+ public TodoCommand(String description) {
+ super();
+ this.description = description;
+ }
+
+ @Override
+ public String read(TaskList taskList, Ui ui, Storage storage) {
+ taskList.addTodo(description);
+ int numOfTasks = taskList.getNumOfTasks();
+ return ui.getAddTaskMessage(taskList.readTask(numOfTasks - 1), numOfTasks);
+ }
+}
diff --git a/src/main/java/duke/command/UnmarkCommand.java b/src/main/java/duke/command/UnmarkCommand.java
new file mode 100644
index 0000000000..5c042ba53f
--- /dev/null
+++ b/src/main/java/duke/command/UnmarkCommand.java
@@ -0,0 +1,20 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+public class UnmarkCommand extends Command {
+ private int index;
+
+ public UnmarkCommand(int index) {
+ super();
+ this.index = index;
+ }
+
+ @Override
+ public String read(TaskList taskList, Ui ui, Storage storage) {
+ taskList.setNotCompleted(index);
+ return ui.getUnmarkedTaskMessage() + taskList.readTask(index);
+ }
+}
diff --git a/src/main/java/duke/exception/InvalidCommandException.java b/src/main/java/duke/exception/InvalidCommandException.java
new file mode 100644
index 0000000000..ecb31fc29a
--- /dev/null
+++ b/src/main/java/duke/exception/InvalidCommandException.java
@@ -0,0 +1,10 @@
+package duke.exception;
+
+/**
+ * Represents an exception when the user enters an invalid command.
+ */
+public class InvalidCommandException extends Exception {
+ public InvalidCommandException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/duke/exception/InvalidDescriptionException.java b/src/main/java/duke/exception/InvalidDescriptionException.java
new file mode 100644
index 0000000000..6761e5e091
--- /dev/null
+++ b/src/main/java/duke/exception/InvalidDescriptionException.java
@@ -0,0 +1,10 @@
+package duke.exception;
+
+/**
+ * Represents an exception where the user enters an invalid description.
+ */
+public class InvalidDescriptionException extends Exception {
+ public InvalidDescriptionException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/duke/parser/Parser.java b/src/main/java/duke/parser/Parser.java
new file mode 100644
index 0000000000..165655ae22
--- /dev/null
+++ b/src/main/java/duke/parser/Parser.java
@@ -0,0 +1,133 @@
+package duke.parser;
+
+import java.io.IOException;
+
+import duke.command.*;
+import duke.exception.InvalidCommandException;
+import duke.exception.InvalidDescriptionException;
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+/**
+ * Represents the location where the commands entered into the program are
+ * processed and how should the Ui, or Seaward, should respond.
+ */
+public class Parser {
+
+ private static TaskList taskList;
+ private Storage storage;
+ private Ui ui;
+
+ /**
+ * Initialises a Parser object which takes in tasks, storage and ui
+ * to make sense of the user commands.
+ * @param tasks TaskList object representing the lists of tasks.
+ * @param storage Storage object which deals with reading and writing
+ * to a file that is located on the user's hard disk.
+ * @param ui Ui object that deals with the interactions with the user.
+ */
+ public Parser(TaskList tasks, Storage storage, Ui ui) {
+ taskList = tasks;
+ this.storage = storage;
+ this.ui = ui;
+ }
+
+ /**
+ * Returns the appropriate response to a command given by the user. If the command is invalid,
+ * then an error message is returned.
+ * @param s Command given by the user.
+ * @return A response depending on the command given by the user.
+ * @throws InvalidCommandException If the command is not one of the cases, or if the index does not
+ * exist in the TaskList object.
+ * @throws InvalidDescriptionException If the command does not have a valid description.
+ * @throws IOException If the Storage object cannot read or write to the file.
+ */
+ public String readInputString(String s) throws InvalidCommandException,
+ InvalidDescriptionException, IOException {
+ String[] splitCommand = s.split(" ", 2);
+ assert splitCommand[0] != null : "Invalid command";
+ String command = splitCommand[0];
+ switch (command) {
+ case "bye": {
+ return new ByeCommand().read(taskList, ui, storage);
+ }
+ case "list": {
+ return new ListCommand().read(taskList, ui, storage);
+ }
+ case "mark": {
+ if (splitCommand.length == 1) {
+ throw new InvalidDescriptionException("Please add a number.");
+ }
+ int index = Integer.parseInt(splitCommand[1]) - 1;
+ if (index + 1 > taskList.getNumOfTasks()) {
+ throw new InvalidCommandException("Task does not exist.");
+ }
+ return new MarkCommand(index).read(taskList, ui, storage);
+ }
+ case "unmark": {
+ if (splitCommand.length == 1) {
+ throw new InvalidDescriptionException("Please add a number.");
+ }
+ int index = Integer.parseInt(splitCommand[1]) - 1;
+ if (index + 1 > taskList.getNumOfTasks()) {
+ throw new InvalidCommandException("Task does not exist.");
+ }
+ return new UnmarkCommand(index).read(taskList, ui, storage);
+ }
+ case "delete": {
+ if (splitCommand.length == 1) {
+ throw new InvalidDescriptionException("Please add a number.");
+ }
+ int index = Integer.parseInt(splitCommand[1]) - 1;
+ int numOfTasks = taskList.getNumOfTasks();
+ if (index + 1 > numOfTasks) {
+ throw new InvalidCommandException("Task does not exist.");
+ }
+ return new DeleteCommand(index).read(taskList, ui, storage);
+ }
+ case "todo": {
+ if (splitCommand.length == 1) {
+ throw new InvalidDescriptionException("Please add a description.");
+ }
+ return new TodoCommand(splitCommand[1]).read(taskList, ui, storage);
+ }
+ case "deadline": {
+ if (splitCommand.length == 1) {
+ throw new InvalidDescriptionException("Please add a description and deadline.");
+ }
+ return new DeadlineCommand(splitCommand[1]).read(taskList, ui, storage);
+ }
+ case "event": {
+ if (splitCommand.length == 1) {
+ throw new InvalidDescriptionException("Please add a description and time/date.");
+ }
+ return new EventCommand(splitCommand[1]).read(taskList, ui, storage);
+ }
+ case "find": {
+ if (splitCommand.length == 1) {
+ throw new InvalidDescriptionException("Please add a number.");
+ }
+ return new FindCommand(splitCommand[1]).read(taskList, ui, storage);
+ }
+ case "findtag": {
+ if (splitCommand.length == 1) {
+ throw new InvalidDescriptionException("Please add a number.");
+ }
+ return new FindTagCommand(splitCommand[1]).read(taskList, ui, storage);
+ }
+ case "cdf": {
+ if (splitCommand.length == 1) {
+ throw new InvalidDescriptionException("Please add a number.");
+ }
+ int index = Integer.parseInt(splitCommand[1]) - 1;
+ if (index + 1 > taskList.getNumOfTasks()) {
+ throw new InvalidCommandException("Task does not exist.");
+ }
+ return new ChangeDateFormatCommand(index).read(taskList, ui, storage);
+ }
+ default:
+ throw new InvalidCommandException("OOPS!!! I'm sorry, but I don't know what that means :-(");
+ }
+ }
+}
diff --git a/src/main/java/duke/storage/Storage.java b/src/main/java/duke/storage/Storage.java
new file mode 100644
index 0000000000..0e96e0fa63
--- /dev/null
+++ b/src/main/java/duke/storage/Storage.java
@@ -0,0 +1,74 @@
+package duke.storage;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+/**
+ * Represents the file interaction between the Parser object
+ * and the file stored on the hard disk of the user.
+ */
+public class Storage {
+
+ private static String filePath;
+ private File taskFile;
+ private ArrayList tasksList;
+
+ /**
+ * Initialises a Storage object that initialises a File
+ * object that will be used to read and write to. Initialises a ArrayList
+ * to store the tasks that was contained in the text file.
+ * @param filePath A String representing the file path.
+ */
+ public Storage(String filePath) {
+ this.filePath = filePath;
+ taskFile = new File(this.filePath);
+ tasksList = new ArrayList<>();
+ }
+
+ /**
+ * Reads the tasks from the file and loads them into an ArrayList
+ * @return An ArrayList containing the tasks from the file.
+ */
+ public ArrayList loadFromFile() {
+ try {
+ if (!taskFile.createNewFile()) {
+ Scanner sc = new Scanner(taskFile);
+ while (sc.hasNext()) {
+ String curr = sc.nextLine();
+ tasksList.add(curr);
+ }
+ sc.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return tasksList;
+ }
+
+ /**
+ * Adds a task from the input string to the file.
+ * @param textToAppend A String containing the description and status of a task.
+ * @throws IOException If FILE_PATH is invalid.
+ */
+ public void appendToFile(String textToAppend) throws IOException {
+ FileWriter fw = new FileWriter(this.filePath, true); // create a FileWriter in append mode
+ fw.write(textToAppend);
+ fw.write(System.lineSeparator());
+ fw.close();
+ }
+
+ /**
+ * Clears the entire file to an empty text file.
+ * @throws FileNotFoundException If the file path is invalid.
+ */
+ public void clearFile() throws FileNotFoundException {
+ PrintWriter writer = new PrintWriter(taskFile);
+ writer.print("");
+ writer.close();
+ }
+}
diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java
new file mode 100644
index 0000000000..01509fca28
--- /dev/null
+++ b/src/main/java/duke/task/Deadline.java
@@ -0,0 +1,51 @@
+package duke.task;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * Represents a task with a deadline.
+ */
+public class Deadline extends Task {
+ protected LocalDate by;
+
+ /**
+ * Initialises a Deadline task with its description and deadline.
+ * @param name The description of the Task.
+ * @param tag The tag of the Task.
+ * @param by The deadline of the Task.
+ */
+ public Deadline(String name, String tag,LocalDate by) {
+ super(name, tag);
+ this.by = by;
+ }
+
+ /**
+ * Returns the date of the deadline of the Deadline.
+ * @return The date of the deadline.
+ */
+ public String getBy() {
+ return this.by.toString();
+ }
+
+
+ /**
+ * Returns a String with a different date format.
+ * @return A Deadline with a different date format.
+ */
+ public String changeDateFormat() {
+ String updatedDate = this.by.format(DateTimeFormatter.ofPattern("d MMM uuuu"));
+ return "[D]" + super.toString()
+ + "(by: " + updatedDate + ")";
+ }
+
+ /**
+ * Returns the description of the Deadline with its deadline.
+ * @return The description of the Deadline with its deadline.
+ */
+ @Override
+ public String toString() {
+ return "[D]" + super.toString()
+ + "(by: " + by + ")";
+ }
+}
diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java
new file mode 100644
index 0000000000..0a69f43c13
--- /dev/null
+++ b/src/main/java/duke/task/Event.java
@@ -0,0 +1,50 @@
+package duke.task;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * Represents a task that happens on a specific date.
+ */
+public class Event extends Task {
+ protected LocalDate at;
+
+ /**
+ * Initialises a Event task with its description and the date that it occurs.
+ * @param name The description of the Task.
+ * @param tag The tag of the Task.
+ * @param at The date that the Task occurs on.
+ */
+ public Event(String name, String tag, LocalDate at) {
+ super(name, tag);
+ this.at = at;
+ }
+
+ /**
+ * Returns the date that the Event occurs on.
+ * @return The date that the Event occurs on.
+ */
+ public String getAt() {
+ return this.at.toString();
+ }
+
+ /**
+ * Returns a String with a different date format.
+ * @return A Event with a different date format.
+ */
+ public String changeDateFormat() {
+ String updatedDate = this.at.format(DateTimeFormatter.ofPattern("d MMM uuuu"));
+ return "[E]" + super.toString()
+ + "(at: " + updatedDate + ")";
+ }
+
+ /**
+ * Returns the description of the Event with its date.
+ * @return The description of the Event with its date.
+ */
+ @Override
+ public String toString() {
+ return "[E]" + super.toString()
+ + "(at: " + at + ")";
+ }
+}
diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java
new file mode 100644
index 0000000000..3d2a73333d
--- /dev/null
+++ b/src/main/java/duke/task/Task.java
@@ -0,0 +1,72 @@
+package duke.task;
+
+/**
+ * Represents a description of what a user has planned to do.
+ */
+public class Task {
+ protected String description;
+ protected boolean isCompleted;
+ protected String tag;
+ protected static final String NO_TAG = " ";
+
+ /**
+ * Initialises a Task object that represents the task that
+ * the user has added. The task is marked incomplete by default.
+ * @param name Description of the Task.
+ * @param tag Tag of the Task.
+ */
+ public Task(String name, String tag) {
+ this.description = name;
+ this.isCompleted = false;
+ this.tag = tag;
+ }
+
+ /**
+ * Returns the status of the task.
+ * @return The status of the task.
+ */
+ public String getStatus() {
+ return isCompleted ? "X" : " ";
+ }
+
+ /**
+ * Marks the task as completed.
+ */
+ public void markAsCompleted() {
+ isCompleted = true;
+ }
+
+ /**
+ * Marks the task as incomplete.
+ */
+ public void markAsNotCompleted() {
+ isCompleted = false;
+ }
+
+ /**
+ * Returns the description of the task.
+ * @return Description of the task.
+ */
+ public String getDescription() {
+ return this.description;
+ }
+
+ /**
+ * Returns the tag of the task.
+ * @return Tag of the task.
+ */
+ public String getTag() {
+ return this.tag;
+ }
+
+ /**
+ * Returns the status, tag and description of the task.
+ * @return The status, tag and description of the task.
+ */
+ @Override
+ public String toString() {
+ return this.tag.equals(NO_TAG)
+ ? "[" + this.getStatus() + "] " + this.description
+ : "[" + this.getStatus() + "] " + this.description + " #" + this.tag;
+ }
+}
diff --git a/src/main/java/duke/task/Todo.java b/src/main/java/duke/task/Todo.java
new file mode 100644
index 0000000000..ee96a38f57
--- /dev/null
+++ b/src/main/java/duke/task/Todo.java
@@ -0,0 +1,26 @@
+package duke.task;
+
+/**
+ * Represents a task with no deadline.
+ */
+public class Todo extends Task {
+
+ /**
+ * Initialises a Todo object with the name as its description.
+ * @param name The description of the Todo task.
+ * @param tag The tag of the Todo task.
+ */
+ public Todo(String name, String tag) {
+ super(name, tag);
+ }
+
+ /**
+ * Returns the description of the Todo task.
+ * @return The description of the Todo task.
+ */
+ @Override
+ public String toString() {
+ return "[T]" + super.toString();
+ }
+
+}
diff --git a/src/main/java/duke/tasklist/TaskList.java b/src/main/java/duke/tasklist/TaskList.java
new file mode 100644
index 0000000000..4ab9378570
--- /dev/null
+++ b/src/main/java/duke/tasklist/TaskList.java
@@ -0,0 +1,313 @@
+package duke.tasklist;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+
+import duke.task.Deadline;
+import duke.task.Event;
+import duke.task.Task;
+import duke.task.Todo;
+
+/**
+ * Represents a list of tasks that the user has added. A TaskList
+ * contains tasks or a task that the user has added. It also handles the operations
+ * to add, delete, among other operations.
+ */
+public class TaskList {
+ /**
+ * Represents the list of tasks. A ArrayList contains items of type
+ * Task which represents a task added by the user.
+ */
+ private static ArrayList taskList;
+
+ private static final String NO_TAG = " ";
+
+ /**
+ * Initialises a TaskList object that contains the user's tasks.
+ * It takes in tasks so that it can process tasks that were stored on the user's
+ * hard disk so that it can remember tasks that the user had added previously.
+ * @param tasks An ArrayList containing the tasks or task.
+ */
+ public TaskList(ArrayList tasks) {
+ taskList = new ArrayList<>();
+ for (String s : tasks) {
+ String[] splitCommand = s.split("\\| ", 3);
+ String taskType = splitCommand[0];
+ boolean isMarked = splitCommand[1].equals("1 ");
+ String description = splitCommand[2];
+ switch (taskType) {
+ case "T ": {
+ if (description.contains("|")) {
+ String[] splitBy = description.split("\\| ", 2);
+ taskList.add(new Todo(splitBy[0], splitBy[1]));
+ int numOfTasks = taskList.size();
+ if (isMarked) {
+ taskList.get(numOfTasks - 1).markAsCompleted();
+ } else {
+ taskList.get(numOfTasks - 1).markAsNotCompleted();
+ }
+ } else {
+ taskList.add(new Todo(description, " "));
+ int numOfTasks = taskList.size();
+ if (isMarked) {
+ taskList.get(numOfTasks - 1).markAsCompleted();
+ } else {
+ taskList.get(numOfTasks - 1).markAsNotCompleted();
+ }
+ }
+ break;
+ }
+ case "D ": {
+ String[] splitTag = description.split("\\| ", 2);
+ String dateAndOrTag = splitTag[1];
+ if (dateAndOrTag.contains("|")) {
+ String[] splitDate = dateAndOrTag.split("\\| ", 2);
+ LocalDate byDate = LocalDate.parse(splitDate[1]);
+ taskList.add(new Deadline(splitTag[0], splitDate[0], byDate));
+ int numOfTasks = taskList.size();
+ if (isMarked) {
+ taskList.get(numOfTasks - 1).markAsCompleted();
+ } else {
+ taskList.get(numOfTasks - 1).markAsNotCompleted();
+ }
+ } else {
+ LocalDate byDate = LocalDate.parse(dateAndOrTag);
+ taskList.add(new Deadline(splitTag[0], " ", byDate));
+ int numOfTasks = taskList.size();
+ if (isMarked) {
+ taskList.get(numOfTasks - 1).markAsCompleted();
+ } else {
+ taskList.get(numOfTasks - 1).markAsNotCompleted();
+ }
+ }
+ break;
+ }
+ case "E ": {
+ String[] splitTag = description.split("\\| ", 2);
+ String dateAndOrTag = splitTag[1];
+ if (dateAndOrTag.contains("|")) {
+ String[] splitDate = dateAndOrTag.split("\\| ", 2);
+ LocalDate atDate = LocalDate.parse(splitDate[1]);
+ taskList.add(new Event(splitTag[0], splitDate[0], atDate));
+ int numOfTasks = taskList.size();
+ if (isMarked) {
+ taskList.get(numOfTasks - 1).markAsCompleted();
+ } else {
+ taskList.get(numOfTasks - 1).markAsNotCompleted();
+ }
+ } else {
+ LocalDate byDate = LocalDate.parse(dateAndOrTag);
+ taskList.add(new Event(splitTag[0], " ", byDate));
+ int numOfTasks = taskList.size();
+ if (isMarked) {
+ taskList.get(numOfTasks - 1).markAsCompleted();
+ } else {
+ taskList.get(numOfTasks - 1).markAsNotCompleted();
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * Adds a Todo task to the list of tasks.
+ * @param s Description of the todo task.
+ */
+ public void addTodo(String s) {
+ if (s.contains("tag")) {
+ String[] splitWord = s.split("/tag ", 2);
+ taskList.add(new Todo(splitWord[0], splitWord[1]));
+ } else {
+ taskList.add(new Todo(s, NO_TAG));
+ }
+ }
+
+ /**
+ * Adds a Deadline task to the list of tasks.
+ * @param s Description of the Deadline task.
+ */
+ public void addDeadline(String s) {
+ if (s.contains("tag")) {
+ String[] splitDescription = s.split("/tag ", 2);
+ String[] splitTag = splitDescription[1].split("/by ", 2);
+ String description = splitDescription[0];
+ String tag = splitTag[0];
+ String by = splitTag[1];
+ LocalDate byDate = LocalDate.parse(by);
+ taskList.add(new Deadline(description, tag, byDate));
+ } else {
+ String[] splitDescription = s.split("/by ", 2);
+ String description = splitDescription[0];
+ String by = splitDescription[1];
+ LocalDate byDate = LocalDate.parse(by);
+ taskList.add(new Deadline(description, NO_TAG, byDate));
+ }
+ }
+
+ /**
+ * Adds a Event task to the list of tasks.
+ * @param s Description of the Event task.
+ */
+ public void addEvent(String s) {
+ if (s.contains("tag")) {
+ String[] splitDescription = s.split("/tag ", 2);
+ String[] splitTag = splitDescription[1].split("/at ", 2);
+ String description = splitDescription[0];
+ String tag = splitTag[0];
+ String at = splitTag[1];
+ LocalDate atDate = LocalDate.parse(at);
+ taskList.add(new Event(description, tag, atDate));
+ } else {
+ String[] splitDescription = s.split("/at ", 2);
+ String description = splitDescription[0];
+ String at = splitDescription[1];
+ LocalDate atDate = LocalDate.parse(at);
+ taskList.add(new Event(description, NO_TAG, atDate));
+ }
+ }
+
+ /**
+ * Returns the description of the task along with its status.
+ * @param index The index of the task in the list.
+ * @return A description and status of the task.
+ */
+ public String readTask(int index) {
+ return taskList.get(index).toString();
+ }
+
+ /**
+ * Returns the status of the task.
+ * @param index The index of the task in the list.
+ * @return The status of the task.
+ */
+ public String readStatus(int index) {
+ return taskList.get(index).getStatus();
+ }
+
+ /**
+ * Sets the status of the task to complete.
+ * @param index The index of the task in the list.
+ */
+ public void setCompleted(int index) {
+ taskList.get(index).markAsCompleted();
+ }
+
+ /**
+ * Sets the status of the task to not complete.
+ * @param index The index of the task in the list.
+ */
+ public void setNotCompleted(int index) {
+ taskList.get(index).markAsNotCompleted();
+ }
+
+ /**
+ * Returns the number of tasks in the list.
+ * @return The number of tasks in the list.
+ */
+ public int getNumOfTasks() {
+ return taskList.size();
+ }
+
+ /**
+ * Deletes a task from the list.
+ * @param index The index of the task in the list.
+ */
+ public void deleteTask(int index) {
+ taskList.remove(index);
+ }
+
+ /**
+ * Converts the status of the task to either 1 or 0 that would be stored in the taskFile in
+ * Storage.
+ * @param status The status of the Task.
+ * @return A representation of the Task status in taskFile.
+ */
+ public String convertStatus(String status) {
+ return status.equals("X") ? "1" : "0";
+ }
+
+ /**
+ * Returns an appropriate format that will represent a Task in the taskFile.
+ * @param type The type of Task
+ * @param status Status of the Task.
+ * @param description Description of the Task.
+ * @param date The date associated with the Task
+ * @return A String format suitable for the taskFile.
+ */
+ public String storeIntoFileFormat(String type, String status, String description, String tag, String date) {
+ switch (type) {
+ case "T": {
+ return tag.equals(" ")
+ ? "T | " + status + " | " + description
+ : "T | " + status + " | " + description + "| " + tag;
+ }
+ case "D": {
+ return tag.equals(" ")
+ ? "D | " + status + " | " + description + "| " + date
+ : "D | " + status + " | " + description + "| " + tag + "| " + date;
+ }
+ case "E": {
+ return tag.equals(" ")
+ ? "E | " + status + " | " + description + "| " + date
+ : "E | " + status + " | " + description + "| " + tag + "| " + date;
+ }
+ default:
+ return "";
+ }
+ }
+
+ /**
+ * Returns the different date format of the Deadline or Event task in the list.
+ * @param index The index of the task in the list.
+ */
+ public String changeDateFormat(int index) {
+ if (taskList.get(index) instanceof Deadline) {
+ Deadline updatedDeadline = (Deadline) taskList.get(index);
+ return updatedDeadline.changeDateFormat();
+ } else if (taskList.get(index) instanceof Event) {
+ Event updatedEvent = (Event) taskList.get(index);
+ return updatedEvent.changeDateFormat();
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Returns the description of the task.
+ * @param index The index of the task in the list.
+ * @return The description of the task.
+ */
+ public String getDescription(int index) {
+ return taskList.get(index).getDescription();
+ }
+
+ /**
+ * Returns the date of the Deadline or Event task. If called on a Todo task,
+ * it will return a failed message.
+ * @param index The index of the task in the list.
+ * @return The date of the task.
+ */
+ public String getDate(int index) {
+ Task curr = taskList.get(index);
+ if (curr instanceof Deadline) {
+ return ((Deadline) curr).getBy();
+ } else if (curr instanceof Event) {
+ return ((Event) curr).getAt();
+ } else {
+ return "There is no date for this task.";
+ }
+ }
+
+ /**
+ * Returns the tag of the task.
+ * @param index The index of the task in the list.
+ * @return The tag of the task.
+ */
+ public String getTag(int index) {
+ return taskList.get(index).getTag();
+ }
+}
diff --git a/src/main/java/duke/ui/Ui.java b/src/main/java/duke/ui/Ui.java
new file mode 100644
index 0000000000..b13d2747e8
--- /dev/null
+++ b/src/main/java/duke/ui/Ui.java
@@ -0,0 +1,129 @@
+package duke.ui;
+
+import duke.tasklist.TaskList;
+
+/**
+ * Represents the interactions between the user and the chatbot Seaward.
+ * A Ui object corresponds to a user interface that
+ * interacts with the user input through replying on the user interface
+ * with the corresponding commands given in the input.
+ * The Ui's name is Seaward.
+ */
+
+public class Ui {
+ /**
+ * Returns a message informing the user that there are no tasks in their list.
+ * @return An empty list message.
+ */
+ public String getEmptyTaskMessage() {
+ return "You currently have no tasks. Add some!";
+ }
+
+ /**
+ * Returns a list containing all of the tasks that the user has given.
+ * @param taskList A list containing all the tasks.
+ * @return A list of the tasks.
+ */
+ public String getList(TaskList taskList) {
+ StringBuilder list = new StringBuilder();
+ for (int i = 0; i < taskList.getNumOfTasks(); i++) {
+ int index = i + 1;
+ String taskDescription = taskList.readTask(i);
+ if (index == taskList.getNumOfTasks()) {
+ list.append(index).append(".").append(taskDescription);
+ } else {
+ list.append(index).append(".").append(taskDescription).append("\n");
+ }
+ }
+ return list.toString();
+ }
+
+ /**
+ * Returns a success message informing the user that the task has been marked.
+ * @return A success message.
+ */
+ public String getMarkedTaskMessage() {
+ return "I have marked this task as done:\n";
+ }
+
+ /**
+ * Returns a success message informing the user that the task has been unmarked.
+ * @return A success message.
+ */
+ public String getUnmarkedTaskMessage() {
+ return "I have marked this task as undone:\n";
+ }
+
+ /**
+ * Returns a success message informing the user that they have deleted a task.
+ * @param description Description of the task
+ * @param numOfTasks Number of tasks remaining in the list.
+ * @return A success message.
+ */
+ public String getDeleteMessage(String description, int numOfTasks) {
+ return "Noted. I have removed this task:\n" + description
+ + "\n" + "Now you have "
+ + numOfTasks + " task(s) in your list.";
+ }
+
+ /**
+ * Returns a success message informing the user that they have added a task.
+ * @param description Description of the task.
+ * @param numOfTasks Number of tasks in the list after adding the task.
+ * @return A success message.
+ */
+ public String getAddTaskMessage(String description, int numOfTasks) {
+ return "Noted. I have added:\n" + description + "\n"
+ + "Now you have "
+ + numOfTasks + " task(s) in your list.";
+ }
+
+ /**
+ * Returns a failure message informing the user that there are no matching tasks in the tasklist.
+ * @return A failure message.
+ */
+ public String getNoMatchingTaskMessage() {
+ return "Sorry! There are no matching tasks that contains ";
+ }
+
+ /**
+ * Returns a success message informing the user that there is a matching task in the tasklist.
+ * @return A success message.
+ */
+ public String getMatchingTaskMessage() {
+ return "Here are the matching tasks in your list:";
+ }
+
+ public String getNoMatchingTagMessage() {
+ return "Sorry! There are no matching tasks with a tag that contains ";
+ }
+
+ public String getMatchingTagMessage() {
+ return "Here are the tasks with the matching tags in your list:";
+ }
+
+ /**
+ * Returns a goodbye message for the user.
+ * @return A goodbye message.
+ */
+ public String getGoodbyeMessage() {
+ return "Seaward out! See you next time buddy!";
+ }
+
+ /**
+ * Returns a success message showing the user a different date format.
+ * @return A success message.
+ */
+ public String getDateChangedMessage() {
+ return "Here is a different date format for this task!";
+ }
+
+ /**
+ * Returns a failure message telling the user that the Task does not have
+ * a date.
+ * @return A failure message.
+ */
+ public String getNoDateMessage() {
+ return "This task has no date!";
+ }
+}
diff --git a/src/main/resources/images/DaDuke.png b/src/main/resources/images/DaDuke.png
new file mode 100644
index 0000000000..d893658717
Binary files /dev/null and b/src/main/resources/images/DaDuke.png differ
diff --git a/src/main/resources/images/DaUser.png b/src/main/resources/images/DaUser.png
new file mode 100644
index 0000000000..3c82f45461
Binary files /dev/null and b/src/main/resources/images/DaUser.png differ
diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml
new file mode 100644
index 0000000000..ede775d4f9
--- /dev/null
+++ b/src/main/resources/view/DialogBox.fxml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
new file mode 100644
index 0000000000..ecde92a22d
--- /dev/null
+++ b/src/main/resources/view/MainWindow.fxml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/duke/tasklist/TaskListTest.java b/src/test/java/duke/tasklist/TaskListTest.java
new file mode 100644
index 0000000000..2478f57141
--- /dev/null
+++ b/src/test/java/duke/tasklist/TaskListTest.java
@@ -0,0 +1,31 @@
+package duke.tasklist;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+
+import org.junit.jupiter.api.Test;
+
+
+public class TaskListTest {
+ private TaskList taskList = new TaskList(new ArrayList<>());
+
+ @Test
+ public void getEmptyList() {
+ assertEquals(0, taskList.getNumOfTasks());
+ }
+
+ @Test
+ public void getReadTask() {
+ taskList.addDeadline("watch lecture 1 /by 2022-08-27");
+ assertEquals("[D][ ] watch lecture 1 (by: 2022-08-27)",
+ taskList.readTask(0));
+ }
+
+ @Test
+ public void getReadDescription() {
+ taskList.addDeadline("watch lecture 1 /by 2022-08-27");
+ assertEquals("watch lecture 1 ",
+ taskList.getDescription(0));
+ }
+}
diff --git a/src/test/java/duke/ui/UiTest.java b/src/test/java/duke/ui/UiTest.java
new file mode 100644
index 0000000000..0538b29e68
--- /dev/null
+++ b/src/test/java/duke/ui/UiTest.java
@@ -0,0 +1,34 @@
+package duke.ui;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+
+import org.junit.jupiter.api.Test;
+
+import duke.tasklist.TaskList;
+
+
+
+public class UiTest {
+ private Ui ui = new Ui();
+ private TaskList taskList = new TaskList(new ArrayList<>());
+
+ @Test
+ public void testGetEmptyList() {
+ assertEquals("", ui.getList(taskList));
+ }
+
+ @Test
+ public void testGetList() {
+ taskList.addEvent("watch TF2 i69 /at 2022-08-27");
+ assertEquals("1.[E][ ] watch TF2 i69 (at: 2022-08-27)",
+ ui.getList(taskList));
+ }
+
+ @Test
+ public void testGetMarkedTaskMessage() {
+ assertEquals("I have marked this task as done:\n",
+ ui.getMarkedTaskMessage());
+ }
+}
diff --git a/tasks.txt b/tasks.txt
new file mode 100644
index 0000000000..b170e84f9d
--- /dev/null
+++ b/tasks.txt
@@ -0,0 +1,5 @@
+D | 0 | watch lecture | urgent | 2022-09-10
+E | 0 | attend TI | hype | 2022-10-01
+T | 0 | return book | urgent
+T | 0 | read book
+E | 0 | birthday | Charlie | 2022-10-22
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e7..8ffb40710b 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,26 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
-
+Hello! I'm Seaward,
+your friendly neighbourhood chatbot.
+Type something and I will reply!
+Noted. I have added:
+[T][ ] read book
+Now you have 1 task(s) in your list.
+Noted. I have added:
+[D][ ] return book (by: Sunday)
+Now you have 2 task(s) in your list.
+Noted. I have added:
+[E][ ] project meeting (at: 2-4pm)
+Now you have 3 task(s) in your list.
+1.[T][ ] read book
+2.[D][ ] return book (by: Sunday)
+3.[E][ ] project meeting (at: 2-4pm)
+I have marked this task as done:
+[T][X] read book
+1.[T][X] read book
+2.[D][ ] return book (by: Sunday)
+3.[E][ ] project meeting (at: 2-4pm)
+I have marked this task as undone:
+[T][ ] read book
+1.[T][ ] read book
+2.[D][ ] return book (by: Sunday)
+3.[E][ ] project meeting (at: 2-4pm)
+Seaward out!
\ No newline at end of file
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb2..13bd43e6eb 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,9 @@
+todo read book
+deadline return book /by Sunday
+event project meeting /at 2-4pm
+list
+mark 1
+list
+unmark 1
+list
+bye
\ No newline at end of file
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
index 0873744649..f1e8152655 100644
--- a/text-ui-test/runtest.bat
+++ b/text-ui-test/runtest.bat
@@ -19,3 +19,4 @@ java -classpath ..\bin Duke < input.txt > ACTUAL.TXT
REM compare the output to the expected output
FC ACTUAL.TXT EXPECTED.TXT
+PAUSE
\ No newline at end of file
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
old mode 100644
new mode 100755
index c9ec870033..c6ef5278e8
--- a/text-ui-test/runtest.sh
+++ b/text-ui-test/runtest.sh
@@ -35,4 +35,5 @@ then
else
echo "Test result: FAILED"
exit 1
-fi
\ No newline at end of file
+fi
+PAUSE
\ No newline at end of file