diff --git a/README.md b/README.md
index 9d95025bce..da61b7869f 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Duke project template
+# duke project template
This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.
@@ -15,7 +15,7 @@ Prerequisites: JDK 11, update Intellij to the most recent version.
1. Click `Open or Import`.
1. Select the project directory, and click `OK`
1. If there are any further prompts, accept the defaults.
-1. After the importing is complete, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()`. If the setup is correct, you should see something like the below:
+1. After the importing is complete, locate the `src/main/java/duke.java` file, right-click it, and choose `Run duke.main()`. If the setup is correct, you should see something like the below:
```
Hello from
____ _
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000..d8c36eb05d
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,61 @@
+plugins {
+ id 'java'
+ id 'application'
+ id 'checkstyle'
+ id 'com.github.johnrengelman.shadow' version '5.1.0'
+}
+
+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 = "ip"
+ archiveClassifier = null
+}
+
+checkstyle {
+ toolVersion = '8.29'
+}
+
+run{
+ standardInput = System.in
+}
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
new file mode 100644
index 0000000000..7951f3a6c4
--- /dev/null
+++ b/config/checkstyle/checkstyle.xml
@@ -0,0 +1,398 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml
new file mode 100644
index 0000000000..6423654db1
--- /dev/null
+++ b/config/checkstyle/suppressions.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
diff --git a/docs/README.md b/docs/README.md
index fd44069597..8b86c1bacc 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -2,19 +2,191 @@
## Features
-### Feature 1
-Description of feature.
+### Tasks
+3 Different Task types exists, ToDo, Event and Deadline
-## Usage
+* ### Deadline
+ Use it to add a task involving a deadline(eg submission)
+
+ ## User uses it to add a particular deadline
+
+ Adds a task involving a deadline to the current list of tasks
+ Gives a response saying that it has been added, and gives the current
+ Number of tasks present
+ * Syntax: deadline (task name) /by (date and/or time)
+
+ Examples of usage:
+
+ deadline return book /by 23:59
+
+ Got it. I've added this task:
+ [D][✗] return book (by: 23:59)
+ Now you have 6 tasks in the list.
+
+* ### Event
+ Use it to add a task involving a period o time,
+
+ ## User uses it to add a particular deadline(eg competition)
+
+ Adds a task that occurs over a period of time, where date and/or time has to be given in the format as shown below
+
+ Gives a response saying that it has been added and gives the current
+ Number of tasks present.
+ * Syntax: event (event name) /at (start date and/or time)-(end date and/or time)
+
+ Examples of usage:
+
+ event competition/at 12:00-14:00
+
+ Got it. I've added this task:
+ [D][✗] return book (at: 23:59)
+ Now you have 6 tasks in the list.
+* ###ToDo
+ This is to add a normal task without a need to be completed by a certain time frame
+
+ ## User uses it to keep reminder of tasks without a specific time frame
+
+ After this is added, a message saying that the todo task is added and the current number
+ Of tasks is printed
+
+ * Syntax: todo (todo name)
+ Example of Usage:
+ todo read book
+
+ Got it. I've added this task:
+ [T][✗] read book
+ Now you have 3 tasks in the list.
-### `Keyword` - Describe action
-Describe action and its outcome.
+### Delete
+Use it to delete a specific task
-Example of usage:
+## User uses it to to delete a task
-`keyword (optional arguments)`
+### ‘delete’ - deletes specific task based on the number given
-Expected outcome:
+Deletes a task provided based on the number provided after delete, where the
+Number provided should coincide with the ordering given in the list
+If delete is absent or number given is more than the number of items available
+Error is printed
+* Syntax: delete (number)
-`outcome`
+Examples of usage:
+
+delete 3 (if at least 3 tasks in the list)
+
+ Noted. I've removed this task:
+ [E][✗] project meeting (at: Aug 6th 2-4pm)
+ Now you have 4 tasks in the list.
+
+
+### Find
+Used to find tasks containing the words given by user
+Allows user to search for tasks with specific words
+
+##User uses it to search for tasks
+
+Finds out tasks using their names and the tasks containing all the words given are given
+* Syntax: find (words you wish to search for)
+
+Examples of usage:
+
+find book
+
+ Here are the matching tasks in your list:
+ 1.[T][✓] buy book
+
+ ### Done
+Use it to mark a task as done, once a task is completed
+
+##User uses it to mark a task as done, to keep track of tasks done
+
+Marks the task at the number(input by user) as done and returns a string representing it
+* Syntax: done (ID as number)
+
+Examples:
+
+done 2
+
+ Nice! I've marked this task as done:
+ [E][✓] concert (at: 12:00-14:00)
+
+
+### List
+Lists out all the current tasks that the user has
+
+##User can use it to check and keep track of
+ current tasks she has, and how many she has completed and how many she has uncompleted
+
+The tasks are given in order in which it has been added and tick represents completed tasks
+Cross represents undone tasks
+
+* Syntax: list
+
+Examples:
+
+ 1. [T][✓] buy book
+ 2. [E][✓] concert (at: 12:00-14:00)
+ 3. [T][✗] read book
+ 4. [T][✗] read book
+
+### Exit
+Used to exit app
+
+##After this one more input would lead to the app to close immediately
+
+After this, a bye message would be printed, then another input causes the app to close immediately.
+
+* Syntax: bye
+
+Examples of usage:
+Bye
+
+ Bye. Hope to see you again soon!
+
+###ShortCuts
+This is to make app more user friendly so that users do not have to type much
+
+## User can use existing short forms or define own short forms
+
+ShortForms-Original
+ * b - Bye
+ * t - todo
+ * e - event
+ * s - short
+ * l -list
+ * de - deadline
+ * do - done
+ * d - delete
+ * f - find
+You can also define your own short forms using syntax shown below:
+short (original) (short form)
+* Syntax: (short form) (same format as original excluding key word)
+
+Example:
+b
+
+ Bye. Hope to see you again soon!
+
+You can also define your own short cuts
+
+##You can use a short cuts, that is user defined
+
+Syntax: short (original form) (short form)
+
+Example:
+by
+
+ short cut successfully added
+
+Example of using user defined short cut:
+by
+
+ Bye. Hope to see you again soon!
+
+### Random Command
+If you insert none of the above commands a random command would be given
+
+Example: blah
+
+ '☹ OOPS!!! I'm sorry, but I don't know what that means :-(
\ No newline at end of file
diff --git a/docs/Ui.png b/docs/Ui.png
new file mode 100644
index 0000000000..b664a62da3
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..26bfbb87eb
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Sep 09 11:19:39 SGT 2020
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-all.zip
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
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/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..2c9a9745c5
--- /dev/null
+++ b/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: duke.Duke
+
diff --git a/src/main/java/duke/DialogBox.java b/src/main/java/duke/DialogBox.java
new file mode 100644
index 0000000000..f06d658116
--- /dev/null
+++ b/src/main/java/duke/DialogBox.java
@@ -0,0 +1,107 @@
+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.layout.Background;
+import javafx.scene.layout.BackgroundFill;
+import javafx.scene.layout.Border;
+import javafx.scene.layout.BorderStroke;
+import javafx.scene.layout.BorderStrokeStyle;
+import javafx.scene.layout.CornerRadii;
+import javafx.scene.layout.HBox;
+import javafx.scene.paint.Color;
+import javafx.scene.paint.ImagePattern;
+import javafx.scene.shape.Circle;
+import javafx.scene.text.Font;
+import javafx.scene.text.FontPosture;
+import javafx.scene.text.FontWeight;
+
+
+
+/**
+ * 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; //displays String given by user or Duke
+ @FXML
+ private Circle circleDisplayPicture; //display picture of Duke or user
+
+ /**
+ * Constructor for DialogBox used to initialize DialogBox object
+ *
+ * @param text is input placed in dialog
+ * @param img used in the image for circleDisplayPicture
+ */
+ 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);
+ dialog.setBackground(new Background(new BackgroundFill(Color.THISTLE, new CornerRadii(5), null)));
+ circleDisplayPicture.setRadius(50);
+ circleDisplayPicture.setFill(new ImagePattern(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);
+ }
+
+ /**
+ * Gives the DialogBox of the user
+ *
+ * @param text input by the user
+ * @param img user image
+ * @return DialogBox of user
+ */
+ public static DialogBox getUserDialog(String text, Image img) {
+ var db = new DialogBox(text, img);
+ db.setBackground(new Background(new BackgroundFill(Color.MISTYROSE, new CornerRadii(20), null)));
+ //sets background to MISTYROSE
+ db.setBorder(new Border(new BorderStroke(Color.BLACK, BorderStrokeStyle.DOTTED,
+ new CornerRadii(20), null))); //sets dotted border
+ return db;
+ }
+
+ /**
+ * Gives the DialogBox of Duke
+ *
+ * @param response input by duke in response to the input given by user
+ * @param img Duke image
+ * @return DialogBox of Duke
+ */
+ public static DialogBox getDukeDialog(Response response, Image img) {
+ String text = response.getOutput();
+ var db = new DialogBox(text, img);
+ db.dialog.setFont(Font.font("Times new Roman"));
+ db.setBackground(new Background(new BackgroundFill(Color.SALMON, new CornerRadii(20), null)));
+ //sets background to salmon
+ db.flip(); //to have a Duke appear on different side
+ if (response.getIsException()) {
+ db.dialog.setFont(Font.font("Times new Roman", FontWeight.BOLD, FontPosture.ITALIC, 12));
+ //when the response given is an exception, it is emphasized with BOLD and italic
+ } else { }
+ return db;
+ }
+}
diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java
new file mode 100644
index 0000000000..da78ebf3fd
--- /dev/null
+++ b/src/main/java/duke/Duke.java
@@ -0,0 +1,152 @@
+package duke;
+
+import java.io.IOException;
+
+import duke.commands.Command;
+import duke.errors.DukeException;
+import duke.helpers.Parser;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.helpers.Ui;
+
+
+/**
+ * This Duke class is the main class that prints out the relevant outputs based on input given by user
+ */
+public class Duke {
+ private boolean isExit = false;
+ //checks whether the Duke has been given the user command, true if exit command is given and false otherwise
+ private Storage storage; //deals with loading tasks from the file, saving tasks and shortcuts in the file
+ private TaskList tasks; //contains the task list e.g., it has operations to add/delete tasks in the list
+ private Ui ui = new Ui(); //deals with interactions with the user
+
+ /**
+ * A constructor used to initialise Duke.
+ */
+ public Duke(){}
+
+ /**
+ * Assigns the above member variables with the appropriate values, and throws certain exceptions if file in
+ * the filePath mentioned is empty or absent
+ *
+ * @param filePath represents where the filepath of where the file may exist.
+ * @param shortFormPath contains all the pre user defined short forms
+ */
+ public Duke(String filePath, String shortFormPath) {
+ ui = new Ui();
+ storage = new Storage(filePath, shortFormPath);
+ try {
+ tasks = new TaskList(storage.load());
+ storage.setShortForm();
+ } catch (DukeException e) {
+ ui.setDukeException(e);
+ ui.showLoadingError();
+ tasks = new TaskList();
+ }
+ }
+
+ /**
+ * Assigns the above member variables with the appropriate values, and throws certain exceptions if file in
+ * the filePath mentioned is empty or absent
+ *
+ * @param filePath represents where the filepath of where the file may exist.
+ * @param input filepath for the inputs
+ * @param shortFormPath filepath for file containing short cuts
+ */
+ public Duke(String filePath, String input, String shortFormPath) {
+ storage = new Storage(filePath, shortFormPath);
+ try {
+ ui = new Ui(input);
+ tasks = new TaskList(storage.load());
+ } catch (DukeException e) {
+ ui.setDukeException(e);
+ ui.showLoadingError();
+ tasks = new TaskList();
+ }
+ }
+ /**
+ * This gives the boolean value of isExit
+ *
+ * @return returns the value of isExit.
+ */
+ public boolean isExit() {
+ return isExit;
+ }
+
+ /**
+ * This gives the respective output based on the input
+ *
+ * @param inputs what the user inputs in the GUI, can be multiple inputs.
+ * @return the output based on the output in the form of an array, where
+ */
+ public Response[] getResponse(String... inputs) {
+ Response[] responses = new Response[inputs.length];
+ for (int i = 0; i < inputs.length; i++) {
+ String input = inputs[i];
+ Response response = getResponse(input); //receives input depending on input depending on
+ responses[i] = response;
+ }
+ return responses;
+ }
+
+ /**
+ * Returns a Response depending on the input given by the user
+ *
+ * @param input given by user
+ * @return Response with a boolean value true if the user input is wrong, leading to an exception
+ */
+ private Response getResponse(String input) {
+ Command c = Parser.parse(input); //respective command depending on input
+ Response response;
+ String output;
+ try {
+ isExit = c.isExit();
+ output = c.execute(tasks, new Ui(), storage); //concatenates output message
+ response = new Response(output, false); //since user input is in correct
+ } catch (DukeException e) {
+ output = e.getMessage(); //concatenates error message
+ response = new Response(output, true); //since user input is wrong
+ }
+ return response;
+ }
+ /**
+ * gives main logic of the App,
+ * where exceptions are caught and printed and if bye is there code stops. also starts with hello
+ */
+ public void run() {
+ ui.showWelcome();
+ ui.showLine();
+ boolean isExit = false;
+ while (!isExit) {
+ try {
+ String fullCommand = ui.readCommand();
+ ui.showLine(); // show the divider line ("_______")
+ Command c = Parser.parse(fullCommand);
+ System.out.println(c.execute(tasks, ui, storage));
+ isExit = c.isExit(); //if true exits program as bye is mentioned
+ } catch (DukeException e) {
+ ui.showLoadingError();
+ } finally {
+ ui.showLine();
+ }
+ }
+ }
+ /**
+ *
+ * @param args of type String[]
+ * reads input using scan() and adds it to todos.
+ * Then, prints out relevant information using the output() func.
+ */
+ public static void main(String[] args) throws IOException {
+ Duke duke = new Duke("src/main/java/tasks.txt", "src/main/java/shortCuts.txt");
+ duke.run();
+ //String s = duke.getResponse("ToDo read book");
+ /*PrintStream fileOut = new PrintStream("src/main/java/output.txt");
+ System.setOut(fileOut);
+ FileWriter fw = new FileWriter("src/main/java/tasks.txt");
+ fw.write("");
+ fw.close();
+ Duke duke = new Duke("src/main/java/tasks.txt", "src/main/java/input.txt", "src/main/java/shortCuts.txt");
+ duke.run();*/
+ }
+}
diff --git a/src/main/java/duke/Launcher.java b/src/main/java/duke/Launcher.java
new file mode 100644
index 0000000000..fd3e841ece
--- /dev/null
+++ b/src/main/java/duke/Launcher.java
@@ -0,0 +1,18 @@
+package duke;
+
+import javafx.application.Application;
+
+/**
+ * Class that launches GUI for Duke
+ */
+public class Launcher {
+ /**
+ * Launches the GUI
+ *
+ * @param 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..c3a592253f
--- /dev/null
+++ b/src/main/java/duke/Main.java
@@ -0,0 +1,43 @@
+package duke;
+
+import java.io.IOException;
+
+import javafx.application.Application;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Scene;
+import javafx.scene.layout.Background;
+import javafx.scene.layout.BackgroundFill;
+import javafx.scene.paint.Color;
+import javafx.stage.Stage;
+
+/**
+ * A GUI for Duke.
+ */
+public class Main extends Application {
+ private Duke duke = new Duke("tasks.txt", "shortCuts.txt");
+
+ /**
+ * Implements the abstract start method in Application class
+ *
+ * @param stage it is to show the main screen
+ */
+ @Override
+ public void start(Stage stage) {
+ if (duke.isExit()) {
+ stage.close();
+ }
+ try {
+ stage.setTitle("Duke");
+ FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml"));
+ MainWindow ap = fxmlLoader.load();
+ ap.setBackground(new Background(new BackgroundFill(Color.BLACK, null, null)));
+ Scene scene = new Scene(ap);
+ stage.setScene(scene);
+ fxmlLoader.getController().setDuke(duke, stage);
+ 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..9b8a5ed57e
--- /dev/null
+++ b/src/main/java/duke/MainWindow.java
@@ -0,0 +1,75 @@
+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.HBox;
+import javafx.scene.layout.VBox;
+import javafx.stage.Stage;
+
+/**
+ * Controller for Duke.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;
+ @FXML
+ private TextField display;
+ 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"));
+ private Stage stage;
+
+ /**
+ * Initializes scrollPane
+ */
+ @FXML
+ public void initialize() {
+ scrollPane.vvalueProperty().bind(dialogContainer.heightProperty());
+ }
+
+ /**
+ * Also ensures that the getDukeDialog prints hello when opened
+ *
+ * @param d assigns duke value of d
+ * @param stage assigns stage value of stage
+ */
+ public void setDuke(Duke d, Stage stage) {
+ duke = d;
+ this.stage = stage;
+ Response hello = new Response(" Hello! I'm Duke\n" + " What can I do for you?", false);
+ //opening message and isException is false as it is not an error
+ dialogContainer.getChildren().add(DialogBox.getDukeDialog(hello, dukeImage)); //Introduction given by Duke
+ }
+
+ /**
+ * 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() {
+ if (duke.isExit()) {
+ stage.close(); //since bye message is given
+ }
+ String input = userInput.getText(); //input can be multiple input separated by ',' sign
+ String[] inputs = input.split(", ");
+ Response[] responses = duke.getResponse(inputs); //response given by duke
+ for (int i = 0; i < inputs.length; i++) {
+ DialogBox user = DialogBox.getUserDialog(inputs[i], userImage); //DialogBox for user
+ DialogBox dukeResponse = DialogBox.getDukeDialog(responses[i], dukeImage); //DialogBox from Duke
+ dialogContainer.getChildren().addAll(user, dukeResponse); //Duke input displayed
+ }
+ userInput.clear();
+ HBox buttonsContainer = new HBox();
+ buttonsContainer.getStyleClass().add("jfx-decorator-buttons-container");
+ }
+}
diff --git a/src/main/java/duke/Response.java b/src/main/java/duke/Response.java
new file mode 100644
index 0000000000..bffa3102f3
--- /dev/null
+++ b/src/main/java/duke/Response.java
@@ -0,0 +1,38 @@
+package duke;
+
+/**
+ * Returns the Response to the input given by user
+ */
+public class Response {
+ private String output; //string output given by Duke
+ private boolean isException; //tests whether the output given is an exception
+
+ /**
+ * Constructor that assigns respective values to
+ *
+ * @param response
+ * @param isException
+ */
+ public Response(String response, boolean isException) {
+ this.output = response;
+ this.isException = isException;
+ }
+
+ /**
+ * Returns String value of response
+ *
+ * @return value of output
+ */
+ public String getOutput() {
+ return output;
+ }
+
+ /**
+ * Returns value of isException
+ *
+ * @return boolean value of isException, which is true if Duke gives exception and false otherwise
+ */
+ public boolean getIsException() {
+ return isException;
+ }
+}
diff --git a/src/main/java/duke/commands/AddCommand.java b/src/main/java/duke/commands/AddCommand.java
new file mode 100644
index 0000000000..bdecb560e1
--- /dev/null
+++ b/src/main/java/duke/commands/AddCommand.java
@@ -0,0 +1,58 @@
+package duke.commands;
+
+import java.io.FileWriter;
+import java.io.IOException;
+
+import duke.errors.DukeException;
+import duke.errors.FileAbsentException;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.tasks.Task;
+
+/**
+ * This class handles the case of adding different tasks which are ToDo, deadline and Event
+ */
+public abstract class AddCommand extends Command {
+ /**
+ * constructor that assigns string value of string
+ *
+ * @param input passes it to super class constructor
+ */
+ public AddCommand(String input, int lengthOfKeyword) {
+ super(input, lengthOfKeyword);
+ }
+
+ /**
+ * Gives a String saying that the task list has been updated
+ *
+ * @param task to be added into taskList
+ * @param taskList where task is added
+ * @return String that informs task is added into taskList
+ */
+ protected static String stringToUpdateTaskList(Task task, TaskList taskList) {
+ return " Got it. I've added this task:\n " + task.toString() + "\n" + //Task added message
+ " Now you have " + taskList.getAllTasks().size() + " tasks in the list.";
+ }
+
+ /**
+ * adds the task to list of task in taskList and into the file in storage
+ *
+ * @param storage where the file here is updated
+ * @param task this task is added into storage and taskList
+ * @param taskList where the tasks here is updated with task added
+ * @throws DukeException when the file in storage is not present
+ */
+ protected static String updateTaskList(Storage storage, Task task, TaskList taskList) throws DukeException {
+ try {
+ FileWriter fw = new FileWriter(storage.getFilePath(), true);
+ //updates the file in storage as new task is added
+ taskList.getAllTasks().add(task);
+ fw.write(task.inputListFormat() + "\n");
+ fw.close();
+ } catch (IOException i) {
+ throw new FileAbsentException(storage.getFilePath());
+ }
+ return stringToUpdateTaskList(task, taskList);
+ }
+
+}
diff --git a/src/main/java/duke/commands/Command.java b/src/main/java/duke/commands/Command.java
new file mode 100644
index 0000000000..7a132248ad
--- /dev/null
+++ b/src/main/java/duke/commands/Command.java
@@ -0,0 +1,59 @@
+package duke.commands;
+
+import duke.errors.DukeException;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.helpers.Ui;
+
+/**
+ * this is an abstract class used for polymorphism, parent class of all Command classes
+ */
+public abstract class Command {
+ /**
+ * commandName which contains information on task and details to perform task
+ * isExit is used to tell whether program terminates, where id true, it terminates
+ */
+ protected String userInput; //the String input given by user
+ protected int lengthOfKeyword; //length of keyword eg for find is 4
+ private boolean isExit = false;
+
+ /**
+ * Assigns string to a value
+ *
+ * @param userInput assigns this.string to string
+ * @param lengthOfKeyword assigns this to this.lengthOfKeyword
+ */
+ public Command(String userInput, int lengthOfKeyword) {
+ this.userInput = userInput;
+ this.lengthOfKeyword = lengthOfKeyword;
+ }
+
+ /**
+ * gets value of exit
+ * @return exit
+ */
+ public boolean isExit() {
+ return this.isExit;
+ }
+
+ /**
+ * Executes the necessary task
+ *
+ * @param tasks used to access tasks in its list and change if necessary
+ * @param ui used to assign ui's dukeException if there is an error in user input
+ * @param storage to change the input there if necessary
+ * @throws DukeException if there are exceptions present
+ */
+ public abstract String execute(TaskList tasks, Ui ui, Storage storage) throws DukeException;
+
+ /**
+ * Returns whether the number/description is present.
+ *
+ * @return true is the number/description is absent and false if number is present.
+ */
+ protected boolean isNumberOrDescriptionAbsent() {
+ return userInput.length() == lengthOfKeyword || userInput.length() == lengthOfKeyword + 1;
+ //since the delete number appears after length of keyword/+1
+ }
+
+}
diff --git a/src/main/java/duke/commands/DeadlineCommand.java b/src/main/java/duke/commands/DeadlineCommand.java
new file mode 100644
index 0000000000..7327b5b75e
--- /dev/null
+++ b/src/main/java/duke/commands/DeadlineCommand.java
@@ -0,0 +1,55 @@
+package duke.commands;
+
+import duke.errors.DeadlineException;
+import duke.errors.DukeException;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.helpers.Ui;
+import duke.tasks.Deadline;
+
+/**
+ * Handles when input is deadline
+ */
+public class DeadlineCommand extends AddCommand {
+ /**
+ * assigns string to a value of string and initialize Deadline Command
+ *
+ * @param input assigns string to this this.string
+ * @param lengthOfKeyword assigns this to this.lengthOfKeyword
+ */
+ public DeadlineCommand(String input, int lengthOfKeyword) {
+ super(input, lengthOfKeyword);
+ }
+
+ /**
+ * to add deadline into a task list in TaskList
+ *
+ * @param tasks to change the taskList if necessary
+ * @param ui to store the DukeException that may be thrown if there is an error in user input
+ * @param storage to change the file in the if necessary
+ * @return String returns the string of the output that informs the action is successful
+ * @throws DukeException whenever there is an error, where the time adn or date is absent or in wrong format, no
+ * description
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws DukeException {
+ try {
+ exceptionThrownIfNumberOrDescriptionAbsent();
+ return Deadline.addDeadlineTask(tasks, ui, storage, userInput);
+ } catch (DukeException dukeException) {
+ ui.setDukeException(dukeException);
+ throw dukeException;
+ }
+ }
+
+ /**
+ * Test whether description is absent and exception is thrown if absent
+ *
+ * @throws DukeException thrown if description for event is absent
+ */
+ protected void exceptionThrownIfNumberOrDescriptionAbsent() throws DukeException {
+ if (isNumberOrDescriptionAbsent()) {
+ throw new DeadlineException(true, false, false); //Since description is absent
+ }
+ }
+
+}
diff --git a/src/main/java/duke/commands/DeleteCommand.java b/src/main/java/duke/commands/DeleteCommand.java
new file mode 100644
index 0000000000..eb245d977f
--- /dev/null
+++ b/src/main/java/duke/commands/DeleteCommand.java
@@ -0,0 +1,153 @@
+package duke.commands;
+
+import java.io.FileWriter;
+import java.io.IOException;
+
+import duke.errors.DeleteException;
+import duke.errors.DukeException;
+import duke.errors.FileAbsentException;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.helpers.Ui;
+
+/**
+ * Handles the case when the keyword is delete
+ */
+public class DeleteCommand extends Command {
+ /**
+ * assigns string to a value of string
+ *
+ * @param input assigns string to this this.string
+ * @param lengthOfKeyword assigns this to this.lengthOfKeyword
+ */
+ public DeleteCommand(String input, int lengthOfKeyword) {
+ super(input, lengthOfKeyword);
+ }
+
+ /**
+ * Deletes task and handles error
+ *
+ * @param tasks to change the taskList since item is deleted
+ * @param ui to set its dukeException variable is exception is thrown
+ * @param storage to change the file since item is deleted
+ * @return String returns the string of the output that informs the delete action has been complete.
+ * @throws DukeException thrown if the ID is more than number of ID is absent
+ */
+ @Override
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws DukeException {
+ try {
+ return process(tasks, storage);
+ } catch (DukeException dukeException) {
+ ui.setDukeException(dukeException);
+ throw dukeException;
+ }
+ }
+
+ /**
+ * Returns a String if the input is given in the correct order, else Exception is thrown
+ *
+ * @param tasks is used to check whether the tasks to be found is present in TaskList, to delete the task
+ * @param storage is used to update the file in storage that contains current tasks, to remove it from the file
+ * @return String if the user input is correct
+ * @throws DukeException if the user input is wrong
+ */
+ private String process(TaskList tasks, Storage storage) throws DukeException {
+ if (isNumberOrDescriptionAbsent()) {
+ throw new DeleteException(true, false); //when number is absent
+ } else {
+ int id = Integer.parseInt(userInput.substring(lengthOfKeyword + 1));
+ if (isNumberNotInList(id, tasks)) {
+ throw new DeleteException(false, true); //when ID is more than number of tasks in list
+ } else {
+ return rewrite(storage, tasks, id); //to update TaskList and file in Storage
+ }
+ }
+ }
+ /**
+ * Returns whether the task is present in the list.
+ *
+ * @param iD of task to be removed
+ * @param tasks from which the task is to be removed.
+ * @return true if the task is not present in list.
+ */
+ private boolean isNumberNotInList(int iD, TaskList tasks) {
+ return iD > tasks.getAllTasks().size(); //ID cannot be more than length of tasks
+ }
+
+ /**
+ * Returns the String informing that the task is deleted
+ *
+ * @param tasks uses to give the current number of tasks
+ * @param iD uses to get the task to be deleted.
+ * @return String informing that the task is deleted.
+ */
+ private String deleteTaskString(TaskList tasks, int iD) {
+ return " Noted. I've removed this task:\n" + // gives delete message
+ " " + tasks.getAllTasks().get(iD - 1).toString() + "\n"
+ + " Now you have " + (tasks.getAllTasks().size() - 1) + " tasks in the list.";
+ }
+
+ /**
+ * updates the the file in storage after task is deleted.
+ *
+ * @param newList where this is the new input replaces the old input in the file
+ * @param storage which contains file to be changed
+ * @throws FileAbsentException when the file to be updated is absent in Storage
+ */
+ private void updateTaskInStorage(String newList, Storage storage) throws FileAbsentException {
+ try {
+ FileWriter fw = new FileWriter(storage.getFilePath()); //updates the file in Storage with new String
+ fw.write(newList);
+ fw.close();
+ } catch (IOException i) {
+ throw new FileAbsentException(storage.getFilePath());
+ }
+ }
+
+ /**
+ * gives the string for the new task list
+ *
+ * @param tasks contains current tasks
+ * @return the string for the new task list
+ */
+ private String newInputInStorageFIle(TaskList tasks) {
+ String s = "";
+ for (int i = 0; i < tasks.getAllTasks().size(); i++) {
+ s = s + tasks.getAllTasks().get(i).inputListFormat() + "\n";
+ // Task of ID is deleted and then the String of tasks is updated
+ }
+ return s;
+ }
+
+ /**
+ * Removes task that has to be deleted from TaskList
+ *
+ * @param tasks where task with index (ID - 1) is removed
+ * @param iD gives information on which task to remove.
+ */
+ private void deleteTaskInTaskList(TaskList tasks, int iD) {
+ tasks.getAllTasks().remove(iD - 1); //removes task with ID from task
+ }
+ /**
+ * This returns the string that the task has been deleted and also updated the TakList.
+ *
+ * @param storage in which the file is updated.
+ * @param tasks used to update the task for the task to be deleted.
+ * @param iD of the task to be deleted.
+ * @return String saying that task has been deleted.
+ * @throws DukeException throws if file is absent
+ */
+ private String rewrite(Storage storage, TaskList tasks, int iD) throws DukeException {
+ try {
+ String message = deleteTaskString(tasks, iD);
+ deleteTaskInTaskList(tasks, iD); //deleted the task with ID in TaskList
+ String newTaskList = newInputInStorageFIle(tasks); //gives new file input and deletes
+ updateTaskInStorage(newTaskList, storage); //replaces old list in storage file with this
+ return message;
+ } catch (DukeException dukeException) {
+ throw new FileAbsentException(storage.getFilePath());
+ }
+ }
+
+}
+
diff --git a/src/main/java/duke/commands/DoneCommand.java b/src/main/java/duke/commands/DoneCommand.java
new file mode 100644
index 0000000000..d69c6a2733
--- /dev/null
+++ b/src/main/java/duke/commands/DoneCommand.java
@@ -0,0 +1,153 @@
+package duke.commands;
+
+import java.io.FileWriter;
+import java.io.IOException;
+
+import duke.errors.DoneException;
+import duke.errors.DukeException;
+import duke.errors.FileAbsentException;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.helpers.Ui;
+import duke.tasks.Task;
+
+/**
+ * Handles case when done is keyword
+ */
+public class DoneCommand extends Command {
+ /**
+ * assigns string to a value of string
+ *
+ * @param input assigns string to this this.string
+ * @param lengthOfKeyword assigns this to this.lengthOfKeyword
+ */
+ public DoneCommand (String input, int lengthOfKeyword) {
+ super(input, lengthOfKeyword);
+ }
+
+ /**
+ * Completes done task and handle error
+ *
+ * @param tasks to change the taskList as a task is completed
+ * @param ui to store the DukeException that may be thrown if there is an error in user input
+ * @param storage to change the file as task is completed
+ * @return String returns the string of the output that informs the done action has been complete.
+ * @throws DukeException thrown if the ID is more than number of ID is absent
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws DukeException {
+ try {
+ return process(tasks, storage);
+ } catch (DukeException dukeException) {
+ ui.setDukeException(dukeException);
+ throw dukeException;
+ }
+ }
+
+ /**
+ * Returns a String if the input is given in the correct order, else Exception is thrown
+ *
+ * @param tasks is used to check whether the tasks to be found is present in TaskList, to mark as done
+ * @param storage is used to update the file in storage that contains current tasks, to mark that task as done
+ * @return String if the user input is correct
+ * @throws DukeException if the user input is wrong
+ */
+ private String process(TaskList tasks, Storage storage) throws DukeException {
+ if (isNumberOrDescriptionAbsent()) {
+ throw new DoneException(true, false, false); //when number is absent
+ } else {
+ int iD = Integer.parseInt(userInput.substring(lengthOfKeyword + 1));
+ if (isNumberNotInList(iD, tasks)) {
+ throw new DoneException(false, true, false); //when number is not in list
+ } else if (isDone(iD, tasks)) {
+ throw new DoneException(false, false, true);
+ } else {
+ return rewrite(storage, tasks, iD); //where the file in Storage is updated and TaskList is updated
+ }
+ }
+ }
+ /**
+ * Returns whether the task is present in the list.
+ *
+ * @param iD of task to be removed
+ * @param tasks from which the task is to be removed.
+ * @return true if the task is not present in list.
+ */
+ private boolean isNumberNotInList(int iD, TaskList tasks) {
+ return iD > tasks.getAllTasks().size(); //since ID cannot be more that number of tasks present
+ }
+
+ /**
+ * Gives whether the task at a particular input has been completed
+ *
+ * @param iD of the task that user wants to mark as complete
+ * @param tasks where you want
+ * @return true if task is completed and false otherwise
+ */
+ private boolean isDone(int iD, TaskList tasks) {
+ Task task = tasks.getAllTasks().get(iD - 1);
+ return task.getIsDone();
+ }
+ /**
+ * updates the the file in storage after task is marked as done.
+ *
+ * @param newList where this is the new input replaces the old input in the file.
+ * @param storage which contains file to be changed.
+ * @throws FileAbsentException when the file to be updated is absent in Storage.
+ */
+ private void updateTaskInStorage(String newList, Storage storage) throws FileAbsentException {
+ try {
+ FileWriter fw = new FileWriter(storage.getFilePath());
+ fw.write(newList); //updates task list to newList since one task is marked as done
+ fw.close();
+ } catch (IOException i) {
+ throw new FileAbsentException(storage.getFilePath());
+ }
+ }
+
+ /**
+ * gives the string for the new task list
+ *
+ * @param tasks marks the task as done
+ * @return the string for the new task list
+ */
+ private String newInputInStorageFIle(TaskList tasks) {
+ String s = "";
+ for (int i = 0; i < tasks.getAllTasks().size(); i++) {
+ s = s + tasks.getAllTasks().get(i).inputListFormat() + "\n";
+ //new taskList String since done is being set for task with iD mentioned by user
+ }
+ return s;
+ }
+
+ /**
+ * Returns the String informing that the task that is marked as done
+ *
+ * @param tasks uses to give the current number of tasks.
+ * @param iD uses to get the task to mark done.
+ * @return String informing that the task is marked as done.
+ */
+ private String doneMessage(TaskList tasks, int iD) {
+ return " Nice! I've marked this task as done:\n" + " "
+ + tasks.getAllTasks().get(iD - 1).toString(); //gives the doneMessage
+ }
+ /**
+ * This returns the string that the task has been deleted adn also updated the TakList.
+ *
+ * @param storage in which the file is updated.
+ * @param tasks used to update the task for the task to mark as done.
+ * @param iD of the task to mark as done.
+ * @return String of done message
+ * @throws DukeException throws if file is absent
+ */
+ private String rewrite(Storage storage, TaskList tasks, int iD) throws DukeException {
+ tasks.getAllTasks().get(iD - 1).setDone(true); //sets the task at (ID - 1) as done
+ String s = newInputInStorageFIle(tasks); //new List for storage file
+ try {
+ updateTaskInStorage(s, storage); //updates the TaskList and the file in storage file
+ return doneMessage(tasks, iD); // returns done message
+ } catch (FileAbsentException f) {
+ throw new FileAbsentException(storage.getFilePath());
+ }
+ }
+
+}
diff --git a/src/main/java/duke/commands/EventCommand.java b/src/main/java/duke/commands/EventCommand.java
new file mode 100644
index 0000000000..32b67eda1d
--- /dev/null
+++ b/src/main/java/duke/commands/EventCommand.java
@@ -0,0 +1,56 @@
+package duke.commands;
+
+import duke.errors.DukeException;
+import duke.errors.EventException;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.helpers.Ui;
+import duke.tasks.Event;
+
+/**
+ * Handles cases when Event is keyword
+ */
+public class EventCommand extends AddCommand {
+ /**
+ * Assigns string to a value of string
+ *
+ * @param input assigns string to this this.string
+ * @param lengthOfKeyword assigns this to this.lengthOfKeyword
+ */
+ public EventCommand(String input, int lengthOfKeyword) {
+ super(input, lengthOfKeyword);
+ }
+
+ /**
+ * Adds Event task or handle exceptions
+ *
+ * @param tasks to change the taskList if necessary when no error
+ * @param ui to store the DukeException that may be thrown if there is an error in user input
+ * @param storage to change the file in the if necessary when no error
+ * @return String returns the string of the output that informs the action has been complete.
+ * @throws DukeException if there no description after Event no time or time is wrong format
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws DukeException {
+ try {
+ exceptionThrownIfNumberOrDescriptionAbsent();
+ return Event.addEventTask(tasks, ui, storage, userInput);
+ //Returns string if correct input and updates tasks and file in storage if correct input by user, else
+ // throws exception
+ } catch (DukeException dukeException) {
+ ui.setDukeException(dukeException);
+ throw dukeException;
+ }
+ }
+
+ /**
+ * Test whether description is absent and exception is thrown if absent
+ *
+ * @throws DukeException thrown if description for event is absent
+ */
+ protected void exceptionThrownIfNumberOrDescriptionAbsent() throws DukeException {
+ if (isNumberOrDescriptionAbsent()) { //tests whether the description is absent
+ throw new EventException(true, false, false, false, false);
+ }
+ }
+}
+
diff --git a/src/main/java/duke/commands/ExitCommand.java b/src/main/java/duke/commands/ExitCommand.java
new file mode 100644
index 0000000000..01be963a02
--- /dev/null
+++ b/src/main/java/duke/commands/ExitCommand.java
@@ -0,0 +1,51 @@
+package duke.commands;
+
+import duke.errors.DukeException;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.helpers.Ui;
+
+/**
+ * Handles case when exit is the keyword
+ */
+public class ExitCommand extends Command {
+ /**
+ * assigns string to a value of string
+ * @param input assigns string to this this.string
+ * @param lengthOfKeyword assigns this to this.lengthOfKeyword
+ */
+ public ExitCommand(String input, int lengthOfKeyword) {
+ super(input, lengthOfKeyword);
+ }
+
+ /**
+ * Gives the exit message
+ *
+ * @return String of exit message.
+ */
+ private String exitMessage() {
+ return " Bye. Hope to see you again soon!";
+ }
+ /**
+ * Prints bye message
+ *
+ * @param tasks no change made
+ * @param ui
+ * @param storage no change made
+ * @return String returns the string of the output that informs the exit action has been complete.
+ * @throws DukeException not thrown here
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws DukeException {
+ return exitMessage();
+ }
+
+ /**
+ * Returns true to exit program
+ *
+ * @return true to exit program
+ */
+ @Override
+ public boolean isExit() {
+ return true;
+ }
+}
diff --git a/src/main/java/duke/commands/FindCommand.java b/src/main/java/duke/commands/FindCommand.java
new file mode 100644
index 0000000000..07326043dc
--- /dev/null
+++ b/src/main/java/duke/commands/FindCommand.java
@@ -0,0 +1,140 @@
+package duke.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import duke.errors.DukeException;
+import duke.errors.FindException;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.helpers.Ui;
+import duke.tasks.Task;
+
+/**
+ * Handles case where find is keyword
+ */
+public class FindCommand extends Command {
+ private List tasks = new ArrayList<>();
+ //contains list of Task objects whose name contains words after the find keyword
+
+ /**
+ * Assigns string to a value of string
+ *
+ * @param input assigns string to this this.string
+ * @param lengthOfKeyword assigns this to this.lengthOfKeyword
+ */
+ public FindCommand(String input, int lengthOfKeyword) {
+ super(input, lengthOfKeyword);
+ }
+
+ /**
+ * Finds the tasks which contains keyword in string
+ *
+ * @param tasks to look for the task's string value
+ * @param ui to store the DukeException that may be thrown if there is an error in user input
+ * @param storage no need
+ * @return String returns the string of the output that informs the find action is successful.
+ * @throws DukeException used to throw error when no words mentioned after find or the keyword is not present in
+ * tasks.
+ */
+ @Override
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws DukeException {
+ try {
+ return process(tasks);
+ //Returns string if correct input and updates tasks and file in storage if correct input by user, else
+ // throws exception
+ } catch (DukeException dukeException) {
+ ui.setDukeException(dukeException);
+ throw dukeException;
+ }
+ }
+
+ /**
+ * Returns String informing user that find command is successful otherwise throws FindException
+ *
+ * @param tasks to access the tasks to find out the description used and to compare keywords given for this command
+ * @return String if user input is in correct format
+ * @throws FindException when user input is given in wrong format
+ */
+ public String process(TaskList tasks) throws FindException {
+ if (isNumberOrDescriptionAbsent()) {
+ throw new FindException(false, true, "");
+ }
+ String find = userInput.substring(5);
+ String[] strings = find.split(" ", -2); // keywords split into different Strings
+ setTasks(strings, tasks);
+ if (this.tasks.size() == 0) {
+ throw new FindException(true, false, find);
+ } else {
+ return findMessage();
+ }
+ }
+ /**
+ * sets the Tasks list here with Tasks containing words given by user.
+ *
+ * @param strings contains String of key words
+ * @param tasks contains all the current tasks
+ */
+ private void setTasks(String[] strings, TaskList tasks) {
+ List allTasks = tasks.getAllTasks();
+ for (int i = 0; i < tasks.getAllTasks().size(); i++) {
+ Task task = allTasks.get(i);
+ String string = task.getName(); //gives name of Task object
+ String[] comp = string.split(" ", -2); //split object into separate words
+ boolean contains = taskContainsUserWords(strings, comp); //
+ if (contains) {
+ this.tasks.add(task); //if contains is true, Task is added to ArrayList of tasks.
+ }
+ }
+ }
+
+ /**
+ * Checks whether the Task contains the words given by user
+ *
+ * @param strings array of Task name split into different words
+ * @param comp array of user words split into different words
+ * @return true is task contains words given by user and false otherwise
+ */
+ private boolean taskContainsUserWords(String[] strings, String[] comp) {
+ boolean contains = false;
+ for (int j = 0; j < strings.length; j++) {
+ String word = strings[j];
+ contains = wordPresentInUserWords(word, comp);
+ }
+ return contains;
+ }
+
+ /**
+ * Checks whether a word is the same as the array of words(String) given by user
+ *
+ * @param word a word from from Task name
+ * @param comp array of words given by user
+ * @return true if word is contained in comp and false otherwise
+ */
+ private boolean wordPresentInUserWords(String word, String[] comp) {
+ boolean contains = false;
+ for (int k = 0; k < comp.length; k++) {
+ if (comp[k].equals(word)) { //checks whether Task name/description contains keywords given by user
+ contains = true; //then assigns contains true if that is the case
+ break;
+ }
+ }
+ return contains;
+ }
+ /**
+ * Prints out the find message
+ *
+ * @return String of response
+ */
+ private String findMessage() {
+ String s = " Here are the matching tasks in your list:";
+ for (int i = 0; i < this.tasks.size(); i++) {
+ Task task = this.tasks.get(i);
+ s = s + "\n" + " " + (i + 1) + "." + task.toString(); // concatenates all the Task present in tasks
+ }
+ return s;
+ }
+
+
+}
+
diff --git a/src/main/java/duke/commands/ListCommand.java b/src/main/java/duke/commands/ListCommand.java
new file mode 100644
index 0000000000..125313b498
--- /dev/null
+++ b/src/main/java/duke/commands/ListCommand.java
@@ -0,0 +1,50 @@
+package duke.commands;
+
+import duke.errors.DukeException;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.helpers.Ui;
+
+/**
+ * Used to handle case when list is the keyword
+ */
+public class ListCommand extends Command {
+ /**
+ * Assigns string to a value of string
+ *
+ * @param input assigns string to this this.string
+ * @param lengthOfKeyword assigns this to this.lengthOfKeyword
+ */
+ public ListCommand(String input, int lengthOfKeyword) {
+ super(input, lengthOfKeyword);
+ }
+
+ /**
+ * Lists all the tasks that are currently present in the tasks.
+ *
+ * @param tasks to access the list and print them
+ * @param ui
+ * @param storage
+ * @return String returns the string of the output that informs the action has been complete.
+ * @throws DukeException not returned in this scenario
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws DukeException {
+ return listMessage(tasks);
+ }
+
+ /**
+ * gives the message when list is called.
+ *
+ * @param tasks gives the current list, which is used to return current list
+ * @return all the current list
+ */
+ private String listMessage(TaskList tasks) {
+ String s = "";
+ for (int i = 0; i < tasks.getAllTasks().size(); i++) {
+ s = s + "\n" + " " + (i + 1) + ". " + tasks.getAllTasks().get(i);
+ // concatenates all the string representation of Tasks TaskList
+ }
+ return s.substring(1);
+ }
+}
+
diff --git a/src/main/java/duke/commands/RandomCommand.java b/src/main/java/duke/commands/RandomCommand.java
new file mode 100644
index 0000000000..c5b578fe24
--- /dev/null
+++ b/src/main/java/duke/commands/RandomCommand.java
@@ -0,0 +1,36 @@
+package duke.commands;
+
+import duke.errors.WrongInputException;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.helpers.Ui;
+
+/**
+ * handles case where a random word is being input
+ */
+public class RandomCommand extends Command {
+ /**
+ * Assigns string to a value of string
+ *
+ * @param input assigns string to this this.string
+ * @param lengthOfKeyword assigns this to this.lengthOfKeyword
+ */
+ public RandomCommand(String input, int lengthOfKeyword) {
+ super(input, lengthOfKeyword);
+ }
+
+ /**
+ * Gives wrong input exception
+ *
+ * @param tasks
+ * @param ui to store the DukeException that is thrown since there is an error in user input
+ * @param storage
+ * @return String returns the string of the output that informs the action has been complete.
+ * @throws WrongInputException is thrown
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws WrongInputException {
+ ui.setDukeException(new WrongInputException());
+ throw new WrongInputException();
+ }
+}
+
diff --git a/src/main/java/duke/commands/ShortCutCommand.java b/src/main/java/duke/commands/ShortCutCommand.java
new file mode 100644
index 0000000000..095596f4bc
--- /dev/null
+++ b/src/main/java/duke/commands/ShortCutCommand.java
@@ -0,0 +1,152 @@
+package duke.commands;
+
+import java.io.FileWriter;
+import java.io.IOException;
+
+import duke.errors.DukeException;
+import duke.errors.FileAbsentException;
+import duke.errors.ShortCutException;
+import duke.helpers.ShortCuts;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.helpers.Ui;
+
+
+/**
+ * Handles case when short is the input to add short cuts
+ */
+public class ShortCutCommand extends Command {
+
+ /**
+ * Assigns string to a value and integer to lengthOfKeyword
+ *
+ * @param commandDescription assigns this.string to string
+ * @param lengthOfKeyword assigns length of keyword to this var
+ */
+ public ShortCutCommand(String commandDescription, int lengthOfKeyword) {
+ super(commandDescription, lengthOfKeyword);
+ }
+
+ /**
+ * Duke gives String depending on input, in this case that short cut has been added
+ *
+ * @param tasks used to access tasks in its list and change if necessary
+ * @param ui to store the DukeException that may be thrown if there is an error in user input
+ * @param storage to change the input there if necessary
+ * @return String that short cut is added
+ * @throws DukeException when the user input is wrong such as
+ */
+ @Override
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws DukeException {
+ try {
+ return process(storage);
+ //function processes the given input and gives message that short cut is added or else exception thrown
+ } catch (DukeException dukeException) {
+ ui.setDukeException(dukeException);
+ throw dukeException;
+ }
+ }
+
+ /**
+ * Judges whether the String given is correct, else it throws an error
+ *
+ * @param storage which contains information of the various short forms and checks for short forms in them
+ * @return String value if the String given by user is correct
+ * @throws DukeException thrown if there is an error in user input
+ */
+ private String process(Storage storage) throws DukeException {
+ if (isNumberOrDescriptionAbsent()) {
+ throw new ShortCutException(true, false, false, false, ""); //if description is absent
+ }
+ String[] splitData = splitDescription(userInput);
+ if (shortCutPresent(splitData[1])) {
+ throw new ShortCutException(false, false, true, false, splitData[1]);
+ //if short cut is already present
+ } else if (containsUselessShortCut(splitData[0])) {
+ throw new ShortCutException(false, false, false, true, splitData[1]);
+ //if short cut exception is useless
+ } else if (!shortCutPresent(splitData[0])) {
+ ShortCuts.addShortCut(splitData[0], splitData[1]);
+ updateShortCutFile(splitData[1], splitData[0], storage);
+ return shortCutMessage(); //when it is correct
+ } else {
+ return null;
+ }
+ }
+ /**
+ * splits input into original form and short form
+ *
+ * @param input by user
+ * @return String array containing original form index 0 and short form index 1
+ * @throws DukeException when there are errors in user input
+ */
+ private String[] splitDescription(String input) throws DukeException {
+ boolean originalOfShortFormPresent = false;
+ int index = -1;
+ String originalKeyWord = "";
+
+ for (int i = lengthOfKeyword + 1; i < input.length(); i++) {
+ if (input.charAt(i) == ' ') { //after " " comes short form
+ index = i;
+ originalOfShortFormPresent = true;
+ break;
+ }
+ originalKeyWord = originalKeyWord + input.charAt(i);
+ }
+ if (!originalOfShortFormPresent || userInput.substring(index + 1).length() == 0) {
+ throw new ShortCutException(false, true, false, false, ""); //happens when there is nothing after keyword
+ }
+ String[] splitData = new String[]{originalKeyWord, userInput.substring(index + 1)};
+ return splitData;
+ }
+
+ /**
+ * returns boolean value of whether input is already present
+ *
+ * @param input short cut added by user
+ * @return true if hashMap contains input and false otherwise.
+ */
+ private boolean shortCutPresent(String input) {
+ return ShortCuts.getShortCuts().containsKey(input); //if present is true
+ }
+
+ /**
+ * Informs user that short cut has been added
+ *
+ * @return String that short cut is added
+ */
+ private String shortCutMessage() {
+ return " short cut successfully added";
+ }
+
+ /**
+ * adds new short cuts by user into file
+ *
+ * @param shortCut by user
+ * @param original duke function name
+ * @param storage where the file is contained in
+ * @throws DukeException thrown when file doesn't exist
+ */
+ private void updateShortCutFile(String shortCut, String original, Storage storage) throws DukeException {
+ try {
+ FileWriter fw = new FileWriter(storage.getShortFormsFilePath(), true);
+ //updates the file in storage as new task is added
+ String newShortCutToAdd = shortCut + " " + original;
+ fw.write(newShortCutToAdd + "\n");
+ fw.close();
+ } catch (IOException i) {
+ throw new FileAbsentException(storage.getShortFormsFilePath());
+ }
+ }
+
+ /**
+ * Checks whether original form given is uselss
+ *
+ * @param originalForm given by user
+ * @return true if useless and false otherwise
+ */
+ private boolean containsUselessShortCut(String originalForm) {
+ return !ShortCuts.getShortCuts().containsValue(originalForm);
+ //since the short cut in ShortCut contains value of all tasks recognised by user
+ }
+}
diff --git a/src/main/java/duke/commands/TodoCommand.java b/src/main/java/duke/commands/TodoCommand.java
new file mode 100644
index 0000000000..1f7ed417bb
--- /dev/null
+++ b/src/main/java/duke/commands/TodoCommand.java
@@ -0,0 +1,69 @@
+package duke.commands;
+
+import duke.errors.DukeException;
+import duke.errors.TodoException;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.helpers.Ui;
+import duke.tasks.ToDo;
+
+/**
+ * Handles case where todo is the input
+ */
+public class TodoCommand extends AddCommand {
+ /**
+ * Assigns string to a value of string
+ *
+ * @param input assigns string to this this.string
+ * @param lengthOfKeyword assigns this to this.lengthOfKeyword
+ */
+ public TodoCommand(String input, int lengthOfKeyword) {
+ super(input, lengthOfKeyword);
+ }
+
+ /**
+ * Adds deadline into a task list in TaskList.
+ *
+ * @param tasks to change the taskList if necessary
+ * @param ui to store the DukeException that may be thrown if there is an error in user input
+ * @param storage to change the file in the if necessary
+ * @return String returns the string of the output that informs the action has been complete.
+ * @throws DukeException whenever there is an error, no
+ * description
+ */
+ public String execute(TaskList tasks, Ui ui, Storage storage) throws DukeException {
+ try {
+ return process(tasks, storage);
+ } catch (DukeException dukeException) {
+ ui.setDukeException(dukeException);
+ throw dukeException;
+ }
+ }
+
+ /**
+ * Returns String if user input is correct and updates the TaskList tasks and file containing tasks file in
+ * storage
+ *
+ * @param tasks to add ToDo task here if the user input is correct
+ * @param storage to add ToDo task in the file containing tasks
+ * @return String informing that the user has input the task
+ * @throws DukeException if user input is correct
+ */
+ private String process(TaskList tasks, Storage storage) throws DukeException {
+ if (isNumberOrDescriptionAbsent()) {
+ throw new TodoException();
+ }
+ ToDo t = new ToDo(todoDescription());
+ return updateTaskList(storage, t, tasks);
+ }
+ /**
+ * returns the name of the task
+ *
+ * @return name of task
+ */
+ private String todoDescription() {
+ return userInput.substring(lengthOfKeyword + 1);
+ }
+
+}
+
diff --git a/src/main/java/duke/errors/DeadlineException.java b/src/main/java/duke/errors/DeadlineException.java
new file mode 100644
index 0000000000..2b0cc0ba21
--- /dev/null
+++ b/src/main/java/duke/errors/DeadlineException.java
@@ -0,0 +1,79 @@
+package duke.errors;
+
+/**
+ * This DeadlineException is used to print out exceptions when there is an incomplete input where wether the description
+ * or date is absent.
+ */
+
+public class DeadlineException extends DukeException {
+ /**
+ * descriptionPresent tests shows whether the description is present in the input of the user or not.
+ * If description is not present it is true, else it is false
+ */
+ private boolean isDescriptionAbsent; //true if description for deadline keyword is not given, false otherwise
+ private boolean isDateTimeFormatWrong; //true if date and/ or time is given in wrong format by user, false otherwise
+ private boolean isDateTimeAbsent; //true if date is not given by user, false otherwise
+
+ /**
+ * constructor for deadline exception that assigns description and format values
+ *
+ * @param isDescriptionAbsent true if description absent
+ * @param isDateTimeFormatWrong true if format is wrong
+ * @param isDateTimeAbsent true if date and time are absent.
+ */
+ public DeadlineException(boolean isDescriptionAbsent, boolean isDateTimeFormatWrong, boolean isDateTimeAbsent) {
+ this.isDescriptionAbsent = isDescriptionAbsent;
+ this.isDateTimeFormatWrong = isDateTimeFormatWrong;
+ this.isDateTimeAbsent = isDateTimeAbsent;
+ }
+
+ /**
+ * doesn't take in any arguments, overrides the in-built toString() method.
+ *
+ * @return returns a string informing that the description is empty if descriptionAbsent is true. Else, it tests
+ * whether the format is wrong, if it then a string describing it would be returned.
+ * If isDateTimeAbsent is true then
+ * date time for deadline is absent and a String describing it would be returned.
+ * Else then default returns which
+ * should not occur.
+ */
+ public String toString() {
+ if (this.isDescriptionAbsent) {
+ return descriptionAbsent(); //when descriptionAbsent
+ } else if (this.isDateTimeFormatWrong) {
+ return dateTimeFormatWrong(); //when dateTimeFormat is wrong
+ } else if (this.isDateTimeAbsent) {
+ return dateTimeAbsent(); //when dateTime is absent
+ } else {
+ return "default";
+ }
+ }
+
+ /**
+ * returns String on condition where description for Deadline is absent
+ *
+ * @return String informing user that the description for Deadline is absent
+ */
+ private String descriptionAbsent() {
+ return " '\u2639' OOPS!!! The description of a deadline cannot be empty.";
+ }
+
+ /**
+ * returns String on condition where format for date and/or time format for Deadline is wrong
+ *
+ * @return String informing user format for date and/or time format for Deadline is wrong
+ */
+ private String dateTimeFormatWrong() {
+ return " '\u2639' OOPS!!! The formats of date and/ or include "
+ + "yyyy MM dd/ yyyy MM dd, HH:mm/ HH:mm";
+ }
+
+ /**
+ * returns String on condition where date and/or time for Deadline is absent
+ *
+ * @return String informing user that the date and/or time for Deadline is absent
+ */
+ private String dateTimeAbsent() {
+ return " '\u2639' OOPS!!! The specific date/time of a deadline cannot be empty.";
+ }
+}
diff --git a/src/main/java/duke/errors/DeleteException.java b/src/main/java/duke/errors/DeleteException.java
new file mode 100644
index 0000000000..2e91de16d8
--- /dev/null
+++ b/src/main/java/duke/errors/DeleteException.java
@@ -0,0 +1,65 @@
+package duke.errors;
+
+/**
+ * This DeleteException is used to print out exceptions when there is an incomplete input where the ID
+ * is absent or the ID
+ * of that Task hasn't been defined yet or it has previously been deleted.
+ */
+public class DeleteException extends DukeException {
+ /**
+ * isiDabsent tests shows whether the ID is present in the input of the user or not.
+ * If ID is not present it is true, else it is false
+ * deleted checks whether the task was previously deleted, if deleted it is true else false.
+ */
+ private boolean isiDAbsent; //true if iD is not given by user, false otherwise
+ private boolean isNotiDDefined; // true if iD is not defined yet, false otherwise
+
+ /**
+ * constructor that assigns tne 2 variables its respective values
+ *
+ * @param isiDabsent input, true if ID is input my reader, false otherwise.
+ * @param isNOtiDDefined input, true if ID > number of tasks present, false otherwise.
+ */
+ public DeleteException(boolean isiDabsent, boolean isNOtiDDefined) {
+ this.isiDAbsent = isiDabsent;
+ this.isNotiDDefined = isNOtiDDefined;
+ }
+
+ /**
+ * doesn't take in any arguments, overrides the in-built toString() method, for printing in getMessage().
+ *
+ * @return returns a string depending on the scenario. If the IDAbsent is true, then description
+ * that the description of
+ * delete cannot be empty. Else if isDefined is true then String returning that ID is not defined
+ * is returned. Else,
+ * default is returned which should not occur.
+ */
+ @Override
+ public String toString() {
+ if (isiDAbsent) {
+ return iDAbsent(); //when ID is not input by user
+ } else if (isNotiDDefined) {
+ return iDNotDefined(); //when ID is not defined yet
+ } else {
+ return "default";
+ }
+ }
+
+ /**
+ * returns on condition when user didn't mention the task ID to delete
+ *
+ * @return String informing user that ID of task to be deleted is not mentioned
+ */
+ private String iDAbsent() {
+ return " '\u2639' OOPS!!! The description of delete cannot be empty.";
+ }
+
+ /**
+ * returns on condition when the ID is more than the number of tasks present
+ *
+ * @return String informing user that ID of task to be deleted is not defined yet.
+ */
+ private String iDNotDefined() {
+ return " '\u2639' OOPS!!! The ID is not yet defined.";
+ }
+}
diff --git a/src/main/java/duke/errors/DoneException.java b/src/main/java/duke/errors/DoneException.java
new file mode 100644
index 0000000000..99053c9779
--- /dev/null
+++ b/src/main/java/duke/errors/DoneException.java
@@ -0,0 +1,70 @@
+package duke.errors;
+
+/**
+ * This DoneException is used to print out exceptions when there is an incomplete input where the iD is absent or the iD
+ * of that Task hasnt been defined yet.
+ */
+public class DoneException extends DukeException {
+ /**
+ * IDabsent tests shows whether the iD is present in the input of the user or not.
+ * If ID is not present it is true, else it is false
+ */
+ private boolean isiDAbsent; //true if iD is not given by user, false otherwise
+ private boolean isNotiDDefined; //true if iD is not defined yet, false otherwise
+ private boolean isDone; //true if task is already completed, false otherwise
+
+ /**
+ * constructor that assigns tne 2 variables its respective values
+ * @param isiDabsent input, depending on whether the iD is present or not in the input.txt file.
+ * If present it is false else it is true.
+ * @param isNOtiDDefined input, true if ID > number of tasks present, false otherwise.
+ */
+ public DoneException(boolean isiDabsent, boolean isNOtiDDefined, boolean isDone) {
+ this.isiDAbsent = isiDabsent;
+ this.isNotiDDefined = isNOtiDDefined;
+ this.isDone = isDone;
+ }
+
+ /**
+ * doesn't take in any arguments, overrides the in-built toString() method.
+ *
+ * @return returns a string depending on the scenario. If the IDabsent is true,
+ * then description that the description of
+ * done cannot be empty.Else if isDefined is true then String returning that iD is not defined is returned. Else,
+ * default is returned which should not occur.
+ */
+ @Override
+ public String toString() {
+ if (isiDAbsent) {
+ return iDAbsent(); //when ID is absent
+ } else if (isNotiDDefined) {
+ return iDNotDefined(); //when ID is not defined
+ } else if (isDone) {
+ return isDone();
+ } else {
+ return "default";
+ }
+ }
+
+ /**
+ * Returns when iD is not given by user
+ *
+ * @return String saying that description of done(a number) cannot be empty
+ */
+ private String iDAbsent() {
+ return " '\u2639' OOPS!!! The description of done cannot be empty.";
+ }
+
+ /**
+ * Returns when ID input by user is not defined yet
+ *
+ * @return String saying that ID is not defined.
+ */
+ private String iDNotDefined() {
+ return " '\u2639' OOPS!!! The ID is not yet defined.";
+ }
+
+ private String isDone() {
+ return "You have already completed this task";
+ }
+}
diff --git a/src/main/java/duke/errors/DukeException.java b/src/main/java/duke/errors/DukeException.java
new file mode 100644
index 0000000000..7486347bdc
--- /dev/null
+++ b/src/main/java/duke/errors/DukeException.java
@@ -0,0 +1,17 @@
+package duke.errors;
+
+/**
+ * this is a DukeException class which is the parents class of all the other exceptions in this package.
+ * this is never initialized and therefore is an abstract class and used for polymorphism.
+ */
+public abstract class DukeException extends Exception {
+ /**
+ * overrides getMessage of an error
+ *
+ * @return string of the exception
+ */
+ public String getMessage() {
+ return toString();
+ }
+}
+
diff --git a/src/main/java/duke/errors/EventException.java b/src/main/java/duke/errors/EventException.java
new file mode 100644
index 0000000000..70a940d2cb
--- /dev/null
+++ b/src/main/java/duke/errors/EventException.java
@@ -0,0 +1,108 @@
+package duke.errors;
+
+/**
+ * This EventException is used to print out exceptions when there is an incomplete input where whether the description
+ * or date is absent.
+ */
+public class EventException extends DukeException {
+ /**
+ * description tests shows whether the description is present in the input of the user or not.
+ * If description is not present it is true, else it is false
+ */
+ private boolean isDescriptionAbsent; //true if the user input does not have description, else false
+ private boolean isEndTimeAbsent; //true if end time is not given by user, false otherwise
+ private boolean isStartAfterEnd; //true if start>end, false otherwise
+ private boolean isDateTimeWrongFormat; //true if date and/ or time is in wrong format, false otherwise
+ private boolean isStartDateTimeEmpty; //true if start date and/ or time is not given by user, false otherwise
+
+ /**
+ *
+ * @param isDescriptionAbsent input, depending on whether the description is given by user.
+ * @param isEndTimeAbsent is true when the user has no input for end time
+ * @param isStartAfterEnd is true when the start time is after end time
+ * @param isDateTimeWrongFormat is true when date and/or time is input in wrong format.
+ * @param isStartDateTimeEmpty is true when date abd/or time is input in wrong format
+ */
+ public EventException(boolean isDescriptionAbsent, boolean isEndTimeAbsent, boolean isStartAfterEnd,
+ boolean isDateTimeWrongFormat, boolean isStartDateTimeEmpty) {
+ this.isDescriptionAbsent = isDescriptionAbsent;
+ this.isEndTimeAbsent = isEndTimeAbsent;
+ this.isStartAfterEnd = isStartAfterEnd;
+ this.isDateTimeWrongFormat = isDateTimeWrongFormat;
+ this.isStartDateTimeEmpty = isStartDateTimeEmpty;
+ }
+
+ /**
+ * doesn't take in any arguments, overrides the in-built toString() method.
+ * @return returns a string informing that the description is empty if description is true.
+ * If isEndTimeAbsent is absent is true, end time is absent and then a
+ * description mentioning this would be returned.
+ * Else, if isStartAfterEnd is true, start would be more than end then a
+ * description describing this would be printed
+ * Else if ifDateWrongFormat is true, then the date is in wrong format and
+ * a description describing it would be printed
+ * Else if isDateEmpty is true, then String giving that is returned.
+ * Else default is returned.
+ */
+ public String toString() {
+ if (this.isDescriptionAbsent) {
+ return descriptionAbsent(); //when description is not given by user
+ } else if (this.isEndTimeAbsent) {
+ return endTimeAbsent(); //when end time is not given by user
+ } else if (this.isStartAfterEnd) {
+ return startAfterEnd(); //when start is after end
+ } else if (this.isDateTimeWrongFormat) {
+ return dateTimeWrongFormat(); //when date is given in wrong format
+ } else if (this.isStartDateTimeEmpty) {
+ return startDateTimeEmpty(); //when start date and/or time is absent
+ } else {
+ return "default";
+ }
+ }
+
+ /**
+ * Returns when description of Event is absent
+ *
+ * @return String saying that description of Event is absent.
+ */
+ private String descriptionAbsent() {
+ return " '\u2639' OOPS!!! The description of an Event cannot be empty.";
+ }
+
+ /**
+ * Returns when endTime is not given by user
+ *
+ * @return String saying end time is not given by user
+ */
+ private String endTimeAbsent() {
+ return " '\u2639' OOPS!!! There should be 2 occurrences of date and/or time values.";
+ }
+
+ /**
+ * Returns when start time is more than end
+ *
+ * @return String saying that start < end
+ */
+ private String startAfterEnd() {
+ return " '\u2639' OOPS!!! Start should be less than end.";
+ }
+
+ /**
+ * Returns when date and/or time is in wrong format
+ *
+ * @return String saying that date and/or time is in wrong format and the format it should be in
+ */
+ private String dateTimeWrongFormat() {
+ return " '\u2639' OOPS!!! Start and should be of the same format. The formats include "
+ + "yyyy MM dd/ yyyy MM dd, HH:mm/ HH:mm";
+ }
+
+ /**
+ * Returns when start date and/or time is empty
+ *
+ * @return String saying that start date and/or time is absent
+ */
+ private String startDateTimeEmpty() {
+ return " '\u2639' OOPS!!! The specific date and/or time of an Event cannot be empty.";
+ }
+}
diff --git a/src/main/java/duke/errors/FIleEmptyException.java b/src/main/java/duke/errors/FIleEmptyException.java
new file mode 100644
index 0000000000..bab09fbca2
--- /dev/null
+++ b/src/main/java/duke/errors/FIleEmptyException.java
@@ -0,0 +1,26 @@
+package duke.errors;
+
+/**
+ * This exception is thrown when the file is empty
+ */
+public class FIleEmptyException extends DukeException {
+ /**
+ * this overrides the toString() method
+ *
+ * @return a String representation of FileEmptyException
+ */
+ @Override
+ public String toString() {
+ return fileEmpty(); //when file is empty
+ }
+
+ /**
+ * Returns when file is empty
+ *
+ * @return informs user that file is empty
+ */
+ private String fileEmpty() {
+ return " Task file is empty!";
+ }
+}
+
diff --git a/src/main/java/duke/errors/FileAbsentException.java b/src/main/java/duke/errors/FileAbsentException.java
new file mode 100644
index 0000000000..025f8daef6
--- /dev/null
+++ b/src/main/java/duke/errors/FileAbsentException.java
@@ -0,0 +1,36 @@
+package duke.errors;
+
+/**
+ * This exception is thrown whenever there is a file absent at a specific path mentioned in the filePath
+ */
+public class FileAbsentException extends DukeException {
+ private String isFilePathAbsent; //the String of the filePath where file is not present
+
+ /**
+ * This assigns filePath variable to a value
+ *
+ * @param isFilePathAbsent the value assigned to filePath
+ */
+ public FileAbsentException(String isFilePathAbsent) {
+ this.isFilePathAbsent = isFilePathAbsent;
+ }
+
+ /**
+ * This overrides the toString() method
+ *
+ * @return a String for the exception is printed.
+ */
+ @Override
+ public String toString() {
+ return fileAbsent(); //when file is absent
+ }
+
+ /**
+ * Returns when file is not present
+ *
+ * @return String saying that file is absent.
+ */
+ private String fileAbsent() {
+ return " The file in this directory " + this.isFilePathAbsent + " is absent!";
+ }
+}
diff --git a/src/main/java/duke/errors/FindException.java b/src/main/java/duke/errors/FindException.java
new file mode 100644
index 0000000000..cface66e1b
--- /dev/null
+++ b/src/main/java/duke/errors/FindException.java
@@ -0,0 +1,58 @@
+package duke.errors;
+
+/**
+ * The class FindException deals with what happens when an error occurs for task with find keyword
+ */
+public class FindException extends DukeException {
+ private boolean noMatches; //true if there are no matches from user input to the Task names
+ private boolean isDescriptionAbsent; //true if description is not given by input, false otherwise
+ private String description; //the description given by user(words to search for in tasks)
+
+ /**
+ * constructor assigns values of description and string
+ *
+ * @param noMatches value is assigned to noMatches
+ * @param isDescriptionAbsent value is assigned to this.description
+ * @param description value is assigned to this.string
+ */
+ public FindException(boolean noMatches, boolean isDescriptionAbsent, String description) {
+ this.noMatches = noMatches;
+ this.isDescriptionAbsent = isDescriptionAbsent;
+ this.description = description;
+ }
+
+ /**
+ * overrides the toString() method
+ *
+ * @return if description is present error is due to no matches being present and an error message informing
+ * them would be printed. If it is not present than error is due to keywords being absent therefore an error
+ * message regarding that would be released.
+ */
+ public String toString() {
+ if (noMatches) {
+ return noMatches(); //when there are no matches
+ } else if (isDescriptionAbsent) {
+ return descriptionAbsent(); //when description is absent
+ } else {
+ return "default";
+ }
+ }
+
+ /**
+ * Returns when there are no matches for the keywords given
+ *
+ * @return String that there are no matches to the keywords given
+ */
+ public String noMatches() {
+ return " there are no matches to your keyword: " + description;
+ }
+
+ /**
+ * Returns when there are no keywords given by user
+ *
+ * @return String that the keywords are absent.
+ */
+ private String descriptionAbsent() {
+ return " description of find cannot be empty!";
+ }
+}
diff --git a/src/main/java/duke/errors/ShortCutException.java b/src/main/java/duke/errors/ShortCutException.java
new file mode 100644
index 0000000000..366f01e2c3
--- /dev/null
+++ b/src/main/java/duke/errors/ShortCutException.java
@@ -0,0 +1,88 @@
+package duke.errors;
+
+import duke.helpers.ShortCuts;
+
+/**
+ * used when there is an error in user input while adding short cut
+ */
+public class ShortCutException extends DukeException {
+ private boolean isDescriptionAbsent; //true if the description is absent in user input, false otherwise
+ private boolean isShortCutAbsent; //true if short cut is not provided
+ private boolean isShortCutAlreadyPresent; //true if short cut is already defined, false otherwise
+ private boolean isUselessShortCut; //if short cut is defined for a command not read by Duke
+ private String shortCut;
+
+ /**
+ * constructor which assigns the above 4 member variables into its respective values
+ *
+ * @param isDescriptionAbsent true is description is not given by user, false otherwise
+ * @param isShortCutAbsent true if short form is not given by user, false otherwise
+ * @param isShortCutAlreadyPresent true if short cut is already present
+ * @param isUselessShortCut true if short cut's original value means nothing to Duke
+ * @param shortCut shortcut provided by user
+ */
+ public ShortCutException(boolean isDescriptionAbsent, boolean isShortCutAbsent,
+ boolean isShortCutAlreadyPresent, boolean isUselessShortCut, String shortCut) {
+ this.isDescriptionAbsent = isDescriptionAbsent;
+ this.isShortCutAbsent = isShortCutAbsent;
+ this.isShortCutAlreadyPresent = isShortCutAlreadyPresent;
+ this.isUselessShortCut = isUselessShortCut;
+ this.shortCut = shortCut;
+ }
+
+ /**
+ * overrides built-in toString method
+ *
+ * @return String for the reason this Exception is thrown
+ */
+ public String toString() {
+ if (isDescriptionAbsent) {
+ return descriptionAbsent(); //when description is absent
+ } else if (isShortCutAbsent) {
+ return shortCutAbsent(); //when short cut is absent
+ } else if (isShortCutAlreadyPresent) {
+ return shortCutAlreadyPresent(); //when short cut is already present
+ } else if (isUselessShortCut) {
+ return uselessShortCut(); //when short cut has no meaning
+ } else {
+ return "default";
+ }
+ }
+
+ /**
+ * Describes that description of short cannot be empty
+ *
+ * @return String informing user that description of short cannot be empty"
+ */
+ private String descriptionAbsent() {
+ return " The description of short cannot be empty";
+ }
+
+ /**
+ * Describes that short cut cannot be empty
+ *
+ * @return String informing user that short cut is not provided.
+ */
+ private String shortCutAbsent() {
+ return "short cut is not provided";
+ }
+
+ /**
+ * Describes that short cut is already present
+ *
+ * @return String informing user that short cut is already present
+ */
+ private String shortCutAlreadyPresent() {
+ assert ShortCuts.getShortCuts().containsKey(this.shortCut);
+ return this.shortCut + " is already present as a short form for" + ShortCuts.getShortCuts().get(this.shortCut);
+ }
+
+ /**
+ * Describes that short cut has no meaning
+ *
+ * @return String informing user that short cut has no meaning
+ */
+ private String uselessShortCut() {
+ return this.shortCut + " has no meaning";
+ }
+}
diff --git a/src/main/java/duke/errors/TodoException.java b/src/main/java/duke/errors/TodoException.java
new file mode 100644
index 0000000000..1d6613fab6
--- /dev/null
+++ b/src/main/java/duke/errors/TodoException.java
@@ -0,0 +1,26 @@
+package duke.errors;
+
+/**
+ * This TodoException is used to print out exceptions when there is an incomplete input where whether the description
+ * or date is absent.
+ */
+public class TodoException extends DukeException {
+ /**
+ * doesn't take in any arguments, overrides the in-built toString() method.
+ *
+ * @return returns a string informing that the description of the ToDo is absent as it cant be.
+ */
+ public String toString() {
+ return descriptionAbsent(); //when description is absent
+ }
+
+ /**
+ * Returns when description is absent
+ *
+ * @return String informign user that the description of ToDo cannot be empty.
+ */
+ private String descriptionAbsent() {
+ return " '\u2639' OOPS!!! The description of a ToDo cannot be empty";
+ }
+}
+
diff --git a/src/main/java/duke/errors/WrongInputException.java b/src/main/java/duke/errors/WrongInputException.java
new file mode 100644
index 0000000000..46b5325336
--- /dev/null
+++ b/src/main/java/duke/errors/WrongInputException.java
@@ -0,0 +1,24 @@
+package duke.errors;
+
+/**
+ * This prints the exception when a wrong word is being input.
+ */
+public class WrongInputException extends DukeException {
+ /**
+ * This takes not args and overrides the toString() method
+ *
+ * @return a string that describes the error that took place which is that an invalid string has been inserted
+ */
+ public String toString() {
+ return wrongInputString();
+ }
+
+ /**
+ * returns when user gives something Duke doesn't understand.
+ *
+ * @return String that the user has mentioned something that the Duke cannot understand
+ */
+ private String wrongInputString() {
+ return " '\u2639 OOPS!!! I'm sorry, but I don't know what that means :-(";
+ }
+}
diff --git a/src/main/java/duke/helpers/Parser.java b/src/main/java/duke/helpers/Parser.java
new file mode 100644
index 0000000000..c7dbbc2eaa
--- /dev/null
+++ b/src/main/java/duke/helpers/Parser.java
@@ -0,0 +1,267 @@
+package duke.helpers;
+
+
+import duke.commands.Command;
+import duke.commands.DeadlineCommand;
+import duke.commands.DeleteCommand;
+import duke.commands.DoneCommand;
+import duke.commands.EventCommand;
+import duke.commands.ExitCommand;
+import duke.commands.FindCommand;
+import duke.commands.ListCommand;
+import duke.commands.RandomCommand;
+import duke.commands.ShortCutCommand;
+import duke.commands.TodoCommand;
+
+/**
+ * This is a Parser class that determines which command operation to choose, which in turn determines
+ * the action to be taken.
+ */
+public class Parser {
+
+ /**
+ * Returns a Command, depending on the string being input
+ *
+ * @param input where the first words determines command to be returned
+ * @return Command is returned based on the first word of param string
+ */
+ public static Command parse(String input) {
+ assert !input.contains(","); //to ensure that no , appears when multiple inputs are given
+ if (ShortCuts.containsShortCut(input)) {
+ String properInput = shortCutStringUpdate(input);
+ return parse(properInput);
+ } else if (isShortCutDefined(input)) {
+ return shortCutCommand(input);
+ } else if (isBye(input)) { //represents ExitCommand
+ return exitCommand(input);
+ } else if (isList(input)) { //represents ListCommand
+ return listCommand(input);
+ } else if (isDelete(input)) { //represents deleteCommand
+ return deleteCommand(input);
+ } else if (isDone(input)) { //represents doneCommand
+ return doneCommand(input);
+ } else if (isTodo(input)) { //represents ToDoCommand
+ return todoCommand(input);
+ } else if (isEvent(input)) { //represents EventCommand
+ return eventCommand(input);
+ } else if (isDeadline(input)) { //represents DeadlineCommand
+ return deadlineCommand(input);
+ } else if (isFind(input)) { //represents FindCommand
+ return findCommand(input);
+ } else { //rest are RandomCommand
+ return randomCommand(input);
+ }
+ }
+
+ /**
+ * checks whether short cut is attempted to be defined
+ *
+ * @param input String by user
+ * @return boolean whether short cut is attempted to be defined
+ */
+ private static boolean isShortCutDefined(String input) {
+ return input.length() >= 5 && input.substring(0, 5).equals("short");
+ }
+
+ /**
+ * checks whether bye is said by user
+ *
+ * @param input String by user
+ * @return boolean whether bye is said, true if bye is said and false otherwise
+ */
+ private static boolean isBye(String input) {
+ return input.length() >= 3 && input.equals("bye");
+ }
+
+ /**
+ * checks whether list is said by user
+ *
+ * @param input String by user
+ * @return boolean whether list is said, true if list is said and false otherwise
+ */
+ private static boolean isList(String input) {
+ return input.length() >= 4 && input.equals("list");
+ }
+
+ /**
+ * checks whether delete is said by user
+ *
+ * @param input String by user
+ * @return boolean whether delete is said, true if delete is said and false otherwise
+ */
+ private static boolean isDelete(String input) {
+ return input.length() >= 6 && input.substring(0, 6).equals("delete");
+ }
+
+ /**
+ * checks whether done is said by user
+ *
+ * @param input String by user
+ * @return boolean whether done is said, true done is said and false otherwise
+ */
+ private static boolean isDone(String input) {
+ return input.length() >= 4 && input.substring(0, 4).equals("done");
+ }
+
+ /**
+ * checks whether todo is said by user
+ *
+ * @param input String by user
+ * @return boolean whether todo is said, true if bye is said and false otherwise
+ */
+ private static boolean isTodo(String input) {
+ return input.length() >= 4 && input.substring(0, 4).equals("todo");
+ }
+
+ /**
+ * checks whether event is said by user
+ *
+ * @param input String by user
+ * @return boolean whether event is said, true if event is said and false otherwise
+ */
+ private static boolean isEvent(String input) {
+ return input.length() >= 5 && input.substring(0, 5).equals("event");
+ }
+
+ /**
+ * checks whether deadline is said by user
+ *
+ * @param input String by user
+ * @return boolean whether deadline is said, true if deadline is said and false otherwise
+ */
+ private static boolean isDeadline(String input) {
+ return input.length() >= 8 && input.substring(0, 8).equals("deadline");
+ }
+
+ /**
+ *checks whether find is said by user
+ *
+ * @param input String by user
+ * @return boolean whether find is said, true if find is said and false otherwise
+ */
+ private static boolean isFind(String input) {
+ return input.length() >= 4 && input.substring(0, 4).equals("find");
+ }
+
+ private static ShortCutCommand shortCutCommand(String input) {
+ int lengthOfKeyword = "short".length();
+ return new ShortCutCommand(input, lengthOfKeyword);
+ }
+ /**
+ * Gives exit command
+ *
+ * @param input String given by user
+ * @return ExitCommand
+ */
+ private static ExitCommand exitCommand(String input) {
+ int lengthOfKeyWord = "list".length();
+ return new ExitCommand(input, lengthOfKeyWord); //when in short form
+ }
+
+ /**
+ * Gives list command
+ *
+ * @param input String given by user
+ * @return ListCommand
+ */
+ private static ListCommand listCommand(String input) {
+ int lengthOfKeyWord = "list".length();
+ return new ListCommand(input, lengthOfKeyWord); //when in short form
+ }
+
+ /**
+ * Gives delete command
+ *
+ * @param input String given by user
+ * @return DeleteCommand
+ */
+ private static DeleteCommand deleteCommand(String input) {
+ int lengthOfKeyWord = "delete".length();
+ return new DeleteCommand(input, lengthOfKeyWord); //when not in short form
+ }
+
+ /**
+ * Gives done command
+ *
+ * @param input String given by user
+ * @return DoneCommand
+ */
+ private static DoneCommand doneCommand(String input) {
+ int lengthOfKeyWord = "done".length();
+ return new DoneCommand(input, lengthOfKeyWord); //when not in short form
+ }
+
+ /**
+ * Gives todo command
+ *
+ * @param input String given by user
+ * @return ToDoCommand
+ */
+ private static TodoCommand todoCommand(String input) {
+ int lengthOfKeyWord = "todo".length();
+ return new TodoCommand(input, lengthOfKeyWord); //when not in short form
+ }
+
+ /**
+ * Gives event command
+ *
+ * @param input String given by user
+ * @return EventCommand
+ */
+ private static EventCommand eventCommand(String input) {
+ int lengthOfKeyWord = "event".length();
+ return new EventCommand(input, lengthOfKeyWord); //when not in short form
+ }
+
+ /**
+ * Gives deadline command
+ *
+ * @param input String given by user
+ * @return DeadlineCommand
+ */
+ private static DeadlineCommand deadlineCommand(String input) {
+ int lengthOfKeyWord = "deadline".length();
+ return new DeadlineCommand(input, lengthOfKeyWord); //when not in short form
+ }
+
+ /**
+ * Gives exit command
+ *
+ * @param input String given by user
+ * @return ExitCommand
+ */
+ private static FindCommand findCommand(String input) {
+ int lengthOfKeyWord = "find".length();
+ return new FindCommand(input, lengthOfKeyWord); //when not in short form
+ }
+
+ /**
+ * If short cuts is present it gives the original string, converts it to proper form.
+ *
+ * @param input String given by user
+ * @return gives proper String input without the short form
+ */
+ public static String shortCutStringUpdate(String input) {
+ String[] strings = input.split(" ");
+ String command = ShortCuts.getShortCuts().get(strings[0]);
+ String properInput = command;
+
+ for (int i = 1; i < strings.length; i++) {
+ properInput = properInput + " " + strings[i];
+ }
+ return properInput;
+ }
+
+ /**
+ * Gives random command when user doesn't make sense
+ *
+ * @param input String given by user
+ * @return RandomCommand
+ */
+ private static RandomCommand randomCommand(String input) {
+ return new RandomCommand(input, -1);
+ }
+
+
+
+}
diff --git a/src/main/java/duke/helpers/ShortCuts.java b/src/main/java/duke/helpers/ShortCuts.java
new file mode 100644
index 0000000000..fdde2e6ea7
--- /dev/null
+++ b/src/main/java/duke/helpers/ShortCuts.java
@@ -0,0 +1,75 @@
+package duke.helpers;
+
+import java.util.HashMap;
+
+/**
+ * ShortCuts class is used to define shortcuts and access defined shortucts
+ */
+public class ShortCuts {
+ private static HashMap shortCuts = new HashMap<>();
+ //Contains the shortcuts, where the Key is the short form and the value is the original value
+
+ /**
+ * Constructor to insert shortCuts into shortCuts hashMap
+ *
+ * @param shortCut is the key for the hashMap
+ * @param originalForm is the value for the hashMap
+ */
+ private ShortCuts(String shortCut, String originalForm) {
+ shortCuts.put(shortCut, originalForm);
+ }
+ /**
+ * gets the shortCuts and sets default values of short cut to proper keywords
+ *
+ * @return shortCuts
+ */
+ public static HashMap getShortCuts() {
+ defaultShortCut(); //sets the default short cuts to shortcuts
+ return shortCuts;
+ }
+
+ /**
+ * default short cuts provided by Duke
+ */
+ public static void defaultShortCut() {
+ shortCuts.put("s", "short"); //s is short form for short
+ shortCuts.put("b", "bye"); //b is short form for bye
+ shortCuts.put("l", "list"); //l is short form for list
+ shortCuts.put("d", "delete"); //d is short form for delete
+ shortCuts.put("do", "done"); //do is short form for done
+ shortCuts.put("t", "todo"); //t is short form for todo
+ shortCuts.put("e", "event"); //e is short form for event
+ shortCuts.put("de", "deadline"); //de is short form for deadline
+ shortCuts.put("f", "find"); //f is short for find
+ }
+
+ /**
+ * Adds shortcuts to the shortCuts hashMap given by user
+ *
+ * @param originalForm is the actual keyword
+ * @param shortForm the short form given by user
+ */
+ public static void addShortCut(String originalForm, String shortForm) {
+ new ShortCuts(shortForm, originalForm);
+ //calls constructor which then puts originalForm into key and shortForm into value
+ }
+
+ /**
+ * Checks whether the input contains the short cut
+ *
+ * @param input given by user
+ * @return boolean value on whether the keyword given by the user is a defined short cut.
+ */
+ public static boolean containsShortCut(String input) {
+ defaultShortCut();
+ String keyWord = "";
+ for (int i = 0; i < input.length(); i++) {
+ if (input.charAt(i) == ' ') { //space indicates that the keyword is over.
+ break;
+ }
+ keyWord = keyWord + input.charAt(i);
+ }
+ return shortCuts.containsKey(keyWord); //checks whether hashmap contains keyword.
+ }
+
+}
diff --git a/src/main/java/duke/helpers/Storage.java b/src/main/java/duke/helpers/Storage.java
new file mode 100644
index 0000000000..fa5b1f3409
--- /dev/null
+++ b/src/main/java/duke/helpers/Storage.java
@@ -0,0 +1,192 @@
+package duke.helpers;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+import duke.errors.DeadlineException;
+import duke.errors.DukeException;
+import duke.errors.FIleEmptyException;
+import duke.errors.FileAbsentException;
+import duke.tasks.Deadline;
+import duke.tasks.Event;
+import duke.tasks.Task;
+import duke.tasks.ToDo;
+
+
+/**
+ * Deals with loading tasks from the file and saving tasks in the file and stores shortcuts
+ */
+public class Storage {
+ private String filePath;
+ private String shortFormsFilePath;
+ /**
+ * Constructor assigns filePath to filePath
+ * @param filePath assigns this value to variable
+ */
+ public Storage(String filePath, String shortFormsFile) {
+ this.filePath = filePath;
+ this.shortFormsFilePath = shortFormsFile;
+ }
+ public void setShortForm() throws DukeException {
+ File f = new File(this.shortFormsFilePath);
+ assert f.exists(); //file should exist to keep track of tasks
+ try {
+ Scanner sc = new Scanner(f);
+ if (sc.hasNextLine()) {
+ do {
+ String shortFormString = sc.nextLine();
+ String[] shortFormDictionary = shortFormDictionary(shortFormString);
+ ShortCuts.getShortCuts().put(shortFormDictionary[0], shortFormDictionary[1]);
+ } while (sc.hasNextLine());
+ }
+ } catch (IOException i) {
+ throw new FileAbsentException(shortFormsFilePath);
+ }
+ }
+ /**
+ * Converts the string form of tasks on the file to Task objects
+ *
+ * @return the List of tasks containing Task instead of String
+ * @throws DukeException when a file with FilePath doesnt exist.
+ */
+ public List load() throws DukeException {
+
+ File f = new File(this.filePath);
+ assert f.exists(); //file should exist to keep track of tasks
+ try {
+ List tasks = new ArrayList<>();
+ Scanner sc = new Scanner(f);
+ while (sc.hasNext()) {
+ addTasks(tasks, sc);
+ }
+ //addTasks(tasks, sc);
+ if (tasks.size() == 0) {
+ throw new FIleEmptyException();
+ } else {
+ return tasks;
+ }
+ } catch (IOException error) {
+ throw new FileAbsentException(this.filePath);
+ }
+ }
+
+ /**
+ * Adds all the current tasks to the TaskList tasks
+ *
+ * @param tasks where task being scanned are inserted into TaskList tasks
+ * @param sc Scanner used to scan user input
+ * @throws DukeException
+ */
+ private void addTasks(List tasks, Scanner sc) throws DukeException {
+ String input = sc.nextLine();
+ char bool = input.charAt(4); //gives the char of 1 or 0 as it is always present at index 4
+ boolean isDone = (bool == '1'); //since 1 indicates done
+ if (input.charAt(0) == 'T') {
+ ToDo todoPresent = todoPresent(input, isDone);
+ tasks.add(todoPresent);
+ } else if (input.charAt(0) == 'E') {
+ Event eventPresent = eventPresent(input, isDone);
+ tasks.add(eventPresent);
+ } else if (input.charAt(0) == 'D') {
+ Deadline deadlinePresent = deadlinePresent(input, isDone);
+ tasks.add(deadlinePresent);
+ } else {
+
+ }
+ }
+ /**
+ * Returns ToDo task for that present in the list in storage
+ *
+ * @param input string from the file in storage
+ * @param isDone boolean of whether task is completed or not. True if completed and false otherwise.
+ * @return ToDo task
+ */
+ private ToDo todoPresent(String input, boolean isDone) {
+ return new ToDo(input.substring(8), isDone); // since the string after index 8
+ }
+
+ /**
+ * Returns Event task for that present in list in storage
+ *
+ * @param input string from file in storage
+ * @param isDone boolean of whether task is completed or not. True if completed and false otherwise.
+ * @return Event task
+ */
+ private Event eventPresent(String input, boolean isDone) throws DukeException {
+ String string = "";
+ int index = -1;
+ for (int i = 8; i < input.length(); i++) {
+ if (input.charAt(i) == '|') {
+ index = i;
+ break;
+ }
+ string = string + input.charAt(i); //character "|" splits the description of event and time.
+ }
+ String another = "";
+ for (int i = index + 2; i < input.length(); i++) {
+ if (input.charAt(i) == '-') {
+ index = i;
+ break;
+ }
+ another = another + input.charAt(i); // character "-" separates the start and end time.
+ }
+ return Event.eventTask(string, another, input.substring(index + 1), isDone);
+ }
+ /**
+ * Returns Deadline task for that present in list in storage
+ *
+ * @param input string from file in storage
+ * @param isDone boolean of whether task is completed or not. True if completed and false otherwise.
+ * @return Deadline task
+ */
+ private Deadline deadlinePresent(String input, boolean isDone) throws DeadlineException {
+ String string = "";
+ int index = -1;
+ for (int i = 8; i < input.length(); i++) {
+ if (input.charAt(i) == '|') {
+ index = i;
+ break;
+ }
+ string = string + input.charAt(i); //line '|' splits the description of deadline and time.
+ }
+ return Deadline.deadlineTask(string, input.substring(index + 2), isDone);
+ }
+ /**
+ * gives the filePath
+ * @return the value of filePath
+ */
+ public String getFilePath() {
+ return filePath;
+ }
+
+ /**
+ * This splits the short form into the original form and short form
+ *
+ * @param shortFormString is the String input by user
+ * @return String array containing the original and the short form of keywords
+ */
+ public String[] shortFormDictionary(String shortFormString) {
+ String shortForm = "";
+ int index = -1;
+ for (int i = 0; i < shortFormString.length(); i++) {
+ if (shortFormString.charAt(i) == ' ') {
+ index = i;
+ break;
+ }
+ shortForm = shortForm + shortFormString.charAt(i);
+ }
+ return new String[]{shortForm, shortFormString.substring(index + 1)};
+ }
+
+ /**
+ * Gets the shortFormsFilePath
+ *
+ * @return value of shortFormsFilePath
+ */
+ public String getShortFormsFilePath() {
+ return shortFormsFilePath;
+ }
+}
diff --git a/src/main/java/duke/helpers/TaskList.java b/src/main/java/duke/helpers/TaskList.java
new file mode 100644
index 0000000000..6597d50013
--- /dev/null
+++ b/src/main/java/duke/helpers/TaskList.java
@@ -0,0 +1,37 @@
+package duke.helpers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import duke.tasks.Task;
+
+/**
+ * contains the task list e.g., it has operations to add/delete tasks in the list
+ */
+public class TaskList {
+ private List allTasks; //Contains all the current tasks
+ /**
+ * Assigns allTasks a value
+ *
+ * @param tasks assings the mem var a value of allTasks
+ */
+ public TaskList(List tasks) {
+ this.allTasks = new ArrayList<>(tasks);
+ }
+
+ /**
+ * another constructor, where the allTasks variable is just empty
+ */
+ public TaskList() {
+ allTasks = new ArrayList<>();
+ }
+
+ /**
+ * Returns the list of tasks.
+ *
+ * @return the list of tasks.
+ */
+ public List getAllTasks() {
+ return allTasks;
+ }
+}
diff --git a/src/main/java/duke/helpers/Ui.java b/src/main/java/duke/helpers/Ui.java
new file mode 100644
index 0000000000..2cfac1c11d
--- /dev/null
+++ b/src/main/java/duke/helpers/Ui.java
@@ -0,0 +1,85 @@
+package duke.helpers;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Scanner;
+
+import duke.errors.DukeException;
+import duke.errors.FileAbsentException;
+
+/**
+ * deals with interactions with the user
+ */
+public class Ui {
+ private DukeException dukeException; //Contains the DukeException if it is thrown
+ private Scanner sc; //Used to scan the user input
+
+ /**
+ * Constructor that assigns Scanner sc to Scanner object, to scan values given by user
+ */
+ public Ui() {
+ sc = new Scanner(System.in);
+ }
+
+ /**
+ * constructor that assigns variables with respective values
+ *
+ * @param file assigned to variable file
+ * @throws DukeException if file is absent at String file given
+ */
+ public Ui(String file) throws DukeException {
+ try {
+ sc = new Scanner(new File(file));
+ } catch (FileNotFoundException f) {
+ sc = new Scanner(System.in);
+ throw new FileAbsentException(file);
+ }
+
+ }
+
+ public void setDukeException(DukeException dukeException) {
+ this.dukeException = dukeException;
+ }
+ /**
+ * This prints out if there is an error when tasks are loaded
+ */
+ public void showLoadingError() {
+ System.out.println(dukeException.getMessage());
+ }
+ /**
+ * prints welcome message
+ */
+ public void showWelcome() {
+ System.out.println(" ____________________________________________________________\n"
+ + " Hello! I'm Duke\n" + " What can I do for you?");
+ }
+
+ /**
+ * This prints the ____ for easier readability
+ */
+ public void showLine() {
+ System.out.println(" ____________________________________________________________\n");
+ }
+
+ /**
+ * This prints the next line of code to execute if it exists
+ *
+ * @return the string of command
+ */
+ public String readCommand() {
+ if (sc.hasNextLine()) {
+ return sc.nextLine();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Prints out the error
+ *
+ * @param s s is the error that is printed
+ */
+ public void showError(String s) {
+ System.out.println(s);
+ }
+}
diff --git a/src/main/java/duke/tasks/Deadline.java b/src/main/java/duke/tasks/Deadline.java
new file mode 100644
index 0000000000..404dcda1f3
--- /dev/null
+++ b/src/main/java/duke/tasks/Deadline.java
@@ -0,0 +1,199 @@
+package duke.tasks;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+import duke.errors.DeadlineException;
+import duke.errors.DukeException;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.helpers.Ui;
+
+/**
+ * The deadline is a subclass of Task and it is used to describe tasks that has to be completed by a specific day.
+ */
+public class Deadline extends Task {
+ private String dayAndOrTime; //the day and or time that Task deadline had to be completed by
+ private LocalDate deadlineInDate;
+ private LocalDateTime deadlineInDateAndTime;
+ private LocalTime deadlineInTime;
+
+ /**
+ * Assigns the name, dayAndOrTime, deadlineInDate with values initializes Deadline task
+ *
+ * @param name assigns this.name with value
+ * @param dayAndOrTime assigns this.dayAndOrTime with value(String format of deadlineInDate)
+ * @param deadlineInDate assigns this.deadlineInDate with value
+ */
+ private Deadline(String name, String dayAndOrTime, LocalDate deadlineInDate) {
+ super(name);
+ this.dayAndOrTime = dayAndOrTime;
+ this.deadlineInDate = deadlineInDate;
+ }
+
+ /**
+ * Assigns the name, dayAndOrTime, deadlineInDateAndTime with values initializes Deadline task
+ *
+ * @param name assigns this.name with value
+ * @param dayAndOrTime assigns this.dayAndOrTime with value(String format of deadlineInDateAndTime)
+ * @param deadlineInDateAndTime assigns this.deadlineInDate with value
+ */
+ public Deadline(String name, String dayAndOrTime, LocalDateTime deadlineInDateAndTime) {
+ super(name);
+ this.dayAndOrTime = dayAndOrTime;
+ this.deadlineInDateAndTime = deadlineInDateAndTime;
+ }
+
+ /**
+ * Assigns the name, dayAndOrTime, deadlineInDate with values initializes Deadline task
+ *
+ * @param name assigns this.name with value
+ * @param dayAndOrTime assigns this.dayAndOrTime with value(String format of deadlineInTime)
+ * @param deadlineInTime assigns this.deadlineInDate with value
+ */
+ public Deadline(String name, String dayAndOrTime, LocalTime deadlineInTime) {
+ super(name);
+ this.dayAndOrTime = dayAndOrTime;
+ this.deadlineInTime = deadlineInTime;
+ }
+ /**
+ * Takes no arguments and overrides the toString method
+ *
+ * @return the specific representation for deadline class as mentioned with [D]
+ * indicating that it is a deadline class
+ * and also mentions the deadline.
+ */
+ public String toString() {
+ return "[D]" + super.toString() + "(by: " + this.dayAndOrTime + ")";
+ }
+
+ /**
+ * Gives a specific string representation for that in the tasks.txt file and overrides that in Task to make
+ * it unique to that for Deadline
+ *
+ * @return the string representation
+ */
+ public String inputListFormat() {
+ String s = super.inputListFormat();
+ return "D" + super.inputListFormat() + "| " + this.dayAndOrTime; //format of Tasks to appear in file in Storage
+ }
+
+ /**
+ * Used to add a deadline task to tasks in TaskList and update the tasks file in storage
+ *
+ * @param tasks contains all the current Tasks in a list, and to update this
+ * @param ui to set its DukeException if it is thrown
+ * @param storage contains all the current Tasks in a file, and to update this
+ * @param userInput String of the user input
+ * @return String message that Deadline has been added successfully
+ * @throws DukeException thrown if error is present in user input
+ */
+ public static String addDeadlineTask(TaskList tasks, Ui ui, Storage storage, String userInput)
+ throws DukeException {
+ try {
+ String[] dataSplit = splitData(userInput);
+ //Split userInput into description name and time and/or date
+ Deadline d = deadlineTask(dataSplit[0], dataSplit[1]); //gives the Deadline
+ return updateTaskList(storage, d, tasks); //updates the tasks and file in storage
+ } catch (DukeException dukeException) {
+ ui.setDukeException(dukeException);
+ throw dukeException;
+ }
+ }
+ /**
+ * splits the userInput into Deadline description and the Deadline date and/ or time.
+ * If the date and/or time is absent then DeadlineException is thrown.
+ *
+ * @return the String array where the first String is the name of the Deadline and the second is the date
+ * and/or time of deadline
+ * @throws DeadlineException thrown when the time and/or date is absent.
+ */
+ private static String[] splitData(String userInput) throws DeadlineException {
+ String s = "";
+ int index = -1;
+ boolean time = false;
+ for (int i = 8; i < userInput.length(); i++) {
+ if (userInput.charAt(i) == '/') {
+ index = i;
+ time = true; //since date appears after
+ break;
+ }
+ s = s + userInput.charAt(i);
+ }
+ if (!time) {
+ throw new DeadlineException(false, false, true);
+ }
+ assert !s.substring(1, s.length() - 1).contains("/"); // description should not contain /
+ assert !userInput.substring(index + 4).contains("/by"); ////date and/or time should not contain /at
+ String[] dataSplit = new String[]{s.substring(1, s.length() - 1), userInput.substring(index + 4)};
+ return dataSplit;
+ }
+
+ /**
+ * This method creates a deadline task by checking whether the date and/or time given is in the correct
+ * format. If it is then Deadline task is returned else, DeadlineException is returned.
+ *
+ * @param name description of Deadline task
+ * @param dateTime gives the dateTime, to check whether they are in the correct format
+ * @return deadline if the dateTime is in the correct format
+ * @throws DeadlineException if the dateTime is in the incorrect format
+ */
+ private static Deadline deadlineTask(String name, String dateTime) throws DeadlineException {
+ Deadline e;
+ try {
+ LocalDate parsedDate = stringToLocalDate(dateTime); //converts string to date
+ e = new Deadline(name, parsedDate.format(DateTimeFormatter.ofPattern("dd LLL yyyy")), parsedDate);
+ } catch (DateTimeException d) {
+ try {
+ LocalDateTime parsedDate = stringToLocalDateTime(dateTime); //converts string to date and time
+ e = new Deadline(name, parsedDate.format(DateTimeFormatter.ofPattern("dd LLL yyyy, HH:mm")),
+ parsedDate);
+ } catch (DateTimeException g) {
+ try {
+ LocalTime parsedDate = stringToLocalTime(dateTime); //converts string to date
+ e = new Deadline(name, parsedDate.format(DateTimeFormatter.ofPattern("HH:mm")), parsedDate);
+ } catch (DateTimeException f) {
+ throw new DeadlineException(false, true, false);
+ }
+ }
+ }
+ return e;
+ }
+ /**
+ * This method creates a deadline task by checking whether the date and/or time given is in the correct
+ * format. If it is then Deadline task is returned else, DeadlineException is returned.
+ *
+ * @param name description of Deadline task
+ * @param dateTime gives the dateTime, to check whether they are in the correct format
+ * @param done true if task is done and false if not done and is assigned to isDone variable
+ * @return deadline if the dateTime is in the correct format
+ * @throws DeadlineException if the dateTime is in the incorrect format
+ */
+ public static Deadline deadlineTask(String name, String dateTime, boolean done) throws DeadlineException {
+ Deadline e;
+ try {
+ LocalDate parsedDate = stringToLocalDateExistingTask(dateTime); //converts string to date
+ e = new Deadline(name, parsedDate.format(DateTimeFormatter.ofPattern("dd LLL yyyy")), parsedDate);
+ } catch (DateTimeException d) {
+ try {
+ LocalDateTime parsedDate = stringToLocalDateTimeExistingTask(dateTime);
+ //converts string to date and time
+ e = new Deadline(name, parsedDate.format(DateTimeFormatter.ofPattern("dd LLL yyyy, HH:mm")),
+ parsedDate);
+ } catch (DateTimeException g) {
+ try {
+ LocalTime parsedDate = stringToLocalTimeExistingTask(dateTime); //converts string to date
+ e = new Deadline(name, parsedDate.format(DateTimeFormatter.ofPattern("HH:mm")), parsedDate);
+ } catch (DateTimeException f) {
+ throw new DeadlineException(false, true, false);
+ }
+ }
+ }
+ e.setDone(done);
+ return e;
+ }
+
+}
diff --git a/src/main/java/duke/tasks/Event.java b/src/main/java/duke/tasks/Event.java
new file mode 100644
index 0000000000..3e08ab7f35
--- /dev/null
+++ b/src/main/java/duke/tasks/Event.java
@@ -0,0 +1,294 @@
+package duke.tasks;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+import duke.errors.DeadlineException;
+import duke.errors.DukeException;
+import duke.errors.EventException;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+import duke.helpers.Ui;
+
+
+/**
+ * The Event is a subclass of Task and it is used to describe tasks that has to be completed by a specific day and time
+ */
+public class Event extends Task {
+ private String startDateAndOrTime; //the start date and/or time of the event
+ private String endDateAndOrTime; //the end date and/or time of the event
+ private LocalDate startDate;
+ private LocalDate endDate;
+ private LocalDateTime startDateTime;
+ private LocalDateTime endDateTime;
+ private LocalTime startTime;
+ private LocalTime endTime;
+ /**
+ * Assigns the name, done and day variables with values and used to initialize Event task
+ *
+ * @param name super(name) so that it does whatever is mentioned in the parent class
+ * @param start assigns this.dayTime to dayTime value
+ */
+ public Event(String name, String start, String end) {
+ super(name);
+ this.startDateAndOrTime = start;
+ this.endDateAndOrTime = end;
+ }
+
+ /**
+ * Assigns the name, starDateAndOrTime, endDateAndOrTime, startDate, endDate with values and initializes Event task
+ *
+ * @param name assigned to super.name(name of deadline)
+ * @param startDateAndOrTime assigned to this.startDateAndOrTime
+ * @param endDateAndOrTime assigned to this.endDateAndOrTime
+ * @param startDate assigned to this.startDate
+ * @param endDate assigned to this.endDate
+ */
+ public Event(String name, String startDateAndOrTime, String endDateAndOrTime, LocalDate startDate,
+ LocalDate endDate) {
+ super(name);
+ this.startDateAndOrTime = startDateAndOrTime;
+ this.endDateAndOrTime = endDateAndOrTime;
+ this.startDate = startDate;
+ this.endDate = endDate;
+ }
+
+ /**
+ * Assigns the name, starDateAndOrTime, endDateAndOrTime, startDateTime,
+ * endDateTime with values and initializes Event task
+ *
+ * @param name assigned to super.name(name of deadline)
+ * @param startDateAndOrTime assigned to this.startDateAndOrTime
+ * @param endDateAndOrTime assigned to this.endDateAndOrTime
+ * @param startDateTime assigned to this.startDateTime
+ * @param endDateTime assigned to this.endDateTime
+ */
+ public Event(String name, String startDateAndOrTime, String endDateAndOrTime, LocalDateTime startDateTime,
+ LocalDateTime endDateTime) {
+ super(name);
+ this.startDateAndOrTime = startDateAndOrTime;
+ this.endDateAndOrTime = endDateAndOrTime;
+ this.startDateTime = startDateTime;
+ this.endDateTime = endDateTime;
+ }
+
+ /**
+ * Assigns the name, starDateAndOrTime, endDateAndOrTime, startTime, endTime with values and initializes Event task
+ *
+ * @param name assigned to super.name(name of deadline)
+ * @param startDateAndOrTime assigned to this.startDateAndOrTime
+ * @param endDateAndOrTime assigned to this.endDateAndOrTime
+ * @param startTime assigned to this.startTime
+ * @param endTime assigned to this.endTime
+ */
+ public Event(String name, String startDateAndOrTime, String endDateAndOrTime, LocalTime startTime,
+ LocalTime endTime) {
+ super(name);
+ this.startDateAndOrTime = startDateAndOrTime;
+ this.endDateAndOrTime = endDateAndOrTime;
+ this.startTime = startTime;
+ this.endTime = endTime;
+ }
+ /**
+ * Overrides the toString methods
+ *
+ * @return the specific representation for Event class as mentioned with [E] indicating that it is a Event class
+ * * and also mentions the Event.
+ */
+ public String toString() {
+ return "[E]" + super.toString() + "(at: " + this.startDateAndOrTime + "-" + this.endDateAndOrTime + ")";
+ }
+
+ /**
+ * Gives a specific string representation for that in the tasks.txt file and overrides that in Task to make
+ * it unique to that for Event
+ *
+ * @return the string representation
+ */
+ public String inputListFormat() {
+ return "E" + super.inputListFormat() + "| " + this.startDateAndOrTime + "-" + this.endDateAndOrTime;
+ //format of Tasks to appear in file in Storage
+ }
+ public static String addEventTask(TaskList tasks, Ui ui, Storage storage, String commandDescription)
+ throws DukeException {
+ return process(tasks, storage, commandDescription);
+ }
+ /**
+ * Returns String if the user input is correct and throws exception otherwise
+ *
+ * @param tasks used to add Event into tasks if user input is correct
+ * @param storage used to update file in storage that contains file if user input is correct
+ * @return String informing user that Event has been added to list
+ * @throws DukeException thrown if user input is wrong
+ */
+ private static String process(TaskList tasks, Storage storage, String commandDescription) throws DukeException {
+ String[] dataSplit = splitData(commandDescription);
+ //splits String into different of Event name, start and end time and/or date
+ Event event = eventTask(dataSplit[0], dataSplit[1], dataSplit[2]);
+ //gives the event or throws exception
+ return updateTaskList(storage, event, tasks);
+ //updates the Task list in Storage and TaskList since the Event is added
+ }
+ /**
+ * splits the data into Deadline description and the Deadline date and/ or time. If the date and/or time is absent
+ * then DeadlineException is thrown.
+ *
+ * @return the String array where the first String is the name of the Deadline
+ * and the second is the date and/or time
+ * of start for event, third is the date and/or time of end for event.
+ * @throws EventException thrown when the time and/or date is absent.
+ */
+ private static String[] splitData(String commandDescription) throws EventException {
+ String s = "";
+ int index = -1;
+ int end = -1;
+ boolean startPresent = false;
+ boolean endPresent = false;
+ String start = "";
+ for (int i = 5; i < commandDescription.length(); i++) {
+ if (commandDescription.charAt(i) == '/') {
+ index = i;
+ startPresent = true; //the presence of / indicates that the start time is present.
+ break;
+ }
+ s = s + commandDescription.charAt(i);
+ }
+ for (int i = index + 1; i < commandDescription.length(); i++) {
+ if (commandDescription.charAt(i) == '-' && i != commandDescription.length() - 1) {
+ end = i;
+ endPresent = true; // - indicates that end time is present
+ break;
+ }
+ start = start + commandDescription.charAt(i);
+ }
+ if (!startPresent) {
+ throw new EventException(false, false, false, false, true);
+ }
+ if (!endPresent) {
+ throw new EventException(false, true, false, false, false);
+ }
+ String[] dataSplit = new String[3];
+
+ assert !s.substring(1, s.length() - 1).contains("/"); //description cannot contain
+ assert !commandDescription.substring(index + 4).contains("/at"); //start date and/or time cannot contain /at
+ assert !commandDescription.substring(end + 1).contains("-"); //end date and/or time cannot contain -
+
+
+ dataSplit[0] = s.substring(1, s.length() - 1);
+ dataSplit[1] = commandDescription.substring(index + 4, end);
+ dataSplit[2] = commandDescription.substring(end + 1);
+ return dataSplit;
+ }
+ /**
+ * This method creates a deadline task by checking whether the date and/or time given is in the correct
+ * format. If it is then Deadline task is returned else, DeadlineException is returned.
+ *
+ * @param name description of Deadline task
+ * @param start gives the dateTime of the start to check whether they are in the correct format
+ * @param end gives the dateTime of the end to check whether they are in the correct format
+ * @return deadline if the dateTime is in the correct format
+ * @throws DeadlineException if the dateTime is in the incorrect format
+ */
+ private static Event eventTask(String name, String start, String end) throws DukeException {
+ Event e;
+ try {
+ LocalDate startDate = stringToLocalDateExistingTask(start); //converts start to date
+ LocalDate endDate = stringToLocalDateExistingTask(end); //converts end to date
+
+ if (startDate.isAfter(endDate)) {
+ throw new EventException(false, false, true, false, false); //if start > end then it throws this error.
+ }
+ e = new Event(name, startDate.format(DateTimeFormatter.ofPattern("dd LLL yyyy")),
+ endDate.format(DateTimeFormatter.ofPattern("dd LLL yyyy")), startDate, endDate);
+ } catch (EventException event) {
+ throw new EventException(false, false, true, false, false);
+ } catch (DateTimeException d) {
+ try {
+ LocalDateTime startDateTime = stringToLocalDateTimeExistingTask(start); //converts start to dateTime
+ LocalDateTime endDateTime = stringToLocalDateTimeExistingTask(end); //converts end to dateTime
+ if (startDateTime.isAfter(endDateTime)) {
+ throw new EventException(false, false, true, false, false); //if start > end it throws this error
+ }
+ e = new Event(name, startDateTime.format(DateTimeFormatter.ofPattern("dd LLL yyyy, HH:mm")),
+ endDateTime.format(DateTimeFormatter.ofPattern("dd LLL yyyy, HH:mm")),
+ startDateTime, endDateTime);
+ } catch (EventException event) {
+ throw new EventException(false, false, true, false, false);
+ } catch (DateTimeException g) {
+ try {
+ LocalTime startTime = stringToLocalTimeExistingTask(start); //converts start to time
+ LocalTime endTime = stringToLocalTimeExistingTask(end); //converts end to time
+ if (startTime.isAfter(endTime)) {
+ throw new EventException(false, false, true, false, false); //if start > end it throws error
+ }
+ e = new Event(name, startTime.format(DateTimeFormatter.ofPattern("HH:mm")),
+ endTime.format(DateTimeFormatter.ofPattern("HH:mm")), startTime, endTime);
+ } catch (EventException y) {
+ throw new EventException(false, false, true, false, false);
+ } catch (DateTimeException z) {
+ throw new EventException(false, false, false, true, false);
+ }
+ }
+ }
+ return e;
+ }
+
+ /**
+ * This method creates a deadline task by checking whether the date and/or time given is in the correct
+ * format. If it is then Deadline task is returned else, DeadlineException is returned.
+ *
+ * @param name description of Deadline task
+ * @param start gives the dateTime of the start to check whether they are in the correct format
+ * @param end gives the dateTime of the end to check whether they are in the correct format
+ * @param isDone true if task is done and false if not done and is assigned to isDone variable
+ * @return deadline if the dateTime is in the correct format
+ * @throws DeadlineException if the dateTime is in the incorrect format
+ */
+ public static Event eventTask(String name, String start, String end, boolean isDone) throws DukeException {
+ Event e;
+ try {
+ LocalDate startDate = stringToLocalDateExistingTask(start); //converts start to date
+ LocalDate endDate = stringToLocalDateExistingTask(end); //converts end to date
+
+ if (startDate.isAfter(endDate)) {
+ throw new EventException(false, false, true, false, false); //if start > end then it throws this error.
+ }
+ e = new Event(name, startDate.format(DateTimeFormatter.ofPattern("dd LLL yyyy")),
+ endDate.format(DateTimeFormatter.ofPattern("dd LLL yyyy")), startDate, endDate);
+ } catch (EventException event) {
+ throw new EventException(false, false, true, false, false);
+ } catch (DateTimeException d) {
+ try {
+ LocalDateTime startDateTime = stringToLocalDateTimeExistingTask(start); //converts start to dateTime
+ LocalDateTime endDateTime = stringToLocalDateTimeExistingTask(end); //converts end to dateTime
+ if (startDateTime.isAfter(endDateTime)) {
+ throw new EventException(false, false, true, false, false); //if start > end it throws this error
+ }
+ e = new Event(name, startDateTime.format(DateTimeFormatter.ofPattern("dd LLL yyyy, HH:mm")),
+ endDateTime.format(DateTimeFormatter.ofPattern("dd LLL yyyy, HH:mm")),
+ startDateTime, endDateTime);
+ } catch (EventException event) {
+ throw new EventException(false, false, true, false, false);
+ } catch (DateTimeException g) {
+ try {
+ LocalTime startTime = stringToLocalTimeExistingTask(start); //converts start to time
+ LocalTime endTime = stringToLocalTimeExistingTask(end); //converts end to time
+ if (startTime.isAfter(endTime)) {
+ throw new EventException(false, false, true, false, false); //if start > end it throws error
+ }
+ e = new Event(name, startTime.format(DateTimeFormatter.ofPattern("HH:mm")),
+ endTime.format(DateTimeFormatter.ofPattern("HH:mm")), startTime, endTime);
+ } catch (EventException y) {
+ throw new EventException(false, false, true, false, false);
+ } catch (DateTimeException z) {
+ throw new EventException(false, false, false, true, false);
+ }
+ }
+ }
+ e.setDone(isDone);
+ return e;
+ }
+}
diff --git a/src/main/java/duke/tasks/Task.java b/src/main/java/duke/tasks/Task.java
new file mode 100644
index 0000000000..06236e86fb
--- /dev/null
+++ b/src/main/java/duke/tasks/Task.java
@@ -0,0 +1,208 @@
+package duke.tasks;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+import duke.errors.DukeException;
+import duke.errors.FileAbsentException;
+import duke.helpers.Storage;
+import duke.helpers.TaskList;
+
+/**
+ * This Task is made abstract because it is never initialized in the actual code, however,
+ * it is used so that polymorphism
+ * is able to work properly.
+ */
+public abstract class Task {
+ /**
+ * Tasks is made static because it contains the different tasks that are added, and therefore it is not limited to
+ * a single instance of Task
+ */
+ private boolean isDone; //true if Task is completed, false otherwise
+ private String name; //gives name of the Task
+ /**
+ * constructor assigns name variable a value
+ *
+ * @param name this assigns the name of the Task to the name being given in the constructor
+ */
+ Task(String name) {
+ this.isDone = false;
+ this.name = name;
+ }
+
+ /**
+ * constructor assigns name and done a value.
+ *
+ * @param name assigns name to this.name
+ * @param isDone assigns name to this.done
+ */
+ Task(String name, boolean isDone) {
+ this.isDone = isDone;
+ this.name = name;
+ }
+ /**
+ * gives name of task
+ *
+ * @return name of task
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns value isDone of a task
+ *
+ * @return true if task is done, false otherwise
+ */
+ public boolean getIsDone() {
+ return isDone;
+ }
+ /**
+ * setter that sets Done to the done value stated
+ *
+ * @param done value given to set it to done var
+ */
+ public void setDone(boolean done) {
+ this.isDone = done;
+ }
+
+ /**
+ * Overrides the toString methods
+ *
+ * @return String which contains info on task name as well as whether it is completed(tick sign) or not(cross sign).
+ */
+ public String toString() {
+ if (this.isDone) {
+ return "[" + "\u2713" + "] " + this.name; //\u2713 is a tick, denoting done
+ } else if (!this.isDone) {
+ return "[" + "\u2717" + "] " + this.name; //\u2717 is a cross, deonoting not done
+ } else {
+ return "default";
+ }
+ }
+
+ /**
+ * Gives a specific string representation for that in the tasks.txt file
+ *
+ * @return the string representation
+ */
+ public String inputListFormat() { //format of Tasks to appear in file in Storage
+ if (this.isDone) {
+ return " | 1 | " + this.name; //1 denotes done
+ } else if (!this.isDone) {
+ return " | 0 | " + this.name; //0 denotes not done
+ } else {
+ return "default";
+ }
+ }
+ /**
+ * converts string to date
+ *
+ * @param string string to convert to date
+ * @return local date which is converted from string, if cannot then DateTimeException thrown
+ */
+ protected static LocalDate stringToLocalDate(String string) {
+ try {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
+ LocalDate parsedDate = LocalDate.parse(string, formatter); //converts string to date
+ return parsedDate;
+ } catch (DateTimeException d) {
+ throw d;
+ }
+ }
+ /**
+ * converts string to dateTime
+ *
+ * @param string string to convert to dateTime
+ * @return local dateTime which is converted from string, if cannot then DateTimeException thrown
+ */
+ protected static LocalDateTime stringToLocalDateTime(String string) {
+ try {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd, HH:mm");
+ LocalDateTime parsedDate = LocalDateTime.parse(string, formatter); //converts string to date and time
+ return parsedDate;
+ } catch (DateTimeException g) {
+ throw g;
+ }
+ }
+
+ /**
+ * converts string to time
+ *
+ * @param string string to convert to time
+ * @return local time which is converted from string, if cannot then DateTimeException thrown
+ */
+ protected static LocalTime stringToLocalTime(String string) {
+ try {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");
+ LocalTime parsedDate = LocalTime.parse(string, formatter); //converts string to time
+ return parsedDate;
+ } catch (DateTimeException f) {
+ throw f;
+ }
+ }
+ protected static LocalDate stringToLocalDateExistingTask(String string) {
+ try {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd LLL yyyy");
+ LocalDate parsedDate = LocalDate.parse(string, formatter); //converts string to time
+ return parsedDate;
+ } catch (DateTimeException f) {
+ throw f;
+ }
+ }
+ protected static LocalDateTime stringToLocalDateTimeExistingTask(String string) {
+ try {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd LLL yyyy, HH:mm");
+ LocalDateTime parsedDate = LocalDateTime.parse(string, formatter); //converts string to time
+ return parsedDate;
+ } catch (DateTimeException f) {
+ throw f;
+ }
+ }
+ protected static LocalTime stringToLocalTimeExistingTask(String string) {
+ try {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");
+ LocalTime parsedDate = LocalTime.parse(string, formatter); //converts string to time
+ return parsedDate;
+ } catch (DateTimeException f) {
+ throw f;
+ }
+ }
+ /**
+ * adds the task to list of task in taskList and into the file in storage
+ *
+ * @param storage where the file here is updated
+ * @param task this task is added into storage and taskList
+ * @param taskList where the tasks here is updated with task added
+ * @throws DukeException when the file in storage is not present
+ */
+ protected static String updateTaskList(Storage storage, Task task, TaskList taskList) throws DukeException {
+ try {
+ FileWriter fw = new FileWriter(storage.getFilePath(), true);
+ //updates the file in storage as new task is added
+ taskList.getAllTasks().add(task);
+ fw.write(task.inputListFormat() + "\n");
+ fw.close();
+ } catch (IOException i) {
+ throw new FileAbsentException(storage.getFilePath());
+ }
+ return stringToUpdateTaskList(task, taskList);
+ }
+
+ /**
+ * Gives a String saying that the task list has been updated
+ *
+ * @param task to be added into taskList
+ * @param taskList where task is added
+ * @return String that informs task is added into taskList
+ */
+ protected static String stringToUpdateTaskList(Task task, TaskList taskList) {
+ return " Got it. I've added this task:\n " + task.toString() + "\n" + //Task added message
+ " Now you have " + taskList.getAllTasks().size() + " tasks in the list.";
+ }
+}
diff --git a/src/main/java/duke/tasks/ToDo.java b/src/main/java/duke/tasks/ToDo.java
new file mode 100644
index 0000000000..4e949ffe11
--- /dev/null
+++ b/src/main/java/duke/tasks/ToDo.java
@@ -0,0 +1,42 @@
+package duke.tasks;
+
+/**
+ * The ToDo is a subclass of Task and it is used to describe tasks that have no specific deadline
+ */
+
+public class ToDo extends Task {
+ /**
+ * Constructor assigns name to name value and initialize ToDO task
+ *
+ * @param name super(name) so that it does whatever is mentioned in the parent class
+ */
+ public ToDo(String name) {
+ super(name);
+ }
+
+ /**
+ * Constructor assigns name and done to values and initialize ToDO task
+ *
+ * @param name assigns name to this.name
+ * @param done assigns done to this.done
+ */
+ public ToDo(String name, boolean done) {
+ super(name, done);
+ }
+
+ /**
+ * Takes no arguments and overrides the toString method
+ *
+ * @return the specific representation for ToDo class as mentioned with [T] indicating that it is a ToDo class
+ *
+ */
+ @Override
+ public String toString() {
+ return "[T]" + super.toString();
+ }
+
+
+ public String inputListFormat() {
+ return "T" + super.inputListFormat(); //format of Tasks to appear in file in Storage
+ }
+}
diff --git a/src/main/java/expected.txt b/src/main/java/expected.txt
new file mode 100644
index 0000000000..37e22c7a90
--- /dev/null
+++ b/src/main/java/expected.txt
@@ -0,0 +1,57 @@
+ Task file is empty!
+ ____________________________________________________________
+ Hello! I'm Duke
+ What can I do for you?
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ '☹' OOPS!!! Start should be less than end.
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ Got it. I've added this task:
+ [T][✗] buy book
+ Now you have 1 tasks in the list.
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ Nice! I've marked this task as done:
+ [T][✓] buy book
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ '☹' OOPS!!! Start should be less than end.
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ '☹' OOPS!!! The ID is not yet defined.
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ Got it. I've added this task:
+ [D][✗] submission(by: 14 Nov 2020)
+ Now you have 2 tasks in the list.
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+[T][✓] buy book
+[D][✗] submission(by: 14 Nov 2020)
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ '☹ OOPS!!! I'm sorry, but I don't know what that means :-(
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ Bye. Hope to see you again soon!
+ ____________________________________________________________
+
diff --git a/src/main/java/input.txt b/src/main/java/input.txt
new file mode 100644
index 0000000000..cf55267da8
--- /dev/null
+++ b/src/main/java/input.txt
@@ -0,0 +1,9 @@
+event concert /at 12:00-10:00
+todo buy book
+done 1
+event book club /at 12:00-10:00
+delete 2
+deadline submission /by 2020 11 14
+list
+blah
+bye
diff --git a/src/main/java/output.txt b/src/main/java/output.txt
new file mode 100644
index 0000000000..593dd101f0
--- /dev/null
+++ b/src/main/java/output.txt
@@ -0,0 +1,57 @@
+ Task file is empty!
+ ____________________________________________________________
+ Hello! I'm Duke
+ What can I do for you?
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ '☹' OOPS!!! Start should be less than end.
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ Got it. I've added this task:
+ [T][✗] buy book
+ Now you have 1 tasks in the list.
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ Nice! I've marked this task as done:
+ [T][✓] buy book
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ '☹' OOPS!!! Start should be less than end.
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ '☹' OOPS!!! The ID is not yet defined.
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ Got it. I've added this task:
+ [D][✗] submission(by: 14 Nov 2020)
+ Now you have 2 tasks in the list.
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ [T][✓] buy book
+ [D][✗] submission(by: 14 Nov 2020)
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ '☹ OOPS!!! I'm sorry, but I don't know what that means :-(
+ ____________________________________________________________
+
+ ____________________________________________________________
+
+ Bye. Hope to see you again soon!
+ ____________________________________________________________
+
diff --git a/src/main/java/shortCuts.txt b/src/main/java/shortCuts.txt
new file mode 100644
index 0000000000..ea08d51874
--- /dev/null
+++ b/src/main/java/shortCuts.txt
@@ -0,0 +1,7 @@
+by bye
+li list
+to todo
+dead deadline
+fi find
+tod todo
+x bye
diff --git a/src/main/java/tasks.txt b/src/main/java/tasks.txt
new file mode 100644
index 0000000000..a2a6b3d13c
--- /dev/null
+++ b/src/main/java/tasks.txt
@@ -0,0 +1,4 @@
+T | 1 | buy book
+E | 1 | concert | 12:00-14:00
+T | 0 | read book
+T | 0 | read book
diff --git a/src/main/resources/images/DaDuke.png b/src/main/resources/images/DaDuke.png
new file mode 100755
index 0000000000..ed8c75fdfa
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 100755
index 0000000000..1ad5098c89
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..a9fc8e054c
--- /dev/null
+++ b/src/main/resources/view/DialogBox.fxml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
new file mode 100644
index 0000000000..9b910aa6fa
--- /dev/null
+++ b/src/main/resources/view/MainWindow.fxml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/java/duke/DukeTest.java b/src/test/java/duke/DukeTest.java
new file mode 100644
index 0000000000..9040e71db9
--- /dev/null
+++ b/src/test/java/duke/DukeTest.java
@@ -0,0 +1,203 @@
+package duke;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Scanner;
+
+import org.junit.jupiter.api.Test;
+
+public class DukeTest {
+ /**
+ * Tests whether the 2 files at the filePaths given contain same content
+ *
+ * @param s1 filePath of expected result
+ * @param s2 filePath of the actual result
+ * @return true if both files contain the same values and false otherwise
+ * @throws FileNotFoundException if file is not present in either scenario
+ */
+ private static boolean equal(String s1, String s2) throws FileNotFoundException {
+ File exp = new File(s1);
+ File act = new File(s2);
+ Scanner e = new Scanner(exp);
+ Scanner a = new Scanner(act);
+ boolean equal = true;
+ while (e.hasNext() && a.hasNext()) {
+ if (!e.next().equals(a.next())) {
+ equal = false;
+ break;
+ }
+ }
+ if (equal) {
+ if (e.hasNext() && !a.hasNext()) {
+ equal = false;
+ }
+ if (!e.hasNext() && a.hasNext()) {
+ equal = false;
+ }
+ }
+ return equal;
+ }
+ @Test
+ public void test1() throws IOException {
+ try {
+ FileWriter fw = new FileWriter("src/main/java/input.txt");
+ fw.write("bye");
+ fw.close();
+ FileWriter fileWriter = new FileWriter("src/main/java/expected.txt");
+ fileWriter.write(" Task file is empty!\n"
+ + " ____________________________________________________________\n"
+ + " Hello! I'm Duke\n" + " What can I do for you?\n"
+ + " ____________________________________________________________\n" + "\n"
+ + " ____________________________________________________________\n" + "\n"
+ + " Bye. Hope to see you again soon!\n"
+ + " ____________________________________________________________\n" + "\n");
+ fileWriter.close();
+ String[] args = new String[2];
+ Duke.main(args);
+ boolean equal = equal("src/main/java/expected.txt", "src/main/java/output.txt");
+ assertTrue(equal);
+ } catch (IOException f) {
+ throw f;
+ }
+ }
+ @Test
+ public void test2() throws IOException {
+ try {
+ FileWriter fw = new FileWriter("src/main/java/input.txt");
+ fw.append("event book club /at 12:00-14:00\n");
+ fw.append("todo read book\n");
+ fw.append("deadline submission /by 2019 12 12\n");
+ fw.append("done 1\n");
+ fw.append("delete 4\n");
+ fw.append("list\n");
+ fw.append("bye\n");
+ fw.close();
+ FileWriter fileWriter = new FileWriter("src/main/java/expected.txt");
+ fileWriter.write("Task file is empty!\n"
+ + " ____________________________________________________________\n"
+ + " Hello! I'm Duke\n"
+ + " What can I do for you?\n"
+ + " ____________________________________________________________\n"
+ + "\n" + " ____________________________________________________________\n" + "\n"
+ + " Got it. I've added this task:\n"
+ + " [E][✗] book club(at: 12:00-14:00)\n"
+ + " Now you have 1 tasks in the list.\n"
+ + " ____________________________________________________________\n" + "\n"
+ + " ____________________________________________________________\n" + "\n"
+ + " Got it. I've added this task:\n" + " [T][✗] read book\n"
+ + " Now you have 2 tasks in the list.\n"
+ + " ____________________________________________________________\n" + "\n"
+ + " ____________________________________________________________\n" + "\n"
+ + " Got it. I've added this task:\n" + " [D][✗] submission(by: 12 Dec 2019)\n"
+ + " Now you have 3 tasks in the list.\n"
+ + " ____________________________________________________________\n" + "\n"
+ + " ____________________________________________________________\n" + "\n"
+ + " Nice! I've marked this task as done:\n"
+ + " [E][✓] book club(at: 12:00-14:00)\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " ____________________________________________________________\n" + "\n"
+ + " '☹' OOPS!!! The ID is not yet defined.\n"
+ + " ____________________________________________________________\n"
+ + "\n" + " ____________________________________________________________\n"
+ + "\n" + "[E][✓] book club(at: 12:00-14:00)\n"
+ + "[T][✗] read book\n" + "[D][✗] submission(by: 12 Dec 2019)\n"
+ + " ____________________________________________________________\n"
+ + "\n" + " ____________________________________________________________\n"
+ + "\n" + " Bye. Hope to see you again soon!\n"
+ + " ____________________________________________________________\n" + "\n");
+ fileWriter.close();
+ Duke.main(new String[10]);
+ boolean equal = equal("src/main/java/expected.txt", "src/main/java/output.txt");
+ assertTrue(equal);
+ } catch (IOException f) {
+ throw f;
+ }
+ }
+ @Test
+ public void test3() throws IOException {
+ try {
+ FileWriter fw = new FileWriter("src/main/java/input.txt");
+ FileWriter fileWriter = new FileWriter("src/main/java/expected.txt");
+ fw.write("event concert /at 12:00-10:00\n" + "todo buy book\n" + "done 1\n"
+ + "event book club /at 12:00-10:00\n"
+ + "delete 2\n"
+ + "deadline submission /by 2020 11 14\n"
+ + "list\n"
+ + "blah\n"
+ + "bye\n");
+ fw.close();
+ fileWriter.write(" Task file is empty!\n"
+ + " ____________________________________________________________\n"
+ + " Hello! I'm Duke\n"
+ + " What can I do for you?\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " '☹' OOPS!!! Start should be less than end.\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " Got it. I've added this task:\n"
+ + " [T][✗] buy book\n"
+ + " Now you have 1 tasks in the list.\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " Nice! I've marked this task as done:\n"
+ + " [T][✓] buy book\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " '☹' OOPS!!! Start should be less than end.\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " '☹' OOPS!!! The ID is not yet defined.\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " Got it. I've added this task:\n"
+ + " [D][✗] submission(by: 14 Nov 2020)\n"
+ + " Now you have 2 tasks in the list.\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + "[T][✓] buy book\n"
+ + "[D][✗] submission(by: 14 Nov 2020)\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " '☹ OOPS!!! I'm sorry, but I don't know what that means :-(\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " ____________________________________________________________\n"
+ + "\n"
+ + " Bye. Hope to see you again soon!\n"
+ + " ____________________________________________________________\n"
+ + "\n");
+ fileWriter.close();
+ Duke.main(new String[10]);
+ boolean equal = equal("src/main/java/expected.txt", "src/main/java/output.txt");
+ assertTrue(equal);
+ } catch (IOException f) {
+ throw f;
+ }
+ }
+ public static void main(String[] args){
+
+ }
+
+}
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e7..54a6b9fe91 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,57 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
+ ____________________________________________________________
+ Hello! I'm duke
+ What can I do for you?
+ ____________________________________________________________
+
+event book club /at 12:00-14:00
+ ____________________________________________________________
+
+ Got it. I've added this task:
+ [E][✗] book club(at: 12:00-14:00)
+ Now you have 1 tasks in the list.
+ ____________________________________________________________
+
+todo read book
+ ____________________________________________________________
+
+ Got it. I've added this task:
+ [T][✗] read book
+ Now you have 2 tasks in the list.
+ ____________________________________________________________
+
+deadline submission /by 2019 12 12
+ ____________________________________________________________
+
+ Got it. I've added this task:
+ [D][✗] submission(by: 12 Dec 2019)
+ Now you have 3 tasks in the list.
+ ____________________________________________________________
+
+done 1
+ ____________________________________________________________
+
+ Nice! I've marked this task as done:
+ [E][✓] book club(at: 12:00-14:00)
+ ____________________________________________________________
+
+delete 4
+ ____________________________________________________________
+
+ '☹' OOPS!!! The ID is not yet defined.
+ ____________________________________________________________
+
+list
+ ____________________________________________________________
+
+ Here are the tasks in your list:
+ 1.[E][✓] book club(at: 12:00-14:00)
+ 2.[T][✗] read book
+ 3.[D][✗] submission(by: 12 Dec 2019)
+ ____________________________________________________________
+
+bye
+ ____________________________________________________________
+
+ Bye. Hope to see you again soon!
+ ____________________________________________________________
diff --git a/text-ui-test/TIMETABLE.TXT b/text-ui-test/TIMETABLE.TXT
new file mode 100644
index 0000000000..bb7f538705
--- /dev/null
+++ b/text-ui-test/TIMETABLE.TXT
@@ -0,0 +1,3 @@
+T | 0 | read book
+D | 0 | submission | 12 Dec 1999, 12:00
+E | 0 | book club | 12:00
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb2..7ab58ef4fc 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,7 @@
+event book club /at 12:00-14:00
+todo read book
+deadline submission /by 2019 12 12
+done 1
+delete 4
+list
+bye
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
index d0facc6310..398b1efae5 100644
--- a/text-ui-test/runtest.bat
+++ b/text-ui-test/runtest.bat
@@ -7,7 +7,7 @@ REM delete output from previous run
del ACTUAL.TXT
REM compile the code into the bin folder
-javac -cp ..\src -Xlint:none -d ..\bin ..\src\main\java\Duke.java
+javac -cp ..\src -Xlint:none -d ..\bin ..\src\main\java\duke.java
IF ERRORLEVEL 1 (
echo ********** BUILD FAILURE **********
exit /b 1
@@ -15,7 +15,7 @@ IF ERRORLEVEL 1 (
REM no error here, errorlevel == 0
REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT
-java -classpath ..\bin Duke < input.txt > ACTUAL.TXT
+java -classpath ..\bin duke < input.txt > ACTUAL.TXT
REM compare the output to the expected output
FC ACTUAL.TXT EXPECTED.TXT
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
old mode 100644
new mode 100755
index e169618a34..dc763e38ed
--- a/text-ui-test/runtest.sh
+++ b/text-ui-test/runtest.sh
@@ -12,22 +12,23 @@ then
rm ACTUAL.TXT
fi
+export LC_ALL=en_GB.UTF-8
# compile the code into the bin folder, terminates if error occurred
-if ! javac -cp ../src -Xlint:none -d ../bin ../src/main/java/Duke.java
+if
+ ! (
+ find ../src/main/java -name "*.java" >sources.txt
+ javac -cp ../src -Xlint:none -d ../bin @sources.txt
+ )
then
echo "********** BUILD FAILURE **********"
exit 1
fi
# run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT
-java -classpath ../bin Duke < input.txt > ACTUAL.TXT
-
-# convert to UNIX format
-cp EXPECTED.TXT EXPECTED-UNIX.TXT
-dos2unix ACTUAL.TXT EXPECTED-UNIX.TXT
+java -classpath ../bin duke < input.txt > ACTUAL.TXT
# compare the output to the expected output
-diff ACTUAL.TXT EXPECTED-UNIX.TXT
+diff ACTUAL.TXT EXPECTED.TXT
if [ $? -eq 0 ]
then
echo "Test result: PASSED"
diff --git a/text-ui-test/sources.txt b/text-ui-test/sources.txt
new file mode 100644
index 0000000000..dd94b95d70
--- /dev/null
+++ b/text-ui-test/sources.txt
@@ -0,0 +1,24 @@
+../src/main/java/duke/Tasks/event.java
+../src/main/java/duke/Tasks/Task.java
+../src/main/java/duke/Tasks/Deadline.java
+../src/main/java/duke/Tasks/todo.java
+../src/main/java/duke/Commands/DeleteCommand.java
+../src/main/java/duke/Commands/ListCommand.java
+../src/main/java/duke/Commands/Command.java
+../src/main/java/duke/Commands/AddCommand.java
+../src/main/java/duke/Commands/ExitCommand.java
+../src/main/java/duke/Commands/DoneCommand.java
+../src/main/java/duke/duke.java
+../src/main/java/duke/Errors/EventException.java
+../src/main/java/duke/Errors/FileAbsentException.java
+../src/main/java/duke/Errors/FIleEmptyException.java
+../src/main/java/duke/Errors/DeadlineException.java
+../src/main/java/duke/Errors/DeleteException.java
+../src/main/java/duke/Errors/DoneException.java
+../src/main/java/duke/Errors/TodoException.java
+../src/main/java/duke/Errors/WrongInputException.java
+../src/main/java/duke/Errors/DukeException.java
+../src/main/java/duke/Helpers/TaskList.java
+../src/main/java/duke/Helpers/Storage.java
+../src/main/java/duke/Helpers/Parser.java
+../src/main/java/duke/Helpers/Ui.java