diff --git a/README.md b/README.md
index 8715d4d9..938cdbe7 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,32 @@
-# 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.
-
-## Setting up in Intellij
-
-Prerequisites: JDK 11, update Intellij to the most recent version.
-
-1. Open Intellij (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project first)
-1. Open the project into Intellij as follows:
- 1. Click `Open`.
- 1. Select the project directory, and click `OK`.
- 1. If there are any further prompts, accept the defaults.
-1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
- 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:
- ```
- Hello from
- ____ _
- | _ \ _ _| | _____
- | | | | | | | |/ / _ \
- | |_| | |_| | < __/
- |____/ \__,_|_|\_\___|
- ```
+# Duke assignment TIC2002
+
+Program that takes in user input and create a list of task which should benefit the user.
+
+## Commands
+Add and assignment to do.
+`Todo` --- **todo assignment**
+
+Add an assignment with deadline on 10 Oct 2021 2359
+`Deadline` --- **deadline assignment submission /by 2021-10-10 2359**
+
+Add an event that happens from 21 Dec 2021 8PM to 9:30PM
+`Event` --- **event live concert /at 2021-12-21 2000 /for 1:30**
+
+List all task.
+`List` --- **list**
+
+Set a task as done according to the order in list. Sets task 1 as done if it exists.
+`Done` --- **done 1**
+
+Delete a task according to the order in list. Deletes task 1 if it exists.
+`Delete` --- **delete 1**
+
+Find the task with description matching the keyword. Find all task with assignment in description.
+`Find` --- **find assignment**
+
+View the task with date matching the search date. Find all task which occurs on Nov 15 2021.
+`View` --- **view 2021-11-15**
+
+Saves and exit program.
+`Bye` --- **bye**
+
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 00000000..977f5f8c
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,70 @@
+plugins {
+ id 'java'
+ id 'application'
+ id 'checkstyle'
+ id 'com.github.johnrengelman.shadow' version '5.1.0'
+ id 'org.openjfx.javafxplugin' version '0.0.10'
+}
+
+
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation 'org.jetbrains:annotations:20.1.0'
+ testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0'
+ testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0'
+
+ String javaFxVersion = '11'
+
+ implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux'
+ implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux'
+ implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux'
+ implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux'
+}
+
+test {
+ useJUnitPlatform()
+
+ testLogging {
+ events "passed", "skipped", "failed"
+
+ showExceptions true
+ exceptionFormat "full"
+ showCauses true
+ showStackTraces true
+ showStandardStreams = false
+ }
+}
+
+application {
+ mainClassName = "Launcher"
+}
+
+shadowJar {
+ archiveBaseName = "duke"
+ archiveClassifier = null
+}
+
+checkstyle {
+ toolVersion = '8.29'
+}
+
+run{
+ standardInput = System.in
+}
+
+javafx {
+ version = "17"
+ modules = [ 'javafx.controls', 'javafx.fxml' ]
+}
diff --git a/data/tasks.txt b/data/tasks.txt
new file mode 100644
index 00000000..696d7000
--- /dev/null
+++ b/data/tasks.txt
@@ -0,0 +1,5 @@
+D | 1 | Complete assignment | 2021-10-21 2359
+E | 0 | Concert | 2021-10-22 1300 | 01:30
+D | 0 | Assignment 2 | 2021-11-30 0001
+T | 0 | Sumbit assignment
+E | 0 | concert 2 | 2021-11-21 2000 | 02:30
diff --git a/data/test.txt b/data/test.txt
new file mode 100644
index 00000000..37521afe
--- /dev/null
+++ b/data/test.txt
@@ -0,0 +1,3 @@
+D | 1 | Complete assignment | 2021-10-21 2359
+E | 0 | Concert | 2021-10-22 1300
+D | 0 | Assignment 2 | 2021-11-30 0001
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/DialogBox.java b/src/main/java/DialogBox.java
new file mode 100644
index 00000000..16e5c0d2
--- /dev/null
+++ b/src/main/java/DialogBox.java
@@ -0,0 +1,62 @@
+import java.io.IOException;
+import java.util.Collections;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.HBox;
+
+
+/**
+ * An example of a custom control using FXML.
+ * This control represents a dialog box consisting of an ImageView to represent the speaker's face and a label
+ * containing text from the speaker.
+ */
+public class DialogBox extends HBox {
+ @FXML
+ private Label dialog;
+ @FXML
+ private ImageView displayPicture;
+
+ private DialogBox(String text, Image img) {
+ try {
+ FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource("/view/DialogBox.fxml"));
+ fxmlLoader.setController(this);
+ fxmlLoader.setRoot(this);
+ fxmlLoader.load();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ dialog.setText(text);
+ displayPicture.setImage(img);
+
+
+ }
+
+ /**
+ * Flips the dialog box such that the ImageView is on the left and text on the right.
+ */
+ private void flip() {
+ ObservableList tmp = FXCollections.observableArrayList(this.getChildren());
+ Collections.reverse(tmp);
+ getChildren().setAll(tmp);
+ setAlignment(Pos.TOP_LEFT);
+ }
+
+ public static DialogBox getUserDialog(String text, Image img) {
+ return new DialogBox(text, img);
+ }
+
+ public static DialogBox getDukeDialog(String text, Image img) {
+ var db = new DialogBox(text, img);
+ db.flip();
+ return db;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java
index 5d313334..9cf7c85d 100644
--- a/src/main/java/Duke.java
+++ b/src/main/java/Duke.java
@@ -1,10 +1,114 @@
+import parser.Parser;
+import storage.Storage;
+import ui.UI;
+import task.List;
+import command.Command;
+
+import error.DukeException;
+import error.FileException;
+import error.UnrecognizedException;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+
public class Duke {
+
+ private UI ui;
+ private Parser Parser;
+ private List tasks;
+ private Storage storage;
+ private boolean isExit = false;
+ private static String Path = "data/tasks.txt";
+ ;
+
+ /**
+ * Constructor for new Duke object using filePath given in main.
+ * Creates a new ui.UI, parser.Parser and storage.Storage object.
+ * Try to load a new List object from path.
+ * If path does not exist, create a new empty List object
+ *
+ * @param filePath Path of file to be executed
+ */
+
+ public Duke(String filePath) {
+ ui = new UI();
+ Parser = new Parser();
+ storage = new Storage(filePath);
+ try {
+ tasks = new List(storage.load());
+ System.out.println("File loaded successfully.");
+ } catch (FileException e) {
+ System.out.println("File format is corrupted. Creating new file.");
+ tasks = new List();
+ } catch (Exception e) {
+ System.out.println("Error reading file or does not exist. Creating new file.");
+ tasks = new List();
+ }
+ }
+
+
+ //javaFX
+ public String getResponse(String input) {
+ assert input.length() > 0;
+ ByteArrayOutputStream outputMsg = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(outputMsg));
+ try {
+ Command c = Parser.parse(input);
+ c.execute(tasks, storage, ui);
+ if (c.isExit()) {
+ isExit = true;
+ }
+ return outputMsg.toString();
+
+ } catch (UnrecognizedException e) {
+ return ("Unrecognized Command");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return ("Please enter description after command");
+ } catch (DukeException e) {
+ ui.showError(e.getMessage());
+ return outputMsg.toString();
+ }
+ }
+
+ public Boolean getIsExit() {
+ return isExit;
+ }
+
+ /* Unused after JavaFX implementation
public static void main(String[] args) {
- String logo = " ____ _ \n"
- + "| _ \\ _ _| | _____ \n"
- + "| | | | | | | |/ / _ \\\n"
- + "| |_| | |_| | < __/\n"
- + "|____/ \\__,_|_|\\_\\___|\n";
- System.out.println("Hello from\n" + logo);
+ new Duke(Path).run();
+ }
+ */
+ /**
+ *
+ * Executes the program until isExit is true
+ *
+ */
+ /* Unused after JavaFX implementation
+ public void run(){
+ ui.printIntro();
+
+ while (!isExit){
+ try{
+ String fullCommand = ui.readCommand();
+ ui.printLine();
+ assert fullCommand.length() > 0;
+ Command c = Parser.parse(fullCommand);
+ c.execute(tasks,storage,ui);
+ isExit = c.isExit();
+ } catch (UnrecognizedException e){
+ System.out.println("Unrecognized Command");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ System.out.println("Please enter description after command");
+ } catch (DukeException e){
+ ui.showError(e.getMessage());
+ }
+ finally {
+ ui.printLine();
+ }
+ }
+
}
+ */
}
diff --git a/src/main/java/Launcher.java b/src/main/java/Launcher.java
new file mode 100644
index 00000000..11dbf00c
--- /dev/null
+++ b/src/main/java/Launcher.java
@@ -0,0 +1,10 @@
+import javafx.application.Application;
+
+/**
+ * A launcher class to workaround classpath issues.
+ */
+public class Launcher {
+ public static void main(String[] args) {
+ Application.launch(Main.class, args);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/Main.java b/src/main/java/Main.java
new file mode 100644
index 00000000..9475278e
--- /dev/null
+++ b/src/main/java/Main.java
@@ -0,0 +1,33 @@
+import java.io.IOException;
+
+import javafx.application.Application;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Scene;
+import javafx.scene.layout.AnchorPane;
+import javafx.stage.Stage;
+
+/**
+ * A GUI for Duke using FXML.
+ */
+public class Main extends Application {
+ private static String Path = "data/tasks.txt";
+ ;
+
+ private Duke duke = new Duke(Path);
+
+ @Override
+ public void start(Stage stage) {
+ try {
+ FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml"));
+ AnchorPane ap = fxmlLoader.load();
+ Scene scene = new Scene(ap);
+ stage.setScene(scene);
+ fxmlLoader.getController().setDuke(duke);
+ stage.show();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/main/java/MainWindow.java b/src/main/java/MainWindow.java
new file mode 100644
index 00000000..3b8c5cf8
--- /dev/null
+++ b/src/main/java/MainWindow.java
@@ -0,0 +1,62 @@
+import javafx.application.Platform;
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.control.TextField;
+import javafx.scene.image.Image;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.VBox;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Controller for MainWindow. Provides the layout for the other controls.
+ */
+public class MainWindow extends AnchorPane {
+ @FXML
+ private ScrollPane scrollPane;
+ @FXML
+ private VBox dialogContainer;
+ @FXML
+ private TextField userInput;
+ @FXML
+ private Button sendButton;
+
+ private Duke duke;
+
+ private Image userImage = new Image(this.getClass().getResourceAsStream("/images/DaUser.png"));
+ private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png"));
+
+ @FXML
+ public void initialize() {
+ scrollPane.vvalueProperty().bind(dialogContainer.heightProperty());
+ String intro = "Hello. Welcome to Toh Shao Wei TIC2002 Project. Please enter your instruction." +
+ "\nEnter help to see the list of instructions.";
+ dialogContainer.getChildren().addAll(
+ DialogBox.getDukeDialog(intro, dukeImage));
+ }
+
+ public void setDuke(Duke d) {
+ duke = d;
+ }
+
+ /**
+ * Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to
+ * the dialog container. Clears the user input after processing.
+ */
+ @FXML
+ private void handleUserInput() {
+ String input = userInput.getText();
+ String response = duke.getResponse(input);
+ dialogContainer.getChildren().addAll(
+ DialogBox.getUserDialog(input, userImage),
+ DialogBox.getDukeDialog(response, dukeImage)
+ );
+ userInput.clear();
+
+ if (duke.getIsExit()) {
+ Platform.exit();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/command/AddCommand.java b/src/main/java/command/AddCommand.java
new file mode 100644
index 00000000..9cdff3f5
--- /dev/null
+++ b/src/main/java/command/AddCommand.java
@@ -0,0 +1,54 @@
+package command;
+
+import storage.Storage;
+import ui.UI;
+import task.List;
+import error.*;
+
+public class AddCommand extends Command {
+ protected String add;
+
+ public AddCommand(CommandType action, String add) {
+ setAction(action);
+ setAdd(add);
+ }
+
+ public void setAdd(String add) {
+ this.add = add;
+ }
+
+ public void execute(List tasks, Storage storage, UI ui) {
+ try {
+ addTask(action, add, tasks);
+ } catch (DukeException e) {
+ ui.showError(e.getMessage());
+ }
+
+ }
+ /**
+ * task function to determine the type of task to add.
+ * Action is an enumeration of TODO, DEADLINE and EVENT,
+ * where the String action only allows todo, deadline and event.
+ * Converts action into an Enumeration and determine the type of task to
+ * be added. inputMsg determines what is the full command description sent
+ * when adding task.
+ *
+ * @param action the type of task to be added
+ * @param inputMsg the message be added in taskArrayList
+ */
+ public void addTask(CommandType action, String inputMsg, List tasks) throws DukeException {
+ switch (action) {
+ case TODO:
+ tasks.addTodo(inputMsg);
+ break;
+ case DEADLINE:
+ tasks.addDeadline(inputMsg);
+ break;
+ case EVENT:
+ tasks.addEvent(inputMsg);
+ break;
+ default:
+ assert false : action;
+ }
+ }
+}
diff --git a/src/main/java/command/Command.java b/src/main/java/command/Command.java
new file mode 100644
index 00000000..970b2ed5
--- /dev/null
+++ b/src/main/java/command/Command.java
@@ -0,0 +1,25 @@
+package command;
+
+import storage.Storage;
+import ui.UI;
+import task.List;
+
+public abstract class Command {
+ protected CommandType action;
+
+ public Command() {
+
+ }
+
+ public void setAction(CommandType action) {
+ this.action = action;
+ }
+
+ public boolean isExit() {
+ return false;
+ }
+
+ public abstract void execute(List tasks, Storage storage, UI ui);
+
+
+}
diff --git a/src/main/java/command/CommandType.java b/src/main/java/command/CommandType.java
new file mode 100644
index 00000000..97be801a
--- /dev/null
+++ b/src/main/java/command/CommandType.java
@@ -0,0 +1,38 @@
+package command;
+
+import error.DukeException;
+import error.UnrecognizedException;
+
+public enum CommandType {
+
+ TODO("todo"),
+ DEADLINE("deadline"),
+ EVENT("event"),
+ BYE("bye"),
+ DELETE("delete"),
+ DONE("done"),
+ LIST("list"),
+ FIND("find"),
+ VIEW("view"),
+ HELP("help");
+
+ private String commandType;
+
+ CommandType(String commandType) {
+ this.commandType = commandType;
+ }
+
+ public String getCommandType() {
+ return commandType;
+ }
+
+ public static CommandType getCommandType(String inputAction) throws DukeException {
+ for (CommandType command : CommandType.values()) {
+ if (command.getCommandType().equals(inputAction)) {
+ return command;
+ }
+ }
+ assert false;
+ throw new DukeException("INVALID_ACTION");
+ }
+}
diff --git a/src/main/java/command/ExitCommand.java b/src/main/java/command/ExitCommand.java
new file mode 100644
index 00000000..e5b4440e
--- /dev/null
+++ b/src/main/java/command/ExitCommand.java
@@ -0,0 +1,22 @@
+package command;
+
+import storage.Storage;
+import ui.UI;
+import task.List;
+
+public class ExitCommand extends Command {
+ public ExitCommand() {
+
+ }
+
+ public void execute(List tasks, Storage storage, UI ui) {
+ tasks.saveList();
+ ui.printExit();
+ storage.saveFile(tasks.getSave());
+ }
+
+ @Override
+ public boolean isExit() {
+ return true;
+ }
+}
diff --git a/src/main/java/command/HelpCommand.java b/src/main/java/command/HelpCommand.java
new file mode 100644
index 00000000..d2027948
--- /dev/null
+++ b/src/main/java/command/HelpCommand.java
@@ -0,0 +1,15 @@
+package command;
+
+import storage.Storage;
+import task.List;
+import ui.UI;
+
+public class HelpCommand extends Command {
+ public HelpCommand() {
+
+ }
+
+ public void execute(List tasks, Storage storage, UI ui) {
+ ui.printInstruction();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/command/ListCommand.java b/src/main/java/command/ListCommand.java
new file mode 100644
index 00000000..48152b0f
--- /dev/null
+++ b/src/main/java/command/ListCommand.java
@@ -0,0 +1,15 @@
+package command;
+
+import storage.Storage;
+import ui.UI;
+import task.List;
+
+public class ListCommand extends Command {
+ public ListCommand() {
+
+ }
+
+ public void execute(List tasks, Storage storage, UI ui) {
+ tasks.printList();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/command/ModifyCommand.java b/src/main/java/command/ModifyCommand.java
new file mode 100644
index 00000000..0e455d4f
--- /dev/null
+++ b/src/main/java/command/ModifyCommand.java
@@ -0,0 +1,39 @@
+package command;
+
+import storage.Storage;
+import ui.UI;
+import task.List;
+import error.*;
+
+public class ModifyCommand extends Command {
+ protected String modify;
+
+ public ModifyCommand(CommandType action, String modify) {
+ setAction(action);
+ setModify(modify);
+ }
+
+ public void setModify(String modify) {
+ this.modify = modify;
+ }
+
+ public void execute(List tasks, Storage storage, UI ui) {
+ try {
+ switch (action) {
+ case DONE:
+ tasks.taskDone(modify);
+ break;
+ case DELETE:
+ tasks.taskDelete(modify);
+ break;
+ default:
+ assert false : action;
+ }
+
+ } catch (NotFoundException e) {
+ ui.printNotFound();
+ } catch (NumberFormatException e) {
+ ui.printInvalidEntry();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/command/SearchCommand.java b/src/main/java/command/SearchCommand.java
new file mode 100644
index 00000000..3b9aa025
--- /dev/null
+++ b/src/main/java/command/SearchCommand.java
@@ -0,0 +1,33 @@
+package command;
+
+import error.DukeException;
+import storage.Storage;
+import ui.UI;
+import task.List;
+
+public class SearchCommand extends Command {
+ protected String searchValue;
+
+ public SearchCommand(CommandType action, String searchValue) {
+ setAction(action);
+ setSearchValue(searchValue);
+ }
+
+ public void setSearchValue(String searchValue) {
+ this.searchValue = searchValue;
+ }
+
+ public void execute(List tasks, Storage storage, UI ui) {
+ try {
+ switch (action) {
+ case FIND:
+ tasks.printSearchList((searchValue));
+ break;
+ case VIEW:
+ tasks.printSchedule(searchValue);
+ }
+ } catch (DukeException e) {
+ ui.showError(e.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/error/DukeException.java b/src/main/java/error/DukeException.java
new file mode 100644
index 00000000..8995fcf2
--- /dev/null
+++ b/src/main/java/error/DukeException.java
@@ -0,0 +1,8 @@
+package error;
+
+public class DukeException extends Exception {
+ public DukeException (String errorMessage){
+ super(errorMessage);
+ }
+
+}
diff --git a/src/main/java/error/FileException.java b/src/main/java/error/FileException.java
new file mode 100644
index 00000000..6d0c7837
--- /dev/null
+++ b/src/main/java/error/FileException.java
@@ -0,0 +1,4 @@
+package error;
+
+public class FileException extends Exception{
+}
diff --git a/src/main/java/error/NotFoundException.java b/src/main/java/error/NotFoundException.java
new file mode 100644
index 00000000..47caec63
--- /dev/null
+++ b/src/main/java/error/NotFoundException.java
@@ -0,0 +1,4 @@
+package error;
+
+public class NotFoundException extends Exception{
+}
diff --git a/src/main/java/error/UnrecognizedException.java b/src/main/java/error/UnrecognizedException.java
new file mode 100644
index 00000000..23436f5c
--- /dev/null
+++ b/src/main/java/error/UnrecognizedException.java
@@ -0,0 +1,6 @@
+package error;
+
+public class UnrecognizedException extends Exception{
+
+
+}
diff --git a/src/main/java/parser/Parser.java b/src/main/java/parser/Parser.java
new file mode 100644
index 00000000..7377ba61
--- /dev/null
+++ b/src/main/java/parser/Parser.java
@@ -0,0 +1,55 @@
+package parser;
+
+import command.CommandType;
+import command.Command;
+import command.AddCommand;
+import command.ExitCommand;
+import command.HelpCommand;
+import command.ListCommand;
+import command.ModifyCommand;
+import command.SearchCommand;
+import error.DukeException;
+import error.UnrecognizedException;
+
+
+public class Parser {
+ /**
+ * Parser to read user input
+ *
+ * @param input users input message
+ * @return type of command
+ * @throws UnrecognizedException if action is not a recognized command
+ * @throws DukeException if format has a "|" which will conflict with save format
+ */
+ public Command parse(String input) throws UnrecognizedException, DukeException {
+ if (input.contains("|")) {
+ throw new DukeException("INPUT_FORMAT_ERROR");
+ }
+ String action;
+ String[] inputArray;
+ inputArray = input.split(" ", 2);
+ action = inputArray[0].toLowerCase();
+ CommandType commandType = CommandType.getCommandType(action);
+ switch (commandType) {
+ case BYE:
+ return new ExitCommand();
+ case TODO:
+ case DEADLINE:
+ case EVENT:
+ return new AddCommand(commandType, inputArray[1]);
+ case DELETE:
+ case DONE:
+ return new ModifyCommand(commandType, inputArray[1]);
+ case LIST:
+ return new ListCommand();
+ case FIND:
+ case VIEW:
+ return new SearchCommand(commandType, inputArray[1]);
+ case HELP:
+ return new HelpCommand();
+ default:
+ assert false:commandType;
+ throw new UnrecognizedException();
+ }
+ }
+}
diff --git a/src/main/java/storage/Storage.java b/src/main/java/storage/Storage.java
new file mode 100644
index 00000000..1db79110
--- /dev/null
+++ b/src/main/java/storage/Storage.java
@@ -0,0 +1,83 @@
+package storage;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Scanner;
+import java.io.FileWriter;
+import java.io.IOException;
+
+public class Storage {
+ private static String filePath;
+ private ArrayList loadFile;
+ public Storage(String filePath){
+ this.filePath = filePath;
+ loadFile = new ArrayList<>();
+ }
+
+ /**
+ *
+ * Creates a new file with parent directory if it does not exist
+ *
+ */
+ public void newFile(){
+ try {
+ File f = new File(filePath);
+ f.getParentFile().mkdirs();
+ if (f.createNewFile())
+ System.out.println("File created");
+ else
+ System.out.println("Loading existing file");
+ } catch (Exception e) {
+ System.err.println(e);
+ }
+ }
+
+ /**
+ *
+ * Creates a new file with parent directory if it does not exist
+ *
+ * @param saveFileList an array of strings to save into the txt file in path.
+ */
+ public void saveFile(ArrayList saveFileList){
+ try {
+ writeToFile(saveFileList);
+ } catch (IOException e) {
+ System.out.println("Something went wrong: " + e.getMessage());
+ }
+ }
+
+ /**
+ *
+ * Create a new
+ *
+ * @return loaded file
+ */
+ public ArrayList load(){
+ try {
+ readFile(filePath);
+ } catch (FileNotFoundException e) {
+ newFile(); //create new file
+ System.out.println("File not found");
+ }
+ return loadFile;
+ }
+
+ private void writeToFile(ArrayList saveFileList) throws IOException {
+ FileWriter fw = new FileWriter(filePath);
+ for(String saveFile : saveFileList) {
+ fw.write(saveFile + System.lineSeparator());
+ }
+ fw.close();
+ }
+
+ private void readFile(String filePath) throws FileNotFoundException {
+ File f = new File(filePath);
+ Scanner s = new Scanner(f);
+ while (s.hasNext()) {
+ String read = s.nextLine();
+ loadFile.add(read);
+ }
+ }
+
+}
diff --git a/src/main/java/task/Action.java b/src/main/java/task/Action.java
new file mode 100644
index 00000000..44d39813
--- /dev/null
+++ b/src/main/java/task/Action.java
@@ -0,0 +1,22 @@
+package task;
+
+public enum Action {
+ TODO("todo"),
+ DEADLINE("deadline"),
+ EVENT("event");
+
+ private String addType;
+
+ Action(String addType) {
+ setAddType(addType);
+ }
+
+ public void setAddType(String addType) {
+ this.addType = addType;
+ }
+
+ public String getAddType() {
+ return addType;
+ }
+
+}
diff --git a/src/main/java/task/Deadline.java b/src/main/java/task/Deadline.java
new file mode 100644
index 00000000..0473e263
--- /dev/null
+++ b/src/main/java/task/Deadline.java
@@ -0,0 +1,102 @@
+package task;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+
+public class Deadline extends Task {
+ private final String PRINT_FORMAT = "MMM d yyyy HH:mm a";
+ private final String SAVE_FORMAT = "yyyy-MM-dd HHmm";
+ private final String DATE_FORMAT = "yyyy-MM-dd";
+ protected LocalDateTime by;
+
+ /**
+ * Constructor for a new deadline created by user command
+ * sets the description and by of the task to be description and by argument respectively
+ * and isDone is always false for newly added task.
+ *
+ * @param description description of the task
+ * @param by date of task to be completed by
+ */
+ public Deadline(String description, LocalDateTime by) {
+ super(description);
+ setBy(by);
+ setType();
+ }
+
+ /**
+ * Constructor for a new task created by loading file
+ * sets the description and by of the task to be description and by argument respectively.
+ * isDone argument determines whether task isDone is true or false.
+ *
+ * @param description description of the task
+ * @param by date of task to be completed by
+ * @param isDone is program set as done
+ */
+ public Deadline(String description, LocalDateTime by, Boolean isDone) {
+ super(description);
+ setBy(by);
+ setType();
+ this.isDone = isDone;
+ }
+
+ public void setDone() {
+ this.isDone = true;
+ System.out.println("Nice! I've marked this task as done:\n" +
+ " [D][X] " + getDescription() + "(by: " + getByFormat() + ")");
+ }
+
+ public void setType() {
+ type = Action.DEADLINE;
+ }
+
+ public void print() {
+ if (isDone) {
+ System.out.println(" [D][X] " + getDescription() + "(by: " + getByFormat() + ")");
+ } else {
+ System.out.println(" [D][ ] " + getDescription() + "(by: " + getByFormat() + ")");
+ }
+
+ }
+
+ public void setBy(LocalDateTime by) {
+ this.by = by;
+ }
+
+ public String getTask() {
+ return "D";
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getByFormat() {
+ return by.format(DateTimeFormatter.ofPattern(PRINT_FORMAT));
+ }
+
+ public LocalDateTime getDateTime() {
+ return by;
+ }
+
+ /**
+ * Returns the format of the task to be saved.
+ * gets task, isDone and description separated by ' | '
+ *
+ * @return the file format
+ */
+ public String getSave() {
+ String s = getTask() + " | " + getDone() + " | " + getDescription() + " | " +
+ getDateTime().format(DateTimeFormatter.ofPattern(SAVE_FORMAT));
+ return s;
+ }
+
+ @Override
+ public String toString() {
+ String box = "[D][ ] ";
+ if (isDone) {
+ box = "[D][X] ";
+ }
+ return (box + description + "(by: " + getByFormat() + ")");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/task/Event.java b/src/main/java/task/Event.java
new file mode 100644
index 00000000..b25cd9da
--- /dev/null
+++ b/src/main/java/task/Event.java
@@ -0,0 +1,128 @@
+package task;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.LocalTime;
+
+public class Event extends Task {
+ protected LocalDateTime eventTime;
+ protected LocalTime to;
+
+ private final String PRINT_FORMAT = "MMM d yyyy HH:mm a";
+ private final String DATE_FORMAT = "yyyy-MM-dd";
+ private final String SAVE_FORMAT = "yyyy-MM-dd HHmm";
+
+ /**
+ * Constructor for a new event created by user command
+ * sets the description, eventTime and to of the task to be
+ * description, eventTime and to argument respectively
+ * and isDone is always false for newly added task.
+ *
+ * @param description description of the task
+ * @param eventTime start time of event
+ * @param to how long the event will be
+ */
+ public Event(String description, LocalDateTime eventTime, LocalTime to) {
+ super(description);
+ setEventTime(eventTime);
+ setTo(to);
+ setType();
+ }
+
+ /**
+ * Constructor for a new task created by loading file
+ * sets the description, eventTime and to of the task to be
+ * description, eventTime and to argument respectively
+ * isDone argument determines whether task isDone is true or false.
+ *
+ * @param description description of the task
+ * @param eventTime start time of event
+ * @param to how long the event will be
+ * @param isDone is program set as done
+ */
+ public Event(String description, LocalDateTime eventTime, LocalTime to, Boolean isDone) {
+ super(description);
+ setEventTime(eventTime);
+ setTo(to);
+ setType();
+ this.isDone = isDone;
+ }
+
+ public void setDone() {
+ this.isDone = true;
+ System.out.println("Nice! I've marked this task as done:\n" +
+ " [E][X] " + getDescription() + "(at: " + getEventTimeFormat() + ")");
+ }
+
+ public void print() {
+ if (isDone) {
+ System.out.println(" [E][X] " + getDescription() + "(at: " + getEventTimeFormat() + ")");
+ } else {
+ System.out.println(" [E][ ] " + getDescription() + "(at: " + getEventTimeFormat() + ")");
+ }
+
+ }
+
+ public void setEventTime(LocalDateTime eventTime) {
+ this.eventTime = eventTime;
+ }
+
+ public void setTo(LocalTime to) {
+ this.to = to;
+ }
+
+ public void setType() {
+ type = Action.EVENT;
+ }
+
+ public String getTask() {
+ return "E";
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getEventTimeFormat() {
+ return eventTime.format(DateTimeFormatter.ofPattern(PRINT_FORMAT));
+ }
+
+ public LocalDateTime getDateTime() {
+ return eventTime;
+ }
+
+ public LocalTime getTime() {
+ return to;
+ }
+
+ public String getHours() {
+ String hours = to.getHour() + " Hours ";
+ return hours;
+ }
+
+ public String getMinutes() {
+ String minutes = to.getMinute() + " Minutes ";
+ return minutes;
+ }
+
+ /**
+ * Returns the format of the task to be saved.
+ * gets task, isDone and description separated by ' | '
+ *
+ * @return the file format
+ */
+ public String getSave() {
+ String s = getTask() + " | " + getDone() + " | " + getDescription() + " | " +
+ getDateTime().format(DateTimeFormatter.ofPattern(SAVE_FORMAT)) + " | " + getTime();
+ return s;
+ }
+
+ @Override
+ public String toString() {
+ String box = "[E][ ] ";
+ if (isDone) {
+ box = "[E][X] ";
+ }
+ return (box + getDescription() + "(at: " + getEventTimeFormat() + " for " + getHours() + getMinutes() + ")");
+ }
+}
diff --git a/src/main/java/task/EventDateTime.java b/src/main/java/task/EventDateTime.java
new file mode 100644
index 00000000..9c3dda04
--- /dev/null
+++ b/src/main/java/task/EventDateTime.java
@@ -0,0 +1,52 @@
+package task;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+public class EventDateTime {
+ public LocalDateTime startTime;
+ public LocalDateTime endTime;
+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm");
+
+ public EventDateTime(LocalDateTime dateTime, LocalTime time) {
+ setEventDate(dateTime, time);
+ }
+
+ public void setEventDate(LocalDateTime dateTime, LocalTime time) {
+ startTime = dateTime;
+ int hours = time.getHour();
+ int minutes = time.getMinute();
+ endTime = startTime.plusHours(hours).plusMinutes(minutes);
+ }
+
+ public LocalDateTime getStartTime() {
+ return startTime;
+ }
+
+ public LocalDateTime getEndTime() {
+ return endTime;
+ }
+
+ /**
+ * Compares the event to be added with existing event to find any anomaly
+ * where startTime of event to be added is between the existing event start and end time
+ * Or endTime of event to be added is between the existing event start and end time.
+ *
+ * @param exist Date and time of existing task
+ * @return true if anomaly detected else returns false
+ */
+ public Boolean isAnomaly(EventDateTime exist) {
+ if (getStartTime().isAfter(exist.getStartTime()) && getStartTime().isBefore(exist.getEndTime())) {
+ return true;
+ } else if (getEndTime().isAfter(exist.getStartTime()) && getEndTime().isBefore(exist.getEndTime())) {
+ return true;
+ } else if (getStartTime().isBefore(exist.getStartTime()) && getEndTime().isAfter(exist.getStartTime())) {
+ return true;
+ } else if (getStartTime().isEqual(exist.getStartTime()) || getEndTime().isEqual(exist.getEndTime())) {
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/src/main/java/task/List.java b/src/main/java/task/List.java
new file mode 100644
index 00000000..31707394
--- /dev/null
+++ b/src/main/java/task/List.java
@@ -0,0 +1,320 @@
+package task;
+
+import error.DukeException;
+import error.FileException;
+import error.NotFoundException;
+
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.time.LocalDateTime;
+import java.time.LocalDate;
+import java.time.LocalTime;
+
+
+public class List {
+ private static ArrayList taskArrayList;
+ private static ArrayList taskSave;
+ public static Task recentDelete;
+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(
+ "yyyy-MM-dd HHmm");
+ private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(
+ "yyyy-MM-dd");
+ private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("H:mm");
+
+ /**
+ * Create new a new empty List
+ */
+ public List() {
+ taskArrayList = new ArrayList<>();
+ taskSave = new ArrayList<>();
+ }
+
+ /**
+ * Create new a new loaded List
+ *
+ * @param loadFile loaded txt file
+ */
+ public List(ArrayList loadFile) throws FileException {
+ taskArrayList = new ArrayList<>();
+ taskSave = new ArrayList<>();
+ String[] taskArr;
+ loadFile.listIterator();
+ for (String task : loadFile) {
+ taskArr = task.split(" \\| ");
+ String taskType, taskDone, taskDescription;
+ LocalDateTime date;
+ LocalTime time;
+ Boolean isDone = false;
+ taskType = taskArr[0];
+ taskDone = taskArr[1];
+ taskDescription = taskArr[2];
+ if (taskDone.equals("1")) {
+ isDone = true;
+ }
+ switch (taskType) {
+ case "T":
+ taskArrayList.add(new Todo(taskDescription, isDone));
+ break;
+ case "D":
+ try {
+ date = LocalDateTime.parse(taskArr[3], DATE_TIME_FORMATTER);
+ taskArrayList.add(new Deadline(taskDescription, date, isDone));
+ } catch (Exception e) {
+ throw new FileException();
+ }
+ break;
+
+ case "E":
+ try {
+ date = LocalDateTime.parse(taskArr[3], DATE_TIME_FORMATTER);
+ time = LocalTime.parse(taskArr[4], TIME_FORMATTER);
+ taskArrayList.add(new Event(taskDescription, date, time, isDone));
+ } catch (Exception e) {
+ throw new FileException();
+ }
+ break;
+
+ }
+ }
+
+ }
+
+ /**
+ * Adds new to do task to taskList as a TODO object
+ * The inputMsg contains the instruction all input is part of the description
+ * "description"
+ * On successful adding of task, it prints the task added
+ *
+ * @param inputMsg description to be added
+ * @throws DukeException if inputMsg is empty
+ */
+ public void addTodo(String inputMsg) throws DukeException {
+ if (inputMsg.isEmpty()) {
+ throw new DukeException("TODO_DESCRIPTION_ERROR");
+ }
+ taskArrayList.add(new Todo(inputMsg));
+ printAdd();
+ }
+
+ /**
+ * Adds new deadline task to taskList as a DEADLINE object.
+ * The inputMsg contains the instruction where only the format
+ * "description" /by "DateTime" is accepted
+ * On successful adding of task, it prints the task added.
+ *
+ * @param inputMsg description and /by to be added
+ * @throws DukeException if inputMsg is does not contain /by or more than 1 /at OR date is not valid
+ */
+ public void addDeadline(String inputMsg) throws DukeException {
+ String[] input = inputMsg.split(" /by ");
+ LocalDateTime date;
+ if (input.length < 2) {
+ throw new DukeException("DEADLINE_DESCRIPTION_ERROR");
+ } else if (input.length > 2) {
+ throw new DukeException("DEADLINE_LENGTH_ERROR");
+ }
+ try {
+ date = LocalDateTime.parse(input[1], DATE_TIME_FORMATTER);
+ } catch (Exception e) {
+ throw new DukeException("INVALID_DATETIME_FORMAT");
+ }
+ taskArrayList.add(new Deadline(input[0], date));
+ printAdd();
+ }
+
+ /**
+ * Adds new event task to taskList as a EVENT object
+ * The inputMsg contains the instruction where only the format
+ * "description" /by "DateTime" /for "Time" is accepted
+ * It checks if there is any existing task with clashing timings and
+ * on successful adding of task, it prints the task added.
+ *
+ * @param inputMsg description and /at to be added
+ * @throws DukeException if inputMsg does not contain /at or more than 1 /at
+ */
+ public void addEvent(String inputMsg) throws DukeException {
+ String[] input = inputMsg.split(" /at ");
+ String[] event;
+ LocalDateTime date;
+ LocalTime time;
+ Boolean clash = false;
+ assert input.length == 2;
+ if (input.length < 2) {
+ throw new DukeException("EVENT_DESCRIPTION_ERROR");
+ }
+ if (input.length > 2) {
+ throw new DukeException("EVENT_LENGTH_ERROR");
+ }
+ event = input[1].split(" /for ");
+ if (event.length > 2) {
+ throw new DukeException("EVENT_LENGTH_ERROR");
+ }
+ try {
+ date = LocalDateTime.parse(event[0], DATE_TIME_FORMATTER);
+ } catch (Exception e) {
+ throw new DukeException("INVALID_DATETIME_FORMAT");
+ }
+ try {
+ time = LocalTime.parse(event[1], TIME_FORMATTER);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new DukeException("EVENT_LENGTH_ERROR");
+ } catch (Exception e) {
+ throw new DukeException("INVALID_TIME_FORMAT");
+ }
+ //anomaly checker
+ EventDateTime addEvent = new EventDateTime(date, time);
+ for (Task task : taskArrayList) {
+ if (task.getType().equals(Action.EVENT)) {
+ EventDateTime existEvent = new EventDateTime(task.getDateTime(), task.getTime());
+ if (addEvent.isAnomaly(existEvent)) {
+ printClash(task);
+ clash = true;
+ break;
+ }
+ }
+ }
+ if (!clash) {
+ taskArrayList.add(new Event(input[0], date, time));
+ printAdd();
+ }
+ }
+
+ /**
+ * Modify the task to be set as done.
+ * taskNumber is parsed into an integer and modifies the task in the array
+ * of parsed integer to be set as done.
+ *
+ * @param taskNumber number to determine which task to modify
+ * @throws NotFoundException if the taskNumber is not within array size
+ */
+ public void taskDone(String taskNumber) throws NotFoundException {
+ Integer inputNumber = Integer.parseInt(taskNumber);
+ assert inputNumber > 0;
+ if (taskArrayList.size() < inputNumber) {
+ throw new NotFoundException();
+ }
+ taskArrayList.get(inputNumber - 1).setDone();
+ }
+
+ /**
+ * Deletes the task.
+ * taskNumber is parsed into an integer and gets the task in the array
+ * of parsed integer to be deleted and stores it first.
+ * Upon successful deletion, the deleted task in printed.
+ *
+ * @param taskNumber number to determine which task to delete
+ * @throws NotFoundException if the taskNumber is not within array size
+ */
+ public void taskDelete(String taskNumber) throws NotFoundException {
+ Integer inputNumber = Integer.parseInt(taskNumber);
+ if (taskArrayList.size() < inputNumber) {
+ throw new NotFoundException();
+ }
+ recentDelete = taskArrayList.get(inputNumber - 1);
+ taskArrayList.remove(inputNumber - 1);
+ printDelete();
+ }
+
+ /**
+ * Prints out all the task in the taskArrayList.
+ */
+ public void printList() {
+ if (taskArrayList.size() == 0) { //0 items in list
+ System.out.println("List is empty!"); //throw empty list
+ } else {
+ int count = 1;
+ for (Task task : taskArrayList) {
+ System.out.println("" + (count) + "." + task);
+ count++;
+ }
+ }
+ }
+
+ /**
+ * Prints out all the task that contains the search keyword(non-case sensitive).
+ *
+ * @param search the keyword to search for in description
+ */
+ public void printSearchList(String search) {
+ int count = 1;
+ for (Task task : taskArrayList) {
+ if (task.getDescription().toLowerCase().contains(search.toLowerCase())) {
+ System.out.println("" + (count) + "." + task);
+ count++;
+ }
+ }
+ if (count == 1) {
+ System.out.println("Nothing found");
+ }
+ }
+
+ /**
+ * Prints out all the task that contains the search keyword(non-case sensitive)
+ * excluding those without a valid DateTime.
+ *
+ * @param searchDate the keyword to search for in date
+ */
+ public void printSchedule(String searchDate) throws DukeException {
+ int count = 1;
+ try {
+ LocalDate date = LocalDate.parse(searchDate, DATE_FORMATTER);
+ for (Task task : taskArrayList) {
+ if (task.getDateTime() != null) { //excludes task without date
+ if (task.getDateTime().toLocalDate().equals(date)) {
+ System.out.println("" + (count) + "." + task);
+ count++;
+ }
+ }
+ }
+ if (count == 1) {
+ System.out.println("Nothing found");
+ }
+ } catch (Exception e) {
+ throw new DukeException("INVALID_DATE_FORMAT");
+ }
+ }
+
+ public void saveList() {
+ for (Task task : taskArrayList) {
+ taskSave.add(task.getSave());
+ }
+ }
+
+ public ArrayList getSave() {
+ return taskSave;
+ }
+
+ /**
+ * Print out the most recent task added.
+ */
+ public void printAdd() {
+ System.out.println("Got it. Item successfully added to the list: ");
+ taskArrayList.get(taskArrayList.size() - 1).print();
+ System.out.println("Now you have " + (taskArrayList.size()) + " task(s) in the list");
+ }
+
+ /**
+ * Print out the task that clash with the event trying to be added.
+ */
+ public void printClash(Task clashTask) {
+ System.out.println("Event clashes with an existing event.");
+ clashTask.print();
+ System.out.println("Delete existing event or change the timing.");
+ }
+
+ /**
+ * Print out the most recent task deleted.
+ */
+ public void printDelete() {
+ System.out.println("Noted. I have removed the task: ");
+ recentDelete.print();
+ System.out.println("Now you have " + (taskArrayList.size()) + " task(s) in the list");
+ }
+
+ public int getArraySize() {
+ return taskArrayList.size();
+ }
+
+
+}
+
diff --git a/src/main/java/task/Task.java b/src/main/java/task/Task.java
new file mode 100644
index 00000000..46ef8630
--- /dev/null
+++ b/src/main/java/task/Task.java
@@ -0,0 +1,73 @@
+package task;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+abstract class Task {
+ protected String description;
+ protected Boolean isDone;
+ protected Action type;
+
+ /**
+ * Constructor for a new task created by user command
+ * sets the description of the task to be description argument and isDone is always
+ * false for newly added task.
+ *
+ * @param description description of the task
+ */
+ public Task(String description) {
+ setDescription(description);
+ isDone = false;
+ }
+
+ /**
+ * Constructor for a new task created by loading file
+ * sets the description of the task to be description argument.
+ * isDone argument determines whether task isDone is true or false.
+ *
+ * @param description description of the task
+ * @param isDone is program set as done
+ */
+ public Task(String description, Boolean isDone) {
+ setDescription(description);
+ this.isDone = isDone;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+
+ public abstract void setDone();
+
+ public abstract void print();
+
+ public abstract void setType();
+
+ public abstract String getTask();
+
+ public abstract String getDescription();
+
+ public abstract String getSave();
+
+ public LocalDateTime getDateTime() {
+ return null;
+ }
+
+ public LocalTime getTime() {
+ return null;
+ }
+
+ public Action getType() {
+ return type;
+ }
+
+ public String getDone() {
+ if (isDone) {
+ return "1";
+ } else {
+ return "0";
+ }
+ }
+
+}
diff --git a/src/main/java/task/Todo.java b/src/main/java/task/Todo.java
new file mode 100644
index 00000000..4843fedb
--- /dev/null
+++ b/src/main/java/task/Todo.java
@@ -0,0 +1,74 @@
+package task;
+
+public class Todo extends Task {
+ /**
+ * Constructor for a new to do created by user command
+ * sets the description of the task to be description argument and isDone is always
+ * false for newly added task. Type is set to TODO.
+ *
+ * @param description description of the task
+ */
+ public Todo(String description) {
+ super(description);
+ setType();
+ }
+
+ /**
+ * Constructor for a new task created by loading file
+ * sets the description of the task to be description argument.
+ * isDone argument determines whether task isDone is true or false.
+ *
+ * @param description description of the task
+ */
+ public Todo(String description, Boolean isDone) {
+ super(description);
+ this.isDone = isDone;
+ setType();
+ }
+
+ public void setDone() {
+ this.isDone = true;
+ System.out.println("Nice! I've marked this task as done:\n" +
+ " [T][X] " + getDescription());
+ }
+
+ public void setType() {
+ type = Action.TODO;
+ }
+
+ public void print() {
+ if (isDone) {
+ System.out.println(" [T][X] " + getDescription());
+ } else {
+ System.out.println(" [T][ ] " + getDescription());
+ }
+ }
+
+ public String getTask() {
+ return "T";
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Returns the format of the task to be saved.
+ * gets task, isDone and description separated by ' | '
+ *
+ * @return the file format
+ */
+ public String getSave() {
+ String s = getTask() + " | " + getDone() + " | " + getDescription();
+ return s;
+ }
+
+ @Override
+ public String toString() {
+ String box = "[T][ ] ";
+ if (isDone) {
+ box = "[T][X] ";
+ }
+ return (box + getDescription());
+ }
+}
diff --git a/src/main/java/ui/UI.java b/src/main/java/ui/UI.java
new file mode 100644
index 00000000..ddacbb17
--- /dev/null
+++ b/src/main/java/ui/UI.java
@@ -0,0 +1,111 @@
+package ui;
+
+//import java.util.Scanner;
+
+public class UI {
+ private final String LINE_BREAK = "_______________________________________________________";
+ private final String INPUT_FORMAT_ERROR = "'|' is not allowed as it is part of the save format.";
+ private final String TODO_DESCRIPTION_ERROR = "Todo is missing a description.";
+ private final String DEADLINE_DESCRIPTION_ERROR = "Deadline command is missing a description and/or deadline.";
+ private final String DEADLINE_LENGTH_ERROR = "Deadline command has too many /by.";
+ private final String EVENT_DESCRIPTION_ERROR = "Event command is missing a description and/or time.";
+ private final String EVENT_LENGTH_ERROR = "Event command has too many /at.";
+ private final String INVALID_DATETIME_FORMAT = "Incorrect Date formatting. Only accepts yyyy-MM-dd HHmm format " +
+ "\ne.g. 2021-10-21 1300";
+ private final String INVALID_DATE_FORMAT = "Incorrect Date formatting. Only accepts yyyy-MM-dd HHmm format " +
+ "\ne.g. 2021-10-21";
+ private final String INVALID_TIME_FORMAT = "Incorrect Time formatting. Only accepts H:mm format " +
+ "\ne.g. 1:30";
+ private final String INVALID_ACTION = "Action not recognized. Please try again";
+
+ public void printIntro() {
+ printLine();
+ System.out.println("Hello!");
+ printInstruction();
+ System.out.println("Welcome to Toh Shao Wei TIC2002 Project. Please enter your instruction. " +
+ "\nEnter help to see the list of instructions.");
+ printLine();
+ }
+
+ public void printInstruction() {
+ System.out.println("1.) Enter *todo 'text'* to add todo task."); //
+ System.out.println("2.) Enter *deadline 'text' /by 'DateTime'*to add deadline task.");
+ System.out.println("3.) Enter *event 'text' /at 'DateTime' /for 'Time'* to add event task.");
+ System.out.println("4.) Enter *list* to show list of tasks.");
+ System.out.println("5.) Enter *done 'integer'* mark task as done.");
+ System.out.println("6.) Enter *delete 'integer'* to delete task.");
+ System.out.println("7.) Enter *find 'text'* to search for the word.");
+ System.out.println("8.) Enter *view 'date'* to search all task on specific date.");
+ System.out.println("9.) Enter *bye* to save and exit program.");
+ System.out.println("10.) Enter *help* To see all the possible commands.");
+ printFormats();
+ }
+ public void printFormats(){
+ System.out.println("Program accepts date format : yyyy-MM-dd HHmm " +
+ "\ne.g. 2021-10-21 1300");
+ System.out.println("Program accepts time format : H:mm " +
+ "\ne.g. 01:30");
+ }
+ /* Unused after JavaFX implementation
+ public String readCommand() {
+ Scanner in = new Scanner(System.in);
+ return in.nextLine();
+ }
+ */
+ public void printExit() {
+ System.out.println("Bye. Hope to see you again soon!");
+ System.out.println("Updating files.");
+ }
+
+ public void printNotFound() {
+ System.out.println("Task cannot be found.");
+ }
+
+ public void printInvalidEntry() {
+ System.out.println("Invalid task number entry.");
+ }
+
+
+ public void printLine() {
+ System.out.println(LINE_BREAK);
+ }
+
+ public void showError(String errorMessage) {
+ System.out.print("Error occurred: ");
+ switch (errorMessage) {
+ case "INPUT_FORMAT_ERROR":
+ System.out.println(INPUT_FORMAT_ERROR);
+ break;
+ case "TODO_DESCRIPTION_ERROR":
+ System.out.println(TODO_DESCRIPTION_ERROR);
+ break;
+ case "DEADLINE_DESCRIPTION_ERROR":
+ System.out.println(DEADLINE_DESCRIPTION_ERROR);
+ break;
+ case "DEADLINE_LENGTH_ERROR":
+ System.out.println(DEADLINE_LENGTH_ERROR);
+ break;
+ case "EVENT_DESCRIPTION_ERROR":
+ System.out.println(EVENT_DESCRIPTION_ERROR);
+ break;
+ case "EVENT_LENGTH_ERROR":
+ System.out.println(EVENT_LENGTH_ERROR);
+ break;
+ case "INVALID_DATETIME_FORMAT":
+ System.out.println(INVALID_DATETIME_FORMAT);
+ break;
+ case "INVALID_DATE_FORMAT":
+ System.out.println(INVALID_DATE_FORMAT);
+ break;
+ case "INVALID_TIME_FORMAT":
+ System.out.println(INVALID_TIME_FORMAT);
+ break;
+ case "INVALID_ACTION":
+ System.out.println(INVALID_ACTION);
+ break;
+ default:
+ System.out.println("Unrecognized error");
+
+ }
+ }
+}
diff --git a/src/main/resources/images/DaDuke.png b/src/main/resources/images/DaDuke.png
new file mode 100644
index 00000000..1de1a76f
Binary files /dev/null and b/src/main/resources/images/DaDuke.png differ
diff --git a/src/main/resources/images/DaUser.png b/src/main/resources/images/DaUser.png
new file mode 100644
index 00000000..41cb81c5
Binary files /dev/null and b/src/main/resources/images/DaUser.png differ
diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml
new file mode 100644
index 00000000..ef64f84b
--- /dev/null
+++ b/src/main/resources/view/DialogBox.fxml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
new file mode 100644
index 00000000..0c029d0a
--- /dev/null
+++ b/src/main/resources/view/MainWindow.fxml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/command/AddCommandTest.java b/src/test/java/command/AddCommandTest.java
new file mode 100644
index 00000000..dfbd231b
--- /dev/null
+++ b/src/test/java/command/AddCommandTest.java
@@ -0,0 +1,83 @@
+package command;
+
+import error.DukeException;
+import org.junit.jupiter.api.Test;
+import task.List;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+public class AddCommandTest
+{
+ private List taskTest;
+ public String error;
+
+ @Test
+ /**
+ * Test for adding deadline of task that fails.
+ */
+
+ public void failTestDeadlineCases() {
+ taskTest = new List();
+ try{
+ taskTest.addDeadline("Borrow book /by 2020" );
+ } catch (DukeException e){
+ error = e.getMessage();
+ }
+ assertEquals("INVALID_DATETIME_FORMAT", error);
+ try{
+ taskTest.addDeadline("Borrow book /by" );
+ } catch (DukeException e){
+ error = e.getMessage();
+ }
+ assertEquals("DEADLINE_DESCRIPTION_ERROR", error);
+
+ }
+
+
+ @Test
+ /**
+ * Test for adding different types of task.
+ */
+ public void failTestEventCases() {
+ taskTest = new List();
+ try{
+ taskTest.addEvent("Concert /at 2020" );
+ } catch (DukeException e){
+ error = e.getMessage();
+ }
+ assertEquals("INVALID_DATETIME_FORMAT", error);
+
+ try{
+ taskTest.addEvent("Concert /at" );
+ } catch (DukeException e){
+ error = e.getMessage();
+ }
+ assertEquals("EVENT_DESCRIPTION_ERROR", error);
+
+ try{
+ taskTest.addEvent("Concert /at 2020-10-21 1300 /for 1" );
+ } catch (DukeException e){
+ error = e.getMessage();
+ }
+ assertEquals("INVALID_TIME_FORMAT", error);
+
+ try{
+ taskTest.addEvent("Concert /at 2020-10-21 1300 /for 01:30 /for 02:30" );
+ } catch (DukeException e){
+ error = e.getMessage();
+ }
+ assertEquals("EVENT_LENGTH_ERROR", error);
+ }
+ @Test
+ public void anomalyTest() {
+ taskTest = new List();
+ try{
+ taskTest.addEvent("Concert /at 2020-10-21 1300 /for 01:30" ); //first event
+ taskTest.addEvent("Concert /at 2020-10-21 1300 /for 01:30" ); //same time
+ taskTest.addEvent("Concert /at 2020-10-21 1330 /for 00:30" ); //during event
+ taskTest.addEvent("Concert /at 2020-10-20 2300 /for 19:30" ); //next day
+ } catch (DukeException e){
+ fail("Exception found");
+ }
+ assertEquals(1,taskTest.getArraySize());
+ }
+}
diff --git a/src/test/java/task/DeadlineTest.java b/src/test/java/task/DeadlineTest.java
new file mode 100644
index 00000000..1c3f2c6a
--- /dev/null
+++ b/src/test/java/task/DeadlineTest.java
@@ -0,0 +1,23 @@
+package task;
+
+import error.DukeException;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+public class DeadlineTest {
+
+ @Test
+ /**
+ * Test for deadline constructor
+ */
+ public void deadlineConstructor() {
+ Deadline test = new Deadline("test description", LocalDateTime.of(2021, 12, 10, 13, 10));
+ assertEquals("test description", test.getDescription());
+ assertEquals(LocalDateTime.of(2021, 12, 10, 13, 10), test.getDateTime());
+ }
+
+}
diff --git a/src/test/java/task/EventTest.java b/src/test/java/task/EventTest.java
new file mode 100644
index 00000000..1b0116a3
--- /dev/null
+++ b/src/test/java/task/EventTest.java
@@ -0,0 +1,27 @@
+package task;
+
+import error.DukeException;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+public class EventTest {
+ private List taskTest;
+ public String error;
+
+ @Test
+ /**
+ * Test for deadline constructor
+ */
+ public void eventConstructor() {
+ Event test = new Event("test description", LocalDateTime.of(2021, 12, 10, 13, 10), LocalTime.of(10, 30));
+ assertEquals("test description", test.getDescription());
+ assertEquals(LocalDateTime.of(2021, 12, 10, 13, 10), test.getDateTime());
+ assertEquals(LocalTime.of(10, 30), test.getTime());
+ }
+
+}
diff --git a/src/test/java/task/ListTest.java b/src/test/java/task/ListTest.java
new file mode 100644
index 00000000..da2849e5
--- /dev/null
+++ b/src/test/java/task/ListTest.java
@@ -0,0 +1,49 @@
+package task;
+
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.*;
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+public class ListTest {
+ ArrayList testList = new ArrayList<>();
+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(
+ "yyyy-MM-dd HHmm");
+ private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("H:mm");
+
+ @Test
+ /**
+ * Test for adding different types of task.
+ */
+ public void addTaskTest() {
+
+ testList.add(new Todo("todo"));
+ testList.add(new Deadline("deadline", LocalDateTime.parse(
+ "2021-12-20 1359", DATE_TIME_FORMATTER)));
+ testList.add(new Event("event", LocalDateTime.parse(
+ "2021-05-12 2359", DATE_TIME_FORMATTER), LocalTime.parse("01:23", TIME_FORMATTER)));
+
+ assertEquals("todo", testList.get(0).getDescription());
+ assertEquals("deadline", testList.get(1).getDescription());
+ assertEquals("event", testList.get(2).getDescription());
+ testList.clear();
+ }
+
+ @Test
+ /**
+ * Test if task successfully set to done
+ */
+ public void setDoneTest() {
+
+ Task t = new Todo("HELLO");
+ assertEquals("0", t.getDone());
+ t.setDone();
+ assertEquals("1", t.getDone());
+ }
+
+}
diff --git a/src/test/java/task/TodoTest.java b/src/test/java/task/TodoTest.java
new file mode 100644
index 00000000..ad3c8296
--- /dev/null
+++ b/src/test/java/task/TodoTest.java
@@ -0,0 +1,18 @@
+package task;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+public class TodoTest {
+ @Test
+ /**
+ * Test for todo constructor
+ */
+ public void todoConstructor() {
+ Todo test = new Todo("test description");
+ assertEquals("test description", test.getDescription());
+ }
+
+}
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
index 08737446..78a373cd 100644
--- a/text-ui-test/runtest.bat
+++ b/text-ui-test/runtest.bat
@@ -14,7 +14,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
+REM run the program, feed command from input.txt file and redirect the output to the ACTUAL.TXT
java -classpath ..\bin Duke < input.txt > ACTUAL.TXT
REM compare the output to the expected output
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
old mode 100644
new mode 100755