diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000..9e476279dc
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,19 @@
+plugins {
+ id 'java'
+}
+
+group 'org.example'
+version '1.0-SNAPSHOT'
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
+}
+
+test {
+ useJUnitPlatform()
+}
\ No newline at end of file
diff --git a/data/tasks.txt b/data/tasks.txt
new file mode 100644
index 0000000000..2d8a1dee0f
--- /dev/null
+++ b/data/tasks.txt
@@ -0,0 +1 @@
+T | 0 | CS2103T 05-20
diff --git a/dukeChatBox/.gradle/7.1/dependencies-accessors/dependencies-accessors.lock b/dukeChatBox/.gradle/7.1/dependencies-accessors/dependencies-accessors.lock
new file mode 100644
index 0000000000..2409dd2650
Binary files /dev/null and b/dukeChatBox/.gradle/7.1/dependencies-accessors/dependencies-accessors.lock differ
diff --git a/dukeChatBox/.gradle/7.1/dependencies-accessors/gc.properties b/dukeChatBox/.gradle/7.1/dependencies-accessors/gc.properties
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/dukeChatBox/.gradle/7.1/executionHistory/executionHistory.bin b/dukeChatBox/.gradle/7.1/executionHistory/executionHistory.bin
new file mode 100644
index 0000000000..e47fb81ee0
Binary files /dev/null and b/dukeChatBox/.gradle/7.1/executionHistory/executionHistory.bin differ
diff --git a/dukeChatBox/.gradle/7.1/executionHistory/executionHistory.lock b/dukeChatBox/.gradle/7.1/executionHistory/executionHistory.lock
new file mode 100644
index 0000000000..fa2d4fad32
Binary files /dev/null and b/dukeChatBox/.gradle/7.1/executionHistory/executionHistory.lock differ
diff --git a/dukeChatBox/.gradle/7.1/fileChanges/last-build.bin b/dukeChatBox/.gradle/7.1/fileChanges/last-build.bin
new file mode 100644
index 0000000000..f76dd238ad
Binary files /dev/null and b/dukeChatBox/.gradle/7.1/fileChanges/last-build.bin differ
diff --git a/dukeChatBox/.gradle/7.1/fileHashes/fileHashes.bin b/dukeChatBox/.gradle/7.1/fileHashes/fileHashes.bin
new file mode 100644
index 0000000000..ded00c3b06
Binary files /dev/null and b/dukeChatBox/.gradle/7.1/fileHashes/fileHashes.bin differ
diff --git a/dukeChatBox/.gradle/7.1/fileHashes/fileHashes.lock b/dukeChatBox/.gradle/7.1/fileHashes/fileHashes.lock
new file mode 100644
index 0000000000..9ac9360be3
Binary files /dev/null and b/dukeChatBox/.gradle/7.1/fileHashes/fileHashes.lock differ
diff --git a/dukeChatBox/.gradle/7.1/gc.properties b/dukeChatBox/.gradle/7.1/gc.properties
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/dukeChatBox/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/dukeChatBox/.gradle/buildOutputCleanup/buildOutputCleanup.lock
new file mode 100644
index 0000000000..ac005ab048
Binary files /dev/null and b/dukeChatBox/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
diff --git a/dukeChatBox/.gradle/buildOutputCleanup/cache.properties b/dukeChatBox/.gradle/buildOutputCleanup/cache.properties
new file mode 100644
index 0000000000..1f46a5a41b
--- /dev/null
+++ b/dukeChatBox/.gradle/buildOutputCleanup/cache.properties
@@ -0,0 +1,2 @@
+#Wed Apr 19 18:51:26 SGT 2023
+gradle.version=7.1
diff --git a/dukeChatBox/.gradle/buildOutputCleanup/outputFiles.bin b/dukeChatBox/.gradle/buildOutputCleanup/outputFiles.bin
new file mode 100644
index 0000000000..60a0f87d09
Binary files /dev/null and b/dukeChatBox/.gradle/buildOutputCleanup/outputFiles.bin differ
diff --git a/dukeChatBox/.gradle/checksums/checksums.lock b/dukeChatBox/.gradle/checksums/checksums.lock
new file mode 100644
index 0000000000..8ca705452a
Binary files /dev/null and b/dukeChatBox/.gradle/checksums/checksums.lock differ
diff --git a/dukeChatBox/.gradle/vcs-1/gc.properties b/dukeChatBox/.gradle/vcs-1/gc.properties
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/dukeChatBox/.idea/.gitignore b/dukeChatBox/.idea/.gitignore
new file mode 100644
index 0000000000..26d33521af
--- /dev/null
+++ b/dukeChatBox/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/dukeChatBox/.idea/compiler.xml b/dukeChatBox/.idea/compiler.xml
new file mode 100644
index 0000000000..fb7f4a8a46
--- /dev/null
+++ b/dukeChatBox/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dukeChatBox/.idea/gradle.xml b/dukeChatBox/.idea/gradle.xml
new file mode 100644
index 0000000000..bbcf987636
--- /dev/null
+++ b/dukeChatBox/.idea/gradle.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dukeChatBox/.idea/jarRepositories.xml b/dukeChatBox/.idea/jarRepositories.xml
new file mode 100644
index 0000000000..fdc392fe87
--- /dev/null
+++ b/dukeChatBox/.idea/jarRepositories.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dukeChatBox/.idea/misc.xml b/dukeChatBox/.idea/misc.xml
new file mode 100644
index 0000000000..65f8b8ed08
--- /dev/null
+++ b/dukeChatBox/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dukeChatBox/.idea/runConfigurations.xml b/dukeChatBox/.idea/runConfigurations.xml
new file mode 100644
index 0000000000..797acea53e
--- /dev/null
+++ b/dukeChatBox/.idea/runConfigurations.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dukeChatBox/.idea/vcs.xml b/dukeChatBox/.idea/vcs.xml
new file mode 100644
index 0000000000..6c0b863585
--- /dev/null
+++ b/dukeChatBox/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dukeChatBox/.idea/workspace.xml b/dukeChatBox/.idea/workspace.xml
new file mode 100644
index 0000000000..4d9fa6a5d9
--- /dev/null
+++ b/dukeChatBox/.idea/workspace.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1681901476349
+
+
+ 1681901476349
+
+
+
+
\ No newline at end of file
diff --git a/dukeChatBox/build.gradle b/dukeChatBox/build.gradle
new file mode 100644
index 0000000000..9e476279dc
--- /dev/null
+++ b/dukeChatBox/build.gradle
@@ -0,0 +1,19 @@
+plugins {
+ id 'java'
+}
+
+group 'org.example'
+version '1.0-SNAPSHOT'
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
+}
+
+test {
+ useJUnitPlatform()
+}
\ No newline at end of file
diff --git a/dukeChatBox/gradle/wrapper/gradle-wrapper.jar b/dukeChatBox/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..7454180f2a
Binary files /dev/null and b/dukeChatBox/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/dukeChatBox/gradle/wrapper/gradle-wrapper.properties b/dukeChatBox/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..69a9715077
--- /dev/null
+++ b/dukeChatBox/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/dukeChatBox/gradlew b/dukeChatBox/gradlew
new file mode 100755
index 0000000000..744e882ed5
--- /dev/null
+++ b/dukeChatBox/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
+ ;;
+ MSYS* | MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "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/dukeChatBox/gradlew.bat b/dukeChatBox/gradlew.bat
new file mode 100644
index 0000000000..ac1b06f938
--- /dev/null
+++ b/dukeChatBox/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/dukeChatBox/settings.gradle b/dukeChatBox/settings.gradle
new file mode 100644
index 0000000000..7bd32fa431
--- /dev/null
+++ b/dukeChatBox/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = 'dukeChatBox'
+
diff --git a/dukeChatBox/src/main/java/duke/Duke.java b/dukeChatBox/src/main/java/duke/Duke.java
new file mode 100644
index 0000000000..0d0031b4e1
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/Duke.java
@@ -0,0 +1,87 @@
+package duke;
+
+import duke.command.Command;
+import duke.exception.DukeException;
+import duke.parser.Parser;
+import duke.storage.Storage;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+
+/**
+ * The chatting bot Duke.
+ */
+public class Duke {
+
+ private Storage storage;
+ private TaskList tasks;
+ private Ui ui;
+
+ /**
+ * Initialization of Duke and loading of file.
+ *
+ * @param filePath The path of the file that stores the tasks.
+ */
+ public Duke(String filePath) {
+ ui = new Ui();
+ storage = new Storage(filePath);
+ tasks = loadTasks();
+ }
+
+ private TaskList loadTasks() {
+ TaskList taskList;
+ try {
+ taskList = new TaskList(storage.load());
+ } catch (DukeException e) {
+ ui.showLoadingError();
+ taskList = new TaskList();
+ }
+ return taskList;
+ }
+
+ /**
+ * Process of user's input and storage of the new taskList.
+ */
+ public void run() {
+ ui.showWelcome();
+ boolean isExit = false;
+ while (!isExit) {
+ processUserInput();
+ isExit = checkForExit();
+ }
+ }
+
+ private void processUserInput() {
+ try {
+ String fullCommand = ui.readCommand();
+ ui.showLine();
+ Command c = Parser.parse(fullCommand);
+ c.execute(tasks, ui, storage);
+ } catch (DukeException e) {
+ ui.showError(e.getMessage());
+ } finally {
+ ui.showLine();
+ }
+ }
+
+ private boolean checkForExit() {
+ String fullCommand = ui.readCommand();
+ Command c = null;
+ try {
+ c = Parser.parse(fullCommand);
+ } catch (DukeException e) {
+ e.printStackTrace();
+ }
+ return c.isExit();
+ }
+
+ /**
+ * Set the filePath and activate run function.
+ */
+ public static void main(String[] args) {
+ new Duke("./data/tasks.txt").run();
+ }
+}
+
+
+
diff --git a/dukeChatBox/src/main/java/duke/command/ByeCommand.java b/dukeChatBox/src/main/java/duke/command/ByeCommand.java
new file mode 100644
index 0000000000..0239cdfa99
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/command/ByeCommand.java
@@ -0,0 +1,33 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+
+public class ByeCommand extends Command {
+
+ public ByeCommand() {
+ isExit = true;
+ }
+
+ /**
+ * Execute user's "bye" command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ System.out.println(" Bye. Hope to see you again soon!");
+ try {
+ storage.write(tasks);
+ } catch (IOException e) {
+ createDirectory(ui, storage, tasks);
+ }
+ }
+}
diff --git a/dukeChatBox/src/main/java/duke/command/Command.java b/dukeChatBox/src/main/java/duke/command/Command.java
new file mode 100644
index 0000000000..a34298071e
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/command/Command.java
@@ -0,0 +1,54 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+
+
+public abstract class Command {
+
+ String keyword;
+ String statement;
+ Boolean isExit = false;
+
+ /**
+ * Execute a specific user's command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public abstract void execute(TaskList taskList, Ui ui, Storage storage);
+
+ /**
+ * Decide if the user wants to quit.
+ */
+ public Boolean isExit() {
+ return isExit;
+ }
+
+ /**
+ * Create a directory "data" if not exists to contain the "tasks.txt".
+ * @param ui dealing with interactions with the user.
+ * @param tasks the task list.
+ * @param storage The storage file of tasks.
+ */
+ static void createDirectory(Ui ui, Storage storage, ArrayList tasks) {
+ ui.showLine();
+ System.out.println(" Seems the data directory doesn't exist yet. Try to create for you!");
+ try {
+ Path path = Paths.get("./data");
+ Files.createDirectories(path);
+ storage.write(tasks);
+ } catch (IOException ex) {
+ System.out.println(" Sorry, creation failed!");
+ }
+ }
+
+}
diff --git a/dukeChatBox/src/main/java/duke/command/DeadlineCommand.java b/dukeChatBox/src/main/java/duke/command/DeadlineCommand.java
new file mode 100644
index 0000000000..26229465ad
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/command/DeadlineCommand.java
@@ -0,0 +1,34 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import static duke.task.TaskList.tryAddDeadline;
+
+public class DeadlineCommand extends Command {
+ public DeadlineCommand(String keyword, String statement) {
+ this.keyword = keyword;
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "deadline" command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ tryAddDeadline(tasks, statement);
+ try {
+ storage.write(tasks);
+ } catch (IOException e) {
+ createDirectory(ui, storage, tasks);
+ }
+ }
+}
diff --git a/dukeChatBox/src/main/java/duke/command/DeleteCommand.java b/dukeChatBox/src/main/java/duke/command/DeleteCommand.java
new file mode 100644
index 0000000000..4afa7f7188
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/command/DeleteCommand.java
@@ -0,0 +1,34 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import static duke.task.TaskList.tryDeleteTask;
+
+public class DeleteCommand extends Command {
+ public DeleteCommand(String keyword, String statement) {
+ this.keyword = keyword;
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "delete" command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ tryDeleteTask(tasks, statement);
+ try {
+ storage.write(tasks);
+ } catch (IOException e) {
+ createDirectory(ui, storage, tasks);
+ }
+ }
+}
diff --git a/dukeChatBox/src/main/java/duke/command/EventCommand.java b/dukeChatBox/src/main/java/duke/command/EventCommand.java
new file mode 100644
index 0000000000..91996b6b5a
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/command/EventCommand.java
@@ -0,0 +1,33 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import static duke.task.TaskList.tryAddEvent;
+
+public class EventCommand extends Command{
+ public EventCommand(String keyword, String statement) {
+ this.keyword = keyword;
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "event" command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ tryAddEvent(tasks, statement);
+ try {
+ storage.write(tasks);
+ } catch (IOException e) {
+ createDirectory(ui, storage, tasks);
+ }
+ }
+}
diff --git a/dukeChatBox/src/main/java/duke/command/FindCommand.java b/dukeChatBox/src/main/java/duke/command/FindCommand.java
new file mode 100644
index 0000000000..f2673f5740
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/command/FindCommand.java
@@ -0,0 +1,31 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.util.ArrayList;
+
+import static duke.task.TaskList.findTask;
+
+public class FindCommand extends Command{
+
+ String statement;
+
+ public FindCommand(String statement) {
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "find" command.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ @Override
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ findTask(tasks, statement);
+ }
+}
diff --git a/dukeChatBox/src/main/java/duke/command/ListCommand.java b/dukeChatBox/src/main/java/duke/command/ListCommand.java
new file mode 100644
index 0000000000..ab6966a63e
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/command/ListCommand.java
@@ -0,0 +1,28 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.util.ArrayList;
+
+import static duke.task.TaskList.printTaskList;
+
+public class ListCommand extends Command{
+ public ListCommand(String keyword, String statement) {
+ this.keyword = keyword;
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "list" command.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ printTaskList(tasks);
+ }
+}
diff --git a/dukeChatBox/src/main/java/duke/command/MarkCommand.java b/dukeChatBox/src/main/java/duke/command/MarkCommand.java
new file mode 100644
index 0000000000..291be6949a
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/command/MarkCommand.java
@@ -0,0 +1,35 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import static duke.task.TaskList.tryMarkTask;
+
+
+public class MarkCommand extends Command {
+ public MarkCommand(String keyword, String statement) {
+ this.keyword = keyword;
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "mark" command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ tryMarkTask(tasks, statement);
+ try {
+ storage.write(tasks);
+ } catch (IOException e) {
+ createDirectory(ui, storage, tasks);
+ }
+ }
+}
diff --git a/dukeChatBox/src/main/java/duke/command/TodoCommand.java b/dukeChatBox/src/main/java/duke/command/TodoCommand.java
new file mode 100644
index 0000000000..ab4a621ee0
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/command/TodoCommand.java
@@ -0,0 +1,40 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+
+import static duke.task.TaskList.tryAddTodo;
+
+public class TodoCommand extends Command {
+ public TodoCommand(String keyword, String statement) {
+ this.keyword = keyword;
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "todoTask" command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ tryAddTodo(tasks, statement);
+ try {
+ storage.write(tasks);
+ } catch (IOException e) {
+ createDirectory(ui, storage, tasks);
+ }
+ }
+
+
+}
diff --git a/dukeChatBox/src/main/java/duke/command/UnmarkCommand.java b/dukeChatBox/src/main/java/duke/command/UnmarkCommand.java
new file mode 100644
index 0000000000..43d30dc134
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/command/UnmarkCommand.java
@@ -0,0 +1,34 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import static duke.task.TaskList.tryUnmarkTask;
+
+public class UnmarkCommand extends Command{
+ public UnmarkCommand(String keyword, String statement) {
+ this.keyword = keyword;
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "unmark" command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ tryUnmarkTask(tasks, statement);
+ try {
+ storage.write(tasks);
+ } catch (IOException e) {
+ createDirectory(ui, storage, tasks);
+ }
+ }
+}
diff --git a/dukeChatBox/src/main/java/duke/efficiency_command.txt b/dukeChatBox/src/main/java/duke/efficiency_command.txt
new file mode 100644
index 0000000000..63c56440e2
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/efficiency_command.txt
@@ -0,0 +1,13 @@
+在终端中,您可以使用以下命令来移动光标/指针:
+
+Ctrl + A:将光标移动到命令行的开头。
+Ctrl + E:将光标移动到命令行的结尾。
+Ctrl + F:将光标向前移动一个字符。
+Ctrl + B:将光标向后移动一个字符。
+Alt + F:将光标向前移动一个单词。
+Alt + B:将光标向后移动一个单词。
+Ctrl + L:清屏并将光标移动到命令行的顶部。
+Ctrl + U:删除命令行上光标之前的所有字符。
+Ctrl + K:删除命令行上光标之后的所有字符。
+Ctrl + W:删除光标前的一个单词。
+这些命令可以让您更轻松地在终端中编辑命令并移动光标/指针。使用这些命令可以提高您在终端中的效率和速度。
\ No newline at end of file
diff --git a/dukeChatBox/src/main/java/duke/exception/DukeException.java b/dukeChatBox/src/main/java/duke/exception/DukeException.java
new file mode 100644
index 0000000000..ecad03fb21
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/exception/DukeException.java
@@ -0,0 +1,9 @@
+package duke.exception;
+
+/**
+ * Exceptions specific to Duke.
+ */
+public class DukeException extends Exception{
+}
+
+
diff --git a/dukeChatBox/src/main/java/duke/parser/Parser.java b/dukeChatBox/src/main/java/duke/parser/Parser.java
new file mode 100644
index 0000000000..3920821f8a
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/parser/Parser.java
@@ -0,0 +1,65 @@
+package duke.parser;
+
+import duke.command.*;
+import duke.exception.DukeException;
+
+
+public class Parser {
+
+ private static String keyword;
+ private static String statement;
+
+ /**
+ * Parse the user's input into formatted command.
+ * @param fullCommand a single user's command line.
+ */
+ public static Command parse(String fullCommand) throws DukeException {
+ fullCommand = fullCommand.trim();
+ if (countWithSplit(fullCommand) == 0) throw new DukeException();
+ else if (countWithSplit(fullCommand) == 1){
+ keyword = fullCommand;
+ switch (keyword) {
+ case "list":
+ return new ListCommand(keyword, statement);
+ case "bye":
+ return new ByeCommand();
+ default:
+ throw new DukeException();
+ }
+ }
+ else {
+ keyword = fullCommand.split("\\s+")[0];
+ keyword = keyword.toLowerCase();
+ statement = fullCommand.replaceFirst(keyword + "\\s+", "");
+ switch (keyword) {
+ case "mark":
+ return new MarkCommand(keyword, statement);
+ case "unmark":
+ return new UnmarkCommand(keyword, statement);
+ case "todo":
+ return new TodoCommand(keyword, statement);
+ case "deadline":
+ return new DeadlineCommand(keyword, statement);
+ case "event":
+ return new EventCommand(keyword, statement);
+ case "find":
+ return new FindCommand(statement);
+ case "delete":
+ return new DeleteCommand(keyword, statement);
+ default:
+ throw new DukeException();
+ }
+ }
+ }
+
+ public static int countWithSplit(String str) {
+ if (isNullOrBlank(str)) {
+ return 0;
+ }
+ return str.split("\\s+").length;
+ }
+
+ public static boolean isNullOrBlank(String param) {
+ return param == null || param.trim().length() == 0;
+ }
+}
diff --git a/dukeChatBox/src/main/java/duke/storage/Storage.java b/dukeChatBox/src/main/java/duke/storage/Storage.java
new file mode 100644
index 0000000000..a37209f493
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/storage/Storage.java
@@ -0,0 +1,111 @@
+package duke.storage;
+
+import duke.exception.DukeException;
+import duke.task.Deadline;
+import duke.task.Event;
+import duke.task.Task;
+import duke.ui.Ui;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+import static duke.task.TaskList.*;
+
+
+public class Storage {
+ private static ArrayList tasks;
+ private File f;
+ private String filePath;
+ public Storage(String filePath){
+ f = new File(filePath);
+ this.filePath = filePath;
+ }
+ public ArrayList load() throws DukeException {
+ tasks = new ArrayList<>();
+ Scanner s;
+ int numberOfLine = 0;
+ try {
+ s = new Scanner(f);
+ while (s.hasNext()) {
+ String line = s.nextLine();
+ String[] parsedLine = line.split(" \\| ");
+ numberOfLine += 1;
+ switch (parsedLine[0]) {
+ case "T":
+ addTodo(tasks, parsedLine[2]);
+ break;
+ case "D":
+ String deadline = parsedLine[2] + " /by " + parsedLine[3];
+ addDeadline(tasks, deadline);
+ break;
+ case "E":
+ String event = parsedLine[2] + " /at " + parsedLine[3];
+ addEvent(tasks, event);
+ break;
+ default:
+ throw new DukeException();
+ }
+ switch (parsedLine[1]) {
+ case "1":
+ markTask(tasks, numberOfLine);
+ break;
+ case "0":
+ unmarkTask(tasks, numberOfLine);
+ break;
+ default:
+ throw new DukeException();
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException | DukeException | FileNotFoundException e) {
+ throw new DukeException();
+ }
+ Ui.showMessage(" Congrats! Your previous tasks have been loaded.");
+ return tasks;
+ }
+
+ public void write(ArrayList tasks) throws IOException {
+ FileWriter fw = new FileWriter(this.filePath);
+ for (int i = 0; i < tasks.size(); i++) {
+ String line = "";
+ switch (tasks.get(i).getClass().getSimpleName()) {
+ case "Todo":
+ line = line + "T | ";
+ break;
+ case "Deadline":
+ line = line + "D | ";
+ break;
+ case "Event":
+ line = line + "E | ";
+ break;
+ }
+ switch (tasks.get(i).getStatusIcon()) {
+ case "X":
+ line = line + "1 | ";
+ break;
+ case " ":
+ line = line + "0 | ";
+ break;
+ }
+ line = line + tasks.get(i).getDescription();
+ switch (tasks.get(i).getClass().getSimpleName()) {
+ case "Deadline":
+ Deadline d = (Deadline) tasks.get(i);
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm");
+ line = line + " | " + d.getBy().format(formatter);
+ break;
+ case "Event":
+ Event e = (Event) tasks.get(i);
+ line = line + " | " + e.getAt();
+ break;
+ }
+ line = line + System.lineSeparator();
+ fw.write(line);
+ }
+ fw.close();
+ }
+}
diff --git a/dukeChatBox/src/main/java/duke/task/Deadline.java b/dukeChatBox/src/main/java/duke/task/Deadline.java
new file mode 100644
index 0000000000..3e77f746c1
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/task/Deadline.java
@@ -0,0 +1,55 @@
+package duke.task;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+//public class Deadline extends Task {
+//
+// protected String by;
+//
+// public Deadline(String description, String by) {
+// super(description);
+// this.by = by;
+// }
+//
+// public String getBy() {
+// return by;
+// }
+//
+// @Override
+// public String getTaskSymbol() {
+// return "D";
+// }
+//
+// @Override
+// public String toString() {
+// return + super.toString() + " (by: " + by + ")";
+// }
+//}
+
+
+public class Deadline extends Task {
+ private LocalDateTime by;
+
+ public Deadline(String description, String by) throws DateTimeParseException {
+ super(description);
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm");
+ this.by = LocalDateTime.parse(by, formatter);
+ }
+
+ public LocalDateTime getBy() {
+ return this.by;
+ }
+
+ @Override
+ public String getTaskSymbol() {
+ return "D";
+ }
+
+ @Override
+ public String toString() {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm");
+ return "[" + getTaskSymbol() + "]" + super.toString() + " (by: " + by.format(formatter) + ")";
+ }
+}
\ No newline at end of file
diff --git a/dukeChatBox/src/main/java/duke/task/Event.java b/dukeChatBox/src/main/java/duke/task/Event.java
new file mode 100644
index 0000000000..02ce4155ee
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/task/Event.java
@@ -0,0 +1,25 @@
+package duke.task;
+
+public class Event extends Task {
+
+ protected String at;
+
+ public Event(String description, String at) {
+ super(description);
+ this.at = at;
+ }
+
+ public String getAt() {
+ return at;
+ }
+
+ @Override
+ public String getTaskSymbol() {
+ return "E";
+ }
+
+ @Override
+ public String toString() {
+ return "[" + getTaskSymbol() + "]" + super.toString()+ " (at: " + at + ")";
+ }
+}
\ No newline at end of file
diff --git a/dukeChatBox/src/main/java/duke/task/Task.java b/dukeChatBox/src/main/java/duke/task/Task.java
new file mode 100644
index 0000000000..301752fc3f
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/task/Task.java
@@ -0,0 +1,27 @@
+package duke.task;
+
+public abstract class Task {
+ protected String description;
+ protected boolean isDone;
+
+ public Task(String description) {
+ this.description = description;
+ this.isDone = false;
+ }
+
+ public String getStatusIcon() { return (isDone ? "X" : " "); }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public abstract String getTaskSymbol();
+
+ public String toString() { return "[" + getStatusIcon() + "] " + description; }
+
+ public void setDone() {
+ this.isDone = true;
+ }
+
+ public void setNotDone() { isDone = false; }
+}
\ No newline at end of file
diff --git a/dukeChatBox/src/main/java/duke/task/TaskList.java b/dukeChatBox/src/main/java/duke/task/TaskList.java
new file mode 100644
index 0000000000..0219cd2bbe
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/task/TaskList.java
@@ -0,0 +1,302 @@
+package duke.task;
+
+import duke.exception.DukeException;
+
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.stream.Collectors;
+
+public class TaskList {
+ private final ArrayList tasks;
+
+ public void add(Task task) {
+ tasks.add(task);
+ }
+ public TaskList() {
+ this.tasks = new ArrayList<>();
+ }
+
+ public TaskList(ArrayList tasks) {
+ this.tasks = tasks;
+ }
+
+ /**
+ * Show the adding message of the newly added task.
+ *
+ * @param task the new added task.
+ * @param tasksSize the size of taskList.
+ */
+ public static void printNewTask(Task task, int tasksSize) {
+ System.out.println(" Got it. I've added this task:");
+ System.out.println(" " + task);
+ System.out.println(" Now you have " + tasksSize + " tasks in the list.");
+ }
+
+
+ public static void printTaskList(ArrayList tasks) {
+ System.out.println(" Here are the tasks in your list:");
+ for (int i = 0; i < tasks.size(); i++) {
+ System.out.println(" " + (i + 1) + "." + tasks.get(i));
+ }
+ }
+
+ /**
+ * Show the mark message of the newly marked task.
+ *
+ * @param task the new marked task.
+ */
+ public static void printMark(Task task) {
+ System.out.println(" Nice! I've marked this task as done:");
+ System.out.println(" " + task);
+ }
+
+ /**
+ * Show the unmark message of the newly unmarked task.
+ *
+ * @param task the new unmarked task.
+ */
+ public static void printUnmark(Task task) {
+ System.out.println(" OK, I've marked this task as not done yet:");
+ System.out.println(" " + task);
+ }
+
+ /**
+ * Try to add an event, dealing with all the exceptions then adding.
+ *
+ * @param tasks the taskList.
+ * @param statement the description and time of the event.
+ */
+ public static void tryAddEvent(ArrayList tasks, String statement) {
+ try {
+ if (statement.equals("")) {
+ throw new DukeException();
+ }
+ if (!statement.contains(" /at ")) {
+ throw new DukeException();
+ }
+ addEvent(tasks, statement);
+ int eventId = tasks.size() - 1;
+ printNewTask(tasks.get(eventId), tasks.size());
+ } catch (DukeException e) {
+ System.out.println(" T_T OOPS!!! The statement of the event is not correct.");
+ }
+ }
+
+ /**
+ * Directly add an event, having dealt with the exception before.
+ *
+ * @param tasks the taskList.
+ * @param statement the description and time of the event.
+ */
+ public static void addEvent(ArrayList tasks, String statement) {
+ String[] descriptionAt = statement.split("\\s+/at\\s+");
+ String eventDescription = descriptionAt[0];
+ String at = descriptionAt[1];
+ Event newEvent = new Event(eventDescription, at);
+ tasks.add(newEvent);
+ }
+
+ /**
+ * Try to add a deadline, dealing with all the exceptions then adding.
+ *
+ * @param tasks the taskList.
+ * @param statement the description and time of the deadline.
+ */
+ public static void tryAddDeadline(ArrayList tasks, String statement) {
+ try {
+ if (statement.equals("")) {
+ throw new DukeException();
+ }
+ if (!statement.contains(" /by ")) {
+ throw new DukeException();
+ }
+ addDeadline(tasks, statement);
+ int deadlineId = tasks.size() - 1;
+ printNewTask(tasks.get(deadlineId), tasks.size());
+ } catch (DukeException e) {
+ System.out.println(" T_T OOPS!!! The statement of the deadline is not correct.");
+ }
+ }
+
+ /**
+ * Directly add a deadline, having dealt with the exception before.
+ *
+ * @param tasks the taskList.
+ * @param statement the description and time of the deadline.
+ */
+ public static void addDeadline(ArrayList tasks, String statement) {
+ String[] descriptionBy = statement.split("\\s+/by\\s+");
+ String deadlineDescription = descriptionBy[0];
+ String by = descriptionBy[1];
+ Deadline newDeadline = new Deadline(deadlineDescription, by);
+ tasks.add(newDeadline);
+ }
+
+ /**
+ * Try to add a todoTask, dealing with all the exceptions then adding.
+ *
+ * @param tasks the taskList.
+ * @param statement the description of todoTask.
+ */
+ public static void tryAddTodo(ArrayList tasks, String statement) {
+ try {
+ if (statement.equals("")) {
+ throw new DukeException();
+ }
+ addTodo(tasks, statement);
+ int todoId = tasks.size() - 1;
+ printNewTask(tasks.get(todoId), tasks.size());
+ } catch (DukeException e) {
+ System.out.println(" T_T OOPS!!! The description of a todo cannot be empty.");
+ }
+ }
+
+ /**
+ * Directly add an todoTask, having dealt with the exception before.
+ *
+ * @param tasks the taskList.
+ * @param statement the description of todoTask.
+ */
+ public static void addTodo(ArrayList tasks, String statement) {
+ Todo newTodo = new Todo(statement);
+ tasks.add(newTodo);
+ }
+
+ /**
+ * Try to mark a task, dealing with all the exceptions then mark.
+ *
+ * @param tasks the taskList.
+ * @param id the unprocessed markId.
+ */
+ public static void tryMarkTask(ArrayList tasks, String id) {
+ try {
+ if (id.equals("")) {
+ throw new DukeException();
+ }
+ if (!isInteger(id)) {
+ throw new DukeException();
+ }
+ int markId = Integer.parseInt(id);
+ if ((markId > tasks.size()) || (markId <= 0)) {
+ throw new DukeException();
+ }
+ markTask(tasks, markId);
+ printUnmark(tasks.get(markId - 1));
+ } catch (DukeException e) {
+ System.out.println(" T_T OOPS!!! Please input the mark id again.");
+ }
+ }
+
+ /**
+ * Directly mark a task, having dealt with the exception before.
+ *
+ * @param tasks the taskList.
+ * @param markId the ID of the mark task.
+ */
+ public static void markTask(ArrayList tasks, int markId) {
+ markId = markId - 1;
+ tasks.get(markId).setDone();
+ }
+
+ /**
+ * Try to unmark a task, dealing with all the exceptions then unmark.
+ *
+ * @param tasks the taskList.
+ * @param id the unprocessed unmarkId.
+ */
+ public static void tryUnmarkTask(ArrayList tasks, String id) {
+ try {
+ if (id.equals("")) {
+ throw new DukeException();
+ }
+ if (!isInteger(id)) {
+ throw new DukeException();
+ }
+ int unmarkId = Integer.parseInt(id);
+ if ((unmarkId > tasks.size()) || (unmarkId <= 0)) {
+ throw new DukeException();
+ }
+ unmarkTask(tasks, unmarkId);
+ printUnmark(tasks.get(unmarkId - 1));
+ } catch (DukeException e) {
+ System.out.println(" T_T OOPS!!! Please input the unmark id again.");
+ }
+ }
+
+ /**
+ * Directly unmark a task, having dealt with the exception before.
+ *
+ * @param tasks the taskList.
+ * @param unmarkId the ID of the unmark task.
+ */
+ public static void unmarkTask(ArrayList tasks, int unmarkId) {
+ unmarkId = unmarkId - 1;
+ tasks.get(unmarkId).setNotDone();
+ }
+
+ /**
+ * Try to delete a task, dealing with all the exceptions then delete.
+ *
+ * @param tasks the taskList.
+ * @param id the unprocessed deleteId.
+ */
+ public static void tryDeleteTask(ArrayList tasks, String id) {
+ try {
+ if (id.equals("")) {
+ throw new DukeException();
+ }
+ if (!isInteger(id)) {
+ throw new DukeException();
+ }
+ int deleteId = Integer.parseInt(id);
+ if ((deleteId > tasks.size()) || (deleteId <= 0)) {
+ throw new DukeException();
+ }
+ deleteTask(tasks, deleteId - 1);
+ } catch (DukeException e) {
+ System.out.println(" T_T OOPS!!! Please input the delete id again.");
+ }
+ }
+
+ /**
+ * Directly delete a task, having dealt with the exception before.
+ *
+ * @param tasks the taskList.
+ * @param deleteId the id of the task to be deleted.
+ */
+ private static void deleteTask(ArrayList tasks, int deleteId) {
+ System.out.println(" Noted. I've removed this task:");
+ System.out.println(" " + tasks.get(deleteId));
+ System.out.println(" Now you have " + (tasks.size() - 1) + " tasks in the list.");
+ tasks.remove(deleteId);
+ }
+
+ public static void findTask(ArrayList tasks, String statement) {
+ ArrayList result = (ArrayList) tasks.stream()
+ .filter(task -> task.getDescription().contains(statement))
+ .collect(Collectors.toList());
+
+ if (result.isEmpty()) {
+ System.out.println(" Sorry, no matching tasks.");
+ } else {
+ System.out.println(" Here are the matching tasks in your list:");
+ for (int i = 0; i < result.size(); i++) {
+ System.out.println(" " + (i + 1) + "." + result.get(i));
+ }
+ }
+ }
+
+ public ArrayList getTasks() {
+ return tasks;
+ }
+
+ public static boolean isInteger(String str){
+ Pattern pattern = Pattern.compile("[0-9]*");
+ Matcher isNum = pattern.matcher(str);
+ if( !isNum.matches() ){
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/dukeChatBox/src/main/java/duke/task/Todo.java b/dukeChatBox/src/main/java/duke/task/Todo.java
new file mode 100644
index 0000000000..8c44c81ebe
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/task/Todo.java
@@ -0,0 +1,18 @@
+package duke.task;
+
+public class Todo extends Task {
+
+ public Todo(String description) {
+ super(description);
+ }
+
+ @Override
+ public String getTaskSymbol() {
+ return "T";
+ }
+
+ @Override
+ public String toString() {
+ return "[" + getTaskSymbol() + "]" + super.toString();
+ }
+}
\ No newline at end of file
diff --git a/dukeChatBox/src/main/java/duke/ui/Ui.java b/dukeChatBox/src/main/java/duke/ui/Ui.java
new file mode 100644
index 0000000000..3d17bddd9e
--- /dev/null
+++ b/dukeChatBox/src/main/java/duke/ui/Ui.java
@@ -0,0 +1,55 @@
+package duke.ui;
+
+
+import java.util.Scanner;
+
+public class Ui {
+ public static final String HORIZONTAL_LINE = " ____________________________________________________________";
+
+ /**
+ * Show the horizontal divider line.
+ */
+ public static void showLine() {
+ System.out.println(HORIZONTAL_LINE);
+ }
+
+ /**
+ * Show the loading error of the file that stores the tasks, which may not exist.
+ */
+ public void showLoadingError() {
+ showMessage(" Load failed! Please put the formatted file \"tasks.txt\" in the path");
+ }
+
+
+ /**
+ * Show welcome message to the user.
+ */
+ public static void showWelcome() {
+ showMessage(" Hello! I'm Duke\n" +
+ " What can I do for you?");
+ }
+
+ /**
+ * Formatting the output message, adding divider line above and below.
+ *
+ * @param message the message that needs to be formatted and shown.
+ */
+ public static void showMessage(String message) {
+ showLine();
+ System.out.println(message);
+ showLine();
+ }
+
+ public static void showError(String message) {
+ if (message == null) {
+ System.out.println(" T_T OOPS!!! I'm sorry, but I don't know what that means :-(");
+ } else {
+ System.out.println(message);
+ }
+ }
+
+ public String readCommand() {
+ Scanner in = new Scanner(System.in);
+ return in.nextLine();
+ }
+}
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000000..7bd32fa431
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = 'dukeChatBox'
+
diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java
deleted file mode 100644
index 5d313334cc..0000000000
--- a/src/main/java/Duke.java
+++ /dev/null
@@ -1,10 +0,0 @@
-public class Duke {
- public static void main(String[] args) {
- String logo = " ____ _ \n"
- + "| _ \\ _ _| | _____ \n"
- + "| | | | | | | |/ / _ \\\n"
- + "| |_| | |_| | < __/\n"
- + "|____/ \\__,_|_|\\_\\___|\n";
- System.out.println("Hello from\n" + logo);
- }
-}
diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java
new file mode 100644
index 0000000000..3284256a99
--- /dev/null
+++ b/src/main/java/duke/Duke.java
@@ -0,0 +1,96 @@
+package main.java.duke;
+
+import duke.command.Command;
+import duke.exception.DukeException;
+import duke.parser.Parser;
+import duke.storage.Storage;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+
+/**
+ * The chatting bot Duke.
+ */
+public class Duke {
+
+ private Storage storage;
+ private TaskList tasks;
+ private Ui ui;
+
+ /**
+ * Initialization of Duke and loading of file.
+ *
+ * @param filePath The path of the file that stores the tasks.
+ */
+ public Duke(String filePath) {
+ ui = new Ui();
+ storage = new Storage(filePath);
+ tasks = loadTasks();
+ }
+
+ private TaskList loadTasks() {
+ TaskList taskList;
+ try {
+ taskList = new TaskList(storage.load());
+ } catch (DukeException e) {
+ ui.showLoadingError();
+ taskList = new TaskList();
+ }
+ return taskList;
+ }
+
+ /**
+ * Process of user's input and storage of the new taskList.
+ */
+ public void run() {
+ ui.showWelcome();
+ boolean isExit = false;
+ while (!isExit) {
+ try {
+ String fullCommand = ui.readCommand();
+ ui.showLine();
+ Command c = Parser.parse(fullCommand);
+ c.execute(tasks, ui, storage);
+ isExit = c.isExit();
+ } catch (DukeException e) {
+ ui.showError(e.getMessage());
+ } finally {
+ ui.showLine();
+ }
+ }
+ }
+
+ private void processUserInput() {
+ try {
+ String fullCommand = ui.readCommand();
+ ui.showLine();
+ Command c = Parser.parse(fullCommand);
+ c.execute(tasks, ui, storage);
+ } catch (DukeException e) {
+ ui.showError(e.getMessage());
+ } finally {
+ ui.showLine();
+ }
+ }
+
+ private boolean checkForExit() {
+ String fullCommand = ui.readCommand();
+ Command c = null;
+ try {
+ c = Parser.parse(fullCommand);
+ } catch (DukeException e) {
+ e.printStackTrace();
+ }
+ return c.isExit();
+ }
+
+ /**
+ * Set the filePath and activate run function.
+ */
+ public static void main(String[] args) {
+ new Duke("./data/tasks.txt").run();
+ }
+}
+
+
+
diff --git a/src/main/java/duke/command/ByeCommand.java b/src/main/java/duke/command/ByeCommand.java
new file mode 100644
index 0000000000..0239cdfa99
--- /dev/null
+++ b/src/main/java/duke/command/ByeCommand.java
@@ -0,0 +1,33 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+
+public class ByeCommand extends Command {
+
+ public ByeCommand() {
+ isExit = true;
+ }
+
+ /**
+ * Execute user's "bye" command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ System.out.println(" Bye. Hope to see you again soon!");
+ try {
+ storage.write(tasks);
+ } catch (IOException e) {
+ createDirectory(ui, storage, tasks);
+ }
+ }
+}
diff --git a/src/main/java/duke/command/Command.java b/src/main/java/duke/command/Command.java
new file mode 100644
index 0000000000..a34298071e
--- /dev/null
+++ b/src/main/java/duke/command/Command.java
@@ -0,0 +1,54 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+
+
+public abstract class Command {
+
+ String keyword;
+ String statement;
+ Boolean isExit = false;
+
+ /**
+ * Execute a specific user's command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public abstract void execute(TaskList taskList, Ui ui, Storage storage);
+
+ /**
+ * Decide if the user wants to quit.
+ */
+ public Boolean isExit() {
+ return isExit;
+ }
+
+ /**
+ * Create a directory "data" if not exists to contain the "tasks.txt".
+ * @param ui dealing with interactions with the user.
+ * @param tasks the task list.
+ * @param storage The storage file of tasks.
+ */
+ static void createDirectory(Ui ui, Storage storage, ArrayList tasks) {
+ ui.showLine();
+ System.out.println(" Seems the data directory doesn't exist yet. Try to create for you!");
+ try {
+ Path path = Paths.get("./data");
+ Files.createDirectories(path);
+ storage.write(tasks);
+ } catch (IOException ex) {
+ System.out.println(" Sorry, creation failed!");
+ }
+ }
+
+}
diff --git a/src/main/java/duke/command/DeadlineCommand.java b/src/main/java/duke/command/DeadlineCommand.java
new file mode 100644
index 0000000000..910b5cb10b
--- /dev/null
+++ b/src/main/java/duke/command/DeadlineCommand.java
@@ -0,0 +1,37 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+import static duke.task.TaskList.tryAddDeadline;
+
+public class DeadlineCommand extends Command {
+ public DeadlineCommand(String keyword, String statement) {
+ this.keyword = keyword;
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "deadline" command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ tryAddDeadline(tasks, statement);
+ try {
+ storage.write(tasks);
+ } catch (IOException e) {
+ createDirectory(ui, storage, tasks);
+ }
+ }
+}
diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java
new file mode 100644
index 0000000000..4afa7f7188
--- /dev/null
+++ b/src/main/java/duke/command/DeleteCommand.java
@@ -0,0 +1,34 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import static duke.task.TaskList.tryDeleteTask;
+
+public class DeleteCommand extends Command {
+ public DeleteCommand(String keyword, String statement) {
+ this.keyword = keyword;
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "delete" command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ tryDeleteTask(tasks, statement);
+ try {
+ storage.write(tasks);
+ } catch (IOException e) {
+ createDirectory(ui, storage, tasks);
+ }
+ }
+}
diff --git a/src/main/java/duke/command/EventCommand.java b/src/main/java/duke/command/EventCommand.java
new file mode 100644
index 0000000000..91996b6b5a
--- /dev/null
+++ b/src/main/java/duke/command/EventCommand.java
@@ -0,0 +1,33 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import static duke.task.TaskList.tryAddEvent;
+
+public class EventCommand extends Command{
+ public EventCommand(String keyword, String statement) {
+ this.keyword = keyword;
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "event" command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ tryAddEvent(tasks, statement);
+ try {
+ storage.write(tasks);
+ } catch (IOException e) {
+ createDirectory(ui, storage, tasks);
+ }
+ }
+}
diff --git a/src/main/java/duke/command/FindCommand.java b/src/main/java/duke/command/FindCommand.java
new file mode 100644
index 0000000000..f2673f5740
--- /dev/null
+++ b/src/main/java/duke/command/FindCommand.java
@@ -0,0 +1,31 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.util.ArrayList;
+
+import static duke.task.TaskList.findTask;
+
+public class FindCommand extends Command{
+
+ String statement;
+
+ public FindCommand(String statement) {
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "find" command.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ @Override
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ findTask(tasks, statement);
+ }
+}
diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java
new file mode 100644
index 0000000000..ab6966a63e
--- /dev/null
+++ b/src/main/java/duke/command/ListCommand.java
@@ -0,0 +1,28 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.util.ArrayList;
+
+import static duke.task.TaskList.printTaskList;
+
+public class ListCommand extends Command{
+ public ListCommand(String keyword, String statement) {
+ this.keyword = keyword;
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "list" command.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ printTaskList(tasks);
+ }
+}
diff --git a/src/main/java/duke/command/MarkCommand.java b/src/main/java/duke/command/MarkCommand.java
new file mode 100644
index 0000000000..291be6949a
--- /dev/null
+++ b/src/main/java/duke/command/MarkCommand.java
@@ -0,0 +1,35 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import static duke.task.TaskList.tryMarkTask;
+
+
+public class MarkCommand extends Command {
+ public MarkCommand(String keyword, String statement) {
+ this.keyword = keyword;
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "mark" command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ tryMarkTask(tasks, statement);
+ try {
+ storage.write(tasks);
+ } catch (IOException e) {
+ createDirectory(ui, storage, tasks);
+ }
+ }
+}
diff --git a/src/main/java/duke/command/TodoCommand.java b/src/main/java/duke/command/TodoCommand.java
new file mode 100644
index 0000000000..ab4a621ee0
--- /dev/null
+++ b/src/main/java/duke/command/TodoCommand.java
@@ -0,0 +1,40 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+
+import static duke.task.TaskList.tryAddTodo;
+
+public class TodoCommand extends Command {
+ public TodoCommand(String keyword, String statement) {
+ this.keyword = keyword;
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "todoTask" command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ tryAddTodo(tasks, statement);
+ try {
+ storage.write(tasks);
+ } catch (IOException e) {
+ createDirectory(ui, storage, tasks);
+ }
+ }
+
+
+}
diff --git a/src/main/java/duke/command/UnmarkCommand.java b/src/main/java/duke/command/UnmarkCommand.java
new file mode 100644
index 0000000000..43d30dc134
--- /dev/null
+++ b/src/main/java/duke/command/UnmarkCommand.java
@@ -0,0 +1,34 @@
+package duke.command;
+
+import duke.storage.Storage;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.Ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import static duke.task.TaskList.tryUnmarkTask;
+
+public class UnmarkCommand extends Command{
+ public UnmarkCommand(String keyword, String statement) {
+ this.keyword = keyword;
+ this.statement = statement;
+ }
+
+ /**
+ * Execute user's "unmark" command and change the storage file accordingly.
+ * @param taskList The list containing tasks.
+ * @param ui dealing with interactions with the user.
+ * @param storage The storage file of tasks.
+ */
+ public void execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList tasks = taskList.getTasks();
+ tryUnmarkTask(tasks, statement);
+ try {
+ storage.write(tasks);
+ } catch (IOException e) {
+ createDirectory(ui, storage, tasks);
+ }
+ }
+}
diff --git a/src/main/java/duke/efficiency_command.txt b/src/main/java/duke/efficiency_command.txt
new file mode 100644
index 0000000000..63c56440e2
--- /dev/null
+++ b/src/main/java/duke/efficiency_command.txt
@@ -0,0 +1,13 @@
+在终端中,您可以使用以下命令来移动光标/指针:
+
+Ctrl + A:将光标移动到命令行的开头。
+Ctrl + E:将光标移动到命令行的结尾。
+Ctrl + F:将光标向前移动一个字符。
+Ctrl + B:将光标向后移动一个字符。
+Alt + F:将光标向前移动一个单词。
+Alt + B:将光标向后移动一个单词。
+Ctrl + L:清屏并将光标移动到命令行的顶部。
+Ctrl + U:删除命令行上光标之前的所有字符。
+Ctrl + K:删除命令行上光标之后的所有字符。
+Ctrl + W:删除光标前的一个单词。
+这些命令可以让您更轻松地在终端中编辑命令并移动光标/指针。使用这些命令可以提高您在终端中的效率和速度。
\ No newline at end of file
diff --git a/src/main/java/duke/exception/DukeException.java b/src/main/java/duke/exception/DukeException.java
new file mode 100644
index 0000000000..ecad03fb21
--- /dev/null
+++ b/src/main/java/duke/exception/DukeException.java
@@ -0,0 +1,9 @@
+package duke.exception;
+
+/**
+ * Exceptions specific to Duke.
+ */
+public class DukeException extends Exception{
+}
+
+
diff --git a/src/main/java/duke/parser/Parser.java b/src/main/java/duke/parser/Parser.java
new file mode 100644
index 0000000000..3920821f8a
--- /dev/null
+++ b/src/main/java/duke/parser/Parser.java
@@ -0,0 +1,65 @@
+package duke.parser;
+
+import duke.command.*;
+import duke.exception.DukeException;
+
+
+public class Parser {
+
+ private static String keyword;
+ private static String statement;
+
+ /**
+ * Parse the user's input into formatted command.
+ * @param fullCommand a single user's command line.
+ */
+ public static Command parse(String fullCommand) throws DukeException {
+ fullCommand = fullCommand.trim();
+ if (countWithSplit(fullCommand) == 0) throw new DukeException();
+ else if (countWithSplit(fullCommand) == 1){
+ keyword = fullCommand;
+ switch (keyword) {
+ case "list":
+ return new ListCommand(keyword, statement);
+ case "bye":
+ return new ByeCommand();
+ default:
+ throw new DukeException();
+ }
+ }
+ else {
+ keyword = fullCommand.split("\\s+")[0];
+ keyword = keyword.toLowerCase();
+ statement = fullCommand.replaceFirst(keyword + "\\s+", "");
+ switch (keyword) {
+ case "mark":
+ return new MarkCommand(keyword, statement);
+ case "unmark":
+ return new UnmarkCommand(keyword, statement);
+ case "todo":
+ return new TodoCommand(keyword, statement);
+ case "deadline":
+ return new DeadlineCommand(keyword, statement);
+ case "event":
+ return new EventCommand(keyword, statement);
+ case "find":
+ return new FindCommand(statement);
+ case "delete":
+ return new DeleteCommand(keyword, statement);
+ default:
+ throw new DukeException();
+ }
+ }
+ }
+
+ public static int countWithSplit(String str) {
+ if (isNullOrBlank(str)) {
+ return 0;
+ }
+ return str.split("\\s+").length;
+ }
+
+ public static boolean isNullOrBlank(String param) {
+ return param == null || param.trim().length() == 0;
+ }
+}
diff --git a/src/main/java/duke/storage/Storage.java b/src/main/java/duke/storage/Storage.java
new file mode 100644
index 0000000000..a37209f493
--- /dev/null
+++ b/src/main/java/duke/storage/Storage.java
@@ -0,0 +1,111 @@
+package duke.storage;
+
+import duke.exception.DukeException;
+import duke.task.Deadline;
+import duke.task.Event;
+import duke.task.Task;
+import duke.ui.Ui;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+import static duke.task.TaskList.*;
+
+
+public class Storage {
+ private static ArrayList tasks;
+ private File f;
+ private String filePath;
+ public Storage(String filePath){
+ f = new File(filePath);
+ this.filePath = filePath;
+ }
+ public ArrayList load() throws DukeException {
+ tasks = new ArrayList<>();
+ Scanner s;
+ int numberOfLine = 0;
+ try {
+ s = new Scanner(f);
+ while (s.hasNext()) {
+ String line = s.nextLine();
+ String[] parsedLine = line.split(" \\| ");
+ numberOfLine += 1;
+ switch (parsedLine[0]) {
+ case "T":
+ addTodo(tasks, parsedLine[2]);
+ break;
+ case "D":
+ String deadline = parsedLine[2] + " /by " + parsedLine[3];
+ addDeadline(tasks, deadline);
+ break;
+ case "E":
+ String event = parsedLine[2] + " /at " + parsedLine[3];
+ addEvent(tasks, event);
+ break;
+ default:
+ throw new DukeException();
+ }
+ switch (parsedLine[1]) {
+ case "1":
+ markTask(tasks, numberOfLine);
+ break;
+ case "0":
+ unmarkTask(tasks, numberOfLine);
+ break;
+ default:
+ throw new DukeException();
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException | DukeException | FileNotFoundException e) {
+ throw new DukeException();
+ }
+ Ui.showMessage(" Congrats! Your previous tasks have been loaded.");
+ return tasks;
+ }
+
+ public void write(ArrayList tasks) throws IOException {
+ FileWriter fw = new FileWriter(this.filePath);
+ for (int i = 0; i < tasks.size(); i++) {
+ String line = "";
+ switch (tasks.get(i).getClass().getSimpleName()) {
+ case "Todo":
+ line = line + "T | ";
+ break;
+ case "Deadline":
+ line = line + "D | ";
+ break;
+ case "Event":
+ line = line + "E | ";
+ break;
+ }
+ switch (tasks.get(i).getStatusIcon()) {
+ case "X":
+ line = line + "1 | ";
+ break;
+ case " ":
+ line = line + "0 | ";
+ break;
+ }
+ line = line + tasks.get(i).getDescription();
+ switch (tasks.get(i).getClass().getSimpleName()) {
+ case "Deadline":
+ Deadline d = (Deadline) tasks.get(i);
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm");
+ line = line + " | " + d.getBy().format(formatter);
+ break;
+ case "Event":
+ Event e = (Event) tasks.get(i);
+ line = line + " | " + e.getAt();
+ break;
+ }
+ line = line + System.lineSeparator();
+ fw.write(line);
+ }
+ fw.close();
+ }
+}
diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java
new file mode 100644
index 0000000000..d094eb795b
--- /dev/null
+++ b/src/main/java/duke/task/Deadline.java
@@ -0,0 +1,61 @@
+package duke.task;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+//public class Deadline extends Task {
+//
+// protected String by;
+//
+// public Deadline(String description, String by) {
+// super(description);
+// this.by = by;
+// }
+//
+// public String getBy() {
+// return by;
+// }
+//
+// @Override
+// public String getTaskSymbol() {
+// return "D";
+// }
+//
+// @Override
+// public String toString() {
+// return + super.toString() + " (by: " + by + ")";
+// }
+//}
+
+
+public class Deadline extends Task {
+ private LocalDateTime by;
+
+ public Deadline(String description, String by) throws DateTimeParseException {
+ super(description);
+
+ assert description != null : "Description cannot be null";
+ assert by != null : "By (deadline) cannot be null";
+
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
+ this.by = LocalDateTime.parse(by, formatter);
+
+ assert this.by != null : "Parsed LocalDateTime cannot be null";
+ }
+
+ public LocalDateTime getBy() {
+ return this.by;
+ }
+
+ @Override
+ public String getTaskSymbol() {
+ return "D";
+ }
+
+ @Override
+ public String toString() {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm");
+ return "[" + getTaskSymbol() + "]" + super.toString() + " (by: " + by.format(formatter) + ")";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java
new file mode 100644
index 0000000000..02ce4155ee
--- /dev/null
+++ b/src/main/java/duke/task/Event.java
@@ -0,0 +1,25 @@
+package duke.task;
+
+public class Event extends Task {
+
+ protected String at;
+
+ public Event(String description, String at) {
+ super(description);
+ this.at = at;
+ }
+
+ public String getAt() {
+ return at;
+ }
+
+ @Override
+ public String getTaskSymbol() {
+ return "E";
+ }
+
+ @Override
+ public String toString() {
+ return "[" + getTaskSymbol() + "]" + super.toString()+ " (at: " + at + ")";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java
new file mode 100644
index 0000000000..301752fc3f
--- /dev/null
+++ b/src/main/java/duke/task/Task.java
@@ -0,0 +1,27 @@
+package duke.task;
+
+public abstract class Task {
+ protected String description;
+ protected boolean isDone;
+
+ public Task(String description) {
+ this.description = description;
+ this.isDone = false;
+ }
+
+ public String getStatusIcon() { return (isDone ? "X" : " "); }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public abstract String getTaskSymbol();
+
+ public String toString() { return "[" + getStatusIcon() + "] " + description; }
+
+ public void setDone() {
+ this.isDone = true;
+ }
+
+ public void setNotDone() { isDone = false; }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/task/TaskList.java b/src/main/java/duke/task/TaskList.java
new file mode 100644
index 0000000000..f9e33d8594
--- /dev/null
+++ b/src/main/java/duke/task/TaskList.java
@@ -0,0 +1,303 @@
+package duke.task;
+
+import duke.exception.DukeException;
+
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.stream.Collectors;
+
+public class TaskList {
+ private final ArrayList tasks;
+
+ public void add(Task task) {
+ tasks.add(task);
+ }
+ public TaskList() {
+ this.tasks = new ArrayList<>();
+ }
+
+ public TaskList(ArrayList tasks) {
+ this.tasks = tasks;
+ }
+
+ /**
+ * Show the adding message of the newly added task.
+ *
+ * @param task the new added task.
+ * @param tasksSize the size of taskList.
+ */
+ public static void printNewTask(Task task, int tasksSize) {
+ System.out.println(" Got it. I've added this task:");
+ System.out.println(" " + task);
+ System.out.println(" Now you have " + tasksSize + " tasks in the list.");
+ }
+
+
+ public static void printTaskList(ArrayList tasks) {
+ System.out.println(" Here are the tasks in your list:");
+ for (int i = 0; i < tasks.size(); i++) {
+ System.out.println(" " + (i + 1) + "." + tasks.get(i));
+ }
+ }
+
+ /**
+ * Show the mark message of the newly marked task.
+ *
+ * @param task the new marked task.
+ */
+ public static void printMark(Task task) {
+ System.out.println(" Nice! I've marked this task as done:");
+ System.out.println(" " + task);
+ }
+
+ /**
+ * Show the unmark message of the newly unmarked task.
+ *
+ * @param task the new unmarked task.
+ */
+ public static void printUnmark(Task task) {
+ System.out.println(" OK, I've marked this task as not done yet:");
+ System.out.println(" " + task);
+ }
+
+ /**
+ * Try to add an event, dealing with all the exceptions then adding.
+ *
+ * @param tasks the taskList.
+ * @param statement the description and time of the event.
+ */
+ public static void tryAddEvent(ArrayList tasks, String statement) {
+ try {
+ if (statement.equals("")) {
+ throw new DukeException();
+ }
+ if (!statement.contains(" /at ")) {
+ throw new DukeException();
+ }
+ addEvent(tasks, statement);
+ int eventId = tasks.size() - 1;
+ printNewTask(tasks.get(eventId), tasks.size());
+ } catch (DukeException e) {
+ System.out.println(" T_T OOPS!!! The statement of the event is not correct.");
+ }
+ }
+
+ /**
+ * Directly add an event, having dealt with the exception before.
+ *
+ * @param tasks the taskList.
+ * @param statement the description and time of the event.
+ */
+ public static void addEvent(ArrayList tasks, String statement) {
+ String[] descriptionAt = statement.split("\\s+/at\\s+");
+ String eventDescription = descriptionAt[0];
+ String at = descriptionAt[1];
+ Event newEvent = new Event(eventDescription, at);
+ tasks.add(newEvent);
+ }
+
+ /**
+ * Try to add a deadline, dealing with all the exceptions then adding.
+ *
+ * @param tasks the taskList.
+ * @param statement the description and time of the deadline.
+ */
+ public static void tryAddDeadline(ArrayList tasks, String statement) {
+ try {
+ if (statement.equals("")) {
+ throw new DukeException();
+ }
+ if (!statement.contains(" /by ")) {
+ throw new DukeException();
+ }
+ addDeadline(tasks, statement);
+ int deadlineId = tasks.size() - 1;
+ printNewTask(tasks.get(deadlineId), tasks.size());
+ } catch (DukeException e) {
+ System.out.println(" T_T OOPS!!! The statement of the deadline is not correct.");
+ }
+ }
+
+ /**
+ * Directly add a deadline, having dealt with the exception before.
+ *
+ * @param tasks the taskList.
+ * @param statement the description and time of the deadline.
+ */
+ public static void addDeadline(ArrayList tasks, String statement) {
+ //String[] descriptionBy = statement.split("\\s+/by\\s+");
+ String[] descriptionBy = statement.split("\\s?/by\\s+");
+ String deadlineDescription = descriptionBy[0];
+ String by = descriptionBy[1];
+ Deadline newDeadline = new Deadline(deadlineDescription, by);
+ tasks.add(newDeadline);
+ }
+
+ /**
+ * Try to add a todoTask, dealing with all the exceptions then adding.
+ *
+ * @param tasks the taskList.
+ * @param statement the description of todoTask.
+ */
+ public static void tryAddTodo(ArrayList tasks, String statement) {
+ try {
+ if (statement.equals("")) {
+ throw new DukeException();
+ }
+ addTodo(tasks, statement);
+ int todoId = tasks.size() - 1;
+ printNewTask(tasks.get(todoId), tasks.size());
+ } catch (DukeException e) {
+ System.out.println(" T_T OOPS!!! The description of a todo cannot be empty.");
+ }
+ }
+
+ /**
+ * Directly add an todoTask, having dealt with the exception before.
+ *
+ * @param tasks the taskList.
+ * @param statement the description of todoTask.
+ */
+ public static void addTodo(ArrayList tasks, String statement) {
+ Todo newTodo = new Todo(statement);
+ tasks.add(newTodo);
+ }
+
+ /**
+ * Try to mark a task, dealing with all the exceptions then mark.
+ *
+ * @param tasks the taskList.
+ * @param id the unprocessed markId.
+ */
+ public static void tryMarkTask(ArrayList tasks, String id) {
+ try {
+ if (id.equals("")) {
+ throw new DukeException();
+ }
+ if (!isInteger(id)) {
+ throw new DukeException();
+ }
+ int markId = Integer.parseInt(id);
+ if ((markId > tasks.size()) || (markId <= 0)) {
+ throw new DukeException();
+ }
+ markTask(tasks, markId);
+ printUnmark(tasks.get(markId - 1));
+ } catch (DukeException e) {
+ System.out.println(" T_T OOPS!!! Please input the mark id again.");
+ }
+ }
+
+ /**
+ * Directly mark a task, having dealt with the exception before.
+ *
+ * @param tasks the taskList.
+ * @param markId the ID of the mark task.
+ */
+ public static void markTask(ArrayList tasks, int markId) {
+ markId = markId - 1;
+ tasks.get(markId).setDone();
+ }
+
+ /**
+ * Try to unmark a task, dealing with all the exceptions then unmark.
+ *
+ * @param tasks the taskList.
+ * @param id the unprocessed unmarkId.
+ */
+ public static void tryUnmarkTask(ArrayList tasks, String id) {
+ try {
+ if (id.equals("")) {
+ throw new DukeException();
+ }
+ if (!isInteger(id)) {
+ throw new DukeException();
+ }
+ int unmarkId = Integer.parseInt(id);
+ if ((unmarkId > tasks.size()) || (unmarkId <= 0)) {
+ throw new DukeException();
+ }
+ unmarkTask(tasks, unmarkId);
+ printUnmark(tasks.get(unmarkId - 1));
+ } catch (DukeException e) {
+ System.out.println(" T_T OOPS!!! Please input the unmark id again.");
+ }
+ }
+
+ /**
+ * Directly unmark a task, having dealt with the exception before.
+ *
+ * @param tasks the taskList.
+ * @param unmarkId the ID of the unmark task.
+ */
+ public static void unmarkTask(ArrayList tasks, int unmarkId) {
+ unmarkId = unmarkId - 1;
+ tasks.get(unmarkId).setNotDone();
+ }
+
+ /**
+ * Try to delete a task, dealing with all the exceptions then delete.
+ *
+ * @param tasks the taskList.
+ * @param id the unprocessed deleteId.
+ */
+ public static void tryDeleteTask(ArrayList tasks, String id) {
+ try {
+ if (id.equals("")) {
+ throw new DukeException();
+ }
+ if (!isInteger(id)) {
+ throw new DukeException();
+ }
+ int deleteId = Integer.parseInt(id);
+ if ((deleteId > tasks.size()) || (deleteId <= 0)) {
+ throw new DukeException();
+ }
+ deleteTask(tasks, deleteId - 1);
+ } catch (DukeException e) {
+ System.out.println(" T_T OOPS!!! Please input the delete id again.");
+ }
+ }
+
+ /**
+ * Directly delete a task, having dealt with the exception before.
+ *
+ * @param tasks the taskList.
+ * @param deleteId the id of the task to be deleted.
+ */
+ private static void deleteTask(ArrayList tasks, int deleteId) {
+ System.out.println(" Noted. I've removed this task:");
+ System.out.println(" " + tasks.get(deleteId));
+ System.out.println(" Now you have " + (tasks.size() - 1) + " tasks in the list.");
+ tasks.remove(deleteId);
+ }
+
+ public static void findTask(ArrayList tasks, String statement) {
+ ArrayList result = (ArrayList) tasks.stream()
+ .filter(task -> task.getDescription().contains(statement))
+ .collect(Collectors.toList());
+
+ if (result.isEmpty()) {
+ System.out.println(" Sorry, no matching tasks.");
+ } else {
+ System.out.println(" Here are the matching tasks in your list:");
+ for (int i = 0; i < result.size(); i++) {
+ System.out.println(" " + (i + 1) + "." + result.get(i));
+ }
+ }
+ }
+
+ public ArrayList getTasks() {
+ return tasks;
+ }
+
+ public static boolean isInteger(String str){
+ Pattern pattern = Pattern.compile("[0-9]*");
+ Matcher isNum = pattern.matcher(str);
+ if( !isNum.matches() ){
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/duke/task/Todo.java b/src/main/java/duke/task/Todo.java
new file mode 100644
index 0000000000..8c44c81ebe
--- /dev/null
+++ b/src/main/java/duke/task/Todo.java
@@ -0,0 +1,18 @@
+package duke.task;
+
+public class Todo extends Task {
+
+ public Todo(String description) {
+ super(description);
+ }
+
+ @Override
+ public String getTaskSymbol() {
+ return "T";
+ }
+
+ @Override
+ public String toString() {
+ return "[" + getTaskSymbol() + "]" + super.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/ui/Ui.java b/src/main/java/duke/ui/Ui.java
new file mode 100644
index 0000000000..3d17bddd9e
--- /dev/null
+++ b/src/main/java/duke/ui/Ui.java
@@ -0,0 +1,55 @@
+package duke.ui;
+
+
+import java.util.Scanner;
+
+public class Ui {
+ public static final String HORIZONTAL_LINE = " ____________________________________________________________";
+
+ /**
+ * Show the horizontal divider line.
+ */
+ public static void showLine() {
+ System.out.println(HORIZONTAL_LINE);
+ }
+
+ /**
+ * Show the loading error of the file that stores the tasks, which may not exist.
+ */
+ public void showLoadingError() {
+ showMessage(" Load failed! Please put the formatted file \"tasks.txt\" in the path");
+ }
+
+
+ /**
+ * Show welcome message to the user.
+ */
+ public static void showWelcome() {
+ showMessage(" Hello! I'm Duke\n" +
+ " What can I do for you?");
+ }
+
+ /**
+ * Formatting the output message, adding divider line above and below.
+ *
+ * @param message the message that needs to be formatted and shown.
+ */
+ public static void showMessage(String message) {
+ showLine();
+ System.out.println(message);
+ showLine();
+ }
+
+ public static void showError(String message) {
+ if (message == null) {
+ System.out.println(" T_T OOPS!!! I'm sorry, but I don't know what that means :-(");
+ } else {
+ System.out.println(message);
+ }
+ }
+
+ public String readCommand() {
+ Scanner in = new Scanner(System.in);
+ return in.nextLine();
+ }
+}
diff --git a/suggestions/Duke.java b/suggestions/Duke.java
new file mode 100644
index 0000000000..4fb0a35f10
--- /dev/null
+++ b/suggestions/Duke.java
@@ -0,0 +1,127 @@
+import java.util.Objects;
+import java.util.Scanner;
+public class Duke {
+ public static final int MAX_TASK = 100;
+ public static void printWelcomeMessage() {
+ Task.printHorizontalLine();
+ System.out.println(" Hello! I'm Duke");
+ System.out.println(" What can I do for you?");
+ Task.printHorizontalLine();
+ }
+ public static void printBlahMessage() {
+ Task.printHorizontalLine();
+ System.out.println(" blah");
+ Task.printHorizontalLine();
+ }
+ public static void printByeMessage() {
+ Task.printHorizontalLine();
+ System.out.println(" Bye. Hope to see you again soon!");
+ Task.printHorizontalLine();
+ }
+ public static void main(String[] args) {
+ printWelcomeMessage();
+ Scanner in = new Scanner(System.in);
+ Task[] tasks = new Task[MAX_TASK];
+ request:
+ while(true){
+ String line = in.nextLine();
+ String[] parsedInput = line.split(" ");
+ switch (parsedInput[0]) {
+ case "list":
+ Task.printTaskList(tasks);
+ break;
+ case "mark":
+ int markId = Integer.parseInt(parsedInput[1]) - 1;
+ tasks[markId].setDone();
+ tasks[markId].printMark();
+ markTask(tasks, parsedInput);
+ break;
+ case "unmark":
+ int unmarkId = Integer.parseInt(parsedInput[1]) - 1;
+ tasks[unmarkId].setNotDone();
+ tasks[unmarkId].printUnmark();
+ unmarkTask(tasks, parsedInput);
+ break;
+ case "todo":
+ String todoDescription = line.replaceFirst("todo ", "");
+ tasks[Todo.getNumberOfTasks()] = new Todo(todoDescription);
+ int todoId = Todo.getNumberOfTasks() - 1;
+ tasks[todoId].printNewTask();
+ addTodo(tasks, line);
+ break;
+ case "deadline":
+ String[] DescriptionBy = line.replaceFirst("deadline ", "").split(" /by ");
+ String deadlineDescription = DescriptionBy[0];
+ String by = DescriptionBy[1];
+ tasks[Deadline.getNumberOfTasks()] = new Deadline(deadlineDescription, by);
+ int deadlineId = Task.getNumberOfTasks() - 1;
+ tasks[deadlineId].printNewTask();
+ addDeadline(tasks, line);
+ break;
+ case "event":
+ String[] DescriptionAt = line.replaceFirst("event ", "").split(" /at ");
+ String eventDescription = DescriptionAt[0];
+ String at = DescriptionAt[1];
+ tasks[Event.getNumberOfTasks()] = new Event(eventDescription, at);
+ int eventId = Task.getNumberOfTasks() - 1;
+ tasks[eventId].printNewTask();
+ addEvent(tasks, line);
+ break;
+ case "blah":
+ printBlahMessage();
+@@ -76,11 +59,52 @@ public static void main(String[] args) {
+ printByeMessage();
+ break request;
+ default:
+ tasks[Task.getNumberOfTasks()] = new Task(line);
+ int taskId = Task.getNumberOfTasks() - 1;
+ tasks[taskId].printNewTask();
+ addTask(tasks, line);
+ break;
+ }
+ }
+ }
+
+ private static void addTask(Task[] tasks, String line) {
+ tasks[Task.getNumberOfTasks()] = new Task(line);
+ int taskId = Task.getNumberOfTasks() - 1;
+ tasks[taskId].printNewTask();
+ }
+
+ private static void addEvent(Task[] tasks, String line) {
+ String[] DescriptionAt = line.replaceFirst("event ", "").split(" /at ");
+ String eventDescription = DescriptionAt[0];
+ String at = DescriptionAt[1];
+ tasks[Event.getNumberOfTasks()] = new Event(eventDescription, at);
+ int eventId = Task.getNumberOfTasks() - 1;
+ tasks[eventId].printNewTask();
+ }
+
+ private static void addDeadline(Task[] tasks, String line) {
+ String[] DescriptionBy = line.replaceFirst("deadline ", "").split(" /by ");
+ String deadlineDescription = DescriptionBy[0];
+ String by = DescriptionBy[1];
+ tasks[Deadline.getNumberOfTasks()] = new Deadline(deadlineDescription, by);
+ int deadlineId = Task.getNumberOfTasks() - 1;
+ tasks[deadlineId].printNewTask();
+ }
+
+ private static void addTodo(Task[] tasks, String line) {
+ String todoDescription = line.replaceFirst("todo ", "");
+ tasks[Todo.getNumberOfTasks()] = new Todo(todoDescription);
+ int todoId = Todo.getNumberOfTasks() - 1;
+ tasks[todoId].printNewTask();
+ }
+
+ private static void unmarkTask(Task[] tasks, String[] parsedInput) {
+ int unmarkId = Integer.parseInt(parsedInput[1]) - 1;
+ tasks[unmarkId].setNotDone();
+ tasks[unmarkId].printUnmark();
+ }
+
+ private static void markTask(Task[] tasks, String[] parsedInput) {
+ int markId = Integer.parseInt(parsedInput[1]) - 1;
+ tasks[markId].setDone();
+ tasks[markId].printMark();
+ }
+}
diff --git a/suggestions/lab4.java b/suggestions/lab4.java
new file mode 100644
index 0000000000..abf2cbea88
--- /dev/null
+++ b/suggestions/lab4.java
@@ -0,0 +1,16 @@
+class A {
+ private int x;
+ public static A zeroValueA = new A(0);
+
+ private A(int x){
+ this.x = x;
+ }
+
+ public static A construct(int x) {
+ if (x == 0) {
+ return A.zeroValueA;
+ } else {
+ return A(x);
+ }
+ }
+}
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e7..1e4f0f157f 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -5,3 +5,37 @@ Hello from
| |_| | |_| | < __/
|____/ \__,_|_|\_\___|
+ ____________________________________________________________
+ Hello! I'm Duke
+ What can I do for you?
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [T][ ] CS2103T 05-20
+ Now you have 1 tasks in the list.
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [D][ ][ ] weekly CS2030 quiz (by: Tuesday 2359pm)
+ Now you have 2 tasks in the list.
+ ____________________________________________________________
+ ____________________________________________________________
+ Here are the tasks in your list:
+ 1. [T][ ] CS2103T 05-20
+ 2. [D][ ][ ] weekly CS2030 quiz (by: Tuesday 2359pm)
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [E][ ][ ] CS2103T lecture (at: Friday 4 to 6 pm)
+ Now you have 3 tasks in the list.
+ ____________________________________________________________
+ ____________________________________________________________
+ Nice! I've marked this task as done:
+ [T][X] CS2103T 05-20
+ ____________________________________________________________
+ ____________________________________________________________
+ Here are the tasks in your list:
+ 1. [T][X] CS2103T 05-20
+ 2. [D][ ][ ] weekly CS2030 quiz (by: Tuesday 2359pm)
+ 3. [E][ ][ ] CS2103T lecture (at: Friday 4 to 6 pm)
+ ____________________________________________________________
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb2..31e89eff61 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,6 @@
+todo CS2103T 05-20
+deadline weekly CS2030 quiz /by Tuesday 2359pm
+list
+event CS2103T lecture /at Friday 4 to 6 pm
+mark 1
+list
\ No newline at end of file
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
old mode 100644
new mode 100755