diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000..0d739125cb
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "java.configuration.updateBuildConfiguration": "interactive"
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000..7911036cf2
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,59 @@
+plugins {
+ id 'java'
+ id 'application'
+ id 'checkstyle'
+ id 'com.github.johnrengelman.shadow' version '7.1.2'
+}
+
+shadowJar {
+ dependencies {
+ exclude(dependency('org.junit.jupiter:junit-jupiter-api'))
+ exclude(dependency('org.junit.jupiter:junit-jupiter-engine'))
+ }
+}
+
+checkstyle {
+ toolVersion = '10.2'
+}
+
+group 'org.example'
+version '1.0-SNAPSHOT'
+
+repositories {
+ mavenCentral()
+}
+sourceSets {
+ main {
+ java {
+ srcDirs = ['src/main/java','src/test/java']
+ }
+ }
+}
+
+run {
+ enableAssertions = true
+}
+
+test {
+ useJUnitPlatform()
+}
+
+dependencies {
+ String javaFxVersion = '17'
+
+ 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'
+ testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.7.1'
+ testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.7.1'
+
+}
\ No newline at end of file
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
new file mode 100644
index 0000000000..e826593748
--- /dev/null
+++ b/config/checkstyle/checkstyle.xml
@@ -0,0 +1,434 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml
new file mode 100644
index 0000000000..7fa38b37cf
--- /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..91257592e1 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -2,28 +2,295 @@
## Features
-### Feature-ABC
+### Feature-1: Adding and deleting Tasks to the chatbot
-Description of the feature.
+Tasks can be added to the chatbot, and there are 3 different types of tasks: Todo, Event and Deadline.
+1. Todo: a generic task type which only has a description of the task.
+2. Event: A more specific task type about an upcoming event that happens at a certain date. Has both a description and a date field.
+3. Deadline: Another more specific task about an upcoming deadline that is set at a certain date. Had both a description and a date field.
-### Feature-XYZ
+These tasks can also be deleted by the user.
-Description of the feature.
+### Feature-2: Listing out all tasks in the task list
+
+Tasks can be listed out for the user to see. Users will see a full description of every task. Listing is also related both to deleting and marking tasks as the list index is used to specify which task to delete and mark.
+
+### Feature-3: Finding and listing out all tasks which have a specific keyword
+
+Lists out all tasks which contains a user specified keyword.
+
+### Feature-4: Marking completion of tasks
+
+Tasks can be marked as "done" or "not done". This will show when the user lists out all the tasks as a marking next to the task with an "x" marking indicating a task that is done while as absence of said marking indicating it is not yet done.
+
+### Feature-5: Saving and loading tasks to a log file
+
+Tasks are saved to a log file when the user enters the bye command, these tasks can later be loaded again.
+
+### Feature-6: Archiving tasks
+
+Tasks can be archived by the user to different archives, allowing users to save task configurations and load them at will. These archives are named by the user so that they may track them easier. Users may also list out all archive names so they don't lose track. Users may also clear all archives once they are done.
## Usage
-### `Keyword` - Describe action
+### 'todo [description]'
+
+Adds a todo task with the description into the list.
+
+Example of usage:
+
+```
+todo Buy the groceries
+```
+
+Expected outcome:
+
+Adds a todo task into the list with description "Buy the groceries"
+
+```
+Task added:
+[T][]Buy the groceries
+```
+
+### 'event [description] [at date in format DD/MM/YYYY]'
+
+Adds a event task with the description and at date into the list
+
+Example of usage:
+
+```
+event Uncle's bday /at 2/2/2023
+```
+
+Expected outcome:
+
+Adds a event task into the list with description "Uncle's bday" and at date of "2/2/2023"
+
+```
+Task added:
+[E][]Uncle's bday (at: Thu, 2 Feb 2023)
+```
+
+### 'deadline [description] [by date]'
+
+Adds a deadline task with description and by date into the list
+
+Example of usage:
+
+```
+deadline homework /by 4/6/2023
+```
+
+Expected outcome:
+
+Adds a deadline task into the list with description "homework" and by date of "4/6/2023"
+
+```
+Task added:
+[D][]homework (by: Sun, 4 Jun 2023)
+```
+### 'delete [index]'
-Describe the action and its outcome.
+Deletes task at the given index of the tasklist
Example of usage:
-`keyword (optional arguments)`
+```
+todo run
+delete 1
+```
+
+Expected outcome:
+
+Deletes the todo task which is the only task in the list
+
+```
+Task deleted:
+[T][] run
+```
+
+### 'list'
+
+Lists out all tasks in the task list
+
+Example of usage:
+
+```
+todo run
+event hide /at 2/4/2025
+list
+```
Expected outcome:
-Description of the outcome.
+lists out both the todo task and the event task
+
+```
+Tasks:
+1. [T][]run
+2. [E][]hide (at: Wed, 2 Apr 2025)
+```
+### 'find [keyword]'
+
+Lists out all tasks in the task list which contains the keyword
+
+Example of usage:
+
+```
+todo run
+todo away we run
+todo cycle
+find run
+```
+
+Expected outcome:
+
+lists out both the todo task and the event task
+
+```
+Tasks found:
+Tasks:
+1. [T][]run
+2. [T][]away we run
+```
+### 'mark [index]'
+
+marks the task in the task list at the given index as done
+
+Example of usage:
+
+```
+todo run
+mark 1
+```
+
+Expected outcome:
+
+marks the todo task as done
+
+```
+Tasks:
+1. [T][]run
+2. [E][]hide (at: Wed, 2 Apr 2025)
+```
+### 'unmark [index]'
+
+marks the task in the task list at the given index as not done
+
+Example of usage:
+
+```
+todo run
+mark 1
+unmark 1
+```
+
+Expected outcome:
+marks the todo task as not done
+
+```
+Task has been marked not done: [T][]run
+```
+### 'bye [-optional: log file name]'
+
+saves the current tasks to the log file, optional argument to specify the log file's name in case the user does not want the default name
+
+Example of usage:
+
+```
+todo run
+bye
+```
+
+Expected outcome:
+saves the todo task to the log file
+
+```
+Saved 1 tasks.
+Bye bye! :D
+```
+### 'load [-optional log file name]'
+
+saves the current tasks to the log file, optional argument to specify the log file's name in case it is not the default one
+
+Example of usage:
+
+```
+load
+```
+
+Expected outcome:
+loads the tasks in the log file into the program.
+
+```
+Loaded 1 tasks.
+Have a productive day!
+```
+### 'archive [archive file name]'
+
+saves the current tasks to the archive file with the name specified, then clears the task list.
+
+Example of usage:
+
+```
+todo run
+archive MyArchive
+```
+
+Expected outcome:
+the todo task is archived in the "MyArchive.txt" archive file.
+
+```
+Archived 1 tasks
+```
+### 'loadA [archive file name]'
+
+Loads the tasks in the archive file with the specified name into the current programs task list, while clearing the previous tasks in it.
+
+Example of usage:
+
+```
+loadA MyArchive
+```
+
+Expected outcome:
+the tasks archived in the "MyArchive.txt" file are loaded into the program, with previous tasks being cleared.
+
+```
+Loaded 1 tasks from archive!
+```
+### 'listA'
+
+Lists all the archives the program has created in that session.
+
+Example of usage:
+
+```
+archive MyArchive
+listA
+```
+
+Expected outcome:
+lists all the archives the program is tracking, that being the "MyArchive" archive
+
+```
+Archive list:
+1. MyArchive
+```
+### 'clear'
+
+Clears all the archives in the archive list, deleting the files as well
+
+Example of usage:
+
+```
+archive MyArchive
+clear
+```
+
+Expected outcome:
+clears the archive list and deletes the "MyArchive" file.
```
-expected output
+Cleared 1 archives
```
diff --git a/docs/Ui.png b/docs/Ui.png
new file mode 100644
index 0000000000..15f6d5d733
Binary files /dev/null and b/docs/Ui.png differ
diff --git a/dukeLog.txt b/dukeLog.txt
new file mode 100644
index 0000000000..25f4e3160a
--- /dev/null
+++ b/dukeLog.txt
@@ -0,0 +1 @@
+0,todo run
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..41d9927a4d
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..41dfb87909
--- /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-7.4-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000000..1b6c787337
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,234 @@
+#!/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/master/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
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+APP_NAME="Gradle"
+APP_BASE_NAME=${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 "$*"
+} >&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
+ 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" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ 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
+
+# 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 \
+ "$@"
+
+# 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..ac1b06f938
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@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 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%"=="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/ip.jar b/ip.jar
new file mode 100644
index 0000000000..6fe74c8b46
Binary files /dev/null and b/ip.jar differ
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000000..bc747d203d
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = "ip"
\ No newline at end of file
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/command/ArchiveCommand.java b/src/main/java/command/ArchiveCommand.java
new file mode 100644
index 0000000000..4415ed9b01
--- /dev/null
+++ b/src/main/java/command/ArchiveCommand.java
@@ -0,0 +1,43 @@
+package command;
+
+import exception.MeowerException;
+
+import task.Task;
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+
+public class ArchiveCommand extends Command {
+
+ private String archiveFileAddress = "";
+
+ public ArchiveCommand(String newAddress) {
+ super();
+ this.archiveFileAddress = newAddress;
+ }
+
+ /**
+ * Executes the functionality of the command, in the tasklist,
+ * UI and storage that are taken in as arguments, in this case saves the chatbot logs to an archive
+ * @param tasks tasklist from Meower chatbot
+ * @param ui ui from Meower chatbot
+ * @param storage storage from Meower chatbot
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws MeowerException {
+ try {
+ int numOfTasks = storage.archiveToFile(this.archiveFileAddress);
+ return ui.archive(numOfTasks);
+ } catch (MeowerException e) {
+ throw e;
+ }
+ }
+
+ /**
+ * Returns the task that will be generated from the command, returns an empty task if no task is to be generated
+ * @return Task
+ */
+ public Task getTask() {
+ return Task.empty();
+ }
+}
diff --git a/src/main/java/command/ByeCommand.java b/src/main/java/command/ByeCommand.java
new file mode 100644
index 0000000000..5da0a79d3b
--- /dev/null
+++ b/src/main/java/command/ByeCommand.java
@@ -0,0 +1,48 @@
+package command;
+
+import exception.MeowerException;
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+import task.Task;
+
+public class ByeCommand extends Command {
+
+ private String logFileAddress = "";
+
+ public ByeCommand() {
+ super();
+ }
+
+ public ByeCommand(String newAddress) {
+ super();
+ this.logFileAddress = newAddress;
+ }
+
+ /**
+ * Executes the functionality of the command, in the tasklist,
+ * UI and storage that are taken in as arguments, in this case saves the chatbot logs
+ * @param tasks tasklist from Meower chatbot
+ * @param ui ui from Meower chatbot
+ * @param storage storage from Meower chatbot
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws MeowerException {
+ if (this.logFileAddress.equals("")) {
+ int numOfTasks = storage.saveToFile(true);
+ return ui.bye(numOfTasks);
+ } else {
+ int numOfTasks = storage.saveToFile(this.logFileAddress);
+ return ui.bye(numOfTasks);
+ }
+ }
+
+ /**
+ * Returns the task that will be generated from the command, returns an empty task if no task is to be generated
+ * @return Task
+ */
+ public Task getTask() {
+ return Task.empty();
+ }
+
+}
diff --git a/src/main/java/command/ClearCommand.java b/src/main/java/command/ClearCommand.java
new file mode 100644
index 0000000000..c2b1314f43
--- /dev/null
+++ b/src/main/java/command/ClearCommand.java
@@ -0,0 +1,23 @@
+package command;
+
+import exception.MeowerException;
+import task.Task;
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+
+public class ClearCommand extends Command {
+
+ public ClearCommand() {
+ super();
+ }
+
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws MeowerException {
+ int numOfArchives = storage.clearArchive();
+ return ui.clear(numOfArchives);
+ }
+
+ public Task getTask() {
+ return Task.empty();
+ }
+}
diff --git a/src/main/java/command/Command.java b/src/main/java/command/Command.java
new file mode 100644
index 0000000000..43db087c56
--- /dev/null
+++ b/src/main/java/command/Command.java
@@ -0,0 +1,20 @@
+package command;
+
+import exception.MeowerException;
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+import task.Task;
+/**
+ * Abstract class thats represents a user inputted command to the chatbot.
+ */
+public abstract class Command {
+
+ Command() {
+ ;
+ }
+
+ public abstract String execute(TaskList tasks, Ui ui, Storage storage) throws MeowerException; //Referenced from Marcus Ong Wee's code
+
+ public abstract Task getTask() throws MeowerException;
+}
diff --git a/src/main/java/command/DeadlineCommand.java b/src/main/java/command/DeadlineCommand.java
new file mode 100644
index 0000000000..d4a54a0155
--- /dev/null
+++ b/src/main/java/command/DeadlineCommand.java
@@ -0,0 +1,55 @@
+package command;
+
+import exception.MeowerException;
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+import task.Deadline;
+import task.Task;
+
+public class DeadlineCommand extends Command {
+
+ private String description;
+ private String date;
+
+ public DeadlineCommand(String description, String date) {
+ super();
+ this.description = description;
+ this.date = date;
+ }
+
+
+ /**
+ * Returns description inputted by the user
+ * @return String
+ */
+ public String getDescription() {
+ return this.description;
+ }
+
+ /**
+ * Executes the functionality of the command, in the tasklist, UI and storage that are taken in as arguments,
+ * in this case adds the deadline task described by the user into the tasklist
+ * @param tasks tasklist from Meower chatbot
+ * @param ui ui from Meower chatbot
+ * @param storage storage from Meower chatbot
+ * @throws MeowerException
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws MeowerException {
+ Task newDeadline = this.getTask();
+ tasks.add(newDeadline);
+ return ui.add(newDeadline);
+ }
+
+
+ /**
+ * Returns the task that will be generated from the command, returns an empty task if no task is to be generated
+ * @return Task
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ @Override
+ public Task getTask() throws MeowerException {
+ return new Deadline(description, date);
+ }
+
+}
diff --git a/src/main/java/command/DeleteCommand.java b/src/main/java/command/DeleteCommand.java
new file mode 100644
index 0000000000..a7b6912e5a
--- /dev/null
+++ b/src/main/java/command/DeleteCommand.java
@@ -0,0 +1,40 @@
+package command;
+
+import exception.MeowerException;
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+import task.Task;
+
+public class DeleteCommand extends Command {
+
+ private int pos;
+
+ public DeleteCommand(String pos) {
+ super();
+ this.pos = Integer.parseInt(pos);
+ }
+
+ /**
+ * Executes the functionality of the command, in the tasklist, UI and storage that are taken in as arguments
+ * @param tasks tasklist from Meower chatbot
+ * @param ui ui from Meower chatbot
+ * @param storage storage from Meower chatbot
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws MeowerException {
+ String deletedTask = tasks.delete(this.pos);
+ return ui.delete(deletedTask);
+ }
+
+
+ /**
+ * Returns the task that will be generated from the command, returns an empty task if no task is to be generated
+ * @return Task
+ */
+ @Override
+ public Task getTask() {
+ return Task.empty();
+ }
+
+}
diff --git a/src/main/java/command/EventCommand.java b/src/main/java/command/EventCommand.java
new file mode 100644
index 0000000000..b9c5bbd021
--- /dev/null
+++ b/src/main/java/command/EventCommand.java
@@ -0,0 +1,45 @@
+package command;
+
+import exception.MeowerException;
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+import task.Event;
+import task.Task;
+
+public class EventCommand extends Command {
+
+ private String description;
+ private String duration;
+
+ public EventCommand(String description, String duration) {
+ super();
+ this.description = description;
+ this.duration = duration;
+ }
+
+ /**
+ * Executes the functionality of the command, in the tasklist, UI and storage that are taken in as arguments,
+ * in this case adds the event task described by the user into the tasklist
+ * @param tasks tasklist from Meower chatbot
+ * @param ui ui from Meower chatbot
+ * @param storage storage from Meower chatbot
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws MeowerException {
+ Task newEvent = this.getTask();
+ tasks.add(newEvent);
+ return ui.add(newEvent);
+ }
+
+
+ /**
+ * Returns the task that will be generated from the command, returns an empty task if no task is to be generated
+ * @return Task
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ @Override
+ public Task getTask() throws MeowerException {
+ return new Event(description, duration);
+ }
+}
diff --git a/src/main/java/command/FindCommand.java b/src/main/java/command/FindCommand.java
new file mode 100644
index 0000000000..4d36618adc
--- /dev/null
+++ b/src/main/java/command/FindCommand.java
@@ -0,0 +1,39 @@
+package command;
+
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+import task.Task;
+
+public class FindCommand extends Command {
+
+ private String keyword;
+
+ public FindCommand(String keyword) {
+ super();
+ this.keyword = keyword;
+ }
+
+ /**
+ * Executes the functionality of the command, in the tasklist, UI and storage that are taken in as arguments,
+ * in this case it lists all tasks in the tasklist with the given keyword
+ * @param tasks tasklist from Meower chatbot
+ * @param ui ui from Meower chatbot
+ * @param storage storage from Meower chatbot
+ * @return String
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) {
+ TaskList searchList = tasks.search(keyword);
+ return ui.list(searchList, true);
+ }
+
+
+ /**
+ * Returns the task that will be generated from the command, returns an empty task if no task is to be generated
+ * @return Task
+ */
+ @Override
+ public Task getTask() {
+ return Task.empty();
+ }
+}
diff --git a/src/main/java/command/ListArchiveCommand.java b/src/main/java/command/ListArchiveCommand.java
new file mode 100644
index 0000000000..4e812a2922
--- /dev/null
+++ b/src/main/java/command/ListArchiveCommand.java
@@ -0,0 +1,34 @@
+package command;
+
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+import task.Task;
+
+public class ListArchiveCommand extends Command {
+
+ public ListArchiveCommand() {
+ super();
+ }
+
+ /**
+ * Executes the functionality of the command, in the tasklist, UI and storage that are taken in as arguments,
+ * in this case it lists all archives in the storage
+ * @param tasks tasklist from Meower chatbot
+ * @param ui ui from Meower chatbot
+ * @param storage storage from Meower chatbot
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) {
+ return ui.listArchive(storage);
+ }
+
+
+ /**
+ * Returns the task that will be generated from the command, returns an empty task if no task is to be generated
+ * @return Task
+ */
+ @Override
+ public Task getTask() {
+ return Task.empty();
+ }
+}
diff --git a/src/main/java/command/ListCommand.java b/src/main/java/command/ListCommand.java
new file mode 100644
index 0000000000..b6a1267599
--- /dev/null
+++ b/src/main/java/command/ListCommand.java
@@ -0,0 +1,34 @@
+package command;
+
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+import task.Task;
+
+public class ListCommand extends Command {
+
+ public ListCommand() {
+ super();
+ }
+
+ /**
+ * Executes the functionality of the command, in the tasklist, UI and storage that are taken in as arguments,
+ * in this case it lists all tasks in the tasklist
+ * @param tasks tasklist from Meower chatbot
+ * @param ui ui from Meower chatbot
+ * @param storage storage from Meower chatbot
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) {
+ return ui.list(tasks, false);
+ }
+
+
+ /**
+ * Returns the task that will be generated from the command, returns an empty task if no task is to be generated
+ * @return Task
+ */
+ @Override
+ public Task getTask() {
+ return Task.empty();
+ }
+}
diff --git a/src/main/java/command/LoadArchiveCommand.java b/src/main/java/command/LoadArchiveCommand.java
new file mode 100644
index 0000000000..4e4dc4943a
--- /dev/null
+++ b/src/main/java/command/LoadArchiveCommand.java
@@ -0,0 +1,40 @@
+package command;
+
+import exception.MeowerException;
+
+import task.Task;
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+
+public class LoadArchiveCommand extends Command {
+
+ private String archiveFileAddress;
+
+ public LoadArchiveCommand(String newAddress) {
+ super();
+ this.archiveFileAddress = newAddress;
+ }
+
+ /**
+ * Executes the functionality of the command, in the tasklist,
+ * UI and storage that are taken in as arguments, in this case loads the tasks from an archive file into the tasklist
+ * @param tasks tasklist from Meower chatbot
+ * @param ui ui from Meower chatbot
+ * @param storage storage from Meower chatbot
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws MeowerException {
+ int numOfTasks = storage.loadArchive(this.archiveFileAddress);
+ return ui.loadArchive(numOfTasks);
+ }
+
+ /**
+ * Returns the task that will be generated from the command, returns an empty task if no task is to be generated
+ * @return Task
+ */
+ public Task getTask() {
+ return Task.empty();
+ }
+}
+
diff --git a/src/main/java/command/LoadCommand.java b/src/main/java/command/LoadCommand.java
new file mode 100644
index 0000000000..ab38c48357
--- /dev/null
+++ b/src/main/java/command/LoadCommand.java
@@ -0,0 +1,48 @@
+package command;
+
+import exception.MeowerException;
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+import task.Task;
+
+public class LoadCommand extends Command {
+
+ private String logFileAddress = "";
+
+ public LoadCommand() {
+ super();
+ }
+
+ public LoadCommand(String newAddress) {
+ super();
+ this.logFileAddress = newAddress;
+ }
+
+ /**
+ * Executes the functionality of the command, in the tasklist, UI and storage that are taken in as arguments,
+ * in this case it loads the tasks from a chatbot log file into the current chatbots tasklist
+ * @param tasks tasklist from Meower chatbot
+ * @param ui ui from Meower chatbot
+ * @param storage storage from Meower chatbot
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws MeowerException{
+ if (this.logFileAddress.equals("")) {
+ int numOfTasks = storage.loadFile(true);
+ return ui.load(numOfTasks);
+ } else {
+ int numOfTasks = storage.loadFile(this.logFileAddress);
+ return ui.load(numOfTasks);
+ }
+ }
+
+ /**
+ * Returns the task that will be generated from the command, returns an empty task if no task is to be generated
+ * @return Task
+ */
+ @Override
+ public Task getTask() {
+ return Task.empty();
+ }
+}
diff --git a/src/main/java/command/MarkCommand.java b/src/main/java/command/MarkCommand.java
new file mode 100644
index 0000000000..075ab00870
--- /dev/null
+++ b/src/main/java/command/MarkCommand.java
@@ -0,0 +1,39 @@
+package command;
+
+import exception.MeowerException;
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+import task.Task;
+
+public class MarkCommand extends Command {
+
+ private int pos;
+
+ public MarkCommand(String pos) {
+ super();
+ this.pos = Integer.parseInt(pos);
+ }
+
+ /**
+ * Executes the functionality of the command, in the tasklist, UI and storage that are taken in as arguments,
+ * in this case marks the task that the user specified as done
+ * @param tasks tasklist from Meower chatbot
+ * @param ui ui from Meower chatbot
+ * @param storage storage from Meower chatbot
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws MeowerException{
+ tasks.mark(this.pos);
+ return ui.mark(this.pos);
+ }
+
+ /**
+ * Returns the task that will be generated from the command, returns an empty task if no task is to be generated
+ * @return Task
+ */
+ @Override
+ public Task getTask() {
+ return Task.empty();
+ }
+}
diff --git a/src/main/java/command/TodoCommand.java b/src/main/java/command/TodoCommand.java
new file mode 100644
index 0000000000..a8110e4e30
--- /dev/null
+++ b/src/main/java/command/TodoCommand.java
@@ -0,0 +1,52 @@
+package command;
+
+import exception.MeowerException;
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+import task.Task;
+import task.ToDo;
+
+public class TodoCommand extends Command {
+
+ private String description;
+
+ public TodoCommand(String description) {
+ super();
+ this.description = description;
+ }
+
+
+ /**
+ * Returns description inputted by the user
+ * @return String
+ */
+ public String getDescription() {
+ return this.description;
+ }
+
+ /**
+ * Executes the functionality of the command, in the tasklist, UI and storage that are taken in as arguments,
+ * in this case adds the Todo Task defined by the user into the tasklist
+ * @param tasks tasklist from Meower chatbot
+ * @param ui ui from Meower chatbot
+ * @param storage storage from Meower chatbot
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws MeowerException{
+ Task newEvent = this.getTask();
+ tasks.add(newEvent);
+ return ui.add(newEvent);
+ }
+
+
+ /**
+ * Returns the task that will be generated from the command, returns an empty task if no task is to be generated
+ * @return Task
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ @Override
+ public Task getTask() throws MeowerException{
+ return new ToDo(description);
+ }
+}
diff --git a/src/main/java/command/UnmarkCommand.java b/src/main/java/command/UnmarkCommand.java
new file mode 100644
index 0000000000..9f38ff38be
--- /dev/null
+++ b/src/main/java/command/UnmarkCommand.java
@@ -0,0 +1,41 @@
+package command;
+
+import exception.MeowerException;
+import meower.Storage;
+import meower.TaskList;
+import meower.Ui;
+import task.Task;
+
+public class UnmarkCommand extends Command {
+
+ private int pos;
+
+ public UnmarkCommand(String pos) {
+ super();
+ this.pos = Integer.parseInt(pos);
+ }
+
+ /**
+ * Executes the functionality of the command, in the tasklist, UI and storage that are taken in as arguments,
+ * in this case marks the task specified by the user as not done
+ * @param tasks tasklist from Meower chatbot
+ * @param ui ui from Meower chatbot
+ * @param storage storage from Meower chatbot
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws MeowerException {
+ tasks.unmark(this.pos);
+ return ui.unmark(this.pos);
+ }
+
+
+ /**
+ * Returns the task that will be generated from the command, returns an empty task if no task is to be generated
+ * @return Task
+ */
+ @Override
+ public Task getTask() {
+ return Task.empty();
+ }
+
+}
diff --git a/src/main/java/exception/InvalidCommandException.java b/src/main/java/exception/InvalidCommandException.java
new file mode 100644
index 0000000000..d21df9a888
--- /dev/null
+++ b/src/main/java/exception/InvalidCommandException.java
@@ -0,0 +1,11 @@
+package exception;
+
+/**
+ * when an invalid command is given by the user
+ */
+public class InvalidCommandException extends MeowerException {
+
+ public InvalidCommandException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/exception/InvalidDateException.java b/src/main/java/exception/InvalidDateException.java
new file mode 100644
index 0000000000..c70af208d0
--- /dev/null
+++ b/src/main/java/exception/InvalidDateException.java
@@ -0,0 +1,11 @@
+package exception;
+
+/**
+ * when an invalid date or non-date format is given by the user
+ */
+public class InvalidDateException extends MeowerException {
+
+ public InvalidDateException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/exception/MeowerException.java b/src/main/java/exception/MeowerException.java
new file mode 100644
index 0000000000..979854217b
--- /dev/null
+++ b/src/main/java/exception/MeowerException.java
@@ -0,0 +1,11 @@
+package exception;
+
+/**
+ * Main exception class from which all custom chatbot exceptions will extend from
+ */
+public class MeowerException extends Exception {
+
+ public MeowerException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/exception/MeowerFileAddressInvalidException.java b/src/main/java/exception/MeowerFileAddressInvalidException.java
new file mode 100644
index 0000000000..48029942b5
--- /dev/null
+++ b/src/main/java/exception/MeowerFileAddressInvalidException.java
@@ -0,0 +1,8 @@
+package exception;
+
+public class MeowerFileAddressInvalidException extends MeowerException {
+
+ public MeowerFileAddressInvalidException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/exception/MeowerFileNotFoundException.java b/src/main/java/exception/MeowerFileNotFoundException.java
new file mode 100644
index 0000000000..6dd7f4f57a
--- /dev/null
+++ b/src/main/java/exception/MeowerFileNotFoundException.java
@@ -0,0 +1,12 @@
+package exception;
+
+/**
+ * When file address given is not valid
+ */
+public class MeowerFileNotFoundException extends MeowerException {
+
+ public MeowerFileNotFoundException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/main/java/exception/MeowerIOException.java b/src/main/java/exception/MeowerIOException.java
new file mode 100644
index 0000000000..1710c12d5f
--- /dev/null
+++ b/src/main/java/exception/MeowerIOException.java
@@ -0,0 +1,11 @@
+package exception;
+
+/**
+ * When there is an error in the IO of the chatbot
+ */
+public class MeowerIOException extends MeowerException {
+
+ public MeowerIOException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/exception/MissingArgumentException.java b/src/main/java/exception/MissingArgumentException.java
new file mode 100644
index 0000000000..2e2af5156b
--- /dev/null
+++ b/src/main/java/exception/MissingArgumentException.java
@@ -0,0 +1,11 @@
+package exception;
+
+/**
+ * When the user is missing arguments when calling commands
+ */
+public class MissingArgumentException extends MeowerException {
+
+ public MissingArgumentException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/exception/TaskListOutOfBoundsException.java b/src/main/java/exception/TaskListOutOfBoundsException.java
new file mode 100644
index 0000000000..9c74ed7120
--- /dev/null
+++ b/src/main/java/exception/TaskListOutOfBoundsException.java
@@ -0,0 +1,11 @@
+package exception;
+
+/**
+ * When the user specifies a positional argument for tasklist that is out of bounds for tasklist of that size
+ */
+public class TaskListOutOfBoundsException extends MeowerException {
+
+ public TaskListOutOfBoundsException(String message) {
+ super(message);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/meower/ArchiveList.java b/src/main/java/meower/ArchiveList.java
new file mode 100644
index 0000000000..29a24c3daa
--- /dev/null
+++ b/src/main/java/meower/ArchiveList.java
@@ -0,0 +1,69 @@
+package meower;
+
+import java.util.ArrayList;
+
+public class ArchiveList {
+
+ private ArrayList archives;
+
+ public ArchiveList() {
+ this.archives = new ArrayList();
+ }
+
+
+ /**
+ * Returns true if archive contains the input archive name, false otherwise
+ * @param target archive name inputted
+ * @return boolean
+ */
+ public boolean contains(String target) {
+ return this.archives.contains(target);
+ }
+
+ /**
+ * Clears the archive list of all archives
+ */
+ public void clear() {
+ this.archives.clear();
+ }
+
+ public ArrayList getArchives() {
+ return this.archives;
+ }
+
+ /**
+ * Returns true if the archive list is empty, false otherwise
+ * @return boolean
+ */
+ public boolean isEmpty() {
+ return this.archives.isEmpty();
+ }
+
+
+ /**
+ * Adds a new archive into the archive list
+ * @param newArchive Input archive to be added
+ */
+ public void add(String newArchive) {
+ this.archives.add(newArchive);
+ }
+
+
+ /**
+ * Returns the string representation of an archive as it is displayed in listA command
+ * @return String
+ */
+ @Override
+ public String toString() {
+ if (this.isEmpty()) {
+ return "There are no archives";
+ }
+ String output = "Archive list:";
+ int count = 0;
+ for (String archive : archives) {
+ count += 1;
+ output += String.format("\n%d. %s", count, archive);
+ }
+ return output;
+ }
+}
diff --git a/src/main/java/meower/DialogBox.java b/src/main/java/meower/DialogBox.java
new file mode 100644
index 0000000000..d77e4598f2
--- /dev/null
+++ b/src/main/java/meower/DialogBox.java
@@ -0,0 +1,63 @@
+package meower;
+
+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;
+
+//taken from textbook
+
+/**
+ * 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;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/meower/Launcher.java b/src/main/java/meower/Launcher.java
new file mode 100644
index 0000000000..e667e44890
--- /dev/null
+++ b/src/main/java/meower/Launcher.java
@@ -0,0 +1,15 @@
+package meower;
+
+import javafx.application.Application;
+
+//taken from textbook
+
+/**
+ * A launcher class to workaround classpath issues.
+ */
+public class Launcher {
+
+ public static void main(String[] args) {
+ Application.launch(Main.class, args);
+ }
+}
diff --git a/src/main/java/meower/Main.java b/src/main/java/meower/Main.java
new file mode 100644
index 0000000000..8437f3c507
--- /dev/null
+++ b/src/main/java/meower/Main.java
@@ -0,0 +1,34 @@
+package meower;
+
+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;
+
+//taken from textbook
+
+/**
+ * A GUI for Duke using FXML.
+ */
+public class Main extends Application {
+
+ private Meower meower = new Meower();
+
+ @Override
+ public void start(Stage stage) {
+ assert meower != null: "meower bot cannot be null";
+ 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().setDuke(meower);
+ stage.show();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/meower/MainWindow.java b/src/main/java/meower/MainWindow.java
new file mode 100644
index 0000000000..eaded7d8ef
--- /dev/null
+++ b/src/main/java/meower/MainWindow.java
@@ -0,0 +1,57 @@
+package meower;
+
+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;
+
+//taken from textbook
+
+/**
+ * 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 Meower duke;
+
+ private Image userImage = new Image(this.getClass().getResourceAsStream("/images/DaUser.jpg"));
+ private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/DaMeower.jpg"));
+
+ @FXML
+ public void initialize() {
+ scrollPane.vvalueProperty().bind(dialogContainer.heightProperty());
+ }
+
+
+ public void setDuke(Meower 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() {
+ assert userImage != null: "userImage should not be null"; //both asserts idea taken from Marcus Ong Wee's code
+ assert dukeImage != null: "dukeImage should not be null";
+ String input = userInput.getText();
+ String response = duke.getResponse(input);
+ dialogContainer.getChildren().addAll(
+ DialogBox.getUserDialog(input, userImage),
+ DialogBox.getDukeDialog(response, dukeImage)
+ );
+ userInput.clear();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/meower/Meower.java b/src/main/java/meower/Meower.java
new file mode 100644
index 0000000000..25d4e6472b
--- /dev/null
+++ b/src/main/java/meower/Meower.java
@@ -0,0 +1,48 @@
+package meower;
+
+import command.Command;
+import exception.MeowerException;
+public class Meower {
+
+ private TaskList tasks;
+ private Parser parser;
+ private Storage storage;
+ private Ui ui;
+
+ public Meower() {
+ this.parser = new Parser();
+ this.tasks = new TaskList();
+ this.ui = new Ui(this.tasks);
+ this.storage = new Storage(this.tasks, this.ui);
+ }
+
+ //methods below taken from textbook and partially adapted
+
+ /**
+ * Process user inputs and generate the corresponding commands and ui events
+ */
+ public String processUserInput(String userInput) {
+ try {
+ Command nextCommand = parser.parse(userInput);
+ return nextCommand.execute(this.tasks, this.ui, this.storage);
+ } catch (MeowerException e) {
+ return ui.errorMessage(e);
+ }
+ }
+
+
+ /**
+ * Generates the reponse to a given userinput
+ * @param input String representation of the userinput
+ * @return String
+ */
+ public String getResponse(String input) {
+ try {
+ Command nextCommand = parser.parse(input);
+ assert this.tasks.getSize() >= 0: "tasklist size pointer should never be negative";
+ return nextCommand.execute(this.tasks, this.ui, this.storage);
+ } catch (MeowerException e) {
+ return ui.errorMessage(e);
+ }
+ }
+}
diff --git a/src/main/java/meower/Parser.java b/src/main/java/meower/Parser.java
new file mode 100644
index 0000000000..575c8ceddf
--- /dev/null
+++ b/src/main/java/meower/Parser.java
@@ -0,0 +1,133 @@
+package meower;
+
+import command.ArchiveCommand;
+import command.ByeCommand;
+import command.ClearCommand;
+import command.Command;
+import command.DeadlineCommand;
+import command.DeleteCommand;
+import command.EventCommand;
+import command.FindCommand;
+import command.ListArchiveCommand;
+import command.ListCommand;
+import command.LoadArchiveCommand;
+import command.LoadCommand;
+import command.MarkCommand;
+import command.TodoCommand;
+import command.UnmarkCommand;
+import exception.InvalidCommandException;
+
+public class Parser {
+
+ private final String MESSAGE_ERROR_UNNECESSARY_ARG = "ERROR: Argument given for command not needing argument";
+ private final String MESSAGE_ERROR_INVALID_COMMAND = "ERROR: Command entered is invalid";
+ private final String MESSAGE_ERROR_WRONG_ARGUMENTS = "ERROR: Arguments given for command are invalid or missing";
+
+ private final String COMMAND_CLEAR = "clear";
+ private final String COMMAND_LIST_ARCHIVE = "listA";
+ private final String COMMAND_LOAD_ARCHIVE = "loadA";
+ private final String COMMAND_ARCHIVE = "archive";
+ private final String COMMAND_FIND = "find";
+ private final String COMMAND_LOAD = "load";
+ private final String COMMAND_LIST = "list";
+ private final String COMMAND_BYE = "bye";
+ private final String COMMAND_DELETE = "delete";
+ private final String COMMAND_TODO = "todo";
+ private final String COMMAND_DEADLINE = "deadline";
+ private final String COMMAND_EVENT = "event";
+ private final String COMMAND_MARK = "mark";
+ private final String COMMAND_UNMARK = "unmark";
+
+ public Parser() {
+ ;
+ }
+
+
+ /**
+ * Parses a given userinput into the respective commands, throws InvalidCommandException when user gives invalid commands
+ * @param userCommand the command inputted by the user
+ * @return Command
+ * @throws InvalidCommandException thrown when an invalid command is inputted by the user
+ */
+ public Command parse(String userCommand) throws InvalidCommandException {
+
+ //split user command into command word and arguments
+ String splitUserStatement[] = userCommand.split(" ", 2);
+ String command = splitUserStatement[0];
+
+ //initialise empty string to store arguments
+ String commandArgs = "";
+ if (splitUserStatement.length > 1){
+ commandArgs = splitUserStatement[1].strip();
+ }
+
+ //switch-case for different command word
+ switch(command) { //no breaks as all cases lead to return
+ case COMMAND_CLEAR:
+ return new ClearCommand();
+ case COMMAND_LIST_ARCHIVE:
+ return new ListArchiveCommand();
+ case COMMAND_ARCHIVE:
+ return new ArchiveCommand(commandArgs);
+ case COMMAND_LOAD_ARCHIVE:
+ return new LoadArchiveCommand(commandArgs);
+ case COMMAND_FIND:
+ return new FindCommand(commandArgs);
+ case COMMAND_LOAD:
+ if (!commandArgs.equals("")) {
+ return new LoadCommand(commandArgs);
+ }
+ return new LoadCommand();
+ case COMMAND_LIST:
+ if (!commandArgs.equals("")) {
+ throw new InvalidCommandException(MESSAGE_ERROR_UNNECESSARY_ARG);
+ }
+ return new ListCommand();
+ case COMMAND_BYE:
+ if (!commandArgs.equals("")) {
+ return new ByeCommand(commandArgs);
+ }
+ return new ByeCommand();
+ case COMMAND_TODO:
+ return new TodoCommand(commandArgs);
+ case COMMAND_DEADLINE:
+ //process arguments to pass into Command constructor
+ String[] deadlineArgs = parseCommandArgs("/by",commandArgs);
+ if (deadlineArgs.length < 2) {
+ throw new InvalidCommandException(MESSAGE_ERROR_WRONG_ARGUMENTS);
+ }
+ String deadlineDescription = deadlineArgs[0];
+ String deadlineDate = deadlineArgs[1].strip();
+ return new DeadlineCommand(deadlineDescription, deadlineDate);
+ case COMMAND_EVENT:
+ //process arguments to pass into Command constructor
+ String[] eventArgs = parseCommandArgs("/at",commandArgs);
+ if (eventArgs.length < 2) {
+ throw new InvalidCommandException(MESSAGE_ERROR_WRONG_ARGUMENTS);
+ }
+ String eventDescription = eventArgs[0];
+ String eventDate = eventArgs[1].strip();
+ return new EventCommand(eventDescription, eventDate);
+ case COMMAND_MARK:
+ return new MarkCommand(commandArgs);
+ case COMMAND_UNMARK:
+ return new UnmarkCommand(commandArgs);
+ case COMMAND_DELETE:
+ return new DeleteCommand(commandArgs);
+ default:
+ throw new InvalidCommandException(MESSAGE_ERROR_INVALID_COMMAND);
+ }
+ }
+
+
+ /**
+ * Parses the arguments of the user inputted commands
+ * @param delimiter the String that will be used to split the given arguments
+ * @param args String representation of user inputted arguments
+ * @return String[]
+ */
+ public String[] parseCommandArgs(String delimiter, String args) {
+ String[] splitByDelimiter = args.split(delimiter, 2);
+ return splitByDelimiter;
+ }
+}
diff --git a/src/main/java/meower/Storage.java b/src/main/java/meower/Storage.java
new file mode 100644
index 0000000000..7c599ea7ad
--- /dev/null
+++ b/src/main/java/meower/Storage.java
@@ -0,0 +1,300 @@
+package meower;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+import command.Command;
+import exception.MeowerException;
+import exception.MeowerFileAddressInvalidException;
+import exception.MeowerFileNotFoundException;
+import exception.MeowerIOException;
+import exception.InvalidCommandException;
+import task.Task;
+
+public class Storage {
+
+ private final String MESSAGE_ERROR_ARCHIVE_MISSING = "ERROR: Archive clearing cannot be done as archive list is corrupted";
+ private final String MESSAGE_ERROR_ARCHIVENAME = "ERROR: Archive name not allowed";
+ private final String MESSAGE_ERROR_FILEPATH = "ERROR: File path specified does not exist";
+ private final String MESSAGE_ERROR_FILESAVE = "ERROR: Error in saving Tasks";
+ private final String MESSAGE_FILE_ADDRESS_ERROR = "ERROR: User file address invalid, please check pathing";
+
+ private final String LOG_FILE_DIRECTORY = "./src/main/resources/logs"; //log files must be in resources directory
+ private final String ARCHIVE_PATH = "./src/main/resources/archive";
+
+ private String logFileAddress = "./src/main/resources/logs/meowerLog.txt"; //default log file address
+ private String saveFileAddress = "./src/main/resources/logs/meowerLog.txt"; //default archive file address
+
+ private ArchiveList archives = new ArchiveList();
+ private ArrayList loggedTasks = new ArrayList();
+ private TaskList existingTasks;
+
+ public Storage(TaskList existingTasks, Ui ui) {
+ this.existingTasks = existingTasks;
+ }
+
+ /**
+ * Creates the archive directory structure if it does not exist
+ * @throws MeowerFileAddressInvalidException Thrown when file address inputted is not a valid system path
+ */
+ public void createArchive() throws MeowerFileAddressInvalidException {
+ if (!this.verifyPath(ARCHIVE_PATH)) {
+ this.createDirectory(ARCHIVE_PATH);
+ this.archives = new ArchiveList();
+ }
+ }
+
+ /**
+ * Clears the archive list of all archives asnd delete all the archive files
+ */
+ public int clearArchive() throws MeowerException{
+ try {
+ int count = 0;
+ ArrayList archiveList = this.archives.getArchives();
+ for (String archive : archiveList) {
+ Path fullPath = Paths.get(this.ARCHIVE_PATH + "/" + archive);
+ Files.deleteIfExists(fullPath);
+ count += 1;
+ }
+ this.archives.clear();
+ return count;
+ } catch (IOException e) {
+ throw new MeowerException(MESSAGE_ERROR_ARCHIVE_MISSING);
+ }
+ }
+
+ /**
+ * loadLog loads the tasks stored in the log or archive file into the current tasklist,
+ * throws DukeExceptions if theres issues with the format of the log or archive file or file address is invalid
+ * @return TaskList
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public int loadFile(boolean isLog) throws MeowerException {
+ this.loggedTasks.clear();
+ if (isLog) {
+ this.saveFileAddress = this.logFileAddress;
+ }
+ assert this.saveFileAddress != null: "There must be a log file address at this point";
+
+ try {
+ //initialise parser, file scanner and tasklist
+ Parser parser = new Parser();
+ Scanner fileReader = new Scanner(new File(this.saveFileAddress));
+ TaskList newTaskList = new TaskList();
+
+ //read the log file and store tasks read to the temporary arraylist of task logs
+ while (fileReader.hasNextLine()) {
+ String nextLogLine = fileReader.nextLine();
+ String[] parsedLogLine = nextLogLine.split(",", 2);
+ loggedTasks.add(parsedLogLine);
+ }
+
+ //close the scanner
+ fileReader.close();
+
+ //add all the tasks in the temporary array list of task logs into the tasklist
+ int numOfTasks = 0;
+ for (String[] loggedTask : loggedTasks) {
+ boolean isDone = Integer.parseInt(loggedTask[0]) == 1;
+ Command parsedCommand = parser.parse(loggedTask[1]);
+ Task newTask = parsedCommand.getTask();
+ numOfTasks += 1;
+ if (isDone) {
+ newTask.mark();
+ }
+ newTaskList.add(parsedCommand.getTask());
+ }
+
+ //return the new tasklist to be used
+ this.existingTasks.replace(newTaskList);
+ return numOfTasks;
+ } catch (InvalidCommandException e) {
+ throw e;
+ } catch (FileNotFoundException e) {
+ throw new MeowerFileNotFoundException(e.getLocalizedMessage());
+ }
+ }
+
+
+ /**
+ * Overloaded constructor for case where user defines a new file address
+ * @param newPath String representation of user defined new file path, relative path from ip folder
+ * @return int
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public int loadFile(String newPath) throws MeowerException {
+ String fullPath = this.LOG_FILE_DIRECTORY + "/" + newPath;
+ if (!this.verifyPath(fullPath)) {
+ throw new MeowerFileAddressInvalidException(MESSAGE_ERROR_FILEPATH);
+ }
+ this.logFileAddress = fullPath;
+ this.saveFileAddress = fullPath;
+ return this.loadFile(true);
+ }
+
+ /**
+ * Archives current tasks in an archive file specified by the user, then clears out the task list
+ * @param archiveName User specified name for the archive file
+ * @return int
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public int archiveToFile(String archiveName) throws MeowerException {
+ //create archive directory structure if it doesn't yet exist
+ this.createArchive();
+
+ //archive by storing file names in a arraylist, dedicated archive folder
+ if (!this.verifyAddress(archiveName)) {
+ throw new MeowerFileAddressInvalidException(MESSAGE_ERROR_ARCHIVENAME); //since archive name is name of file must not have spaces etc
+ }
+ this.saveFileAddress = ARCHIVE_PATH + "/" + archiveName;
+ int numOfTasks = this.saveToFile(false);
+ this.existingTasks.clear();
+ archives.add(archiveName);
+ return numOfTasks;
+ }
+
+ /**
+ * Loads the tasks archived in the user specified archive file, clears the current tasks before loading
+ * @param archiveName User specified archive file to load tasks from
+ * @return int
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public int loadArchive(String archiveName) throws MeowerException {
+ if (!this.archives.contains(archiveName)) {
+ throw new MeowerFileAddressInvalidException(MESSAGE_FILE_ADDRESS_ERROR);
+ }
+ String fullPath = this.ARCHIVE_PATH + "/" + archiveName;
+ this.existingTasks.clear();
+ this.saveFileAddress = fullPath;
+ int numOfTasks = loadFile(false);
+ return numOfTasks;
+ }
+
+ /**
+ * Saves the tasks in the tasklist into a log or archive file given by a pre-loaded file address
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public int saveToFile(boolean isLog) throws MeowerException {
+ if (isLog) {
+ this.saveFileAddress = this.logFileAddress;
+ }
+ assert this.saveFileAddress != null: "There must be a log file address at this point";
+
+ //if no tasks to be saved, exit with message
+ if (existingTasks.getSize() == 0) {
+ return 0;
+ }
+ try {
+ //Verify filepath exists
+ this.verifyAddress(this.saveFileAddress);
+ this.createDirectory(this.saveFileAddress);
+
+ //initialise file writer and integer counter
+ FileWriter fileWriter = new FileWriter(this.saveFileAddress);
+ int numOfTasks = 0;
+
+ //log tasks in tasklist
+ for (Task task : existingTasks.getTasks()) {
+ fileWriter.write(task.log());
+ numOfTasks += 1;
+ }
+
+ //close file writer and show message to user
+ fileWriter.close();
+ return numOfTasks;
+ }
+ catch (IOException e) {
+ throw new MeowerIOException(MESSAGE_ERROR_FILESAVE);
+ }
+ }
+
+ /**
+ * Overloaded constructor that allows for a new user defined file path
+ * @param newFilePath user inputted new file path for saving log files, relative path from ip folder
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public int saveToFile(String newFilePath) throws MeowerException{
+ if (!this.verifyAddress(newFilePath)) {
+ throw new MeowerFileAddressInvalidException(MESSAGE_FILE_ADDRESS_ERROR);
+ }
+ this.logFileAddress = this.LOG_FILE_DIRECTORY + "/" + newFilePath;
+ this.saveFileAddress = this.logFileAddress;
+ return this.saveToFile(true);
+ }
+
+
+ /**
+ * Verifies if the path already exists
+ * @param fullPath file path to be verified
+ * @return boolean
+ */
+ private boolean verifyPath(String fullPath) {
+ Path fullPathToCheck = Paths.get(fullPath);
+ if (Files.exists(fullPathToCheck)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * verify if user given file address is valid
+ * @param address file path address given by user
+ * @return boolean
+ */
+ private boolean verifyAddress(String address) {
+ //pre-process address string
+ String addressToCheck = address.strip();
+ String[] addressSplit = addressToCheck.split(" ");
+
+ //verification
+ if (addressSplit.length > 1) {
+ return false;
+ }
+ if (address.equals("")) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * creates directories along the file path saved in the log file address property
+ */
+ private void createDirectory(String path) throws MeowerFileAddressInvalidException{
+ String directoriesPath = this.removeFilePath(path);
+ Path dirPath = Paths.get(directoriesPath);
+ if (!Files.exists(dirPath)) {
+
+ //if path doesnt exist, create directory
+ File directory = new File(directoriesPath);
+ if (!directory.mkdirs()) {
+ throw new MeowerFileAddressInvalidException("cannot create directory as file address is invalid");
+ }
+ }
+ }
+
+ /**
+ * Returns the String representation of the archive list in the listA format
+ * @return
+ */
+ public String listArchive() {
+ return this.archives.toString();
+ }
+
+
+ /**
+ * Removes the directories in the file path, leaving only the file name
+ * @param fullPath file path to a file
+ * @return String
+ */
+ private String removeFilePath(String fullPath) {
+ return fullPath.substring(0, fullPath.lastIndexOf("/") + 1);
+ }
+}
diff --git a/src/main/java/meower/TaskList.java b/src/main/java/meower/TaskList.java
new file mode 100644
index 0000000000..a415947992
--- /dev/null
+++ b/src/main/java/meower/TaskList.java
@@ -0,0 +1,173 @@
+package meower;
+
+import java.util.ArrayList;
+
+import exception.TaskListOutOfBoundsException;
+import task.Task;
+
+public class TaskList {
+
+ private final String MESSAGE_ERROR_OUTOFBOUNDS = "ERROR: Positional argument out of bounds for TaskList of size ";
+
+ private ArrayList tasks;
+ private TaskList searchTasks;
+ private int size;
+
+ public TaskList() {
+ this.tasks = new ArrayList();
+ this.size = 0;
+ }
+
+ public TaskList(TaskList taskList) {
+ this.tasks = new ArrayList();
+ this.tasks.addAll(taskList.tasks); //deep copy TaskList
+ this.size = taskList.getSize();
+ }
+
+
+ /**
+ * Returns true if tasklist is empty, false otherwise
+ * @return Boolean
+ */
+ public Boolean isEmpty() {
+ return !(this.size > 0);
+ }
+
+
+ /**
+ * Returns number of tasks in the tasklist
+ * @return int
+ */
+ public int getSize() {
+ return this.size;
+ }
+
+ /**
+ * Clears the TaskList of all tasks
+ */
+ public void clear() {
+ this.tasks.clear();
+ }
+
+
+ /**
+ * adds a task into the back of the tasklist
+ * @param newTask task inputted by user to be added to tasklist
+ */
+ public void add(Task newTask) {
+ assert newTask.isEmpty() == false: "Tasks added to tasklist should never be empty";
+ this.tasks.add(newTask);
+ this.size += 1;
+ }
+
+
+ /**
+ * deletes the task at the specified index in the tasklist, throws TaskListOutOfBoundsException if index is out of bounds
+ * @param pos user inputted index to delete task
+ * @throws TaskListOutOfBoundsException thrown when user inputted pos is outside the size of the tasklist
+ */
+ public String delete(int pos) throws TaskListOutOfBoundsException {
+ if (pos > this.getSize()) {
+ throw new TaskListOutOfBoundsException(String.format("%s%d", this.MESSAGE_ERROR_OUTOFBOUNDS,this.getSize()));
+ }
+ String deletedTask = this.tasks.get(pos-1).toString();
+ this.tasks.remove(pos-1);
+ this.size -= 1;
+ return deletedTask;
+ }
+
+
+ /**
+ * returns the task at the specified index in the tasklist, throws TaskListOutOfBoundsException if index is out of bounds
+ * @param pos user inputted index to get task
+ * @return Task
+ * @throws TaskListOutOfBoundsException thrown when user inputted pos is outside the size of the tasklist
+ */
+ public Task get(int pos) throws TaskListOutOfBoundsException {
+ if (pos > this.getSize()) {
+ throw new TaskListOutOfBoundsException(String.format("%s%d", this.MESSAGE_ERROR_OUTOFBOUNDS,this.getSize()));
+ }
+ return this.tasks.get(pos-1);
+ }
+
+
+ /**
+ * marks the task at the specified index in the tasklist as done, throws TaskListOutOfBoundsException if index is out of bounds
+ * @param pos user inputted index to mark task done
+ * @throws TaskListOutOfBoundsException thrown when user inputted pos is outside the size of the tasklist
+ */
+ public void mark(int pos) throws TaskListOutOfBoundsException {
+ if (pos > this.getSize()) {
+ throw new TaskListOutOfBoundsException(String.format("%s%d", this.MESSAGE_ERROR_OUTOFBOUNDS,this.getSize()));
+ }
+ this.tasks.get(pos-1).mark();
+ }
+
+
+ /**
+ * marks the task at the specified index in the tasklist as not done, throws TaskListOutOfBoundsException if index is out of bounds
+ * @param pos user inputted index to mark task not done
+ * @throws TaskListOutOfBoundsException thrown when user inputted pos is outside the size of the tasklist
+ */
+ public void unmark(int pos) throws TaskListOutOfBoundsException {
+ if (pos > this.getSize()) {
+ throw new TaskListOutOfBoundsException(String.format("%s%d", this.MESSAGE_ERROR_OUTOFBOUNDS,this.getSize()));
+ }
+ this.tasks.get(pos-1).unmark();
+ }
+
+
+ /**
+ * returns the ArrayList of tasks
+ * @return ArrayList
+ */
+ public ArrayList getTasks() {
+ return this.tasks;
+ }
+
+
+
+ /**
+ * returns a list of all tasks that have the user specified keyword
+ * @param keyword user inputted string by which to filter the tasks
+ * @return TaskList
+ */
+ public TaskList search(String keyword) {
+ this.searchTasks = new TaskList();
+ for (Task task : tasks) {
+ if (task.getDescription().contains(keyword)) {
+ this.searchTasks.add(task);
+ }
+ }
+ return this.searchTasks;
+ }
+
+
+ /**
+ * replaces the current tasks in the tasklist with the tasks in the user inputted tasklist
+ * @param newList user inputted tasklist
+ */
+ public void replace(TaskList newList) {
+ this.tasks = new ArrayList();
+ this.tasks.addAll(newList.tasks);
+ }
+
+ /**
+ * Returns the list command format of the tasks in index order
+ * @return String
+ */
+ @Override
+ public String toString() {
+ String output = "Tasks: \n";
+ int count = 1;
+ if (tasks.size() == 0) {
+ return "No tasks! Yay!";
+ }
+ for (Task task : tasks) {
+ output += String.valueOf(count) + ". " + task + "\n";
+ count += 1;
+ }
+ output = output.substring(0, output.length()-1);
+ return output;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/meower/Ui.java b/src/main/java/meower/Ui.java
new file mode 100644
index 0000000000..90ef50e32f
--- /dev/null
+++ b/src/main/java/meower/Ui.java
@@ -0,0 +1,178 @@
+package meower;
+
+import exception.MeowerException;
+import exception.TaskListOutOfBoundsException;
+import task.Task;
+
+public class Ui {
+
+ private TaskList tasks;
+ private final String MESSAGE_GREETING = "Hello! I'm Duke \n" + "What can I do for you?";
+ private final String MESSAGE_FIND = "Tasks found:\n";
+ private final String MESSAGE_LOG_ERROR = "File pathing for log file is facing issues, tasks not saved.\n";
+ private final String MESSAGE_MARK = "Task has been marked done:";
+ private final String MESSAGE_UNMARK = "Task has been marked not done:";
+ private final String MESSAGE_ADD = "Task added: \n";
+ private final String MESSAGE_DELETE = "Task deleted: \n";
+ private final String MESSAGE_ERROR_END = "ERROR: Error in saving Tasks, progress from current session is not saved :(";
+
+ public Ui(TaskList tasks) {
+ this.tasks = tasks;
+ }
+
+
+ /**
+ * returns the greeting message
+ * @return String
+ */
+ public String greeting() {
+ return this.chat(this.MESSAGE_GREETING);
+ }
+
+
+ /**
+ * returns a log file error message
+ * @return String
+ */
+ public String logFileError() {
+ return this.chat(MESSAGE_LOG_ERROR);
+ }
+
+ /**
+ * Shows a list of the tasks the chatbot holds to the user in tasklist index order,
+ * indicates the task type, done or not done, task description and task date
+ * @param tasks tasklist of tasks
+ * @param isFind specify if there is a keyword to filter the tasks by
+ */
+ public String list(TaskList tasks, boolean isFind) {
+ if (isFind) {
+ return this.chat(MESSAGE_FIND + tasks.toString());
+ } else {
+ return this.chat(tasks.toString());
+ }
+ }
+
+ public String listArchive(Storage storage) {
+ return this.chat(storage.listArchive());
+ }
+
+
+ /**
+ * Shows the new task that was added to the user, indicates the task type, task description and task date
+ * @param newTask new task inputted by user to be added to tasklist
+ */
+ public String add(Task newTask) {
+ return this.chat(String.format("%s%s", MESSAGE_ADD, newTask));
+ }
+
+
+ /**
+ * Shows the task that was deleted to the user, indicates the task type, task description and task date
+ * @param pos index in tasklist where task to be deleted
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public String delete(String taskDescription) {
+ return this.chat(String.format("%s%s", MESSAGE_DELETE, taskDescription));
+ }
+
+
+ /**
+ * Shows the task that was marked done to the user, indicates the task type, done or not done, task description and task date
+ * @param pos index in tasklist where task to be marked done
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public String mark(int pos) throws MeowerException {
+ try {
+ return this.chat(MESSAGE_MARK + this.tasks.get(pos));
+ } catch (TaskListOutOfBoundsException e) {
+ throw new MeowerException(e.getLocalizedMessage());
+ }
+ }
+
+
+ /**
+ * Shows the task that was marked not done to the user, indicates the task type, done or not done, task description and task date
+ * @param pos index in tasklist where task to be marked not done
+ * @throws MeowerException Main Meower chatbot Exception
+ */
+ public String unmark(int pos) throws MeowerException {
+ try {
+ return this.chat(MESSAGE_UNMARK + tasks.get(pos));
+ } catch (TaskListOutOfBoundsException e) {
+ throw new MeowerException(e.getLocalizedMessage());
+ }
+ }
+
+
+ /**
+ * returns the error messages from exceptions
+ * @param e exception from which error message to be shown
+ */
+ public String errorMessage(MeowerException e) {
+ return this.chat(e.getLocalizedMessage());
+ }
+
+
+ /**
+ * returns the error message when there was an error in ending the program
+ * @return String
+ */
+ public String errorEnd() {
+ return this.chat(MESSAGE_ERROR_END);
+ }
+
+
+ /**
+ * returns the message upon successful loading of task, specifies number of tasks loaded
+ * @param numOfTasks number of tasks loaded
+ * @return String
+ */
+ public String load(int numOfTasks) {
+ return this.chat(String.format("Loaded %d tasks. \nHave a productive day!", numOfTasks));
+ }
+
+ /**
+ * returns the message upon successful loading of archive, specifies number of tasks saved
+ * @param numOfTasks number of tasks saved
+ * @return String
+ */
+ public String loadArchive(int numOfTasks) {
+ return this.chat(String.format("Loaded %d tasks from archive!", numOfTasks));
+ }
+
+ /**
+ * returns the message upon successful archiving of tasks, specifies number of tasks saved
+ * @param numOfTasks number of tasks saved
+ * @return String
+ */
+ public String archive(int numOfTasks) {
+ return this.chat(String.format("Archived %d tasks.", numOfTasks));
+ }
+
+ /**
+ * returns the message upon successful clearing of archives, specifies number of archives cleared
+ * @param numOfArchives number of archives cleared
+ * @return
+ */
+ public String clear(int numOfArchives) {
+ return this.chat(String.format("Cleared %d archives", numOfArchives));
+ }
+
+ /**
+ * returns the message upon successful saving of tasks, specifies number of tasks saved
+ * @param numOfTasks number of tasks saved
+ * @return String
+ */
+ public String bye(int numOfTasks) {
+ return this.chat(String.format("Saved %d tasks. \nBye bye! :D", numOfTasks));
+ }
+
+
+ /**
+ * returns the message
+ * @param message any message from Meower chatbot
+ */
+ public String chat(String message) {
+ return(message);
+ }
+}
diff --git a/src/main/java/task/Deadline.java b/src/main/java/task/Deadline.java
new file mode 100644
index 0000000000..8ef704102c
--- /dev/null
+++ b/src/main/java/task/Deadline.java
@@ -0,0 +1,46 @@
+package task;
+
+import java.time.LocalDate;
+
+import exception.InvalidDateException;
+import exception.MissingArgumentException;
+
+public class Deadline extends Task{
+
+ private final String MESSAGE_ERROR_MISSING_ARGS = "ERROR: Deadline command is missing arguments.";
+ private final String MESSAGE_ERROR_MISSING_DESCRIPTION = "ERROR: Description is missing";
+
+ protected LocalDate date;
+
+ public Deadline(String description, String date) throws MissingArgumentException, InvalidDateException{
+ super("deadline", description, date);
+ if (date.equals("")) {
+ throw new MissingArgumentException(MESSAGE_ERROR_MISSING_ARGS);
+ }
+ if (description.equals("")) {
+ throw new MissingArgumentException(MESSAGE_ERROR_MISSING_DESCRIPTION);
+ }
+ this.date = super.date;
+ }
+
+ public Deadline(String description, String date, boolean isDone) throws MissingArgumentException, InvalidDateException{
+ super("deadline", description, date, isDone);
+ if (date.equals("")) {
+ throw new MissingArgumentException(MESSAGE_ERROR_MISSING_ARGS);
+ }
+ if (description.equals("")) {
+ throw new MissingArgumentException(MESSAGE_ERROR_MISSING_DESCRIPTION);
+ }
+ this.date = super.date;
+ }
+
+
+ /**
+ * returns string representation of deadline task
+ * @return String
+ */
+ @Override
+ public String toString() {
+ return String.format("[D]%s (by: %s)", super.toString(), this.date.format(super.outputDateFormatter));
+ }
+}
diff --git a/src/main/java/task/Event.java b/src/main/java/task/Event.java
new file mode 100644
index 0000000000..fcf8446f08
--- /dev/null
+++ b/src/main/java/task/Event.java
@@ -0,0 +1,46 @@
+package task;
+
+import java.time.LocalDate;
+
+import exception.InvalidDateException;
+import exception.MissingArgumentException;
+
+public class Event extends Task{
+
+ private final String MESSAGE_ERROR_MISSING_ARGS = "ERROR :Event command is missing arguments.";
+ private final String MESSAGE_ERROR_MISSING_DESCRIPTION = "ERROR: Description is missing";
+
+ protected LocalDate duration;
+
+ public Event(String description, String duration) throws MissingArgumentException, InvalidDateException {
+ super("event", description, duration);
+ if (duration.equals("")) {
+ throw new MissingArgumentException(MESSAGE_ERROR_MISSING_ARGS);
+ }
+ if (description.equals("")) {
+ throw new MissingArgumentException(MESSAGE_ERROR_MISSING_DESCRIPTION);
+ }
+ this.duration = super.date;
+ }
+
+ public Event(String description, String duration, boolean isDone) throws MissingArgumentException, InvalidDateException {
+ super("event", description, duration, isDone);
+ if (duration.equals("")) {
+ throw new MissingArgumentException(MESSAGE_ERROR_MISSING_ARGS);
+ }
+ if (description.equals("")) {
+ throw new MissingArgumentException(MESSAGE_ERROR_MISSING_DESCRIPTION);
+ }
+ this.duration = super.date;
+ }
+
+
+ /**
+ * returns string representation of event task
+ * @return String
+ */
+ @Override
+ public String toString() {
+ return String.format("[E]%s (at: %s)", super.toString(), this.duration.format(super.outputDateFormatter));
+ }
+}
diff --git a/src/main/java/task/Task.java b/src/main/java/task/Task.java
new file mode 100644
index 0000000000..c5b50dd073
--- /dev/null
+++ b/src/main/java/task/Task.java
@@ -0,0 +1,154 @@
+package task;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+import exception.InvalidDateException;
+
+public class Task {
+ private final String MESSAGE_ERROR_PAST_DATE = "ERROR: Date should be a future date, not one in the past";
+ private final String MESSAGE_ERROR_WRONG_FORMAT = "ERROR: Date is formatted wrongly";
+
+ protected DateTimeFormatter inputDateFormatter = DateTimeFormatter.ofPattern("d/M/yyyy");
+ protected DateTimeFormatter outputDateFormatter = DateTimeFormatter.ofPattern("E, d MMM yyyy");
+ protected String type;
+ protected String description;
+ protected LocalDate date;
+ protected boolean isDone;
+ protected boolean isEmpty;
+
+ private Task() {
+ this.isEmpty = true;
+ }
+
+ Task (String type, String description) {
+ this.type = type;
+ this.description = description;
+ this.isDone = false;
+ this.isEmpty = false;
+ }
+
+ Task (String type, String description, boolean isDone) {
+ this.type = type;
+ this.description = description;
+ this.isDone = isDone;
+ this.isEmpty = false;
+ }
+
+ Task (String type, String description, String date) throws InvalidDateException {
+ this.type = type;
+ this.description = description;
+ this.date = convert(date);
+ this.isDone = false;
+ this.isEmpty = false;
+ }
+
+ Task (String type, String description, String date, boolean isDone) throws InvalidDateException{
+ this.type = type;
+ this.description = description;
+ this.date = convert(date);
+ this.isDone = isDone;
+ this.isEmpty = false;
+ }
+
+
+ /**
+ * returns an empty task
+ * @return Task
+ */
+ public static Task empty() {
+ return new Task();
+ }
+
+
+ /**
+ * checks if task is empty, returns true if empty and false if not
+ * @return boolean
+ */
+ public boolean isEmpty() {
+ return this.isEmpty;
+ }
+
+
+ /**
+ * returns description of task
+ * @return String
+ */
+ public String getDescription() {
+ return this.description;
+ }
+
+ /**
+ * marks the task done
+ */
+ public void mark() {
+ this.isDone = true;
+ }
+
+ /**
+ * marks the task not done
+ */
+ public void unmark() {
+ this.isDone = false;
+ }
+
+
+ /**
+ * returns the log file format String to save this task to the log file
+ * @return String
+ */
+ public String log() {
+ int binIsDone;
+ if (this.isDone) {
+ binIsDone = 1;
+ } else {
+ binIsDone = 0;
+ }
+ switch(type) {
+ case "todo":
+ return String.format("%d,todo %s\n", binIsDone, this.description);
+ case "deadline":
+ return String.format("%d,deadline %s/by%s\n", binIsDone, this.description, this.date.format(inputDateFormatter));
+ case "event":
+ return String.format("%d,event %s/at%s\n", binIsDone, this.description, this.date.format(inputDateFormatter));
+ default:
+ return "N";
+ }
+ }
+
+
+ /**
+ * converts dates of specified format to LocalDate type
+ * @param date String representation of a date
+ * @return LocalDate
+ * @throws InvalidDateException thrown when an invalid or non-date format is given
+ */
+ public LocalDate convert(String date) throws InvalidDateException { //assumes format is in d/M/yyyy
+ try {
+ LocalDate currentDate = LocalDate.now();
+ LocalDate taskDate = LocalDate.parse(date, inputDateFormatter);
+ if (taskDate.isBefore(currentDate)) {
+ throw new InvalidDateException(MESSAGE_ERROR_PAST_DATE);
+ }
+ return taskDate;
+ } catch (DateTimeParseException e) {
+ throw new InvalidDateException(MESSAGE_ERROR_WRONG_FORMAT);
+ }
+ }
+
+
+ /**
+ * returns the string representation of tasks
+ * @return String
+ */
+ @Override
+ public String toString() {
+ char mark;
+ if (this.isDone) {
+ mark = 'X';
+ } else {
+ mark = ' ';
+ }
+ return ("[" + mark + "] " + this.getDescription());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/task/ToDo.java b/src/main/java/task/ToDo.java
new file mode 100644
index 0000000000..99983a3aa5
--- /dev/null
+++ b/src/main/java/task/ToDo.java
@@ -0,0 +1,32 @@
+package task;
+
+import exception.MissingArgumentException;
+
+public class ToDo extends Task{
+
+ private final String MESSAGE_ERROR_MISSING_DESCRIPTION = "ERROR: Description is missing";
+
+ public ToDo(String description) throws MissingArgumentException{
+ super("todo", description);
+ if (description.equals("")) {
+ throw new MissingArgumentException(MESSAGE_ERROR_MISSING_DESCRIPTION);
+ }
+ }
+
+ public ToDo(String description, boolean isDone) throws MissingArgumentException{
+ super("todo", description, isDone);
+ if (description.equals("")) {
+ throw new MissingArgumentException(MESSAGE_ERROR_MISSING_DESCRIPTION);
+ }
+ }
+
+
+ /**
+ * returns string representation of todo task
+ * @return String
+ */
+ @Override
+ public String toString() {
+ return String.format("[T]%s", super.toString());
+ }
+}
diff --git a/src/main/resources/images/DaMeower.jpg b/src/main/resources/images/DaMeower.jpg
new file mode 100644
index 0000000000..93b4b86ab2
Binary files /dev/null and b/src/main/resources/images/DaMeower.jpg differ
diff --git a/src/main/resources/images/DaUser.jpg b/src/main/resources/images/DaUser.jpg
new file mode 100644
index 0000000000..19496e48c2
Binary files /dev/null and b/src/main/resources/images/DaUser.jpg differ
diff --git a/src/main/resources/images/kittens.jpg b/src/main/resources/images/kittens.jpg
new file mode 100644
index 0000000000..462f6bf52c
Binary files /dev/null and b/src/main/resources/images/kittens.jpg differ
diff --git a/src/main/resources/logs/meowerLog.txt b/src/main/resources/logs/meowerLog.txt
new file mode 100644
index 0000000000..b9ae492dac
--- /dev/null
+++ b/src/main/resources/logs/meowerLog.txt
@@ -0,0 +1 @@
+0,todo run
diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml
new file mode 100644
index 0000000000..1b5260e3a3
--- /dev/null
+++ b/src/main/resources/view/DialogBox.fxml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
new file mode 100644
index 0000000000..f805798007
--- /dev/null
+++ b/src/main/resources/view/MainWindow.fxml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/main/ParserTest.java b/src/test/java/main/ParserTest.java
new file mode 100644
index 0000000000..0d36388f6f
--- /dev/null
+++ b/src/test/java/main/ParserTest.java
@@ -0,0 +1,29 @@
+package main;
+
+import org.junit.jupiter.api.Test;
+
+import exception.MeowerException;
+import exception.InvalidCommandException;
+import meower.Parser;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class ParserTest {
+ @Test
+ public void descriptionTest(){
+ Parser p = new Parser();
+ try {
+ assertEquals(p.parse("todo run").getTask().getDescription(), "run");
+ } catch (InvalidCommandException e) {
+ return;
+ } catch (MeowerException e) {
+ return;
+ }
+ }
+
+ /*@Test
+ public void anotherDummyTest(){
+ assertEquals(4, 4);
+ } */
+}
+
diff --git a/src/test/java/main/TaskListTest.java b/src/test/java/main/TaskListTest.java
new file mode 100644
index 0000000000..5dfcf23696
--- /dev/null
+++ b/src/test/java/main/TaskListTest.java
@@ -0,0 +1,48 @@
+package main;
+
+import org.junit.jupiter.api.Test;
+
+import exception.MeowerException;
+import meower.TaskList;
+import task.Task;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class TaskListTest {
+ @Test
+ public void addTest(){
+ TaskList tasks = new TaskList();
+ Task testTask = Task.empty();
+ try {
+ tasks.add(testTask);
+ assertEquals(tasks.get(1), testTask);
+ } catch (MeowerException e) {
+ return;
+ }
+ }
+
+ @Test
+ public void sizeTest(){
+ TaskList tasks = new TaskList();
+ Task testTask = Task.empty();
+ int testSize = 5;
+ for (int i = 0; i < testSize; i++) {
+ tasks.add(testTask);
+ }
+ assertEquals(tasks.getSize(), testSize);
+ }
+
+ @Test
+ public void deleteTest(){
+ TaskList tasks = new TaskList();
+ Task testTask = Task.empty();
+ try {
+ tasks.add(testTask);
+ tasks.delete(1);
+ assertEquals(tasks.isEmpty(), true);
+ } catch (MeowerException e) {
+ return;
+ }
+ }
+
+}
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e7..2e3044f3bf 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,16 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
+----------------------------------------
+Hello! I'm Duke
+What can I do for you?
+----------------------------------------
+----------------------------------------
+Got it, I've added this task:
+ [T][ ] work
+Now you have 1 tasks in the list
+----------------------------------------
+
+----------------------------------------
+Got it, I've added this task:
+ [D][ ] quiz (by: sunday)
+Now you have 2 tasks in the list
+----------------------------------------
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb2..e4cf5ca80e 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,2 @@
+todo work
+deadline quiz /by sunday
\ No newline at end of file