diff --git a/README.md b/README.md
index 8715d4d9..a8111be7 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Duke project template
+# duke.duke project template
This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.
@@ -13,7 +13,7 @@ Prerequisites: JDK 11, update Intellij to the most recent version.
1. If there are any further prompts, accept the defaults.
1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
In the same dialog, set the **Project language level** field to the `SDK default` option.
-3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output:
+3. After that, locate the `src/main/java/duke.duke.java` file, right-click it, and choose `Run duke.duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output:
```
Hello from
____ _
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 00000000..dda93802
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,46 @@
+plugins {
+ id 'java'
+ id 'application'
+ id 'checkstyle'
+ id 'com.github.johnrengelman.shadow' version '5.1.0'
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0'
+ testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0'
+}
+
+test {
+ useJUnitPlatform()
+
+ testLogging {
+ events "passed", "skipped", "failed"
+
+ showExceptions true
+ exceptionFormat "full"
+ showCauses true
+ showStackTraces true
+ showStandardStreams = false
+ }
+}
+
+application {
+ mainClassName = "duke.Duke"
+}
+
+shadowJar {
+ archiveBaseName = "duke"
+ archiveClassifier = null
+}
+
+checkstyle {
+ toolVersion = '8.29'
+}
+
+run{
+ standardInput = System.in
+}
diff --git a/duke.txt b/duke.txt
new file mode 100644
index 00000000..39424621
--- /dev/null
+++ b/duke.txt
@@ -0,0 +1,14 @@
+T | 0 | eat | 0
+T | 0 | read sales report | 2
+T | 0 | read sales report | 2
+T | 0 | eat | 0
+T | 0 | sleep | 0
+D | 0 | return book | 2021-11-05 | 22:00
+D | 1 | read book | 2021-11-05 | 15:00
+D | 0 | borrow book | 2021-11-05 | 11:00
+E | 0 | project meeting | 2021-11-05 | 14:00 | 16:00
+E | 0 | family dinner | 2021-11-05 | 18:00 | 21:00
+T | 0 | submit claim | 0
+T | 0 | read sales report | 2
+D | 0 | return book | 2021-11-05 | 22:00
+E | 0 | family dinner | 2021-11-05 | 18:00 | 21:00
diff --git a/fixedDurationTask.txt b/fixedDurationTask.txt
new file mode 100644
index 00000000..e786b73e
--- /dev/null
+++ b/fixedDurationTask.txt
@@ -0,0 +1,4 @@
+read sales report | 2
+read book | 1
+do homework | 4
+submit claims | 1
\ 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 00000000..f3d88b1c
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 00000000..b7c8c5db
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 00000000..2fe81a7d
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,183 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 00000000..62bd9b9c
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,103 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java
deleted file mode 100644
index 5d313334..00000000
--- 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 00000000..783fd500
--- /dev/null
+++ b/src/main/java/duke/Duke.java
@@ -0,0 +1,55 @@
+package duke;
+
+import duke.exception.DukeException;
+import duke.parser.Command;
+import duke.parser.CommandParser;
+import duke.storage.StorageTaskList;
+import duke.task.TaskList;
+import duke.ui.UI;
+
+
+public class Duke {
+ private static StorageTaskList storageTaskList;
+ private UI ui;
+ private TaskList taskList;
+
+ /**
+ * Initializes entire duke.
+ *
+ * @param filePath - filepath to storage.
+ */
+ public Duke(String filePath) {
+ ui = new UI();
+ ui.showWelcome();
+ storageTaskList = new StorageTaskList(filePath);
+ try {
+ taskList = new TaskList(storageTaskList.load());
+ } catch (DukeException e) {
+ ui.showLoadingError();
+ taskList = new TaskList();
+ }
+ }
+
+ public void run() throws DukeException {
+ boolean isExit = false;
+
+ while (!isExit) {
+ try {
+ String fullCommand = ui.readCommand();
+ ui.showLine(); // show the divider line ("_______")
+ Command c = CommandParser.parse(fullCommand);
+ c.execute(taskList, ui, storageTaskList);
+ isExit = c.isExit();
+ } catch (DukeException e) {
+ ui.showError(e);
+ } finally {
+ ui.showLine();
+ }
+ }
+ ui.showExit();
+ }
+
+ public static void main(String[] args) throws DukeException {
+ new Duke("duke.txt").run();
+ }
+}
diff --git a/src/main/java/duke/exception/DukeException.java b/src/main/java/duke/exception/DukeException.java
new file mode 100644
index 00000000..7104bc7d
--- /dev/null
+++ b/src/main/java/duke/exception/DukeException.java
@@ -0,0 +1,16 @@
+package duke.exception;
+
+public class DukeException extends RuntimeException{
+ /**
+ * Throws base class for self-defined exceptions.
+ *
+ * @param message the pre-defined message.
+ */
+ public DukeException(String message) {
+ super(message);
+ }
+
+
+ public DukeException() {//testing
+ }
+}
diff --git a/src/main/java/duke/exception/EmptyDescriptionException.java b/src/main/java/duke/exception/EmptyDescriptionException.java
new file mode 100644
index 00000000..926835c7
--- /dev/null
+++ b/src/main/java/duke/exception/EmptyDescriptionException.java
@@ -0,0 +1,14 @@
+package duke.exception;
+
+public class EmptyDescriptionException extends DukeException{
+
+ /**
+ * Throws when user did not give a description for the task.
+ *
+ * @param message the pre-defined message.
+ */
+ public EmptyDescriptionException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/main/java/duke/exception/EmptyTaskListException.java b/src/main/java/duke/exception/EmptyTaskListException.java
new file mode 100644
index 00000000..8b95d89a
--- /dev/null
+++ b/src/main/java/duke/exception/EmptyTaskListException.java
@@ -0,0 +1,16 @@
+package duke.exception;
+
+
+public class EmptyTaskListException extends DukeException{
+
+ /**
+ * Throws when the task list is empty.
+ *
+ * @param message Printing message overload.
+ */
+ public EmptyTaskListException(String message) {
+ super(message);
+ }
+ /*
+ */
+}
diff --git a/src/main/java/duke/exception/SavingException.java b/src/main/java/duke/exception/SavingException.java
new file mode 100644
index 00000000..07da9d8c
--- /dev/null
+++ b/src/main/java/duke/exception/SavingException.java
@@ -0,0 +1,14 @@
+package duke.exception;
+
+public class SavingException extends DukeException{
+ /**
+ * Throws when there is problem saving the current task list.
+ *
+ * @param message the pre-defined message.
+ *
+ */
+ public SavingException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/main/java/duke/exception/TaskNotFoundException.java b/src/main/java/duke/exception/TaskNotFoundException.java
new file mode 100644
index 00000000..15e6181e
--- /dev/null
+++ b/src/main/java/duke/exception/TaskNotFoundException.java
@@ -0,0 +1,13 @@
+package duke.exception;
+
+public class TaskNotFoundException extends DukeException{
+ /**
+ * Throws when failed to identify task, either given wrong information or task does not exist.
+ *
+ * @param message the pre-defined message.
+ */
+ public TaskNotFoundException(String message) {
+ super(message);
+ }
+}
+
diff --git a/src/main/java/duke/exception/TimeManagementException.java b/src/main/java/duke/exception/TimeManagementException.java
new file mode 100644
index 00000000..9fb69947
--- /dev/null
+++ b/src/main/java/duke/exception/TimeManagementException.java
@@ -0,0 +1,8 @@
+package duke.exception;
+
+public class TimeManagementException extends DukeException{
+
+ /** Throws when date-time not given for deadline/event task. */
+ public TimeManagementException() {
+ }
+}
diff --git a/src/main/java/duke/exception/TimeParseException.java b/src/main/java/duke/exception/TimeParseException.java
new file mode 100644
index 00000000..60e9507d
--- /dev/null
+++ b/src/main/java/duke/exception/TimeParseException.java
@@ -0,0 +1,13 @@
+package duke.exception;
+
+
+public class TimeParseException extends DukeException{
+ /**
+ * Throws when error occurred while parsing time.
+ *
+ * @param message the pre-defined message.
+ */
+ public TimeParseException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/duke/exception/UnknownSyntaxException.java b/src/main/java/duke/exception/UnknownSyntaxException.java
new file mode 100644
index 00000000..854663cc
--- /dev/null
+++ b/src/main/java/duke/exception/UnknownSyntaxException.java
@@ -0,0 +1,12 @@
+package duke.exception;
+
+public class UnknownSyntaxException extends DukeException{
+ /**
+ * Throws when user input does not categorize under any of the pre-defined message.
+ *
+ * @param message the pre-defined message.
+ */
+ public UnknownSyntaxException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/duke/parser/Command.java b/src/main/java/duke/parser/Command.java
new file mode 100644
index 00000000..3862440a
--- /dev/null
+++ b/src/main/java/duke/parser/Command.java
@@ -0,0 +1,49 @@
+package duke.parser;
+
+import duke.storage.StorageTaskList;
+import duke.task.TaskList;
+import duke.ui.UI;
+
+public class Command {
+
+ /** Declares CommandBase Object. */
+ private CommandBase commandBase;
+
+ /** Checks if the input is "bye". */
+ private boolean shouldExit;
+
+ /**
+ * Checks if to exit or continue the runtime after each execution.
+ *
+ * @param taskList task list object
+ * @param ui ui object
+ * @param storageTaskList storage task list object
+ */
+ public void execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) {
+ this.shouldExit = commandBase.execute(taskList, ui, storageTaskList);
+ }
+
+ /**
+ * Checks if isExit true.
+ *
+ * @return isExit true or false.
+ */
+ public boolean isExit() {
+
+ return this.shouldExit;
+ }
+
+ /**
+ * Returns CommandBase object.
+ *
+ * @return CommandBase object.
+ */
+ public CommandBase getCommandBase() {
+ return commandBase;
+ }
+
+ /** Sets CommandBase object. */
+ public void setCmd(CommandBase commandBase) {
+ this.commandBase = commandBase;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/parser/CommandAdd.java b/src/main/java/duke/parser/CommandAdd.java
new file mode 100644
index 00000000..cd77e8ca
--- /dev/null
+++ b/src/main/java/duke/parser/CommandAdd.java
@@ -0,0 +1,13 @@
+package duke.parser;
+
+public class CommandAdd extends CommandBase {
+
+ /**
+ * Creates Add Command Constructor.
+ *
+ * @param command the full command.
+ */
+ public CommandAdd(String command) {
+ super(command);
+ }
+}
diff --git a/src/main/java/duke/parser/CommandBase.java b/src/main/java/duke/parser/CommandBase.java
new file mode 100644
index 00000000..4fb4959a
--- /dev/null
+++ b/src/main/java/duke/parser/CommandBase.java
@@ -0,0 +1,113 @@
+package duke.parser;
+
+import duke.exception.EmptyDescriptionException;
+import duke.exception.EmptyTaskListException;
+import duke.exception.TaskNotFoundException;
+import duke.exception.UnknownSyntaxException;
+import duke.storage.StorageTaskList;
+import duke.task.TaskList;
+import duke.ui.ReturnMessages;
+import duke.ui.UI;
+
+/**
+ * Creates base command class.
+ * CommandBase is the base class of all command objects. It contains some public attributes and methods.
+ * Each class that inherits CommandBase only needs to perform its own duty.
+ */
+public class CommandBase {
+
+ /** Declares command user input. */
+ protected String fullCommand;
+
+ /** Declares command to be executed. */
+ protected String keyword;
+
+ /** Declares command parameters. */
+ protected String detail;
+
+ /** Returns message object. */
+ private static ReturnMessages returnMessage = new ReturnMessages();
+
+ /**
+ * Tells the command to parse into keyword and detail(If needed).
+ *
+ * @param command full command of user input.
+ * @throws IndexOutOfBoundsException thrown when able to identify keyword but not the rest of the descriptions
+ * @throws UnknownSyntaxException thrown when syntax is unreadable
+ * @throws EmptyDescriptionException thrown after detecting description is empty
+ */
+ public CommandBase(String command) throws ArrayIndexOutOfBoundsException, UnknownSyntaxException, EmptyDescriptionException{
+ this.fullCommand = command;
+ this.keyword = "";
+ this.detail = "";
+ if(command.contains(CommandEnums.TODO.getName()) || command.contains(CommandEnums.DEADLINE.getName()) || command.contains(CommandEnums.EVENT.getName()) || command.contains(CommandEnums.VIEW.getName()) || command.contains(CommandEnums.FIND.getName())){
+ try {
+ String[] toWords = command.split(" ", 2);
+ this.keyword = toWords[0];
+ this.detail = toWords[1];
+ } catch(ArrayIndexOutOfBoundsException aio) {
+ if(command.contains(CommandEnums.TODO.getName()) || command.contains(CommandEnums.DEADLINE.getName()) || command.contains(CommandEnums.EVENT.getName())){
+ throw new EmptyDescriptionException(keyword);
+ } else {
+ throw new UnknownSyntaxException(command);
+ }
+ }
+ }
+ }
+
+ public CommandBase() {
+
+ }
+
+ /**
+ * Executes command.
+ *
+ * @param taskList user generate.
+ * @param ui show interactive information.
+ * @param storageTaskList info where to storage.
+ * @return if true, the program stops, otherwise it starts.
+ */
+ public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList){
+ return false;
+ }
+
+ /**
+ * Replies a done/add command.
+ *
+ * @param taskList gets the full task list.
+ * @throws EmptyTaskListException thrown if task list is empty.
+ * @throws UnknownSyntaxException thrown if syntax is unknown.
+ * @throws TaskNotFoundException thrown if task is not found.
+ */
+ public void reply(TaskList taskList) throws EmptyTaskListException, UnknownSyntaxException, TaskNotFoundException {
+ if(fullCommand.contains("done")){
+ assert fullCommand.contains("done"):"It should have confirmed a done command by this stage";
+ try {
+ String[] doneCommand = fullCommand.split(" ");
+ if(Integer.parseInt(doneCommand[1]) - 1 >= taskList.getListSize()){
+ throw new TaskNotFoundException("you only have "+taskList.getListSize()+" and you entered "+Integer.parseInt(doneCommand[1]));
+ }
+ if(taskList.getTask(Integer.parseInt(doneCommand[1]) - 1).isDone()){
+ returnMessage.taskAlreadyDoneFeedback();
+ } else{
+ taskList.getTask(Integer.parseInt(doneCommand[1]) - 1).setDone();
+ returnMessage.taskDoneFeedback();
+ System.out.println(" " + taskList.getTask(Integer.parseInt(doneCommand[1]) - 1).toString());
+ }
+ returnMessage.separator();
+ return;
+ } catch(NumberFormatException nf){
+ throw new TaskNotFoundException("task does not exist");
+ }
+ }
+ returnMessage.taskAddFeedback();
+ assert taskList.getListSize()>0:"There should at least have 1 task";
+ try {
+ System.out.println(" " + taskList.getLastTask().toString());
+ System.out.println(" Now you have " + taskList.getListSize() + " tasks in the list.");
+ returnMessage.separator();
+ } catch(ArrayIndexOutOfBoundsException a){
+ throw new EmptyTaskListException("empty task");
+ }
+ }
+}
diff --git a/src/main/java/duke/parser/CommandBye.java b/src/main/java/duke/parser/CommandBye.java
new file mode 100644
index 00000000..c087ef93
--- /dev/null
+++ b/src/main/java/duke/parser/CommandBye.java
@@ -0,0 +1,30 @@
+package duke.parser;
+
+import duke.storage.StorageTaskList;
+import duke.task.TaskList;
+import duke.ui.UI;
+
+public class CommandBye extends CommandBase {
+ /**
+ * Creates bye command constructor.
+ *
+ * @param command Full command.
+ */
+ public CommandBye(String command){
+ super(command);
+ }
+
+ /**
+ * Executes of bye command.
+ *
+ * @param taskList user generate.
+ * @param ui show interactive information.
+ * @param storageTaskList info where to storage.
+ * @return if true, the program stops, otherwise it starts.
+ */
+ @Override
+ public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) {
+ storageTaskList.save(taskList);
+ return true;
+ }
+}
diff --git a/src/main/java/duke/parser/CommandDeadline.java b/src/main/java/duke/parser/CommandDeadline.java
new file mode 100644
index 00000000..5683fe7a
--- /dev/null
+++ b/src/main/java/duke/parser/CommandDeadline.java
@@ -0,0 +1,71 @@
+package duke.parser;
+
+import duke.exception.TimeManagementException;
+import duke.exception.TimeParseException;
+import duke.exception.UnknownSyntaxException;
+import duke.parser.timeHelper.DateTimeParse;
+import duke.storage.StorageTaskList;
+import duke.task.Deadline;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.UI;
+
+import java.time.LocalDateTime;
+
+
+public class
+CommandDeadline extends CommandBase {
+
+ private DateTimeParse timeHelp = new DateTimeParse();
+
+ /**
+ * Creates deadline constructor.
+ *
+ * @param command full command.
+ */
+ public CommandDeadline(String command){
+ super(command);
+ }
+
+
+ /**
+ * Executes deadline command.
+ *
+ * @param taskList user generate.
+ * @param ui show interactive information.
+ * @param storageTaskList info where to storage.
+ * @return if true, the program stops, otherwise it starts.
+ * @throws TimeManagementException thrown when datetime not specified
+ * @throws TimeParseException thrown when datetime format is wrong
+ */
+ @Override
+ public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) throws TimeManagementException, TimeParseException{
+ boolean isSuccess = false;
+ try {
+ if (!CommandEnums.DEADLINE.getName().equals(super.keyword)){
+ throw new UnknownSyntaxException(super.keyword);
+ }
+ String[] deadlineCommand = super.detail.split("/by", 2);
+ //region time parse
+ String[] dateTimes = deadlineCommand[1].split(" ", 2);
+ LocalDateTime dateT = timeHelp.dateAndTimeParse(dateTimes[1]);
+ //endregion
+ Task task = new Deadline(deadlineCommand[0], dateT);
+ if(taskList.addTask(task)){
+ isSuccess = true;
+ assert taskList.getListSize()>0:"There should at least have 1 task";
+ }
+ } catch (IndexOutOfBoundsException e) {
+ throw new TimeManagementException();
+ } catch (TimeParseException e) {
+ throw new TimeParseException(e.getMessage());
+ }
+
+ if (isSuccess) {
+ reply(taskList);
+ }
+
+ return false;
+ }
+
+}
diff --git a/src/main/java/duke/parser/CommandDelete.java b/src/main/java/duke/parser/CommandDelete.java
new file mode 100644
index 00000000..98494092
--- /dev/null
+++ b/src/main/java/duke/parser/CommandDelete.java
@@ -0,0 +1,31 @@
+package duke.parser;
+
+import duke.storage.StorageTaskList;
+import duke.task.TaskList;
+import duke.ui.UI;
+
+public class CommandDelete extends CommandBase {
+
+ /**
+ * Creates delete command constructor.
+ *
+ * @param command full command.
+ */
+ public CommandDelete(String command) {
+ super(command);
+ }
+
+ /**
+ * Executes delete command.
+ *
+ * @param taskList user generate.
+ * @param ui show interactive information.
+ * @param storageTaskList info where to storage.
+ * @return if true, the program stops, otherwise it starts.
+ */
+ @Override
+ public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) {
+ taskList.deleteTask(Integer.parseInt(super.fullCommand.split(" ", 2)[1]));
+ return false;
+ }
+}
diff --git a/src/main/java/duke/parser/CommandDone.java b/src/main/java/duke/parser/CommandDone.java
new file mode 100644
index 00000000..f8076f71
--- /dev/null
+++ b/src/main/java/duke/parser/CommandDone.java
@@ -0,0 +1,30 @@
+package duke.parser;
+
+import duke.storage.StorageTaskList;
+import duke.task.TaskList;
+import duke.ui.UI;
+
+public class CommandDone extends CommandBase {
+ /**
+ * Creates done command constructor.
+ *
+ * @param command full command
+ */
+ public CommandDone(String command) {
+ super(command);
+ }
+
+ /**
+ * Executes done command.
+ *
+ * @param taskList user generate.
+ * @param ui show interactive information.
+ * @param storageTaskList info where to storage.
+ * @return if true, the program stops, otherwise it starts.
+ */
+ @Override
+ public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) {
+ reply(taskList);
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/parser/CommandEnums.java b/src/main/java/duke/parser/CommandEnums.java
new file mode 100644
index 00000000..a19facd0
--- /dev/null
+++ b/src/main/java/duke/parser/CommandEnums.java
@@ -0,0 +1,34 @@
+package duke.parser;
+
+public enum CommandEnums {
+ LIST("list"),
+ DONE("done"),
+ DELETE("delete"),
+ BYE("bye"),
+ SAVE("save"),
+ TODO("todo"),
+ EVENT("event"),
+ DEADLINE("deadline"),
+ FIND("find"),
+ VIEW("view")
+ ;
+
+ /**
+ * Creates Enum constructor
+ *
+ * @param name the keyword for the command
+ */
+ CommandEnums(String name) {
+ this.name = name;
+ }
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/duke/parser/CommandError.java b/src/main/java/duke/parser/CommandError.java
new file mode 100644
index 00000000..5887f947
--- /dev/null
+++ b/src/main/java/duke/parser/CommandError.java
@@ -0,0 +1,17 @@
+package duke.parser;
+
+import duke.exception.UnknownSyntaxException;
+
+public class CommandError extends CommandBase {
+
+ /**
+ * Creates error command constructor.
+ * Used when unknown syntax is detected.
+ *
+ * @param command full command
+ * @throws UnknownSyntaxException throws unknown syntax if unable to identify
+ */
+ public CommandError(String command) throws UnknownSyntaxException{
+ throw new UnknownSyntaxException(command);
+ }
+}
diff --git a/src/main/java/duke/parser/CommandEvent.java b/src/main/java/duke/parser/CommandEvent.java
new file mode 100644
index 00000000..a2caac8a
--- /dev/null
+++ b/src/main/java/duke/parser/CommandEvent.java
@@ -0,0 +1,72 @@
+package duke.parser;
+
+import duke.exception.TimeManagementException;
+import duke.exception.TimeParseException;
+import duke.exception.UnknownSyntaxException;
+import duke.parser.timeHelper.DateTimeParse;
+import duke.storage.StorageTaskList;
+import duke.task.Events;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.ui.UI;
+
+import java.time.LocalDate;
+
+public class CommandEvent extends CommandBase {
+
+ private DateTimeParse timeHelp = new DateTimeParse();
+
+ /**
+ * Creates event Command Constructor
+ *
+ */
+ public CommandEvent(String command) {
+ super(command);
+ }
+
+
+ /**
+ * Executes event command.
+ *
+ * @param taskList user generate.
+ * @param ui show interactive information.
+ * @param storageTaskList info where to storage.
+ * @return if true, the program stops, otherwise it starts.
+ * @throws TimeManagementException time management exception if no datetime is given
+ */
+ @Override
+ public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) throws TimeManagementException{
+ boolean isSuccess = false;
+ try {
+ if (!CommandEnums.EVENT.getName().equals(super.keyword)){
+ throw new UnknownSyntaxException(super.keyword);
+ }
+ String[] dt = super.detail.split("/at", 2);
+ String description = dt[0];
+ String dateTime = dt[1].substring(1);
+ LocalDate date = timeHelp.dateParse(dateTime);
+ String[] dateTimeInformation = dateTime.split(" ", 2);
+ String timeRange = dateTimeInformation[1];
+ String from = timeRange.split("-", 2)[0];
+ String to = timeRange.split("-", 2)[1];
+ Task task = new Events(description, date, timeHelp.timeParse(timeHelp.get24HrFormat(from)),timeHelp.timeParse(timeHelp.get24HrFormat(to)));
+ if(taskList.addTask(task)){
+ isSuccess = true;
+ assert taskList.getListSize()>0:"There should at least have 1 task";
+ }
+ } catch (IndexOutOfBoundsException e) {
+ throw new TimeManagementException();
+ }
+
+ if (isSuccess) {
+ reply(taskList);
+ }
+
+ return false;
+ }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/duke/parser/CommandFind.java b/src/main/java/duke/parser/CommandFind.java
new file mode 100644
index 00000000..9eaa84fc
--- /dev/null
+++ b/src/main/java/duke/parser/CommandFind.java
@@ -0,0 +1,34 @@
+package duke.parser;
+
+import duke.storage.StorageTaskList;
+import duke.task.TaskList;
+import duke.ui.UI;
+
+public class CommandFind extends CommandBase {
+ /**
+ * Creates find Command Constructor.
+ *
+ * @param command the full command.
+ */
+ public CommandFind(String command) {
+ super(command);
+ }
+
+ /**
+ * Executes done command.
+ *
+ * @param taskList the full task list for saving purpose.
+ * @param ui UI object.
+ * @param storageTaskList storage object.
+ * @return returns false as this command does not end the runtime
+ */
+ @Override
+ public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) {
+ try{
+ taskList.printFoundTaskList(super.detail);
+ } catch(Exception e){
+ System.out.println(e.getMessage());
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/duke/parser/CommandList.java b/src/main/java/duke/parser/CommandList.java
new file mode 100644
index 00000000..b0e7b452
--- /dev/null
+++ b/src/main/java/duke/parser/CommandList.java
@@ -0,0 +1,29 @@
+package duke.parser;
+
+import duke.storage.StorageTaskList;
+import duke.task.TaskList;
+import duke.ui.UI;
+
+public class CommandList extends CommandBase {
+ /**
+ * Creates list Command Constructor
+ *
+ */
+ public CommandList(String command) {
+ super(command);
+ }
+
+ /**
+ * Executes list command
+ *
+ * @param taskList the full task list for saving purpose
+ * @param ui UI object
+ * @param storageTaskList storage object
+ *
+ */
+ @Override
+ public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) {
+ taskList.printTaskList();
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/parser/CommandParser.java b/src/main/java/duke/parser/CommandParser.java
new file mode 100644
index 00000000..ae4bc189
--- /dev/null
+++ b/src/main/java/duke/parser/CommandParser.java
@@ -0,0 +1,37 @@
+package duke.parser;
+
+public class CommandParser {
+
+ /**
+ * Generates different CMD objects according to the input parameters
+ * @see CommandBase
+ */
+ public static Command parse(String fullCommand) {
+ Command command = new Command();
+ if (fullCommand.contains(CommandEnums.DONE.getName())) {
+ command.setCmd(new CommandDone(fullCommand));
+ } else if (fullCommand.contains(CommandEnums.LIST.getName())) {
+ command.setCmd(new CommandList(fullCommand));
+ } else if (fullCommand.contains(CommandEnums.DELETE.getName())) {
+ command.setCmd(new CommandDelete(fullCommand));
+ } else if (fullCommand.contains(CommandEnums.BYE.getName())) {
+ command.setCmd(new CommandBye(fullCommand));
+ } else if (fullCommand.contains(CommandEnums.SAVE.getName())) {
+ command.setCmd(new CommandSave(fullCommand));
+ } else if (fullCommand.contains(CommandEnums.TODO.getName())) {
+ command.setCmd(new CommandTodo(fullCommand));
+ } else if (fullCommand.contains(CommandEnums.EVENT.getName())) {
+ command.setCmd(new CommandEvent(fullCommand));
+ } else if (fullCommand.contains(CommandEnums.DEADLINE.getName())) {
+ command.setCmd(new CommandDeadline(fullCommand));
+ } else if(fullCommand.contains(CommandEnums.FIND.getName())) {
+ command.setCmd(new CommandFind(fullCommand));
+ } else if(fullCommand.contains(CommandEnums.VIEW.getName())) {
+ command.setCmd(new CommandView(fullCommand));
+ } else {
+ command.setCmd(new CommandError(fullCommand));
+ }
+
+ return command;
+ }
+}
diff --git a/src/main/java/duke/parser/CommandSave.java b/src/main/java/duke/parser/CommandSave.java
new file mode 100644
index 00000000..cd3e651a
--- /dev/null
+++ b/src/main/java/duke/parser/CommandSave.java
@@ -0,0 +1,29 @@
+package duke.parser;
+
+import duke.storage.StorageTaskList;
+import duke.task.TaskList;
+import duke.ui.UI;
+
+public class CommandSave extends CommandBase {
+ /**
+ * Creates save Command Constructor
+ *
+ */
+ public CommandSave(String command){
+ super(command);
+ }
+
+ /**
+ * Executes save command
+ *
+ * @param taskList the full task list for saving purpose
+ * @param ui UI object
+ * @param storageTaskList storage object
+ *
+ */
+ @Override
+ public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) {
+ storageTaskList.save(taskList);
+ return false;
+ }
+}
diff --git a/src/main/java/duke/parser/CommandTodo.java b/src/main/java/duke/parser/CommandTodo.java
new file mode 100644
index 00000000..2ee1056e
--- /dev/null
+++ b/src/main/java/duke/parser/CommandTodo.java
@@ -0,0 +1,61 @@
+package duke.parser;
+
+import duke.exception.UnknownSyntaxException;
+import duke.storage.StorageTaskList;
+import duke.storage.StorageFixedDurationReference;
+import duke.task.Task;
+import duke.task.TaskList;
+import duke.task.ToDos;
+import duke.task.FixedDurationTaskList;
+import duke.ui.UI;
+
+public class CommandTodo extends CommandBase {
+ private static StorageFixedDurationReference loadFixedDurationRecord;
+ private static FixedDurationTaskList fixedDurationTaskList;
+ /**
+ * Creates TO DO Command
+ *
+ */
+ public CommandTodo(String command) {
+ super(command);
+ }
+
+ /**
+ * Executes TO DO command
+ *
+ * @param taskList the full task list for saving purpose
+ * @param ui UI object
+ * @param storageTaskList storage object
+ *
+ */
+ @Override
+ public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) {
+ boolean isSuccess = false;
+ try {
+ if (!CommandEnums.TODO.getName().equals(super.keyword)){
+ throw new UnknownSyntaxException(super.keyword);
+ }
+ loadFixedDurationRecord = new StorageFixedDurationReference();
+ fixedDurationTaskList = new FixedDurationTaskList(loadFixedDurationRecord.load());
+ int duration = fixedDurationTaskList.findRecord(super.detail);
+ Task task;
+ if (duration > 0) {
+ task = new ToDos(super.detail, duration);
+ } else{
+ task = new ToDos(super.detail);
+ }
+ if(taskList.addTask(task)){
+ isSuccess = true;
+ assert taskList.getListSize()>0:"There should at least have 1 task";
+ }
+ } catch (IndexOutOfBoundsException e) {
+ throw new UnknownSyntaxException(super.keyword);
+ }
+
+ if (isSuccess) {
+ reply(taskList);
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/duke/parser/CommandView.java b/src/main/java/duke/parser/CommandView.java
new file mode 100644
index 00000000..19ea3d7a
--- /dev/null
+++ b/src/main/java/duke/parser/CommandView.java
@@ -0,0 +1,48 @@
+package duke.parser;
+
+import duke.exception.EmptyTaskListException;
+import duke.exception.UnknownSyntaxException;
+import duke.parser.timeHelper.DateTimeParse;
+import duke.storage.StorageTaskList;
+import duke.task.TaskList;
+import duke.ui.UI;
+
+
+import java.time.LocalDate;
+
+public class CommandView extends CommandBase{
+
+ private DateTimeParse timeHelp = new DateTimeParse();
+
+ /**
+ * Creates view schedule command constructor.
+ *
+ * @param command the full command.
+ */
+ public CommandView(String command){super(command);}
+
+
+ /**
+ * Executes view schedule command
+ *
+ * @param taskList the full task list for sorting purpose.
+ * @param ui show interactive information.
+ * @param storageTaskList storage object.
+ * @return returns false as this command does not end the runtime
+ * @throws EmptyTaskListException when task list is empty no schedule to sort
+ */
+ @Override
+ public boolean execute(TaskList taskList, UI ui, StorageTaskList storageTaskList) throws EmptyTaskListException{
+ try{
+ if (!CommandEnums.VIEW.getName().equals(super.keyword)){
+ throw new UnknownSyntaxException(super.keyword);
+ }
+ LocalDate scheduleDate = timeHelp.dateParse(super.detail);
+ taskList.printAsSchedule(scheduleDate);
+ } catch(EmptyTaskListException e){
+ throw new EmptyTaskListException("Empty");
+ }
+ return false;
+ }
+
+}
diff --git a/src/main/java/duke/parser/timeHelper/DateTimeParse.java b/src/main/java/duke/parser/timeHelper/DateTimeParse.java
new file mode 100644
index 00000000..35dae3d2
--- /dev/null
+++ b/src/main/java/duke/parser/timeHelper/DateTimeParse.java
@@ -0,0 +1,112 @@
+package duke.parser.timeHelper;
+
+import duke.exception.TimeParseException;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+public class DateTimeParse {
+
+ static final int dateLength = 3;
+
+ /**
+ * Returns parsed time in format {DD-MM-YYYY}.
+ *
+ * @param str - the string of datetime.
+ * @return - Date in its correct format.
+ * @throws TimeParseException thrown when time format is wrong
+ */
+ public LocalDate dateParse(String str) throws TimeParseException{
+ if (!str.contains("/")){
+ throw new TimeParseException("Date Format YYYY/MM/DD");
+ }
+ // gen yyyy,mm,dd ssss
+ String[] date = str.split("/", 3);
+ if (date.length < dateLength){
+ throw new TimeParseException("Date Format YYYY/MM/DD");
+ }
+
+ // gen time
+ String[] time = date[2].split(" ", 2);
+ int year = Integer.parseInt(date[0]);
+ int month = Integer.parseInt(date[1]);
+ int dayOfMth = Integer.parseInt(time[0]);
+
+ LocalDate localDate;
+ try {
+ localDate = LocalDate.of(year,month,dayOfMth);
+ } catch (DateTimeException e) {
+ throw new TimeParseException(e.getMessage());
+ }
+
+ return localDate;
+ }
+
+
+ /**
+ * Returns parsed time as format {DD-MM-YYYY}.
+ *
+ * @param str - the string of datetime.
+ * @return - Date in its correct format.
+ * @throws TimeParseException thrown when date format is wrong
+ */
+ public LocalDateTime dateAndTimeParse(String str) throws TimeParseException{
+ if (!str.contains("/")){
+ throw new TimeParseException("Date Format YYYY/MM/DD");
+ }
+ // gen yyyy,mm,dd ssss
+ String[] date = str.split("/", 3);
+ if (date.length < dateLength){
+ throw new TimeParseException("Date Format YYYY/MM/DD");
+ }
+
+ // gen time
+ String[] time = date[2].split(" ", 2);
+ int year = Integer.parseInt(date[0]);
+ int month = Integer.parseInt(date[1]);
+ int dayOfMth = Integer.parseInt(time[0]);
+ int hour = get24HrFormat(time[1]);
+
+ LocalDateTime localDateTime;
+ try {
+ localDateTime = LocalDateTime.of(year,month,dayOfMth,hour,0,0,0);
+ } catch (DateTimeException e) {
+ throw new TimeParseException(e.getMessage());
+ }
+
+ return localDateTime;
+ }
+
+ /**
+ * Transforms time to 24hour format.
+ *
+ * @param t string such as [1AM] [10PM].
+ * @return integer time such as 1, 22.
+ */
+ public int get24HrFormat(String t){
+ int timeInterval = 12;
+ int timeValue;
+ if(t.toUpperCase().contains("AM")){
+ timeValue = Integer.parseInt(t.replace("AM", "").stripTrailing());
+ } else if(t.toUpperCase().contains("PM")){
+ timeValue = Integer.parseInt(t.replace("PM", "").stripTrailing());
+ timeValue += timeInterval;
+ }else{
+ throw new TimeParseException("Time Format 1AM/1PM");
+ }
+
+ return timeValue;
+ }
+
+ /**
+ * Returns time in LocalTime format.
+ *
+ * @param t the integer time [1] [22]
+ * @return time in LocalTime [01:00:00] [22:00:00]
+ */
+ public LocalTime timeParse(int t){
+ return LocalTime.of(t,0,0);
+ }
+}
diff --git a/src/main/java/duke/storage/StorageFixedDurationReference.java b/src/main/java/duke/storage/StorageFixedDurationReference.java
new file mode 100644
index 00000000..c8069bd3
--- /dev/null
+++ b/src/main/java/duke/storage/StorageFixedDurationReference.java
@@ -0,0 +1,88 @@
+package duke.storage;
+
+import duke.exception.DukeException;
+import duke.task.FixedDurationTask;
+import duke.task.FixedDurationTaskList;
+import duke.ui.ReturnMessages;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+public class StorageFixedDurationReference {
+
+ protected boolean isExist;
+ protected String fileName;
+ protected File file;
+ private static ReturnMessages returnMessage = new ReturnMessages();
+
+
+ /** Creates Storage_Unscheduled object. */
+ public StorageFixedDurationReference() {
+ this.file = new File(System.getProperty("user.dir") + "/fixedDurationTask.txt"); // create a File for the given file path
+ this.fileName = file.getName();
+ }
+
+ /**
+ * loads info from hard disk.
+ *
+ * @return task list from hard disk.
+ */
+ public FixedDurationTaskList load() throws DukeException {
+ FixedDurationTaskList unscheduledRecords = new FixedDurationTaskList();
+ assert file.exists():"The file should exist by now";
+ if (file.exists()) {
+ try (BufferedReader br = new BufferedReader(new FileReader(file))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ // process the line
+ unscheduledRecords.addTask(decodeStrToFixedDurationTask(line));
+ }
+ } catch (IOException e) {
+ //fail to parse
+ throw new DukeException("file parse fail");
+ }
+ } else {
+ try {
+ createFile();
+ } catch (IOException e) {
+ //fail to create file
+ throw new DukeException("create file fail");
+ }
+ }
+ return unscheduledRecords;
+ }
+
+
+ /**
+ * Creates File if not exist.
+ *
+ * @exception IOException throws a IO Exception if file exists.
+ *
+ */
+ public void createFile() throws IOException {
+ try {
+ boolean create = file.createNewFile();
+ } catch (IOException ioe) {
+ this.isExist = true;
+ System.out.println("File exists");
+ }
+ this.isExist = true;
+ returnMessage.createSuccessFeedback(file.getName());
+ }
+
+
+ /**
+ * Decodes the str to unscheduled task records with description and duration.
+ *
+ * @param str the full string per line.
+ * @return created task object.
+ */
+ public FixedDurationTask decodeStrToFixedDurationTask(String str) {
+ String[] line = str.split(" \\| ");
+ FixedDurationTask unscheduledRecord;
+ unscheduledRecord = new FixedDurationTask(line[0], Integer.parseInt(line[1]));
+ return unscheduledRecord;
+ }
+}
diff --git a/src/main/java/duke/storage/StorageTaskList.java b/src/main/java/duke/storage/StorageTaskList.java
new file mode 100644
index 00000000..c16aacd8
--- /dev/null
+++ b/src/main/java/duke/storage/StorageTaskList.java
@@ -0,0 +1,162 @@
+package duke.storage;
+
+import duke.exception.DukeException;
+import duke.task.FixedDurationTaskList;
+import duke.task.TaskList;
+import duke.task.Task;
+import duke.task.ToDos;
+import duke.task.Events;
+import duke.task.Deadline;
+import duke.ui.ReturnMessages;
+
+import java.io.File;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+public class StorageTaskList {
+ protected boolean isExist;
+ protected String fileName;
+ protected File file;
+ private static ReturnMessages returnMessage = new ReturnMessages();
+ private static StorageFixedDurationReference loadFixedDurationRecord;
+ private static FixedDurationTaskList fixedDurationTaskList;
+
+ /**
+ * Checks current file existence status.
+ *
+ * @return true or false.
+ */
+ public boolean existence(){
+ return isExist;
+ }
+
+ /**
+ * Creates Storage object.
+ *
+ * @param fileName the file saving the information of task list
+ *
+ */
+ public StorageTaskList(String fileName) {
+ this.fileName = fileName;
+ this.file = new File(System.getProperty("user.dir") + "/"+fileName); // create a File for the given file path
+ }
+
+ /**
+ * Loads info from hard disk.
+ *
+ * @return task list from hard disk.
+ */
+ public TaskList load() throws DukeException {
+ TaskList taskList = new TaskList();
+ assert file.exists():"The file should exist by now";
+ if (file.exists()) {
+ returnMessage.loadingFileFeedback();
+ try (BufferedReader br = new BufferedReader(new FileReader(file))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ // process the line
+ taskList.addTask(decodeStrToTask(line));
+ }
+ } catch (IOException e) {
+ //fail to parse
+ throw new DukeException("file parse fail");
+ }
+ } else {
+ try {
+ createFile();
+ } catch (IOException e) {
+ //fail to create file
+ throw new DukeException("create file fail");
+ }
+ }
+ returnMessage.loadSuccessFeedback();
+ return taskList;
+ }
+
+ /**
+ * Creates File if not exist.
+ *
+ * @exception IOException throws a IO Exception if file exists.
+ *
+ */
+ public void createFile() throws IOException {
+ try {
+ boolean create = file.createNewFile();
+ } catch (IOException ioe) {
+ this.isExist = true;
+ System.out.println("File exists");
+ }
+ this.isExist = true;
+ returnMessage.createSuccessFeedback(file.getName());
+ }
+
+ /**
+ * Saves task list to hard disk.
+ *
+ * @param taskList - data to save.
+ */
+ public void save(TaskList taskList) {
+ assert this.isExist:true;
+ FileWriter myWriter;
+ try {
+ myWriter = new FileWriter(file.getAbsoluteFile(), false);
+ FileWriter finalMyWriter = myWriter;
+ taskList.getTaskList().forEach((task) -> {
+ try {
+ finalMyWriter.write(task.encodeTask() + "\n");
+ } catch (IOException e) {
+ //
+ throw new DukeException(e.getMessage());
+ }
+ });
+ myWriter.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new DukeException(e.getMessage());
+ }
+ returnMessage.saveSuccessFeedback();
+ }
+
+ /**
+ * Decodes the str to its individual task format.
+ *
+ * @param str the full string per line.
+ * @return created task object.
+ */
+ public Task decodeStrToTask(String str) {
+ String[] lines = str.split(" \\| ");
+ Task task = null;
+ switch (lines[0]) {
+ case "T":
+ loadFixedDurationRecord = new StorageFixedDurationReference();
+ fixedDurationTaskList = new FixedDurationTaskList(loadFixedDurationRecord.load());
+ int duration = fixedDurationTaskList.findRecord(lines[2]);
+ if (duration > 0) {
+ task = new ToDos(lines[2], duration);
+ } else{
+ task = new ToDos(lines[2]);
+ }
+ break;
+ case "D":
+ LocalDate date = LocalDate.parse(lines[3]);
+ LocalTime time = LocalTime.parse(lines[4]);
+ task = new Deadline(lines[2], LocalDateTime.of(date,time));
+ break;
+ case "E":
+ task = new Events(lines[2], LocalDate.parse(lines[3]), LocalTime.parse(lines[4]), LocalTime.parse(lines[5]));
+ break;
+ }
+ if (Task.DONE.equals(lines[1])) {
+ if (task != null) {
+ task.setDone();
+ }
+ }
+ return task;
+ }
+}
diff --git a/src/main/java/duke/storage/duke.txt b/src/main/java/duke/storage/duke.txt
new file mode 100644
index 00000000..8a409a9d
--- /dev/null
+++ b/src/main/java/duke/storage/duke.txt
@@ -0,0 +1,15 @@
+T | 0 | read book | 1
+D | 0 | return book | 2021-10-24 | 22:00
+D | 0 | return book | 2021-10-24 | 22:00
+E | 0 | project meeting | 2021-10-24 | 14:00 | 16:00
+D | 0 | return book | 2021-11-05 | 22:00
+E | 0 | project meeting | 2022-07-30 | 14:00 | 16:00
+E | 0 | new year | 2022-02-02 | 00:00 | 12:00
+D | 0 | return book | 2020-10-29 | 03:00
+D | 0 | return book | 2021-12-25 | 16:00
+T | 0 | eat | 0
+E | 0 | Finish Homework | 2021-12-25 | 16:00 | 18:00
+E | 0 | new year | 2022-02-02 | 00:00 | 12:00
+T | 1 | read book | 1
+T | 1 | study book | 0
+E | 0 | meeting | 2021-12-25 | 00:00 | 15:00
diff --git a/src/main/java/duke/storage/fixedDurationTask.txt b/src/main/java/duke/storage/fixedDurationTask.txt
new file mode 100644
index 00000000..71285f2f
--- /dev/null
+++ b/src/main/java/duke/storage/fixedDurationTask.txt
@@ -0,0 +1,4 @@
+read sales report | 2
+read book | 1
+do homework | 4
+submit claims | 1
diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java
new file mode 100644
index 00000000..83485f46
--- /dev/null
+++ b/src/main/java/duke/task/Deadline.java
@@ -0,0 +1,43 @@
+package duke.task;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+public class Deadline extends Task {
+
+ protected LocalDateTime by;
+ protected LocalDate date;
+
+ /**
+ * Creates Deadline task.
+ *
+ * @param description - the task for the deadline.
+ * @param by - the deadline's datetime.
+ */
+ public Deadline(String description, LocalDateTime by) {
+ super(description, "deadline", by.toLocalDate(), by.toLocalTime());
+ this.by = by;
+ this.date = by.toLocalDate();
+ }
+
+ /** Prints task by its own style. */
+ @Override
+ public String toString() {
+ return "[D]" + super.toString() + "(by: " + by.toLocalDate().toString() + "["+ by.toLocalDate().getDayOfWeek() +"] "+ by.toLocalTime().toString()+")";
+ }
+
+ /** Encodes function for storage within text file. */
+ @Override
+ public String encodeTask() {
+ return "D" + super.encodeTask() + " | " + by.toLocalDate().toString() + " | " + by.toLocalTime().toString();
+ }
+
+ public LocalDate getDate(){
+ return this.date;
+ }
+
+ public LocalTime getTime(){
+ return this.by.toLocalTime();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/task/Events.java b/src/main/java/duke/task/Events.java
new file mode 100644
index 00000000..31a52c42
--- /dev/null
+++ b/src/main/java/duke/task/Events.java
@@ -0,0 +1,43 @@
+package duke.task;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+
+public class Events extends Task {
+ protected LocalDate date;
+ protected LocalTime start;
+ protected LocalTime end;
+
+ /**
+ * Creates Event task.
+ *
+ * @param description - Description of Event.
+ * @param start - Date/Time event is held.
+ * @param end - Date/Time event ends.
+ * @param date - the date event is held.
+ */
+ public Events(String description, LocalDate date, LocalTime start, LocalTime end) {
+ super(description, "event", date, start);
+ this.date = date;
+ this.start = start;
+ this.end = end;
+ }
+ /** Prints task by its own style. */
+ @Override
+ public String toString() {
+ return "[E]" + super.toString() + " (on:" + date.toString() + "[" + date.getDayOfWeek().toString() + "] from:" + start.toString() +" to:" + end.toString() +")";
+ }
+ /** Encodes function for storage within text file */
+ @Override
+ public String encodeTask() {
+ return "E" + super.encodeTask() + " | " + date.toString() + " | " + start.toString() + " | " + end.toString();
+ }
+
+ public LocalDate getDate(){
+ return this.date;
+ }
+
+ public LocalTime getTime(){
+ return this.start;
+ }
+}
diff --git a/src/main/java/duke/task/FixedDurationTask.java b/src/main/java/duke/task/FixedDurationTask.java
new file mode 100644
index 00000000..7ced5f7e
--- /dev/null
+++ b/src/main/java/duke/task/FixedDurationTask.java
@@ -0,0 +1,26 @@
+package duke.task;
+
+public class FixedDurationTask {
+ private String description;
+ private int duration;
+
+ /**
+ * Creates FixedDuration Task.
+ *
+ * @param desc its fixed description.
+ * @param duration its fixed duration.
+ */
+ public FixedDurationTask(String desc, int duration){
+ this.description = desc;
+ this.duration = duration;
+ }
+
+ public String getDesc(){
+ return this.description;
+ }
+
+ public int getDuration(){
+ return this.duration;
+ }
+
+}
diff --git a/src/main/java/duke/task/FixedDurationTaskList.java b/src/main/java/duke/task/FixedDurationTaskList.java
new file mode 100644
index 00000000..a18f8bc1
--- /dev/null
+++ b/src/main/java/duke/task/FixedDurationTaskList.java
@@ -0,0 +1,60 @@
+package duke.task;
+
+import java.util.ArrayList;
+
+public class FixedDurationTaskList {
+
+ protected int listSize;
+ private ArrayList unscheduleTaskList;
+
+
+ /** Creates Fixed Duration Task List */
+ public FixedDurationTaskList() {
+ unscheduleTaskList = new ArrayList<>();
+ }
+
+ /**
+ * Creates Fixed Duration Task List with records within.
+ *
+ * @param load - the task list that already contained task.
+ */
+ public FixedDurationTaskList(FixedDurationTaskList load) {
+ this.listSize = load.listSize;
+ this.unscheduleTaskList = load.unscheduleTaskList;
+ }
+
+ /**
+ * Gets the list size.
+ *
+ * @return - list size in integer.
+ */
+ public int getListSize(){
+ return this.listSize;
+ }
+
+
+ /**
+ * Adds an fixed duration task record to list.
+ *
+ * @param task - the full task information.
+ */
+ public void addTask(FixedDurationTask task){
+ this.unscheduleTaskList.add(task);
+ this.listSize++;
+ }
+
+ /**
+ * Finds if a fixed duration task exists in record.
+ *
+ * @param description find by description.
+ * @return the task ID if exists.
+ */
+ public int findRecord(String description){
+ for(FixedDurationTask ut : unscheduleTaskList){
+ if(description.equals(ut.getDesc())){
+ return ut.getDuration();
+ }
+ }
+ return 0;
+ }
+}
diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java
new file mode 100644
index 00000000..295b69f2
--- /dev/null
+++ b/src/main/java/duke/task/Task.java
@@ -0,0 +1,95 @@
+package duke.task;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+
+public class Task {
+ protected String description;
+ protected boolean isDone;
+ protected String taskType;
+ protected LocalDate date;
+ protected LocalTime time;
+
+ public static final String DONE = "1";
+ public static final String UNDONE = "0";
+
+ /**
+ * Creates Task base.
+ *
+ * @param description - the description string.
+ */
+ public Task(String description, String taskType, LocalDate date, LocalTime time) {
+ this.description = description;
+ this.isDone = false;
+ this.taskType = taskType;
+ this.date = date;
+ this.time = time;
+ }
+
+ /**
+ * Returns task's current status.
+ *
+ * @return - done or not done.
+ */
+ public String getStatusIcon() {
+ return (isDone ? "X" : " "); // mark done task with X
+ }
+
+ /**
+ * Returns task's current status for code usage.
+ *
+ * @return - 0 or 1.
+ */
+ public String getStatusCode() {
+ return (isDone ? DONE : UNDONE); // mark done task with 1
+ }
+
+ /**
+ * Returns the full description of each task.
+ *
+ * @return - returns task description.
+ */
+ public String getTaskInfo(){
+ return description;
+ }
+
+ public String getTaskType(){
+ return taskType;
+ }
+
+ /** Gets the task done condition. */
+ public boolean isDone(){
+ return isDone;
+ }
+
+ /** Sets the task to Done. */
+ public void setDone(){
+ isDone = true;
+ }
+
+ /**
+ * Prints task on its own syntax.
+ *
+ * @return tasks [] TASK.
+ */
+ public String toString() {
+ return "["+getStatusIcon()+"] " + description;
+ }
+
+ /**
+ * Encodes task for storage.
+ *
+ * @return | X | TASK.
+ */
+ public String encodeTask() {
+ return " | " + getStatusCode() + " | " + description;
+ }
+
+ public LocalDate getDate(){
+ return this.date;
+ }
+
+ public LocalTime getTime(){
+ return this.time;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/task/TaskEnums.java b/src/main/java/duke/task/TaskEnums.java
new file mode 100644
index 00000000..d4ab162f
--- /dev/null
+++ b/src/main/java/duke/task/TaskEnums.java
@@ -0,0 +1,8 @@
+package duke.task;
+
+/** Enumerate for Task */
+public enum TaskEnums {
+ TODO,
+ DEADLINE,
+ EVENT,
+}
diff --git a/src/main/java/duke/task/TaskList.java b/src/main/java/duke/task/TaskList.java
new file mode 100644
index 00000000..bc2a12ae
--- /dev/null
+++ b/src/main/java/duke/task/TaskList.java
@@ -0,0 +1,158 @@
+package duke.task;
+
+import duke.exception.EmptyTaskListException;
+import duke.exception.TaskNotFoundException;
+import duke.ui.ReturnMessages;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Comparator;
+
+public class TaskList {
+ protected int listSize;
+ private ArrayList taskList;
+ private static ReturnMessages printer = new ReturnMessages();
+
+
+ /** Creates task list. */
+ public TaskList() {taskList = new ArrayList<>();}
+
+ /**
+ * Creates Task list with tasks within.
+ *
+ * @param load - the task list that already contained task.
+ */
+ public TaskList(TaskList load) {
+ this.listSize = load.listSize;
+ this.taskList = load.taskList;
+ }
+
+ /**
+ * Deletes a specific task uniquely identified via taskID.
+ *
+ * @param taskID - the unique identifier for each task.
+ * @throws TaskNotFoundException - when a task is not found.
+ * @throws EmptyTaskListException - when the task list is empty.
+ */
+ public void deleteTask(int taskID) throws TaskNotFoundException, EmptyTaskListException {
+ int taskPosition = taskID -1;
+ if(taskPosition > this.listSize || taskPosition < 0){
+ throw new TaskNotFoundException("task not found");
+ }
+ System.out.println(" Noted. I've removed this task: " );
+ System.out.println(" " + taskList.get(taskPosition).toString());
+ this.taskList.remove(taskPosition);
+ this.listSize--;
+ if(this.listSize == 0){
+ throw new EmptyTaskListException("empty task");
+ }
+ System.out.println(" Now you have " + this.listSize + " tasks in the list.");
+ printer.separator();
+ }
+
+ /**
+ * Adds a task to task list.
+ *
+ * @param task - the full task information.
+ */
+ public boolean addTask(Task task){
+ if(this.taskList.add(task)){
+ this.listSize++;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Gets a task via its task ID.
+ *
+ * @param ID - the unique identifier for a task.
+ * @return - returns the task.
+ */
+ public Task getTask(int ID){
+ return taskList.get(ID);
+ }
+
+ /**
+ * Gets the last task added.
+ *
+ * @return - return the task.
+ */
+ public Task getLastTask(){
+ return taskList.get(listSize-1);
+ }
+
+ /**
+ * Gets the list size.
+ *
+ * @return - list size in integer.
+ */
+ public int getListSize(){
+ return this.listSize;
+ }
+
+
+
+ /**
+ * Prints the tasks within the task list.
+ *
+ * @throws EmptyTaskListException - thrown if task list is empty.
+ */
+ public void printTaskList() throws EmptyTaskListException {
+ if(this.listSize == 0){
+ throw new EmptyTaskListException("empty task");
+ }
+ printer.printFullTaskList(taskList);
+ }
+
+ /**
+ * Getter for getting the task list.
+ *
+ * @return - returns entire task list.
+ */
+ public ArrayList getTaskList() {
+ return taskList;
+ }
+
+
+ /**
+ * Finds tasks containing specific keyword.
+ *
+ * @param keyword - the keyword to find.
+ * @throws EmptyTaskListException - thrown if task list is empty.
+ */
+ public void printFoundTaskList(String keyword) throws EmptyTaskListException {
+
+ if(this.listSize == 0){
+ throw new EmptyTaskListException("empty task");
+ }
+ printer.taskFoundFeedback(keyword, taskList);
+ }
+
+ /**
+ * prints schedule order by date
+ *
+ * @param dateToPrint the date that the schedule is needed
+ * @throws EmptyTaskListException if task list is empty, throws exception on empty task list
+ */
+ public void printAsSchedule(LocalDate dateToPrint) throws EmptyTaskListException{
+ if(this.listSize == 0){
+ throw new EmptyTaskListException("There's nothing in task list yet.");
+ }
+ ArrayList tempTaskList = new ArrayList<>();
+ for(Task t : taskList){
+ if(!t.getTaskType().equals("todo") && t.getDate().equals(dateToPrint)){
+ tempTaskList.add(t);
+ }
+ }
+ sortByTime(tempTaskList);
+ printer.taskSchedulingFeedback(dateToPrint, tempTaskList);
+ }
+
+ // Comparison done using compareTo function
+ protected static void sortByTime(ArrayList list)
+ {
+ list.sort(Comparator.comparing(Task::getTime));
+ }
+
+}
diff --git a/src/main/java/duke/task/ToDos.java b/src/main/java/duke/task/ToDos.java
new file mode 100644
index 00000000..64484a92
--- /dev/null
+++ b/src/main/java/duke/task/ToDos.java
@@ -0,0 +1,47 @@
+package duke.task;
+
+public class ToDos extends Task {
+ protected int duration;
+
+ /**
+ * Creates To Do task
+ *
+ * @param description - Description of To Do task.
+ */
+ public ToDos(String description) {
+ this(description,0);
+
+ }
+ /**
+ * Creates To Do task.
+ *
+ * @param description - Description of To Do task.
+ * @param duration - unscheduled fixed duration.
+ */
+ public ToDos(String description, int duration) {
+ super(description, "todo", null, null);
+ this.duration = duration;
+ }
+ public int getDuration(){
+ return this.duration;
+ }
+
+ public void setDuration(int duration){
+ this.duration = duration;
+ }
+
+ /** Prints task by its own style. */
+ @Override
+ public String toString() {
+ if(this.duration>0){
+ return "[T]" + super.toString()+ " (requires: " + duration + " Hour)";
+ }
+ return "[T]" + super.toString();
+ }
+
+ /** Encodes function for storage within text file. */
+ @Override
+ public String encodeTask() {
+ return "T" + super.encodeTask() + " | " + duration;
+ }
+}
diff --git a/src/main/java/duke/ui/ReturnMessages.java b/src/main/java/duke/ui/ReturnMessages.java
new file mode 100644
index 00000000..32d76266
--- /dev/null
+++ b/src/main/java/duke/ui/ReturnMessages.java
@@ -0,0 +1,227 @@
+package duke.ui;
+
+import duke.exception.TaskNotFoundException;
+import duke.task.Task;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+
+
+/** Handles message output. */
+public class ReturnMessages {
+ public void separator(){
+ System.out.println(" ____________________________________________________________");
+ }
+
+ /** Feedbacks when marking a task done. */
+ public void taskDoneFeedback(){
+ separator();
+ System.out.println(" Nice! I've marked this task as done:");
+ }
+
+ /** Feedbacks when a task is already done. */
+ public void taskAlreadyDoneFeedback(){
+ separator();
+ System.out.println(" This task is already done.");
+ }
+
+
+ /** Feedbacks when adding a task. */
+ public void taskAddFeedback(){
+ separator();
+ System.out.println(" Got it. I've added this task:");
+ }
+
+ /** Feedbacks on program startup. */
+ public void welcomeFeedback(){
+ String logo = " ____ _ \n"
+ + "| _ \\ _ _| | _____ \n"
+ + "| | | | | | | |/ / _ \\\n"
+ + "| |_| | |_| | < __/\n"
+ + "|____/ \\__,_|_|\\_\\___|\n";
+ System.out.println("Hello from\n" + logo);
+ separator();
+ System.out.println(" Hello! I'm Duke");
+ System.out.println(" Here are my functionality....");
+ System.out.println(" Check Existing Tasks: list");
+ System.out.println(" Mark a Task done: done {taskID}");
+ System.out.println(" Delete a Task: delete {taskID}");
+ System.out.println(" Find a Task: find {keyword}");
+ System.out.println(" View Schedule: view {date by YYYY/MM/DD}");
+ System.out.println(" Save Current State: save");
+ System.out.println(" Add a Todo Task: todo {action}");
+ System.out.println(" Add a Event Task: event xxxx /at {date by YYYY/MM/DD} {startTime}AM/PM-{endTime}AM/PM");
+ System.out.println(" Add a Deadline Task: deadline XXXX /by {date by YYYY/MM/DD} {Time}AM/PM");
+ System.out.println(" End the program: bye");
+ separator();
+ }
+
+ /** Feedbacks on program exit. */
+ public void exitFeedback(){
+ separator();
+ System.out.println(" Bye. Hope to see you again soon!");
+ separator();
+ }
+
+ /** Feedbacks when loading file. */
+ public void loadingFileFeedback(){
+ separator();
+ System.out.println(" Loading File...");
+ separator();
+ }
+
+ /** Feedbacks on file load success. */
+ public void loadSuccessFeedback(){
+ separator();
+ System.out.println(" File Loaded Successfully, use command 'list' to view...");
+ separator();
+ }
+
+ /** Feedbacks on file save. */
+ public void saveSuccessFeedback(){
+ separator();
+ System.out.println(" Successfully wrote to the file.");
+ separator();
+ }
+
+ /** Feedbacks on file create. */
+ public void createSuccessFeedback(String name){
+ separator();
+ System.out.println("File created: " + name);
+ separator();
+ }
+
+ /**
+ * Returns full task list with numbering.
+ *
+ * @param list the full task list.
+ */
+ public void printFullTaskList(ArrayList list){
+ separator();
+ int numbering = 1;
+ System.out.println(" Here are the tasks in your list:");
+ for(Task t : list){
+ System.out.println(" "+numbering+"."+t.toString());
+ numbering++;
+ }
+ separator();
+ }
+
+ public void taskSchedulingFeedback(LocalDate datePrint, ArrayList list){
+ separator();
+ System.out.println(" Here are the tasks in your list scheduled for: " +datePrint.toString() + ", "+datePrint.getDayOfWeek());
+ for(Task t : list){
+ System.out.println(" "+t.toString());
+ }
+ separator();
+ }
+
+
+ /**
+ * Returns task found with keyword with its correct numbering.
+ *
+ * @param key keyword.
+ * @param list full task list.
+ */
+ public void taskFoundFeedback(String key, ArrayList list){
+ assert !list.isEmpty():"Should be caught by emptyTaskListException";
+ ArrayList tempList = new ArrayList<>();
+ for(Task t : list){
+ if(t.getTaskInfo().contains(key)){
+ tempList.add(t);
+ }
+ }
+ if(tempList.isEmpty()){
+ throw new TaskNotFoundException("No task found with keyword ["+key+"].");
+ }else{
+ separator();
+ int numbering = 1;
+ System.out.println(" Here are the matching tasks in your list:");
+ for(Task t : tempList){
+ System.out.println(" "+numbering+"."+t);
+ numbering++;
+ }
+ separator();
+ }
+ }
+
+ /**
+ * Feedbacks message on emptyDescription Exception thrown.
+ *
+ * @param taskType The type of task (To Do, Event, Deadline).
+ */
+ public void exception_feedback_emptyDescription(String taskType){
+ separator();
+ System.out.printf(" OOPS!!! The description of a %s cannot be empty.\n", taskType);
+ separator();
+ }
+
+ /** Feedbacks message on emptyTaskList Exception thrown. */
+ public void exception_feedback_emptyTaskList(){
+ separator();
+ System.out.println(" OOPS!!! The list is empty ^_^");
+ separator();
+ }
+
+ /**
+ * Feedbacks message on unknownSyntax Exception thrown.
+ *
+ * @param message - user input.
+ */
+ public void exception_feedback_unknownSyntax(String message){
+ separator();
+ System.out.printf(" OOPS!!! I'm sorry, but I don't know what [%s] means :-(\n", message);
+ separator();
+ }
+
+ /**
+ * Feedbacks message on task not found Exception thrown.
+ *
+ * @param message - the task description.
+ */
+ public void exception_feedback_taskNotFound(String message){
+ separator();
+ System.out.printf(" OOPS!!! Task was not found [%s]\n", message);
+ separator();
+ }
+
+ /** Feedbacks message on noTimeConcept Exception thrown. */
+ public void exception_feedback_noTimeConcept(){
+ separator();
+ System.out.println(" HEY!!! Please give a due date for deadlines and events or the syntax could be wrong");
+ separator();
+ }
+
+ /** Feedbacks message on Time Parse Exception thrown. */
+ public void exception_feedback_timeParse(String message){
+ separator();
+ System.out.printf(" There seems to have problem with your time format [%s]\n", message);
+ separator();
+ }
+
+ /** Feedbacks message on Saving Exception thrown. */
+ public void exception_feedback_cantSave(){
+ separator();
+ System.out.println(" OOPS!!! Exception caught while saving >_<|||");
+ separator();
+ }
+
+ /** Feedbacks message on Loading Exception thrown. */
+ public void exception_feedback_loadingError(){
+ separator();
+ String logo = " ____ _ \n"
+ + "| _ \\ _ _| | _____ \n"
+ + "| | | | | | | |/ / _ \\\n"
+ + "| |_| | |_| | < __/\n"
+ + "|____/ \\__,_|_|\\_\\___|\n";
+ System.out.println(" OOPS!!! Something went wrong while loading");
+ separator();
+ }
+
+ /** Feedbacks message on an Unknown Exception thrown. */
+ public void exception_feedback_unknownError(){
+ separator();
+ System.out.println(" Sorry, An unknown error occurred");
+ separator();
+ }
+}
diff --git a/src/main/java/duke/ui/UI.java b/src/main/java/duke/ui/UI.java
new file mode 100644
index 00000000..ad6a60c1
--- /dev/null
+++ b/src/main/java/duke/ui/UI.java
@@ -0,0 +1,78 @@
+package duke.ui;
+
+
+
+
+import duke.exception.DukeException;
+import duke.exception.EmptyDescriptionException;
+import duke.exception.EmptyTaskListException;
+import duke.exception.SavingException;
+import duke.exception.TaskNotFoundException;
+import duke.exception.TimeManagementException;
+import duke.exception.UnknownSyntaxException;
+import duke.exception.TimeParseException;
+
+import java.util.Scanner;
+
+public class UI{
+
+ private static ReturnMessages returnMessage = new ReturnMessages();
+
+ private Scanner in;
+
+ public void showWelcome(){
+ returnMessage.welcomeFeedback();
+ }
+
+ public void showLoadingError(){
+ returnMessage.exception_feedback_loadingError();
+ }
+
+ /**
+ * Reads cmd user input.
+ *
+ * @return - command read from user Input.
+ */
+ public String readCommand() {
+ boolean end = false;
+ String command;
+ in = new Scanner(System.in);
+ command = in.nextLine();
+ return command;
+ }
+
+ public void showLine() {
+ returnMessage.separator();
+ }
+
+
+ /**
+ * Returns the error msg will output by this.
+ * All exceptions inherit DukeException.
+ *
+ * @param e the exception object.
+ */
+ public void showError(DukeException e) {
+ if (e instanceof EmptyDescriptionException) {
+ returnMessage.exception_feedback_emptyDescription(e.getMessage());
+ } else if (e instanceof EmptyTaskListException) {
+ returnMessage.exception_feedback_emptyTaskList();
+ } else if (e instanceof SavingException) {
+ returnMessage.exception_feedback_cantSave();
+ } else if (e instanceof TaskNotFoundException) {
+ returnMessage.exception_feedback_taskNotFound(e.getMessage());
+ } else if (e instanceof TimeManagementException) {
+ returnMessage.exception_feedback_noTimeConcept();
+ } else if (e instanceof UnknownSyntaxException){
+ returnMessage.exception_feedback_unknownSyntax(e.getMessage());
+ } else if (e instanceof TimeParseException){
+ returnMessage.exception_feedback_timeParse(e.getMessage());
+ } else {
+ returnMessage.exception_feedback_unknownError();
+ }
+ }
+
+ public void showExit() {
+ returnMessage.exitFeedback();
+ }
+}
diff --git a/src/test/java/duke/parsertest/CommandByeTest.java b/src/test/java/duke/parsertest/CommandByeTest.java
new file mode 100644
index 00000000..074c6dfa
--- /dev/null
+++ b/src/test/java/duke/parsertest/CommandByeTest.java
@@ -0,0 +1,44 @@
+package duke.parsertest;
+
+import duke.parser.Command;
+import duke.parser.CommandParser;
+import duke.storage.StorageTaskList;
+import duke.task.TaskList;
+import duke.ui.UI;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.AfterAll;
+import java.io.File;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class CommandByeTest {
+ private static Command c;
+ private static StorageTaskList storageTaskList;
+ private static UI ui;
+ private static TaskList taskList;
+ private static String sampleCmd = "bye";
+
+ @BeforeAll
+ static void init(){
+ ui = new UI();
+ storageTaskList = new StorageTaskList("/byeTest.txt");
+ taskList = new TaskList();
+ }
+
+ @Test
+ void byeCommand_byeTask_successAndTrue(){
+ c = CommandParser.parse(sampleCmd);
+ c.execute(taskList, ui, storageTaskList);
+ assertTrue(c.isExit());
+ }
+
+ @AfterAll
+ static void wrapUp(){
+ File cleanUP = new File(System.getProperty("user.dir") + "/byeTest.txt"); // create a File for the given file path
+ assertTrue(cleanUP.delete());
+ }
+}
diff --git a/src/test/java/duke/parsertest/CommandDeadlineTest.java b/src/test/java/duke/parsertest/CommandDeadlineTest.java
new file mode 100644
index 00000000..22fb6538
--- /dev/null
+++ b/src/test/java/duke/parsertest/CommandDeadlineTest.java
@@ -0,0 +1,52 @@
+package duke.parsertest;
+
+import duke.parser.Command;
+import duke.parser.CommandParser;
+import duke.storage.StorageTaskList;
+import duke.task.Deadline;
+import duke.task.TaskList;
+import duke.ui.UI;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.AfterAll;
+
+import java.io.File;
+import java.time.LocalDateTime;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class CommandDeadlineTest {
+
+ private static Command c;
+ private static StorageTaskList storageTaskList;
+ private static UI ui;
+ private static TaskList taskList;
+ private static String sampleCmd = "deadline submit abc/by 2021/12/25 11PM";
+ Deadline deadline = new Deadline("submit abc", LocalDateTime.of(2021,12,25,23,0,0));
+
+ @BeforeAll
+ static void init(){
+ ui = new UI();
+ storageTaskList = new StorageTaskList("/deadlineTest.txt");
+ taskList = new TaskList();
+ }
+
+ @Test
+ void deadlineCommand_deadlineTask_successAndFalse(){
+ c = CommandParser.parse(sampleCmd);
+ c.execute(taskList, ui, storageTaskList);
+ assertEquals(deadline.toString(), taskList.getLastTask().toString());
+ assertFalse(c.isExit());
+ }
+
+ @AfterAll
+ static void wrapUp(){
+ File cleanUP = new File(System.getProperty("user.dir") + "/deadlineTest.txt");
+ if(cleanUP.exists()){
+ assertTrue(cleanUP.delete());
+ }
+ }
+}
diff --git a/src/test/java/duke/parsertest/CommandDeleteTest.java b/src/test/java/duke/parsertest/CommandDeleteTest.java
new file mode 100644
index 00000000..ac32e665
--- /dev/null
+++ b/src/test/java/duke/parsertest/CommandDeleteTest.java
@@ -0,0 +1,58 @@
+package duke.parsertest;
+
+import duke.exception.EmptyTaskListException;
+import duke.exception.TimeParseException;
+import duke.parser.Command;
+import duke.parser.CommandParser;
+import duke.storage.StorageTaskList;
+import duke.task.Deadline;
+import duke.task.TaskList;
+import duke.task.ToDos;
+import duke.ui.UI;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.AfterAll;
+
+import java.io.File;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class CommandDeleteTest {
+
+ private static Command c;
+ private static StorageTaskList storageTaskList;
+ private static UI ui;
+ private static TaskList taskList;
+ private static String sampleCmd = "delete 1";
+ @BeforeAll
+ static void init(){
+ ui = new UI();
+ storageTaskList = new StorageTaskList("/deleteTest.txt");
+ taskList = new TaskList();
+ ToDos sampleData = new ToDos("sleep");
+ taskList.addTask(sampleData);
+ }
+
+ @Test
+ void deleteCommand_deleteTask_successAndFalse(){
+ c = CommandParser.parse(sampleCmd);
+ EmptyTaskListException exception = assertThrows(EmptyTaskListException.class, () -> {
+ c.execute(taskList, ui, storageTaskList);
+ assertEquals(0, taskList.getListSize());
+ });
+ String errorMsg = exception.getMessage();
+ assertEquals("empty task", errorMsg);
+ assertFalse(c.isExit());
+ }
+
+ @AfterAll
+ static void wrapUp(){
+ File cleanUP = new File(System.getProperty("user.dir") + "/deleteTest.txt");
+ if(cleanUP.exists()){
+ assertTrue(cleanUP.delete());
+ }
+ }
+}
diff --git a/src/test/java/duke/parsertest/CommandDoneTest.java b/src/test/java/duke/parsertest/CommandDoneTest.java
new file mode 100644
index 00000000..15ed3f0a
--- /dev/null
+++ b/src/test/java/duke/parsertest/CommandDoneTest.java
@@ -0,0 +1,53 @@
+package duke.parsertest;
+
+import duke.exception.EmptyTaskListException;
+import duke.parser.Command;
+import duke.parser.CommandParser;
+import duke.storage.StorageTaskList;
+import duke.task.TaskList;
+import duke.task.ToDos;
+import duke.ui.UI;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.AfterAll;
+
+import java.io.File;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class CommandDoneTest {
+
+ private static Command c;
+ private static StorageTaskList storageTaskList;
+ private static UI ui;
+ private static TaskList taskList;
+ private static String sampleCmd = "done 1";
+ @BeforeAll
+ static void init(){
+ ui = new UI();
+ storageTaskList = new StorageTaskList("/doneTest.txt");
+ taskList = new TaskList();
+ ToDos sampleData = new ToDos("sleep");
+ taskList.addTask(sampleData);
+ }
+
+ @Test
+ void doneCommand_doneTask_successAndFalse(){
+ c = CommandParser.parse(sampleCmd);
+ c.execute(taskList, ui, storageTaskList);
+ assertTrue(taskList.getTask(0).isDone());
+ assertFalse(c.isExit());
+ }
+
+ @AfterAll
+ static void wrapUp(){
+ File cleanUP = new File(System.getProperty("user.dir") + "/doneTest.txt");
+ if(cleanUP.exists()){
+ assertTrue(cleanUP.delete());
+ }
+ }
+}
diff --git a/src/test/java/duke/parsertest/CommandEventTest.java b/src/test/java/duke/parsertest/CommandEventTest.java
new file mode 100644
index 00000000..1e37f219
--- /dev/null
+++ b/src/test/java/duke/parsertest/CommandEventTest.java
@@ -0,0 +1,53 @@
+package duke.parsertest;
+
+import duke.parser.Command;
+import duke.parser.CommandParser;
+import duke.storage.StorageTaskList;
+import duke.task.Events;
+import duke.task.TaskList;
+import duke.ui.UI;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.AfterAll;
+
+import java.io.File;
+import java.time.LocalDate;
+import java.time.LocalTime;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class CommandEventTest {
+
+ private static Command c;
+ private static StorageTaskList storageTaskList;
+ private static UI ui;
+ private static TaskList taskList;
+ private static String sampleCmd = "event project meeting/at 2021/12/25 11AM-2PM";
+ Events event = new Events("project meeting", LocalDate.of(2021,12,25), LocalTime.of(11,0), LocalTime.of(14,0));
+
+ @BeforeAll
+ static void init(){
+ ui = new UI();
+ storageTaskList = new StorageTaskList("/eventTest.txt");
+ taskList = new TaskList();
+ }
+
+ @Test
+ void eventCommand_eventTask_successAndFalse(){
+ c = CommandParser.parse(sampleCmd);
+ c.execute(taskList, ui, storageTaskList);
+ assertEquals(event.toString(), taskList.getLastTask().toString());
+ assertFalse(c.isExit());
+ }
+
+ @AfterAll
+ static void wrapUp(){
+ File cleanUP = new File(System.getProperty("user.dir") + "/eventTest.txt");
+ if(cleanUP.exists()){
+ assertTrue(cleanUP.delete());
+ }
+ }
+}
diff --git a/src/test/java/duke/parsertest/CommandTodoTest.java b/src/test/java/duke/parsertest/CommandTodoTest.java
new file mode 100644
index 00000000..01439cfe
--- /dev/null
+++ b/src/test/java/duke/parsertest/CommandTodoTest.java
@@ -0,0 +1,51 @@
+package duke.parsertest;
+
+import duke.parser.Command;
+import duke.parser.CommandParser;
+import duke.storage.StorageTaskList;
+import duke.task.TaskList;
+import duke.task.ToDos;
+import duke.ui.UI;
+
+import java.io.File;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.AfterAll;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class CommandTodoTest {
+
+ private static Command c;
+ private static StorageTaskList storageTaskList;
+ private static UI ui;
+ private static TaskList taskList;
+ private static String sampleCmd = "todo eat";
+ ToDos todo = new ToDos("eat", 0); //since its testing command with the fixed duration database. assume it does not exist.
+
+ @BeforeAll
+ static void init(){
+ ui = new UI();
+ storageTaskList = new StorageTaskList("/todoTest.txt");
+ taskList = new TaskList();
+ }
+
+ @Test
+ void todoCommand_todoTask_successAndFalse(){
+ c = CommandParser.parse(sampleCmd);
+ c.execute(taskList, ui, storageTaskList);
+ assertEquals(todo.toString(), taskList.getLastTask().toString());
+ assertFalse(c.isExit());
+ }
+
+ @AfterAll
+ static void wrapUp(){
+ File cleanUP = new File(System.getProperty("user.dir") + "/todoTest.txt");
+ if(cleanUP.exists()){
+ assertTrue(cleanUP.delete());
+ }
+ }
+}
diff --git a/src/test/java/duke/parsertest/DateTimeParseTest.java b/src/test/java/duke/parsertest/DateTimeParseTest.java
new file mode 100644
index 00000000..d408f010
--- /dev/null
+++ b/src/test/java/duke/parsertest/DateTimeParseTest.java
@@ -0,0 +1,66 @@
+package duke.parsertest;
+
+import duke.exception.TimeParseException;
+import duke.parser.timeHelper.DateTimeParse;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import java.time.LocalDate;
+import java.time.LocalTime;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class DateTimeParseTest {
+ private static final String wrongDate = "20211225";
+ private static final String wrongDT = "20211225 10PM";
+ private static final String rDwT = "2021/12/25 10";
+ private static final String correctDate = "2021/12/25";
+ private static DateTimeParse timeObject;
+
+ @BeforeAll
+ static void init(){
+ timeObject = new DateTimeParse();
+ }
+
+ @Test
+ void dateParse_correctFormattedDate_success(){
+ LocalDate sample = LocalDate.of(2021,12,25);
+ assertEquals(sample, timeObject.dateParse(correctDate));
+ }
+
+ @Test
+ void timeParse_integerTimeToConvert_success(){
+ LocalTime sample = LocalTime.of(10,0,0);
+ assertEquals(sample, timeObject.timeParse(10));
+ }
+
+
+ @Test
+ void dateParse_wrongFormattedDate_exceptionThrown() {
+ TimeParseException exception = assertThrows(TimeParseException.class, () -> {
+ timeObject.dateParse(wrongDate);
+ });
+ String errorMsg = exception.getMessage();
+ assertEquals("Date Format YYYY/MM/DD", errorMsg);
+ }
+
+ @Test
+ void dateTimeParse_wrongFormattedDateTime_exceptionThrown() {
+ TimeParseException exception = assertThrows(TimeParseException.class, () -> {
+ timeObject.dateAndTimeParse(wrongDT);
+ });
+ String errorMsg = exception.getMessage();
+ assertEquals("Date Format YYYY/MM/DD", errorMsg);
+ }
+
+ @Test
+ void dateTimeParse_wrongFormattedTime_exceptionThrown() {
+ TimeParseException exception1 = assertThrows(TimeParseException.class, () -> {
+ timeObject.dateAndTimeParse(rDwT);
+ });
+ String errorMsg1 = exception1.getMessage();
+ assertEquals("Time Format 1AM/1PM", errorMsg1);
+ }
+}
diff --git a/src/test/java/duke/storagetest/StorageTaskListTest.java b/src/test/java/duke/storagetest/StorageTaskListTest.java
new file mode 100644
index 00000000..02e706e9
--- /dev/null
+++ b/src/test/java/duke/storagetest/StorageTaskListTest.java
@@ -0,0 +1,70 @@
+package duke.storagetest;
+
+import duke.storage.StorageTaskList;
+import duke.task.Deadline;
+import duke.task.Events;
+import duke.task.TaskList;
+import duke.task.ToDos;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Order;
+import java.io.File;
+import java.io.IOException;
+import java.time.LocalDateTime;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class StorageTaskListTest {
+ private static TaskList tasks;
+ private static ToDos toDos;
+ private static Deadline deadline;
+ private static Events event;
+ private static StorageTaskList store;
+
+ @BeforeAll
+ static void init(){
+ LocalDateTime sample = LocalDateTime.of(2021,12,25,16,0,0);
+ tasks = new TaskList();
+ toDos = new ToDos("eat");
+ deadline = new Deadline("return book", sample);
+ event = new Events("Finish Homework",sample.toLocalDate(),sample.toLocalTime(),sample.toLocalTime().plusHours(2));
+ tasks.addTask(toDos);
+ assert tasks.getListSize()==1:"There should exist 1 task";
+ tasks.addTask(deadline);
+ assert tasks.getListSize()==2:"There should exist 2 task";
+ tasks.addTask(event);
+ assert tasks.getListSize()==3:"There should exist 3 task";
+ store = new StorageTaskList("Testing.txt");
+ }
+
+ @Test
+ @Order(1)
+ public void fileNotCreated_checkExistenceFunction_false(){
+ assertFalse(store.existence());
+ }
+
+ @Test
+ @Order(2)
+ public void fileCreated_checkExistenceFunction_true() throws IOException {
+ store.createFile();
+ store.save(tasks);
+ assertTrue(store.existence());
+ }
+
+ @Test
+ @Order(3)
+ public void checkFileLoadStatus_anotherSameFile_true(){
+ StorageTaskList store2 = new StorageTaskList("Testing.txt");
+ assertEquals(tasks.getLastTask().toString(), store2.load().getLastTask().toString());
+ }
+
+ @AfterAll
+ static void wrapUp(){
+ File cleanUP = new File(System.getProperty("user.dir") + "/Testing.txt"); // create a File for the given file path
+ assertTrue(cleanUP.delete());
+ }
+}
diff --git a/src/test/java/duke/tasktest/DeadlineTest.java b/src/test/java/duke/tasktest/DeadlineTest.java
new file mode 100644
index 00000000..9687c39b
--- /dev/null
+++ b/src/test/java/duke/tasktest/DeadlineTest.java
@@ -0,0 +1,30 @@
+package duke.tasktest;
+
+
+import duke.task.Deadline;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class DeadlineTest {
+ private static Deadline deadline;
+
+ @BeforeAll
+ static void init(){
+ LocalDateTime sample = LocalDateTime.of(2021,12,25,16,0,0);
+ deadline = new Deadline("return book", sample);
+ }
+ @Test
+ void printDeadlineSyntax_deadlineTaskSample_success(){
+ assertEquals("[D][ ] return book(by: 2021-12-25[SATURDAY] 16:00)", deadline.toString());
+ }
+
+ @Test
+ void deadlineEncodeTest_deadlineTask_success(){
+ assertEquals("D | 0 | return book | 2021-12-25 | 16:00", deadline.encodeTask());
+ }
+
+}
diff --git a/src/test/java/duke/tasktest/EventsTest.java b/src/test/java/duke/tasktest/EventsTest.java
new file mode 100644
index 00000000..b04328b1
--- /dev/null
+++ b/src/test/java/duke/tasktest/EventsTest.java
@@ -0,0 +1,29 @@
+package duke.tasktest;
+
+import duke.task.Events;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class EventsTest {
+
+ private static Events event;
+
+ @BeforeAll
+ static void init(){
+ LocalDateTime sample = LocalDateTime.of(2021,12,25,16,0,0);
+ event = new Events("Finish Homework",sample.toLocalDate(),sample.toLocalTime(),sample.toLocalTime().plusHours(2));
+ }
+ @Test
+ void printEventSyntax_eventTaskSample_success(){
+ assertEquals("[E][ ] Finish Homework (on:2021-12-25[SATURDAY] from:16:00 to:18:00)", event.toString());
+ }
+
+ @Test
+ void eventEncodeTest_eventTask_success(){
+ assertEquals("E | 0 | Finish Homework | 2021-12-25 | 16:00 | 18:00", event.encodeTask());
+ }
+}
diff --git a/src/test/java/duke/tasktest/TaskListTest.java b/src/test/java/duke/tasktest/TaskListTest.java
new file mode 100644
index 00000000..3090e366
--- /dev/null
+++ b/src/test/java/duke/tasktest/TaskListTest.java
@@ -0,0 +1,65 @@
+package duke.tasktest;
+
+import duke.task.*;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Order;
+
+import java.time.LocalDateTime;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class TaskListTest {
+ private static TaskList tasks;
+ private static ToDos toDo;
+ private static Events event;
+ private static Deadline deadline;
+ private static LocalDateTime sample = LocalDateTime.of(2021,12,25,16,0,0);
+ @BeforeAll
+ static void init(){
+ tasks = new TaskList();
+ }
+
+ @Test
+ @Order(1)
+ void addTodo(){
+ toDo = new ToDos("eat");
+ assertTrue(tasks.addTask(toDo));
+ }
+
+ @Test
+ @Order(2)
+ void addDeadline_deadlineTask_success(){
+ deadline = new Deadline("return book", sample);
+ assertTrue(tasks.addTask(deadline));
+ }
+
+ @Test
+ @Order(3)
+ void addEvent_eventTask_success(){
+ event = new Events("Finish Homework",sample.toLocalDate(),sample.toLocalTime(),sample.toLocalTime().plusHours(2));
+ assertTrue(tasks.addTask(event));
+ }
+ @Test
+ @Order(4)
+ void checkSize_taskListSize_success(){
+ assertEquals(3, tasks.getListSize());
+ }
+
+ @Test
+ @Order(5)
+ void getLastTask_retrieveLastTask_success(){
+ assertEquals(event,tasks.getLastTask());
+ }
+
+ @Test
+ @Order(6)
+ void getTaskByID_retrieveTaskID_success(){
+ assertEquals(toDo, tasks.getTask(0));
+ }
+}
diff --git a/src/test/java/duke/tasktest/ToDosTest.java b/src/test/java/duke/tasktest/ToDosTest.java
new file mode 100644
index 00000000..97533a42
--- /dev/null
+++ b/src/test/java/duke/tasktest/ToDosTest.java
@@ -0,0 +1,45 @@
+package duke.tasktest;
+
+import duke.task.ToDos;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Order;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class ToDosTest {
+
+ private static ToDos toDos;
+
+ @BeforeAll
+ static void init(){
+ toDos = new ToDos("eat");
+ }
+ @Test
+ @Order(1)
+ void printToDoSyntax_todoTaskSampleWithoutDuration_success(){
+ assertEquals("[T][ ] eat", toDos.toString());
+ }
+
+ @Test
+ @Order(3)
+ void printToDoSyntax_todoTaskSampleWithDuration_success(){
+ toDos.setDuration(1);
+ assertEquals("[T][ ] eat (requires: 1 Hour)", toDos.toString());
+ }
+
+ @Test
+ @Order(2)
+ void todoEncodeTest_toDoWithNoDuration_success(){
+ assertEquals("T | 0 | eat | 0", toDos.encodeTask());
+ }
+
+ @Test
+ @Order(4)
+ void todoEncodeTest_toDoWithDuration_success(){
+ assertEquals("T | 0 | eat | 1", toDos.encodeTask());
+ }
+}
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6..2ac693cf 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -5,3 +5,36 @@ Hello from
| |_| | |_| | < __/
|____/ \__,_|_|\_\___|
+ ____________________________________________________________
+ Hello! I'm duke.duke
+ What can I do for you?
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [T][ ] return book (by: June 6th)
+ Now you have 2 tasks in the list.
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [D][ ] return book (by: June 6th)
+ Now you have 2 tasks in the list.
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [E][ ] project meeting (at: Aug 6th 2-4pm)
+ Now you have 3 tasks in the list.
+ ____________________________________________________________
+ ____________________________________________________________
+ 1. [ ] read book
+ 2. [ ] return book
+ 3. [ ] buy bread
+ ____________________________________________________________
+ ____________________________________________________________
+ Nice! I've marked this task as done:
+ [X] return book
+ ____________________________________________________________
+ ____________________________________________________________
+ 1. [ ] read book
+ 2. [X] return book
+ 3. [ ] buy bread
+ ____________________________________________________________
\ No newline at end of file
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29b..18b02372 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,25 @@
+to do read book
+deadline return book
+deadline return book /by 2021-10-24 10PM
+deadline return book /by 2021/10/24 10PM
+event project meeting
+event project meeting /at 2021-10-24 2-4PM
+event project meeting /at 2021/10/24 2PM-4PM
+to do join sports club
+to do borrow book
+list
+deadline borrow book /by 2021/11/5 11AM
+deadline read book /by 2021/11/5 3PM
+deadline return book /by 2021/11/5 10PM
+event project meeting /at 2021/11/5 2PM-4PM
+event family dinner /at 2021/11/5 6PM-9PM
+event new year /at 2022/2/2 0AM-12AM
+save
+list
+done 1
+done 2
+list
+done project meeting
+done 3
+done 5
+done 6
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
index 08737446..bca3a295 100644
--- a/text-ui-test/runtest.bat
+++ b/text-ui-test/runtest.bat
@@ -7,7 +7,7 @@ REM delete output from previous run
if exist ACTUAL.TXT del ACTUAL.TXT
REM compile the code into the bin folder
-javac -cp ..\src\main\java -Xlint:none -d ..\bin ..\src\main\java\*.java
+javac -cp ..\src\main\java -Xlint:none -d ..\bin ..\src\main\java\duke.duke.java
IF ERRORLEVEL 1 (
echo ********** BUILD FAILURE **********
exit /b 1
@@ -15,7 +15,7 @@ IF ERRORLEVEL 1 (
REM no error here, errorlevel == 0
REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT
-java -classpath ..\bin Duke < input.txt > ACTUAL.TXT
+java -classpath ..\bin duke.duke < input.txt > ACTUAL.TXT
REM compare the output to the expected output
FC ACTUAL.TXT EXPECTED.TXT
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
old mode 100644
new mode 100755
index c9ec8700..8433cd0b
--- a/text-ui-test/runtest.sh
+++ b/text-ui-test/runtest.sh
@@ -13,7 +13,7 @@ then
fi
# compile the code into the bin folder, terminates if error occurred
-if ! javac -cp ../src/main/java -Xlint:none -d ../bin ../src/main/java/*.java
+if ! javac -cp ../src/main/java -Xlint:none -d ../bin ../src/main/java/Duke.java
then
echo "********** BUILD FAILURE **********"
exit 1