diff --git a/README.md b/README.md
index 0dd8f7fb21..f742d8165d 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,17 @@
-# Duke project template
+# Duke bot project template
This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.
-## Setting up in Intellij
+Setting up in Intellij
Prerequisites: JDK 11, update Intellij to the most recent version.
-1. Open Intellij (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project first)
-1. Open the project into Intellij as follows:
- 1. Click `Open`.
- 1. Select the project directory, and click `OK`.
- 1. If there are any further prompts, accept the defaults.
-1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
-1. After that, 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
- ____ _
- | _ \ _ _| | _____
- | | | | | | | |/ / _ \
- | |_| | |_| | < __/
- |____/ \__,_|_|\_\___|
- ```
+Open Intellij (if you are not in the welcome screen, click File > Close Project to close the existing project dialog first)
+Set up the correct JDK version, as follows:
+Click Configure > Structure for New Projects and then Project Settings > Project > Project SDK
+If JDK 11 is listed in the drop down, select it. If it is not, click New... and select the directory where you installed JDK 11
+Click OK
+Import the project into Intellij as follows:
+Click Open or Import.
+Select the project directory, and click OK
+If there are any further prompts, accept the defaults.
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000..e098eaf471
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,56 @@
+plugins {
+ id 'java'
+ id 'application'
+ id 'checkstyle'
+ id "com.github.johnrengelman.shadow" version "6.0.0"
+}
+
+group 'org.example'
+version '1.0-SNAPSHOT'
+
+repositories {
+ mavenCentral()
+}
+sourceSets {
+ main {
+ java {
+ srcDirs = ['src']
+ }
+ }
+
+}
+
+
+dependencies {
+ compile 'junit:junit:4.12'
+}
+run {
+ enableAssertions = true
+}
+test {
+ useJUnitPlatform()
+}
+
+dependencies {
+ testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.4.0'
+ testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.4.0'
+ implementation 'org.junit.jupiter:junit-jupiter-api:5.5.1'
+ 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'
+}
+checkstyle {
+ toolVersion = '8.23'
+}
+mainClassName ="main.duke.gui.Launcher"
\ No newline at end of file
diff --git a/data/duke.txt b/data/duke.txt
new file mode 100644
index 0000000000..1f5bf42c82
--- /dev/null
+++ b/data/duke.txt
@@ -0,0 +1,2 @@
+E~1~tosleep~2020-01-01 2401
+T~0~sample
diff --git a/docs/Help.PNG b/docs/Help.PNG
new file mode 100644
index 0000000000..ad521ae81e
Binary files /dev/null and b/docs/Help.PNG differ
diff --git a/docs/README.md b/docs/README.md
index fd44069597..e8e0febc4b 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,20 +1,126 @@
# User Guide
+Duke bot is a chat bot designed to be used via a command line interface(CLI) with the benefits of using a graphical user interface(GUI).
## Features
+>list : prints you the list of store tasks
+bye : terminates the program
+help : prints descriptions and samples of each feature
+todo [your task input] : adds a todo type task
+event [your task input] /at [YYYY-MM-DD hhmm]: adds an event type task
+deadline [your task input] /by [YYYY-MM-DD hhmm]: adds a deadline type task
+delete[number] : deletes the selected task
+done[number] : make the selected task done
+find [search string] : finds tasks that matches the string description
-### Feature 1
-Description of feature.
+### `list` - prints you the list of store tasks
+
+
+Example of usage:
+
+`list`
+
+Expected outcome:
+
+`These are the tasks in your list:
+ 1.[T] [X] sample`
+
+### `bye` - terminates the program
+
+
+Example of usage:
+
+`bye`
+
+Expected outcome:
+
+`Goodbye!`
+
+### `help` - prints descriptions and samples of each feature
+
+
+Example of usage:
+
+`help`
+
+Expected outcome:
+
+![Duke_Interface](Help.PNG)
+### `todo` - adds a todo type task
+
+
+
+Example of usage:
+
+`todo sleep`
+
+Expected outcome:
+
+>Added the following task:
+> [T][X] sleep
+>You now have 1 tasks in your list
+
+### `event` - adds an event type task
-## Usage
-### `Keyword` - Describe action
+
+Example of usage:
+
+`event tosleep /at 2020-01-01 1111`
+
+Expected outcome:
+
+>Added the following task:
+> [E][X] tosleep 2020-01-01 1111
+>You now have 1 tasks in your list
+
+### `deadline` - adds a deadline type task
+
+
+Example of usage:
+
+`deadline wakeup /by 2020-01-01 1111`
+
+Expected outcome:
+
+>Added the following task:
+> [D][X] wakeup 2020-01-01 1111
+>You now have 1 tasks in your list
+
+### `delete` - deletes the selected task
+
+
+Example of usage:
+
+`delete 1`
+
+Expected outcome:
+
+>The following task has been removed:
+> [T][X] sample
+>You now have 0 tasks in your list
+
+### `done` - make the selected task done
Describe action and its outcome.
Example of usage:
-`keyword (optional arguments)`
+`done 1`
+
+Expected outcome:
+
+>Following task has been marked done:
+>[T][O] sample
+
+### `find` - finds tasks that matches the string description
+
+
+Example of usage:
+
+`find sample`
Expected outcome:
-`outcome`
+>Here are the tasks you asked for:
+>1. [T][X] sample
+
diff --git a/docs/Ui.png.PNG b/docs/Ui.png.PNG
new file mode 100644
index 0000000000..94b26bed59
Binary files /dev/null and b/docs/Ui.png.PNG differ
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000000..ddeb671b60
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1 @@
+theme: jekyll-theme-time-machine
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..62d4c05355
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..7dcdbdde07
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Feb 23 16:47:37 SGT 2021
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-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 100644
index 0000000000..fbd7c51583
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,185 @@
+#!/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..5093609d51
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,104 @@
+@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/duke/Duke.java b/src/main/duke/Duke.java
new file mode 100644
index 0000000000..a001afff6e
--- /dev/null
+++ b/src/main/duke/Duke.java
@@ -0,0 +1,36 @@
+package main.duke;
+
+import main.duke.io.Storage;
+import main.duke.io.Parser;
+import main.duke.DukeList;
+import main.duke.command.ICommand;
+public class Duke {
+ private Storage storage;
+ private DukeList dukeList;
+ private Ui ui;
+
+ /**
+ * Constructor for duke
+ * @param filePath contains file where the task list is being saved
+ */
+ public Duke(String filePath){
+ ui = new Ui();
+ storage = new Storage(filePath);
+ dukeList = storage.load();
+ }
+
+ public String getReply (String input){
+ Parser parser = new Parser();
+ try{
+ ICommand command = parser.parse(input);
+ String reply = command.run(ui,dukeList, storage);
+ storage.writeFile();
+ assert(reply!=null);
+ return reply;
+ }
+ catch (DukeException e)
+ {
+ return e.getMessage();
+ }
+ }
+}
diff --git a/src/main/duke/DukeException.java b/src/main/duke/DukeException.java
new file mode 100644
index 0000000000..7bd578dfcc
--- /dev/null
+++ b/src/main/duke/DukeException.java
@@ -0,0 +1,11 @@
+package main.duke;
+
+public class DukeException extends Exception{
+ /**
+ *
+ * @param message Exception message being passed
+ */
+ public DukeException (String message){
+ super(message);
+ }
+}
\ No newline at end of file
diff --git a/src/main/duke/DukeList.java b/src/main/duke/DukeList.java
new file mode 100644
index 0000000000..b3db9f9c48
--- /dev/null
+++ b/src/main/duke/DukeList.java
@@ -0,0 +1,25 @@
+package main.duke;
+
+import java.util.ArrayList;
+import java.util.List;
+import main.duke.tasktype.Task;
+
+public class DukeList {
+ private List taskList;
+
+ /**
+ * Constructor for Duke list
+ */
+ public DukeList(){
+ taskList = new ArrayList<>();
+ }
+
+ public DukeList(List taskList){
+ this.taskList = taskList;
+ }
+
+ public List getTaskList(){
+ return taskList;
+ }
+
+}
diff --git a/src/main/duke/Ui.java b/src/main/duke/Ui.java
new file mode 100644
index 0000000000..15d237ba06
--- /dev/null
+++ b/src/main/duke/Ui.java
@@ -0,0 +1,126 @@
+package main.duke;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.function.Predicate;
+import java.lang.StringBuffer;
+import main.duke.tasktype.Task;
+
+public class Ui {
+ /**
+ * Done command in UI
+ * @param task the current task's status
+ * @return string including task name
+ */
+ public String makeDone(String task){
+ assert(task!= null);
+ return String.format("Following task has been marked done: \n" + task);
+ }
+
+ /**
+ * Show the added task
+ * @param task Status of the task being operated on
+ * @param taskList Collection of current list
+ * @return string including the added task name and total task number
+ */
+ public String showTaskAdded(String task , List taskList){
+ assert(task != null && taskList != null);
+ return String.format( "Added the following task : \n" +
+ "%s\n" + "You now have %d tasks in your list.\n", task, taskList.size());
+ }
+
+ /**
+ * Show the deleted task
+ * @param task Status of the task being operated on
+ * @param taskList Collection of current list
+ * @return string including the deleted task name and total task number
+ */
+ public String showTaskDeleted(String task , List taskList){
+ assert(task != null && taskList != null);
+ return String.format("The following task has been removed:\n " +
+ "%s\n" + " You now have %d tasks in your list.\n", task, taskList.size());
+ }
+
+ /**
+ *
+ * @param taskList Collection of current list
+ * @return All of tasks in the tasklist
+ */
+ public String showList(List taskList){
+ assert(taskList != null);
+ int counter = 1;
+ StringBuffer showList = new StringBuffer();
+ showList.append(" These are the tasks in your list:\n");
+ for (Task task : taskList){
+ showList.append(" " + counter + ". " + task.getStatus() + "\n");
+ counter++;
+ }
+ return showList.toString();
+ }
+
+ /**
+ * Goodbye command in UI
+ *
+ */
+ public String sayGoodbye(){
+ return "Goodbye!";
+ }
+
+ /**
+ * Help command in UI
+ *
+ */
+ public String giveHelp(){
+ String helpString = "Try one of these:\n"
+ + "list : prints you the list of store tasks\n"
+ + "bye : terminates the program\n"
+ + "todo [your task input] : adds a todo type task\n"
+ + "event [your task input] /at [YYYY-MM-DD hhmm]: adds an event type task\n"
+ + "deadline [your task input] /by [YYYY-MM-DD hhmm]: adds a deadline type task\n"
+ + "delete[number] : deletes the selected task\n"
+ + "done[number] : mark the selected task as done(notation will be 0 for done and X for not done)\n"
+ + "find [search string] : finds tasks that matches the string description\n"
+ + "\nExamples\n"
+ + "todo sleep : adds a todo type task of description sleep\n"
+ + "event toSleep /at 2020-01-01 0000 : adds an event type task of description toSleep " +
+ "with dateTime 2020-01-01 0000\n"
+ + "deadline wakeup /by 2020-01-01 0001 : adds a deadline type task of description wakeup " +
+ "with dateTime 2020-01-01 0001\n"
+ + "delete[1] : deletes the task with index 1 (will only work if the task with your index exists\n"
+ + "done[1] : marks the task with index 1 to done\n"
+ + "find[sleep] : finds task descriptions that starts with sleep\n"
+ + "[IMPORTANT] Note that the number inputted for done and delete should be equals to or " +
+ "less than the total number of tasks in your list!";
+ return helpString;
+ }
+
+ /**
+ * Show list of tasks with given keyword
+ * @param input Keyword used for find command
+ * @param taskList Collection of current list
+ * @throws DukeException Throws exception if search string is empty
+ */
+ public String showTasks(String input, List taskList) throws DukeException{
+ assert (input != null && taskList != null);
+ if(input.length() <= "find ".length()){
+ throw new DukeException("Please add what you want to find.");
+ }
+ String find = input.substring("find ".length());
+
+ if (find.trim().equals("")){
+ throw new DukeException("Search string is empty");
+ }
+ Predicate stringPredicate = x -> x.contains(find);
+ StringBuffer tasks = new StringBuffer();
+ tasks.append("Here are the tasks you asked for: \n");
+ int counter =1;
+ for(Task t : taskList){
+ if(t.getName() != null && stringPredicate.test(t.getName())){
+ tasks.append(counter + ". " + t.getStatus() + "\n");
+ counter++;
+ }
+ }
+ return tasks.toString();
+ }
+
+}
diff --git a/src/main/duke/command/CBye.java b/src/main/duke/command/CBye.java
new file mode 100644
index 0000000000..5f07b75cd6
--- /dev/null
+++ b/src/main/duke/command/CBye.java
@@ -0,0 +1,27 @@
+package main.duke.command;
+
+import main.duke.DukeList;
+import main.duke.Ui;
+import main.duke.io.Storage;
+
+public class CBye implements ICommand {
+ /**
+ * Check if it is the bye command
+ * @return true as it is the bye command
+ */
+ @Override
+ public boolean isBye() {
+ return true;
+ }
+
+ /**
+ *
+ * @param ui UI object that deal with the program output
+ * @param dukeList Collection of tasks in list form
+ * @param storage Storage object that deal with the file system
+ */
+ @Override
+ public String run(Ui ui, DukeList dukeList, Storage storage) {
+ return ui.sayGoodbye();
+ }
+}
diff --git a/src/main/duke/command/CDeadline.java b/src/main/duke/command/CDeadline.java
new file mode 100644
index 0000000000..f64c845b8a
--- /dev/null
+++ b/src/main/duke/command/CDeadline.java
@@ -0,0 +1,44 @@
+package main.duke.command;
+import java.util.List;
+import main.duke.DukeException;
+import main.duke.DukeList;
+import main.duke.Ui;
+import main.duke.io.Storage;
+import main.duke.tasktype.Task;
+import main.duke.tasktype.Deadline;
+public class CDeadline implements ICommand {
+ private String input;
+ public CDeadline(String command){
+ this.input = command;
+ }
+
+ /**
+ * Check if it is the bye command
+ * @return false as it is not the bye command
+ */
+ @Override
+ public boolean isBye() {
+ return false;
+ }
+ /**
+ *
+ * @param ui UI object that deal with the program output
+ * @param dukeList Collection of tasks in list form
+ * @param storage Storage object that deal with the file system
+ */
+ @Override
+ public String run(Ui ui, DukeList dukeList, Storage storage) throws DukeException{
+ List taskList = dukeList.getTaskList();
+ int endPoint = input.indexOf("/") - 1;
+ String text = input.substring("deadline".length() + 1, endPoint);
+ String dateTime = input.substring(endPoint + 5);
+ Task deadline = new Deadline(text, dateTime);
+ taskList.add(deadline);
+
+ storage.addText(deadline.convertToFile());
+ return ui.showTaskAdded(deadline.getStatus(), taskList);
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/main/duke/command/CDelete.java b/src/main/duke/command/CDelete.java
new file mode 100644
index 0000000000..a1bc1ad64e
--- /dev/null
+++ b/src/main/duke/command/CDelete.java
@@ -0,0 +1,43 @@
+package main.duke.command;
+
+import main.duke.DukeException;
+import main.duke.DukeList;
+import main.duke.Ui;
+import main.duke.io.Storage;
+import main.duke.tasktype.Task;
+import java.util.List;
+
+public class CDelete implements ICommand {
+ private String input;
+ public CDelete(String command){
+ this.input = command;
+ }
+ /**
+ * Check if it is the bye command
+ * @return false as it is not the bye command
+ */
+ @Override
+ public boolean isBye() {
+ return false;
+ }
+ /**
+ *
+ * @param ui UI object that deal with the program output
+ * @param dukeList Collection of tasks in list form
+ * @param storage Storage object that deal with the file system
+ */
+ @Override
+ public String run(Ui ui, DukeList dukeList, Storage storage) throws DukeException{
+ List taskList = dukeList.getTaskList();
+ int index = Integer.parseInt(input.substring(7)) -1;
+ if(index+1 == 0 || index>= taskList.size() +1){
+ throw new DukeException("This task does not exist");
+ }
+ Task removedTask = taskList.remove(index);
+ storage.removeTask(removedTask.convertToFile());
+ return ui.showTaskDeleted(removedTask.getStatus(), taskList);
+
+ }
+
+
+}
diff --git a/src/main/duke/command/CDone.java b/src/main/duke/command/CDone.java
new file mode 100644
index 0000000000..c4990b146e
--- /dev/null
+++ b/src/main/duke/command/CDone.java
@@ -0,0 +1,49 @@
+package main.duke.command;
+import java.util.List;
+import main.duke.DukeException;
+import main.duke.DukeList;
+import main.duke.Ui;
+import main.duke.io.Storage;
+import main.duke.tasktype.Task;
+public class CDone implements ICommand{
+ private String input;
+ public CDone(String command){
+ this.input = command;
+ }
+ /**
+ * Check if it is the bye command
+ * @return false as it is not the bye command
+ */
+
+ @Override
+ public boolean isBye() {
+ return false;
+ }
+ /**
+ *
+ * @param ui UI object that deal with the program output
+ * @param dukeList Collection of tasks in list form
+ * @param storage Storage object that deal with the file system
+ */
+ @Override
+ public String run(Ui ui, DukeList dukeList, Storage storage) throws DukeException {
+ List taskList = dukeList.getTaskList();
+ int index = Integer.parseInt(input.substring(5))-1;
+ Task task = taskList.get(index);
+ if(task == null){
+ throw new DukeException("No such task");
+ }
+ String oldLine = task.convertToFile();
+ task.setDone();
+ String newLine = task.convertToFile();
+ try{
+ storage.changeText(oldLine,newLine);
+ }
+ catch (StringIndexOutOfBoundsException e){
+ System.out.println("Line to replace cannot be found" + e.getMessage());
+ }catch (NumberFormatException e){
+ System.out.println("You have an illegal character" + e.getMessage());
+ }
+ return ui.makeDone(task.getStatus());
+ }
+}
diff --git a/src/main/duke/command/CEvent.java b/src/main/duke/command/CEvent.java
new file mode 100644
index 0000000000..ba7a19b6f4
--- /dev/null
+++ b/src/main/duke/command/CEvent.java
@@ -0,0 +1,42 @@
+package main.duke.command;
+
+import main.duke.DukeException;
+import main.duke.DukeList;
+import main.duke.Ui;
+import main.duke.io.Storage;
+import main.duke.tasktype.Event;
+import main.duke.tasktype.Task;
+import java.util.List;
+
+public class CEvent implements ICommand {
+ private String input;
+ public CEvent(String command){
+ this.input = command;
+ }
+ /**
+ * Check if it is the bye command
+ * @return false as it is not the bye command
+ */
+ @Override
+ public boolean isBye() {
+ return false;
+ }
+ /**
+ *
+ * @param ui UI object that deal with the program output
+ * @param dukeList Collection of tasks in list form
+ * @param storage Storage object that deal with the file system
+ */
+ @Override
+ public String run(Ui ui, DukeList dukeList, Storage storage) throws DukeException {
+ List taskList = dukeList.getTaskList();
+ int endPoint = input.indexOf("/") - 1;
+ String text = input.substring("event".length() + 1, endPoint);
+ String dateTime = input.substring(endPoint + 5);
+ Task event = new Event(text, dateTime);
+ taskList.add(event);
+
+ storage.addText(event.convertToFile());
+ return ui.showTaskAdded(event.getStatus(), taskList);
+ }
+}
diff --git a/src/main/duke/command/CFind.java b/src/main/duke/command/CFind.java
new file mode 100644
index 0000000000..a67021066f
--- /dev/null
+++ b/src/main/duke/command/CFind.java
@@ -0,0 +1,35 @@
+package main.duke.command;
+
+import main.duke.DukeException;
+import main.duke.DukeList;
+import main.duke.Ui;
+import main.duke.io.Storage;
+import main.duke.tasktype.Task;
+import java.util.List;
+
+public class CFind implements ICommand{
+ private String input;
+ public CFind(String command){
+ this.input = command;
+ }
+ /**
+ * Check if it is the bye command
+ * @return false as it is not the bye command
+ */
+
+ @Override
+ public boolean isBye() {
+ return false;
+ }
+ /**
+ *
+ * @param ui UI object that deal with the program output
+ * @param dukeList Collection of tasks in list form
+ * @param storage Storage object that deal with the file system
+ */
+ @Override
+ public String run(Ui ui, DukeList dukeList, Storage storage) throws DukeException {
+ List taskList = dukeList.getTaskList();
+ return ui.showTasks(input,taskList);
+ }
+}
diff --git a/src/main/duke/command/CHelp.java b/src/main/duke/command/CHelp.java
new file mode 100644
index 0000000000..52a581f88f
--- /dev/null
+++ b/src/main/duke/command/CHelp.java
@@ -0,0 +1,25 @@
+package main.duke.command;
+import main.duke.DukeList;
+import main.duke.Ui;
+import main.duke.io.Storage;
+public class CHelp implements ICommand{
+ /**
+ * Check if it is the bye command
+ * @return false as it is not the bye command
+ */
+ @Override
+ public boolean isBye() {
+ return false;
+ }
+
+ /**
+ *
+ * @param ui UI object that deal with the program output
+ * @param dukeList Collection of tasks in list form
+ * @param storage Storage object that deal with the file system
+ */
+ @Override
+ public String run(Ui ui, DukeList dukeList, Storage storage) {
+ return ui.giveHelp();
+ }
+}
diff --git a/src/main/duke/command/CList.java b/src/main/duke/command/CList.java
new file mode 100644
index 0000000000..57c1a40176
--- /dev/null
+++ b/src/main/duke/command/CList.java
@@ -0,0 +1,30 @@
+package main.duke.command;
+import main.duke.DukeException;
+import main.duke.DukeList;
+import main.duke.Ui;
+import main.duke.io.Storage;
+import main.duke.tasktype.Task;
+import java.util.List;
+
+public class CList implements ICommand {
+ /**
+ * Check if it is the bye command
+ * @return false as it is not the bye command
+ */
+ @Override
+ public boolean isBye() {
+ return false;
+ }
+
+ /**
+ *
+ * @param ui UI object that deal with the program output
+ * @param dukeList Collection of tasks in list form
+ * @param storage Storage object that deal with the file system
+ */
+ @Override
+ public String run(Ui ui, DukeList dukeList, Storage storage) {
+ List taskList = dukeList.getTaskList();
+ return ui.showList(taskList);
+ }
+}
diff --git a/src/main/duke/command/CTodo.java b/src/main/duke/command/CTodo.java
new file mode 100644
index 0000000000..1c17daa864
--- /dev/null
+++ b/src/main/duke/command/CTodo.java
@@ -0,0 +1,39 @@
+package main.duke.command;
+import main.duke.DukeException;
+import main.duke.DukeList;
+import main.duke.Ui;
+import main.duke.io.Storage;
+import main.duke.tasktype.Todo;
+import main.duke.tasktype.Task;
+import java.util.List;
+
+public class CTodo implements ICommand {
+ private String input;
+ public CTodo(String command){
+ this.input = command;
+ }
+ /**
+ * Check if it is the bye command
+ * @return false as it is not the bye command
+ */
+
+ @Override
+ public boolean isBye() {
+ return false;
+ }
+ /**
+ *
+ * @param ui UI object that deal with the program output
+ * @param dukeList Collection of tasks in list form
+ * @param storage Storage object that deal with the file system
+ */
+ @Override
+ public String run(Ui ui, DukeList dukeList, Storage storage) throws DukeException {
+ List taskList = dukeList.getTaskList();
+ String name = input.substring(4);
+ Task todo = new Todo(name.trim());
+ taskList.add(todo);
+ storage.addText(todo.convertToFile());
+ return ui.showTaskAdded(todo.getStatus(), taskList);
+ }
+}
diff --git a/src/main/duke/command/ICommand.java b/src/main/duke/command/ICommand.java
new file mode 100644
index 0000000000..045d08ff1b
--- /dev/null
+++ b/src/main/duke/command/ICommand.java
@@ -0,0 +1,9 @@
+package main.duke.command;
+import main.duke.DukeList;
+import main.duke.Ui;
+import main.duke.DukeException;
+import main.duke.io.Storage;
+public interface ICommand {
+ public boolean isBye();
+ public String run(Ui ui, DukeList dukeList, Storage storage) throws DukeException;
+}
diff --git a/src/main/duke/gui/DialogBox.java b/src/main/duke/gui/DialogBox.java
new file mode 100644
index 0000000000..101cc11764
--- /dev/null
+++ b/src/main/duke/gui/DialogBox.java
@@ -0,0 +1,54 @@
+package main.duke.gui;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.HBox;
+import javafx.scene.text.Text;
+
+public class DialogBox extends HBox {
+ @FXML
+ private Label dialog;
+ @FXML
+ private ImageView displayPicture;
+
+ private DialogBox(String text, Image img){
+ try{
+ FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource("/view/DialogBox.fxml"));
+ fxmlLoader.setController(this);
+ fxmlLoader.setRoot(this);
+ fxmlLoader.load();
+ } catch (IOException e){
+ e.printStackTrace();
+ }
+
+ dialog.setText(text);
+ displayPicture.setImage(img);
+ }
+
+ private void flip(){
+ ObservableList tmp = FXCollections.observableArrayList(this.getChildren());
+ Collections.reverse(tmp);
+ getChildren().setAll(tmp);
+ setAlignment(Pos.TOP_LEFT);
+ }
+
+ public static DialogBox getUserDialog(String text, Image img) {
+ return new DialogBox(text, img);
+ }
+
+ public static DialogBox getBotDialog(String text, Image img) {
+ var db = new DialogBox(text, img);
+ db.flip();
+ return db;
+ }
+}
diff --git a/src/main/duke/gui/Launcher.java b/src/main/duke/gui/Launcher.java
new file mode 100644
index 0000000000..d435b2040c
--- /dev/null
+++ b/src/main/duke/gui/Launcher.java
@@ -0,0 +1,14 @@
+package main.duke.gui;
+
+import javafx.application.Application;
+
+public class Launcher {
+ /**
+ * Launch javafx application
+ * @param args Args to initialize main method
+ */
+ public static void main(String[] args){
+
+ Application.launch(Main.class,args);
+ }
+}
\ No newline at end of file
diff --git a/src/main/duke/gui/Main.java b/src/main/duke/gui/Main.java
new file mode 100644
index 0000000000..1faf764124
--- /dev/null
+++ b/src/main/duke/gui/Main.java
@@ -0,0 +1,31 @@
+package main.duke.gui;
+
+import main.duke.Duke;
+import javafx.application.Application;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+import javafx.scene.layout.AnchorPane;
+import java.io.IOException;
+
+import java.io.IOException;
+
+public class Main extends Application {
+
+ private Duke duke = new Duke("data/duke.txt");
+ @Override
+ public void start(Stage stage){
+ try {
+ FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml"));
+ AnchorPane anchorPane = fxmlLoader.load();
+ Scene scene = new Scene(anchorPane);
+ stage.setScene(scene);
+ stage.setTitle("Duke bot");
+ fxmlLoader.getController().makeDuke(duke);
+ stage.show();
+ }
+ catch (IOException e){
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/duke/gui/MainWindow.java b/src/main/duke/gui/MainWindow.java
new file mode 100644
index 0000000000..d9c9ef7801
--- /dev/null
+++ b/src/main/duke/gui/MainWindow.java
@@ -0,0 +1,74 @@
+package main.duke.gui;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.control.TextField;
+import javafx.scene.image.Image;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.VBox;
+import java.io.IOException;
+import java.util.concurrent.CompletableFuture;
+
+import main.duke.Duke;
+
+/**
+ * Controller of the MainWindow
+ */
+public class MainWindow extends AnchorPane {
+ @FXML
+ private ScrollPane scrollPane;
+ @FXML
+ private VBox dialogContainer;
+ @FXML
+ private TextField userInput;
+ @FXML
+ private Button sendButton;
+
+ private Duke duke;
+ private Image userImage = new Image(this.getClass().getResourceAsStream("/images/User.png"));
+ private Image botImage = new Image(this.getClass().getResourceAsStream("/images/Bot.png"));
+ private final String startMessage = "Hello, I am duke bot.\n"
+ + "If you require any assistance with what I accept use my command help\n";
+
+ public MainWindow(){ }
+
+ /**
+ * Initialize the MainWindow with a startMessage
+ */
+ @FXML
+ public void initialize(){
+ this.scrollPane.vvalueProperty().bind(this.dialogContainer.heightProperty());
+ dialogContainer.getChildren().add(DialogBox.getUserDialog(startMessage,botImage));
+ }
+ public void makeDuke(Duke d){
+ duke = d;
+ }
+
+ /**
+ * Makes two dialogBoxes, one which echos the user input and the other contains the reply.
+ * Both are appended to the dialog container and cleared after.
+ */
+ @FXML
+ private void handleUserInput() {
+ String input = userInput.getText().trim();
+ String response = duke.getReply(input);
+ dialogContainer.getChildren().addAll(DialogBox.getUserDialog(input, userImage),
+ DialogBox.getBotDialog(response, botImage));
+ userInput.clear();
+ CompletableFuture.runAsync(() -> {
+ try{
+ if(input.equals("bye")){
+ Thread.sleep(3000);
+ System.exit(0);
+ }
+ }
+ catch (InterruptedException e){
+ Thread.currentThread().interrupt();
+ System.exit(1);
+ }
+ }
+ );
+ assert (userInput.getText().equals(""));
+ }
+}
diff --git a/src/main/duke/io/Parser.java b/src/main/duke/io/Parser.java
new file mode 100644
index 0000000000..2dcc7a9b2f
--- /dev/null
+++ b/src/main/duke/io/Parser.java
@@ -0,0 +1,91 @@
+package main.duke.io;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+import main.duke.command.*;
+import main.duke.DukeException;
+
+public class Parser {
+ /**
+ *
+ * @param input the whole user console input command
+ * @return Command for execution
+ * @throws DukeException thrown when an invalid message is inputted
+ */
+ public ICommand parse(String input) throws DukeException{
+ String[] splitString = input.split(" ");
+ assert (splitString.length > 0);
+ String first = splitString[0];
+ ICommand iCommand;
+ switch (first){
+ case"bye":
+ checkLength(1,splitString);
+ iCommand = new CBye();
+ break;
+ case"done":
+ checkLength(2,splitString);
+ iCommand = new CDone(input);
+ break;
+ case"delete":
+ checkLength(2,splitString);
+ iCommand = new CDelete(input);
+ break;
+ case"deadline":
+ checkMessage(first,input);
+ checkDateTime(splitString);
+ checkBreakExist("/by", input, "deadline");
+ iCommand = new CDeadline(input);
+ break;
+ case"find":
+ checkMessage(first, input);
+ iCommand = new CFind(input);
+ break;
+ case"event":
+ checkMessage(first, input);
+ checkDateTime(splitString);
+ checkBreakExist("/at", input, "event");
+ iCommand = new CEvent(input);
+ break;
+ case"list":
+ checkLength(1, splitString);
+ iCommand = new CList();
+ break;
+ case"todo":
+ checkMessage(first, input);
+ iCommand = new CTodo(input);
+ break;
+ case"help":
+ checkLength(1,splitString);
+ iCommand = new CHelp();
+ break;
+ default:
+ throw new DukeException("The request is not valid");
+ }
+ return iCommand;
+ }
+ public void checkLength(int length, String[] input) throws DukeException{
+ if(length != input.length){
+ throw new DukeException("Your message is not the right length");
+ }
+ }
+ public void checkMessage(String command, String wholeInput) throws DukeException{
+ if(command.length() + 1 >= wholeInput.length()){
+ throw new DukeException(command + " cannot be empty!");
+ }
+ }
+ public void checkBreakExist(String type, String wholeInput, String command) throws DukeException{
+ if(!wholeInput.contains(type)){
+ throw new DukeException(command + " is not complete. You are missing " + type);
+ }
+ }
+ public void checkDateTime(String[] command) throws DukeException {
+ String dateTime = command[command.length - 2] + " " + command[command.length -1];
+ try{
+ LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm"));
+ }
+ catch (DateTimeParseException e){
+ throw new DukeException("You have the wrong date time format. I require YYYY-MM-DD 0000");
+ }
+ }
+}
diff --git a/src/main/duke/io/Storage.java b/src/main/duke/io/Storage.java
new file mode 100644
index 0000000000..0151256678
--- /dev/null
+++ b/src/main/duke/io/Storage.java
@@ -0,0 +1,161 @@
+package main.duke.io;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import main.duke.DukeException;
+import main.duke.tasktype.Task;
+import main.duke.tasktype.Event;
+import main.duke.tasktype.Deadline;
+import main.duke.tasktype.Todo;
+import java.util.List;
+
+import main.duke.DukeList;
+
+public class Storage {
+ private StringBuffer stringBufferOfTasks = new StringBuffer();
+ private String filename;
+
+ /**
+ * Constructor for the Storage Object
+ * @param filename path of the file being accessed
+ */
+ public Storage(String filename) {
+ this.filename = filename;
+ getTaskListInFile(getDirectory());
+ }
+
+
+ private void getTaskListInFile(String current) {
+ String[] parents = filename.split("/");
+ String parent = parents[0];
+ Path directPath = Paths.get(current, parent);
+ Path filePath = Paths.get(current, filename);
+ boolean directoryExist = Files.exists(directPath);
+ boolean fileExist = Files.exists(filePath);
+ try {
+ if (!directoryExist) {
+ Files.createDirectories(directPath);
+ }
+ if (!fileExist) {
+ Files.createFile(filePath);
+ }
+ } catch (IOException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ /**
+ *
+ * @return the current directory
+ */
+ private String getDirectory() {
+ return System.getProperty("user.dir");
+ }
+
+ public void removeTask(String toRemove) {
+ String newLine = System.getProperty("line.separator");
+ toRemove = toRemove + newLine;
+ setReplacing(toRemove, "", stringBufferOfTasks);
+ }
+
+ public void setReplacing(String toReplace, String replacement, StringBuffer stringBuffer) throws StringIndexOutOfBoundsException {
+ int start = stringBuffer.indexOf(toReplace);
+ int end = start + toReplace.length();
+ stringBuffer.replace(start, end, replacement);
+ }
+
+ public void changeText(String toChange, String changeTo) {
+ setReplacing(toChange, changeTo, stringBufferOfTasks);
+ }
+
+ public void addText(String toAdd) {
+ String newLine = System.getProperty("line.separator");
+ toAdd = toAdd + newLine;
+ stringBufferOfTasks.append(toAdd);
+ }
+
+ /**
+ * Creates task objects based on the file information
+ * @return List of task objects
+ */
+ public DukeList load() {
+ DukeList dukeList = new DukeList();
+ stringBufferOfTasks = new StringBuffer();
+ try {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(new DataInputStream(
+ new FileInputStream(this.filename))));
+ String line = reader.readLine();
+ while (line != null) {
+ runCommands(line,dukeList);
+ line = reader.readLine();
+ }
+ reader.close();
+
+ } catch (IOException e) {
+ System.out.println(filename + " could not be opened" + e.getMessage());
+ } catch (ArrayIndexOutOfBoundsException e){
+ System.out.println((e.getMessage()));
+ }
+ return dukeList;
+ }
+ public void convertFromFile(String[] input, DukeList dukeList){
+ List taskList = dukeList.getTaskList();
+ String type = input[0];
+ int done = Integer.parseInt(input[1]);
+ String name = input[2];
+ int counter = dukeList.getTaskList().size();
+ switch(type) {
+ case ("E"):
+ String dateTime = input[3];
+ Task E = new Event(name, dateTime);
+ if(done == 1){
+ E.setDone();
+ }
+ taskList.add(counter, E);
+ break;
+ case("D"):
+ dateTime = input[3];
+ Task D = new Deadline(name, dateTime);
+ if(done == 1){
+ D.setDone();
+ }
+ taskList.add(counter, D);
+ break;
+ case("T"):
+ Task T = new Todo(name);
+ if(done == 1){
+ T.setDone();
+ }
+ taskList.add(counter, T);
+ break;
+ default:
+ break;
+ }
+ }
+ public void runCommands(String line, DukeList dukeList){
+ String[] input = line.split("~");
+ String type = input[0];
+ convertFromFile(input,dukeList);
+ stringBufferOfTasks.append(input).append("\r\n");
+ }
+
+ public void writeFile(){
+ try{
+ BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filename));
+ bufferedWriter.write(stringBufferOfTasks.toString());
+ bufferedWriter.close();
+ }
+ catch(Exception e){
+ System.out.println("Error when writing to File: " + e.getMessage());
+ }
+ }
+}
diff --git a/src/main/duke/tasktype/Deadline.java b/src/main/duke/tasktype/Deadline.java
new file mode 100644
index 0000000000..b7c8d5e445
--- /dev/null
+++ b/src/main/duke/tasktype/Deadline.java
@@ -0,0 +1,22 @@
+package main.duke.tasktype;
+
+public class Deadline extends Task {
+ /**
+ * Constructor for basic deadline
+ * @param name task information
+ */
+ public Deadline (String name){
+ super(name);
+ this.type = "D";
+ }
+
+ /**
+ * Constructor for deadline with date time format
+ * @param name task information
+ * @param dateTime Date time format
+ */
+ public Deadline(String name, String dateTime){
+ super(name,dateTime);
+ this.type = "D";
+ }
+}
diff --git a/src/main/duke/tasktype/Event.java b/src/main/duke/tasktype/Event.java
new file mode 100644
index 0000000000..2bbc5fcd78
--- /dev/null
+++ b/src/main/duke/tasktype/Event.java
@@ -0,0 +1,22 @@
+package main.duke.tasktype;
+
+public class Event extends Task {
+ /**
+ * Constructor for basic event
+ * @param name task information
+ */
+ public Event(String name){
+ super(name);
+ this.type = "E";
+ }
+
+ /**
+ * Constructor for event with date time format
+ * @param name task information
+ * @param dateTime Date time format
+ */
+ public Event(String name, String dateTime){
+ super(name, dateTime);
+ this.type = "E";
+ }
+}
diff --git a/src/main/duke/tasktype/Task.java b/src/main/duke/tasktype/Task.java
new file mode 100644
index 0000000000..c2ab565ec5
--- /dev/null
+++ b/src/main/duke/tasktype/Task.java
@@ -0,0 +1,81 @@
+package main.duke.tasktype;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class Task {
+ protected String name;
+ protected boolean isDone;
+ protected String type;
+ protected LocalDateTime due;
+
+ /**
+ * Constructor for task
+ * @param name task information
+ */
+ public Task(String name){
+ this.name = name;
+ this.isDone = false;
+ }
+
+ /**
+ * Constructor for task with date time format
+ * @param name task information
+ * @param dateTime Date time format
+ */
+ public Task(String name, String dateTime){
+ this.name = name;
+ this.isDone = false;
+ this.due = LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm"));
+ }
+
+ /**
+ * Set task as done
+ */
+ public void setDone(){
+ isDone = true;
+ }
+
+ /**
+ * @return Get task information
+ */
+ public String getName(){
+ return name;
+ }
+
+ /**
+ * @return Get the status of task in symbol form
+ */
+ public String getStatusIcon(){
+ return (isDone ? "O" : "X");
+ }
+
+ /**
+ * Get the current status of task
+ * @return current status of task
+ */
+ public String getStatus(){
+ if(due == null){
+ return " [" + type + "] " + " [" + getStatusIcon() + "] " + getName();
+ }
+ else{
+ return " [" + type + "] " + " [" + getStatusIcon() + "] " + getName() + " "
+ + due.format(DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm"));
+ }
+ }
+ public LocalDateTime getDue(){
+ return due;
+ }
+
+ /**
+ * Changes task information to the suitable format for a file
+ * @return String containing the suitable format
+ */
+ public String convertToFile(){
+ if(due==null){
+ return String.format("%s~%s~%s", type, isDone ? 1:0, getName());
+ }
+ return String.format("%s~%s~%s~%s", type, isDone ? 1:0, getName(),
+ due.format(DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")));
+ }
+}
diff --git a/src/main/duke/tasktype/Todo.java b/src/main/duke/tasktype/Todo.java
new file mode 100644
index 0000000000..8197282b71
--- /dev/null
+++ b/src/main/duke/tasktype/Todo.java
@@ -0,0 +1,12 @@
+package main.duke.tasktype;
+
+public class Todo extends Task {
+ /**
+ * Constructor for Todo
+ * @param name task information
+ */
+ public Todo (String name){
+ super(name);
+ this.type = "T";
+ }
+}
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/resources/images/Bot.png b/src/main/resources/images/Bot.png
new file mode 100644
index 0000000000..03b1d48bfa
Binary files /dev/null and b/src/main/resources/images/Bot.png differ
diff --git a/src/main/resources/images/User.png b/src/main/resources/images/User.png
new file mode 100644
index 0000000000..f6ac09cc2d
Binary files /dev/null and b/src/main/resources/images/User.png differ
diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml
new file mode 100644
index 0000000000..0ef8333993
--- /dev/null
+++ b/src/main/resources/view/DialogBox.fxml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
new file mode 100644
index 0000000000..be1a1d49d5
--- /dev/null
+++ b/src/main/resources/view/MainWindow.fxml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/ParserTest.java b/src/test/java/ParserTest.java
new file mode 100644
index 0000000000..636b147f72
--- /dev/null
+++ b/src/test/java/ParserTest.java
@@ -0,0 +1,72 @@
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+import main.duke.DukeException;
+import main.duke.command.CBye;
+import main.duke.command.CDeadline;
+import main.duke.command.CDelete;
+import main.duke.command.CDone;
+import main.duke.command.CFind;
+import main.duke.command.ICommand;
+import main.duke.io.Parser;
+
+public class ParserTest {
+ private static final Parser parser = new Parser();
+ @Test
+ public void parseByeTest(){
+ ICommand bye = new CBye();
+ try{
+ ICommand parseBye = parser.parse("bye");
+ assertEquals(bye.getClass(), parseBye.getClass());
+ }
+ catch(DukeException dukeException){
+ System.out.println(dukeException.getMessage());
+ }
+ }
+
+ @Test
+ public void parseDeadlineTest(){
+ try{
+ ICommand parseDeadline = parser.parse("deadline sleep /by 1111-11-11 1111");
+ assertEquals(parseDeadline.getClass(), CDeadline.class);
+ }
+ catch(DukeException dukeException){
+ System.out.println(dukeException.getMessage());
+ }
+
+ }
+
+ @Test
+ public void parseDeleteTest(){
+ try{
+ ICommand parseDelete = parser.parse("delete 1");
+ assertEquals(parseDelete.getClass(), CDelete.class);
+ }
+ catch (DukeException dukeException){
+ System.out.println(dukeException.getMessage());
+ }
+ }
+
+ @Test
+ public void parseFindTest(){
+ try{
+ ICommand parseFind = parser.parse("find sleep");
+ assertEquals(parseFind.getClass(), CFind.class);
+ }
+ catch (DukeException dukeException){
+ System.out.println(dukeException.getMessage());
+ }
+ }
+
+ @Test
+ public void parseDoneTest(){
+ try{
+ ICommand parseDone = parser.parse("done 1");
+ assertEquals(parseDone.getClass(), CDone.class);
+ }
+ catch (DukeException dukeException){
+ System.out.println(dukeException.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/UiTest.java b/src/test/java/UiTest.java
new file mode 100644
index 0000000000..ebd132f692
--- /dev/null
+++ b/src/test/java/UiTest.java
@@ -0,0 +1,35 @@
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import main.duke.Ui;
+import main.duke.tasktype.Task;
+
+public class UiTest {
+ @Test
+ public void showDoneTest() {
+ String result = new Ui().makeDone("hello");
+ assertEquals("Following task has been marked done: \nhello", result);
+ }
+
+ @Test
+ public void byeTest(){
+ String result = new Ui().sayGoodbye();
+ assertEquals("Goodbye!", result);
+ }
+
+ @Test
+ public void addTaskTest(){
+ Task task = new Task("task");
+ List taskList = new ArrayList<>();
+ taskList.add(task);
+ String result = new Ui().showTaskAdded("task", taskList);
+ assertEquals("Added the following task : \ntask\n" +
+ "You now have 1 tasks in your list.\n", result);
+ }
+
+
+}
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e7..db20d9040d 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,16 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
+Hello, I am duke bot
+If you require any assistance with what I accept use my command help
+Added the following task:
+ [T] [X] sleep
+You now have 1 tasks in your list
+
+Added the following task:
+ [D] [X] tosleep 2020-01-01 1111
+You now have 2 tasks in your list
+
+These are the tasks in your list:
+ 1. [T] [X] sleep
+ 2. [D] [X] tosleep 2020-01-01 1111
+
+ Goodbye
\ No newline at end of file
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb2..7c490210c8 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,4 @@
+todo sleep
+deadline tosleep /by 2020-01-01 1111
+list
+bye
\ No newline at end of file