diff --git a/.gitignore b/.gitignore
index 99712178bf..06aec6b62d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,10 @@ src/main/resources/docs/
.DS_Store
*.iml
bin/
+
+#data files from program
+/data.txt/
+data.txt
+/recurringData.txt/
+recurringData.txt
+/overdue.txt
diff --git a/README.md b/README.md
index 84755485a7..11e480cd01 100644
--- a/README.md
+++ b/README.md
@@ -1,39 +1,18 @@
-# Setting up
+# ROOMSHARE - Your friendly personal assistant
-**Prerequisites**
+---
+## Introduction
-* JDK 11
-* Recommended: IntelliJ IDE
-* Fork this repo to your GitHub account and clone the fork to your computer
+* RoomShare is personal assistant software in the form of Command Line Interface (CLI). It is designed for you to keep track of your daily tasks and other people sharing your house or apartment. With RoomShare, your can group your tasks into different categories, assign their priorities, mark tasks to be informed to your housemates and many other functions.
-**Importing the project into IntelliJ**
+![](https://github.com/AY1920S1-CS2113T-F14-3/main/blob/master/RoomShareUI.png)
-1. Open IntelliJ (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project dialog first).
-1. Set up the correct JDK version.
- * Click `Configure` > `Structure for new Projects` (in older versions of Intellij:`Configure` > `Project Defaults` > `Project Structure`).
- * If JDK 11 is listed in the drop down, select it. If it is not, click `New...` and select the directory where you installed JDK 11.
- * Click `OK`.
-1. Click `Import Project`.
-1. Locate the project directory and click `OK`.
-1. Select `Create project from existing sources` and click `Next`.
-1. Rename the project if you want. Click `Next`.
-1. Ensure that your src folder is checked. Keep clicking `Next`.
-1. Click `Finish`.
+## Features
+* Roomshare allows you to add tasks into a task list, and track their progress.
+* Supports adding and deleting tasks
+* RoomShare will also help to check if some of your time sensitive tasks have overlap, to prevent you from scheduling clashing events
+* Look for tasks with the in built search
+* Once you're done with the task, just mark it as done!
+* Also supports recurring tasks, so you won't need to manually add the same tasks everytime!
-# Tutorials
-
-Duke Increment | Tutorial
----------------|---------------
-`A-Gradle` | [Gradle Tutorial](tutorials/gradleTutorial.md)
-`A-TextUiTesting` | [Text UI Testing Tutorial](tutorials/textUiTestingTutorial.md)
-`Level-10` | JavaFX tutorials: → [Part 1: Introduction to JavaFX][fx1] → [Part 2: Creating a GUI for Duke][fx2] → [Part 3: Interacting with the user][fx3] → [Part 4: Introduction to FXML][fx4]
-
-[fx1]:
-[fx2]:
-[fx3]:
-[fx4]:
-
-# Feedback, Bug Reports
-
-* If you have feedback or bug reports, please post in [se-edu/duke issue tracker](https://github.com/se-edu/duke/issues).
-* We welcome pull requests too.
\ No newline at end of file
+## Roomshare helps you to organise your tasks, so you can keep your mind on things that matter more!
diff --git a/RoomShare.ipr b/RoomShare.ipr
new file mode 100644
index 0000000000..69b86d38ce
--- /dev/null
+++ b/RoomShare.ipr
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RoomShare.iws b/RoomShare.iws
new file mode 100644
index 0000000000..76dd966376
--- /dev/null
+++ b/RoomShare.iws
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1572320628790
+
+
+ 1572320628790
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ file://$PROJECT_DIR$/src/test/java/TaskListTest.java
+ 38
+
+
+
+
+
+
+ file://$PROJECT_DIR$/src/test/java/TaskListTest.java
+ 92
+
+
+
+
+
+
+ file://$PROJECT_DIR$/src/test/java/TaskListTest.java
+ 106
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RoomShareUI.png b/RoomShareUI.png
new file mode 100644
index 0000000000..b6c0251828
Binary files /dev/null and b/RoomShareUI.png differ
diff --git a/TeamProject.ipr b/TeamProject.ipr
new file mode 100644
index 0000000000..251dfac868
--- /dev/null
+++ b/TeamProject.ipr
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 11
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TeamProject.iws b/TeamProject.iws
new file mode 100644
index 0000000000..b30b951c46
--- /dev/null
+++ b/TeamProject.iws
@@ -0,0 +1,173 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1571283280690
+
+
+ 1571283280690
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000..01ccfb12ff
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,46 @@
+plugins {
+ id 'java'
+ id 'application'
+ id 'com.github.johnrengelman.shadow' version '5.1.0'
+ id 'checkstyle'
+ id 'org.openjfx.javafxplugin' version '0.0.7'
+}
+
+group 'seedu.duke'
+version '0.1.0'
+
+repositories {
+ mavenCentral()
+}
+
+javafx {
+ version = "11.0.2"
+ modules = [ 'javafx.controls', 'javafx.fxml' ]
+}
+
+checkstyle {
+ toolVersion = '8.23'
+}
+
+shadowJar {
+ archiveBaseName = "RoomShare"
+ archiveVersion = "0.1.3"
+ archiveClassifier = null
+ archiveAppendix = null
+}
+
+application {
+ // Change this to your main class.
+ mainClassName = "RoomShare"
+}
+dependencies {
+ testImplementation 'org.junit.jupiter:junit-jupiter:5.4.0'
+}
+
+test {
+ useJUnitPlatform()
+}
+
+run {
+ standardInput = System.in
+}
\ No newline at end of file
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
new file mode 100644
index 0000000000..b1a57ba6c0
--- /dev/null
+++ b/config/checkstyle/checkstyle.xml
@@ -0,0 +1,257 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/AboutUs.adoc b/docs/AboutUs.adoc
new file mode 100644
index 0000000000..11f054c31f
--- /dev/null
+++ b/docs/AboutUs.adoc
@@ -0,0 +1,47 @@
+= About Us
+:site-section: AboutUs
+:relfileprefix: team/
+:imagesDir: images
+:stylesDir: stylesheets
+
+RoomShare was developed by the https://github.com/AY1920S1-CS2113T-F14-3/main[F14-3] team. +
+{empty} +
+We are a team based in the http://www.comp.nus.edu.sg[School of Computing, National University of Singapore].
+
+== Project Team
+
+=== Teh Zi Huai
+image::TehZiHuai.png[width="150", align="left"]
+{empty}[https://github.com/TehZiHuai[github]] [<>]
+
+Role: Team Lead +
+Responsibilities: UI
+
+'''
+
+=== Tay Tze-wei, Caleb
+image::calebtay.png[width="150", align="left"]
+{empty}[https://github.com/calebtay[github]] [<>]
+
+Role: Developer +
+Responsibilities: Debugging
+
+'''
+
+=== Tay Ryan
+image::tyeryan.png[width="150", align="left"]
+{empty}[https://github.com/tyeryan[github]] [<>]
+
+Role: Developer +
+Responsibilities: Dev Ops + Data
+
+'''
+
+=== Tran Minh Duong (Harry)
+image::benitokun123.png[width="150", align="left"]
+{empty}[https://github.com/benitokun123[github]] [<>]
+
+Role: Developer +
+Responsibilities: UI
+
+'''
\ No newline at end of file
diff --git a/docs/[CS2113T-F14-3][RoomShare]DeveloperGuide.pdf b/docs/[CS2113T-F14-3][RoomShare]DeveloperGuide.pdf
new file mode 100644
index 0000000000..4164184cfa
Binary files /dev/null and b/docs/[CS2113T-F14-3][RoomShare]DeveloperGuide.pdf differ
diff --git a/docs/[CS2113T-F14-3][RoomShare]UserGuide.pdf b/docs/[CS2113T-F14-3][RoomShare]UserGuide.pdf
new file mode 100644
index 0000000000..48f759e09b
Binary files /dev/null and b/docs/[CS2113T-F14-3][RoomShare]UserGuide.pdf differ
diff --git a/docs/images/Ui.PNG b/docs/images/Ui.PNG
new file mode 100644
index 0000000000..1207bc7e01
Binary files /dev/null and b/docs/images/Ui.PNG differ
diff --git a/docs/images/benitokun123.png b/docs/images/benitokun123.png
new file mode 100644
index 0000000000..b7e581e15b
Binary files /dev/null and b/docs/images/benitokun123.png differ
diff --git a/docs/images/calebtay.png b/docs/images/calebtay.png
new file mode 100644
index 0000000000..856c045d7c
Binary files /dev/null and b/docs/images/calebtay.png differ
diff --git a/docs/images/tehzihuai.png b/docs/images/tehzihuai.png
new file mode 100644
index 0000000000..81f09cef76
Binary files /dev/null and b/docs/images/tehzihuai.png differ
diff --git a/docs/images/tyeryan.png b/docs/images/tyeryan.png
new file mode 100644
index 0000000000..d4b260d068
Binary files /dev/null and b/docs/images/tyeryan.png differ
diff --git a/docs/images/ui.PNG b/docs/images/ui.PNG
new file mode 100644
index 0000000000..1207bc7e01
Binary files /dev/null and b/docs/images/ui.PNG differ
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..87b738cbd0
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..8c5a1aa5e9
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Oct 11 11:12:47 SGT 2019
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000000..af6708ff22
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## 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"'
+
+# 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, switch paths to Windows format before running java
+if $cygwin ; 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=$((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"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000000..6d57edc706
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@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 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"
+
+@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/release/RoomShare-0.1.3.jar b/release/RoomShare-0.1.3.jar
new file mode 100644
index 0000000000..5dbea5b004
Binary files /dev/null and b/release/RoomShare-0.1.3.jar differ
diff --git a/release/RoomShare-0.1.4.jar b/release/RoomShare-0.1.4.jar
new file mode 100644
index 0000000000..cbf20c6c2e
Binary files /dev/null and b/release/RoomShare-0.1.4.jar differ
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000000..d1e92fe5db
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'duke'
diff --git a/src/main/java/CustomExceptions/DuplicateException.java b/src/main/java/CustomExceptions/DuplicateException.java
new file mode 100644
index 0000000000..df9df95402
--- /dev/null
+++ b/src/main/java/CustomExceptions/DuplicateException.java
@@ -0,0 +1,25 @@
+package CustomExceptions;
+
+public class DuplicateException extends Exception {
+ private static final String LINE = "___________________________________________________________________________________\n";
+ public static final String DUPLICATE_TASK = "\tDuplicate task detected ";
+
+ private String message;
+
+ /**
+ * Adds the appropriate index to the Duplicate task message.
+ * @param index index of the task with the clash
+ */
+ public DuplicateException(int index) {
+ message = DUPLICATE_TASK + "Task: " + (index + 1) + "\n";
+ }
+
+ /**
+ * toString() method returning the message of the Exception.
+ * @return the message of the Exception
+ */
+ @Override
+ public String toString() {
+ return LINE + message + LINE;
+ }
+}
diff --git a/src/main/java/CustomExceptions/RoomShareException.java b/src/main/java/CustomExceptions/RoomShareException.java
new file mode 100644
index 0000000000..aa89517bb0
--- /dev/null
+++ b/src/main/java/CustomExceptions/RoomShareException.java
@@ -0,0 +1,173 @@
+package CustomExceptions;
+
+import Enums.ExceptionType;
+
+public class RoomShareException extends Exception {
+ private static final String LINE = "___________________________________________________________________________________\n";
+ private static final String OUT_OF_BOUNDS_TEXT = "\tIndex is out of Bounds!\n";
+ private static final String ANOMALY_TEXT = "\tAnomaly Detected\n";
+ private static final String EMPTY_LIST_TEXT = "\tList is empty\n";
+
+ private static final String WRONG_FORMAT_TEXT = "\tWrong Format Detected\n";
+ private static final String WRONG_PRIORITY_TEXT = "\tYou've entered wrong format of priority\n";
+ private static final String SUB_TASK_TEXT = "\tOnly Assignments are supported with Subtasks\n";
+ private static final String WRONG_TASK_TYPE_TEXT = "\tOnly meeting, assignment, or leave tag are accepted\n";
+ private static final String EMPTY_DESCRIPTION_TEXT = "\tYou haven't included the description of you task\n";
+ private static final String EMPTY_DATE_TEXT = "\tYou haven't included the date of your task\n";
+ private static final String EMPTY_USER_TEXT = "\tYou haven't included the user of your task\n";
+ private static final String EMPTY_TASK_TYPE_TEXT = "\tYou haven't specified the type of your task: assignment, meeting, or leave\n";
+ private static final String WRITE_ERROR_TEXT = "\tError in writing file, cancelling write process...\n";
+ private static final String WRONG_INDEX_FORMAT_TEXT = "\tThe index you've enter is in the wrong format\n";
+ private static final String WRONG_TIME_FORMAT_TEXT = "\tYou've entered an invalid time format\n";
+ private static final String WRONG_SORT_TYPE_TEXT = "\tPlease enter a valid sort type: "
+ + "priority, alphabetical or deadline\n";
+ private static final String LOG_ERROR_TEXT = "\tError writing to a new log file. Please try again.\n";
+ private static final String NEGATIVE_AMOUNT_TEXT = "\tThe amount of time cannot be negative.\n";
+ private static final String EMPTY_SUB_TASK = "\tYou haven't included your list of sub-tasks\n";
+ private static final String DUPLICATE_SUB = "\tDuplicate subtask detected\n";
+ private static final String LEAVE_DONE = "\tLeave cannot be set to done\n";
+ private static final String INVALID_INPUT_TEXT = "\tYour input String seems to be wrong.\n"
+ + "\tPlease check your formatting and ensure that the use of special characters are correct!\n";
+ private static final String LOAD_ERROR_MESSAGE = "\terror in loading file: will be initialising empty list instead!\n";
+ private static final String INVALID_DATE_MESSAGE = "\tThe date you've input is before the current date!\n";
+ private static final String WRONG_DATE_FORMAT_TEXT = "\tYou've entered invalid date or time\n";
+ private static final String EMPTY_INDEX = "\tPlease enter a valid index within the range of the list! Eg. reopen 1\n";
+ private static final String INVALID_LEAVE_DATE_MESSAGE = "\tPlease check your dates for your leave!\n";
+ private static final String NO_SUCH_SUBTASK = "\tSubtask does not exist!\n";
+ private static final String ASSIGNEE_SET_TO_EVERYONE = "\tThere might have been an error when setting the assignee\n"
+ + "\tIt could be an error in your entry of the assignee field\n"
+ + "\tHowever, if you had intended to set the assignee to 'everyone', then ignore this message\n";
+
+ private String message;
+
+ /**
+ * Constructor for DukeException Exception.
+ * Takes in the exception type thrown and prints out the specific error message
+ * @param type type of exception detected
+ */
+ public RoomShareException(ExceptionType type) {
+ switch (type) {
+
+ case emptyUser:
+ message = EMPTY_USER_TEXT;
+ break;
+
+ case emptyList:
+ message = EMPTY_LIST_TEXT;
+ break;
+
+ case writeError:
+ message = WRITE_ERROR_TEXT;
+ break;
+
+ case wrongIndexFormat:
+ message = WRONG_INDEX_FORMAT_TEXT;
+ break;
+
+ case wrongTimeFormat:
+ message = WRONG_TIME_FORMAT_TEXT;
+ break;
+
+ case wrongFormat:
+ message = WRONG_FORMAT_TEXT;
+ break;
+
+ case outOfBounds:
+ message = OUT_OF_BOUNDS_TEXT;
+ break;
+
+ case wrongPriority:
+ message = WRONG_PRIORITY_TEXT;
+ break;
+
+ case subTaskError:
+ message = SUB_TASK_TEXT;
+ break;
+
+ case wrongTaskType:
+ message = WRONG_TASK_TYPE_TEXT;
+ break;
+
+ case emptyDescription:
+ message = EMPTY_DESCRIPTION_TEXT;
+ break;
+
+ case emptyDate:
+ message = EMPTY_DATE_TEXT;
+ break;
+
+ case emptyTaskType:
+ message = EMPTY_TASK_TYPE_TEXT;
+ break;
+
+ case emptySubTask:
+ message = EMPTY_SUB_TASK;
+ break;
+
+ case wrongSortFormat:
+ message = WRONG_SORT_TYPE_TEXT;
+ break;
+
+ case logError:
+ message = LOG_ERROR_TEXT;
+ break;
+
+ case negativeTimeAmount:
+ message = NEGATIVE_AMOUNT_TEXT;
+ break;
+
+ case duplicateSubtask:
+ message = DUPLICATE_SUB;
+ break;
+
+ case leaveDone:
+ message = LEAVE_DONE;
+ break;
+
+ case invalidInputString:
+ message = INVALID_INPUT_TEXT;
+ break;
+
+ case loadError:
+ message = LOAD_ERROR_MESSAGE;
+ break;
+
+ case invalidDateError:
+ message = INVALID_DATE_MESSAGE;
+ break;
+
+ case invalidDateRange:
+ message = INVALID_LEAVE_DATE_MESSAGE;
+ break;
+
+ case wrongDateFormat:
+ message = WRONG_DATE_FORMAT_TEXT;
+ break;
+
+ case emptyIndex:
+ message = EMPTY_INDEX;
+ break;
+
+ case noSubtask:
+ message = NO_SUCH_SUBTASK;
+ break;
+
+ case assigneeSetToEveyone:
+ message = ASSIGNEE_SET_TO_EVERYONE;
+ break;
+
+ default:
+ message = ANOMALY_TEXT;
+ break;
+ }
+ }
+
+ /**
+ * toString() method returning the message of the Exception.
+ * @return the message of the Exception
+ */
+ @Override
+ public String toString() {
+ return LINE + message + LINE;
+ }
+}
diff --git a/src/main/java/CustomExceptions/TimeClashException.java b/src/main/java/CustomExceptions/TimeClashException.java
new file mode 100644
index 0000000000..08a87ec9f7
--- /dev/null
+++ b/src/main/java/CustomExceptions/TimeClashException.java
@@ -0,0 +1,26 @@
+package CustomExceptions;
+
+public class TimeClashException extends Exception {
+ private static final String LINE = "___________________________________________________________________________________\n";
+ private static final String TIME_CLASH_TEXT = "\tTime Clash Detected ";
+
+ private String message;
+
+ /**
+ * TimeClashException constructor.
+ * Adds the appropriate index to the time clash message
+ * @param index index of task with the clash
+ */
+ public TimeClashException(int index) {
+ message = TIME_CLASH_TEXT + "Task: " + (index + 1) + "\n";
+ }
+
+ /**
+ * toString() method returning the message of the Exception.
+ * @return the message of the Exception
+ */
+ @Override
+ public String toString() {
+ return LINE + message + LINE;
+ }
+}
diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java
deleted file mode 100644
index 5d313334cc..0000000000
--- a/src/main/java/Duke.java
+++ /dev/null
@@ -1,10 +0,0 @@
-public class Duke {
- public static void main(String[] args) {
- String logo = " ____ _ \n"
- + "| _ \\ _ _| | _____ \n"
- + "| | | | | | | |/ / _ \\\n"
- + "| |_| | |_| | < __/\n"
- + "|____/ \\__,_|_|\\_\\___|\n";
- System.out.println("Hello from\n" + logo);
- }
-}
diff --git a/src/main/java/Enums/ExceptionType.java b/src/main/java/Enums/ExceptionType.java
new file mode 100644
index 0000000000..2ce7322712
--- /dev/null
+++ b/src/main/java/Enums/ExceptionType.java
@@ -0,0 +1,31 @@
+package Enums;
+
+public enum ExceptionType {
+wrongTimeFormat,
+wrongIndexFormat,
+wrongSortFormat,
+wrongTaskType,
+wrongFormat,
+wrongPriority,
+wrongDateFormat,
+negativeTimeAmount,
+emptyList,
+emptyUser,
+outOfBounds,
+emptySubTask,
+leaveDone,
+subTaskError,
+duplicateSubtask,
+emptyDescription,
+emptyDate,
+emptyTaskType,
+logError,
+writeError,
+loadError,
+invalidInputString,
+invalidDateRange,
+emptyIndex,
+noSubtask,
+invalidDateError,
+assigneeSetToEveyone
+}
diff --git a/src/main/java/Enums/Priority.java b/src/main/java/Enums/Priority.java
new file mode 100644
index 0000000000..db7a0b0976
--- /dev/null
+++ b/src/main/java/Enums/Priority.java
@@ -0,0 +1,5 @@
+package Enums;
+
+public enum Priority {
+ high, medium, low
+}
diff --git a/src/main/java/Enums/RecurrenceScheduleType.java b/src/main/java/Enums/RecurrenceScheduleType.java
new file mode 100644
index 0000000000..895e4e6dfe
--- /dev/null
+++ b/src/main/java/Enums/RecurrenceScheduleType.java
@@ -0,0 +1,5 @@
+package Enums;
+
+public enum RecurrenceScheduleType {
+ day, week, month, none
+}
diff --git a/src/main/java/Enums/SaveType.java b/src/main/java/Enums/SaveType.java
new file mode 100644
index 0000000000..ff774efe26
--- /dev/null
+++ b/src/main/java/Enums/SaveType.java
@@ -0,0 +1,5 @@
+package Enums;
+
+public enum SaveType {
+ A, L, empty
+}
diff --git a/src/main/java/Enums/SortType.java b/src/main/java/Enums/SortType.java
new file mode 100644
index 0000000000..e74a56ead4
--- /dev/null
+++ b/src/main/java/Enums/SortType.java
@@ -0,0 +1,5 @@
+package Enums;
+
+public enum SortType {
+ priority, alphabetical, deadline, type
+}
diff --git a/src/main/java/Enums/TaskType.java b/src/main/java/Enums/TaskType.java
new file mode 100644
index 0000000000..6149b0cc97
--- /dev/null
+++ b/src/main/java/Enums/TaskType.java
@@ -0,0 +1,27 @@
+package Enums;
+
+public enum TaskType {
+list,
+bye,
+find,
+done,
+delete,
+time,
+snooze,
+others,
+help,
+priority,
+reorder,
+restore,
+add,
+subtask,
+update,
+sort,
+log,
+overdue,
+reschedule,
+completed,
+show,
+removeoverdue,
+reopen
+}
diff --git a/src/main/java/Enums/TimeUnit.java b/src/main/java/Enums/TimeUnit.java
new file mode 100644
index 0000000000..c3a350be05
--- /dev/null
+++ b/src/main/java/Enums/TimeUnit.java
@@ -0,0 +1,5 @@
+package Enums;
+
+public enum TimeUnit {
+ month, day, hours, minutes, unDefined
+}
diff --git a/src/main/java/Model_Classes/Assignment.java b/src/main/java/Model_Classes/Assignment.java
new file mode 100644
index 0000000000..e60e4ae31a
--- /dev/null
+++ b/src/main/java/Model_Classes/Assignment.java
@@ -0,0 +1,75 @@
+package Model_Classes;
+
+import CustomExceptions.RoomShareException;
+import Enums.ExceptionType;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+
+
+
+/**
+ * An object class representing types of tasks: assignment.
+ * Stores the description and when the task should be done by.
+ */
+public class Assignment extends Task {
+
+ private ArrayList subTasks = new ArrayList();
+
+ /**
+ * Constructor for the Assignment object.
+ * Takes in inputs for description and date/time the tasks should be done by.
+ * @param description Description of the task
+ * @param by The time the tasks should be done by.
+ */
+ public Assignment(String description, Date by) {
+ super(description, by);
+ }
+
+ /**
+ * Takes in arraylist of subtasks and sets it as this assignment's subtasks.
+ * @param addList array list containing subtasks
+ */
+ public void addSubTasks(ArrayList addList) {
+ subTasks.addAll(addList);
+ }
+
+ /**
+ * Takes in a String, splits it by "," and sets each new String as a subtask of current Task.
+ * @param subTasks string containing subtasks
+ */
+ public void addSubTasks(String subTasks) {
+ this.subTasks = new ArrayList<>(Arrays.asList(subTasks.trim().split(",")));
+ }
+
+ /**
+ * Returns the ArrayList containing the Assignment's subtasks.
+ * @return ArrayList of subtasks as Strings
+ */
+ public ArrayList getSubTasks() {
+ return subTasks;
+ }
+
+ /**
+ * Removes completed Subtask.
+ * @param index index of completed subtask
+ * @throws RoomShareException when there is no subtask at that index
+ */
+ public void doneSubtask(int index) throws RoomShareException {
+ try {
+ subTasks.remove(index);
+ } catch (IndexOutOfBoundsException a) {
+ throw new RoomShareException(ExceptionType.noSubtask);
+ }
+ }
+
+ /**
+ * Returns the full description including of the assignment.
+ * @return A string indicating the task type, description, and when it should be done by.
+ */
+ @Override
+ public String toString() {
+ return "[A]" + super.toString() + " (by: " + super.getDate() + ")";
+ }
+}
diff --git a/src/main/java/Model_Classes/Leave.java b/src/main/java/Model_Classes/Leave.java
new file mode 100644
index 0000000000..f9f09a4e0d
--- /dev/null
+++ b/src/main/java/Model_Classes/Leave.java
@@ -0,0 +1,87 @@
+package Model_Classes;
+
+import java.util.Date;
+
+/**
+ * An object class representing tasks the are leaves.
+ * Stores the description as well as the start and end time of the leave.
+ */
+
+public class Leave extends Task {
+ private Date from;
+ private Date to;
+ private String user;
+
+ /**
+ * constructor for the leave class.
+ * @param description description of the leave
+ * @param user the person who is taking leave
+ * @param from the start date and time of the leave
+ * @param to the end date and time for the leave
+ */
+ public Leave(String description, String user, Date from, Date to) {
+ super(description, from);
+ this.user = user;
+ this.from = from;
+ this.to = to;
+ }
+
+ /**
+ * gets the start date of the leave.
+ * @return the start date and time of the leave
+ */
+ public Date getStartDate() {
+ return this.from;
+ }
+
+ /**
+ * sets the start date of the leave.
+ * @param date the start date and time of the leave
+ */
+ public void setStartDate(Date date) {
+ this.from = date;
+ }
+
+ /**
+ * gets the end date of the leave.
+ * @return end date and time of the leave
+ */
+ public Date getEndDate() {
+ return this.to;
+ }
+
+ /**
+ * sets the end date of the leave.
+ * @param date the end date and time of the leave
+ */
+ public void setEndDate(Date date) {
+ this.to = date;
+ }
+
+ /**
+ * gets the user who is being assigned to the leave.
+ * @return user who is assigned the leave
+ */
+ @Override
+ public String getAssignee() {
+ return this.user;
+ }
+
+ /**
+ * returns the information of the leave being taken.
+ * @return String with the information of the leave.
+ */
+ @Override
+ public String toString() {
+ return "[L] " + super.getDescription() + " (" + user + ")" + " (From: " + from + " To: " + to + ")";
+ }
+
+ /**
+ * setter for user.
+ * @param user name of user for the leave
+ */
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/Model_Classes/Meeting.java b/src/main/java/Model_Classes/Meeting.java
new file mode 100644
index 0000000000..197cce6df9
--- /dev/null
+++ b/src/main/java/Model_Classes/Meeting.java
@@ -0,0 +1,88 @@
+package Model_Classes;
+
+import Enums.TimeUnit;
+import java.util.Date;
+
+/**
+ * An object class representing types of tasks: meeting.
+ * Stores the description and when the meeting happens.
+ */
+public class Meeting extends Task {
+ private int duration = 0;
+ private TimeUnit timeUnit;
+ /**
+ * Constructor for Meeting object.
+ * Takes in inputs for description of the meeting and the time the meeting occurs.
+ * @param description Description of the meeting
+ * @param at Time the meeting happens
+ */
+ public Meeting(String description, Date at) {
+ super(description, at);
+ this.duration = 0;
+ this.timeUnit = TimeUnit.unDefined;
+ }
+
+ /**
+ * overload constructor for meeting class.
+ * duration is specified in this constructor.
+ * @param description description of the meeting
+ * @param date date and time the meeting starts
+ * @param duration duration of the meeting in numbers
+ * @param unit unit of time the meeting is in (hours, minutes etc)
+ */
+ public Meeting(String description, Date date, int duration, TimeUnit unit) {
+ super(description, date);
+ this.duration = duration;
+ this.timeUnit = unit;
+ }
+
+ /**
+ * Returns a string that has the full description of the meeting including the occurrence time.
+ * @return A string indicating the task type, description and the occurrence of the task
+ */
+ @Override
+ public String toString() {
+ if (this.isFixedDuration()) {
+ return "[M]" + super.toString() + " (on: " + super.getDate()
+ + ") (duration: " + duration + " " + timeUnit.toString() + ")";
+ } else {
+ return "[M]" + super.toString() + " (on: " + super.getDate() + ")";
+ }
+ }
+
+ /**
+ * checks if the meeting is fixed duration.
+ * @return true if meeting does not have an undefined time unit
+ */
+ public boolean isFixedDuration() {
+ // undefined TimeUnit indicates that meeting is not fixed duration
+ return !this.timeUnit.equals(TimeUnit.unDefined);
+ }
+
+ /**
+ * sets the duration of the meeting.
+ * @param duration duration in numbers of the meeting
+ * @param timeUnit time unit of the meeting (minutes, hours, days, months, undefined)
+ */
+ public void setDuration(int duration, TimeUnit timeUnit) {
+ this.duration = duration;
+ this.timeUnit = timeUnit;
+ }
+
+ /**
+ * gets the duration of the meeting.
+ * @return duration of the meeting as a String.
+ */
+ public String getDuration() {
+ return Integer.toString(duration);
+ }
+
+ /**
+ * gets the time unit of the meeting.
+ * @return timeunit of the meeting
+ */
+ public TimeUnit getTimeUnit() {
+ return timeUnit;
+ }
+
+}
diff --git a/src/main/java/Model_Classes/ProgressBar.java b/src/main/java/Model_Classes/ProgressBar.java
new file mode 100644
index 0000000000..51c6f729ed
--- /dev/null
+++ b/src/main/java/Model_Classes/ProgressBar.java
@@ -0,0 +1,40 @@
+package Model_Classes;
+
+import java.text.DecimalFormat;
+import java.util.Arrays;
+
+public class ProgressBar {
+ private String[] bar = new String[50];
+ private float total;
+ private float done;
+
+ /**
+ * Constructor for Progress Bar.
+ * @param total Total number of tasks that are in the task list
+ * @param done Total number of completed tasks in the task list
+ */
+ public ProgressBar(float total, float done) {
+ this.total = total;
+ this.done = done;
+ }
+
+ /**
+ * Displays the number of tasks completed to the total number of task in.
+ * a progress bar format.
+ */
+ public String showBar() {
+ for (int i = 0; i < 50; i++) {
+ bar[i] = " ";
+ }
+ float percentage = 0;
+ if (total >= 1) {
+ percentage = done / total;
+ for (int i = 0; i < (int)(percentage * 50); i++) {
+ bar[i] = "=";
+ }
+ }
+ DecimalFormat df = new DecimalFormat("#.#");
+ return Arrays.toString(bar).replace(",", "").trim()
+ + " " + Float.valueOf(df.format(percentage * 100)) + "%";
+ }
+}
diff --git a/src/main/java/Model_Classes/Task.java b/src/main/java/Model_Classes/Task.java
new file mode 100644
index 0000000000..e419d51d9a
--- /dev/null
+++ b/src/main/java/Model_Classes/Task.java
@@ -0,0 +1,199 @@
+package Model_Classes;
+
+import CustomExceptions.RoomShareException;
+import Enums.ExceptionType;
+import Enums.Priority;
+import Enums.RecurrenceScheduleType;
+
+import java.util.Date;
+
+/**
+ * Parent class for all other types of tasks.
+ */
+public abstract class Task {
+ private String description;
+ private boolean isDone;
+ private Date date;
+ private Priority priority;
+ private String assignee;
+ private RecurrenceScheduleType recurrenceSchedule;
+ private boolean hasRecurring;
+ private boolean isOverdue;
+
+ /**
+ * Constructor for the task object. takes in the description of the task.
+ * @param description Description of the task
+ */
+ public Task(String description, Date date) {
+
+ this.description = description;
+ this.isDone = false;
+ this.isOverdue = false;
+ this.priority = Priority.low;
+ this.date = date;
+ this.assignee = "everyone";
+ this.recurrenceSchedule = RecurrenceScheduleType.none;
+ }
+
+ /**
+ * Returns the description of the task.
+ * @return description Description of the task
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Set the description of the task.
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Returns the time of the Task (deadline of Assignment / time of meeting).
+ * @return time task is due or starts
+ */
+ public Date getDate() {
+ return date;
+ }
+
+ /**
+ * Sets the date and time of the task.
+ * @param date date and time of the task
+ */
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ /**
+ * returns whether the task has been done.
+ * @return isDone The state of completion of the task.
+ */
+ public boolean getDone() {
+ return isDone;
+ }
+
+ /**
+ * Sets the task to be done.
+ */
+ public void setDone(boolean done) throws RoomShareException {
+ if (this instanceof Leave) {
+ throw new RoomShareException(ExceptionType.leaveDone);
+ }
+ isDone = done;
+ }
+
+ public boolean getOverdue() {
+ return isOverdue;
+ }
+
+ public void setOverdue(boolean overdue) {
+ isOverdue = overdue;
+ }
+
+ /**
+ * Returns String of the assignee that was specified.
+ * @return name of the user
+ */
+ public String getAssignee() {
+ return this.assignee;
+ }
+
+ /**
+ * Set the assignee of the task.
+ * @param assignee name of the assignee
+ */
+ public void setAssignee(String assignee) {
+ this.assignee = assignee;
+ }
+
+ /**
+ * Returns the priority of the task.
+ * @return priority of the task
+ */
+ public Priority getPriority() {
+ return priority;
+ }
+
+ /**
+ * Sets the priority of the task.
+ * @param p priority of the task
+ */
+ public void setPriority(Priority p) {
+ priority = p;
+ }
+
+ /**
+ * Gets the recurrence schedule of the task.
+ * @return the recurrence schedule of the task
+ */
+ public RecurrenceScheduleType getRecurrenceSchedule() {
+ return recurrenceSchedule;
+ }
+
+ /**
+ * Sets the recurrence schedule of the task.
+ * @param recurrenceSchedule the recurrence schedule that the task is set to
+ */
+ public void setRecurrenceSchedule(RecurrenceScheduleType recurrenceSchedule) {
+ this.recurrenceSchedule = recurrenceSchedule;
+ if (recurrenceSchedule.equals(RecurrenceScheduleType.none)) {
+ this.hasRecurring = false;
+ } else {
+ this.hasRecurring = true;
+ }
+ }
+
+ /**
+ * Return whether the task is recurred.
+ * @return hasRecurring: whether the task is recurred
+ */
+ public boolean hasRecurring() {
+ return hasRecurring;
+ }
+
+ /**
+ * Snoozes the task by set amount of months.
+ * @param amount number of months to snooze
+ */
+ public void snoozeMonth(int amount) {
+ this.date.setMonth(this.date.getMonth() + amount);;
+ }
+
+ /**
+ * Snoozes the task by set amount of days.
+ * @param amount number of days to snooze
+ */
+ public void snoozeDay(int amount) {
+ this.date.setDate(this.date.getDate() + amount);;
+ }
+
+ /**
+ * Snoozes the task by set amount of hours.
+ * @param amount number of hours to snooze
+ */
+ public void snoozeHour(int amount) {
+ this.date.setHours(this.date.getHours() + amount);
+ }
+
+ /**
+ * Snoozes the task by set amount of hours.
+ * @param amount number of minutes to snooze
+ */
+ public void snoozeMinute(int amount) {
+ this.date.setMinutes(this.date.getMinutes() + amount);
+ }
+
+ /**
+ * Returns both the status icon and the description of the task.
+ * @return the information of the task, consisting of status icon, description and assignee
+ */
+ public String toString() {
+ if (hasRecurring) {
+ return " " + getDescription() + " " + "(" + getAssignee() + ") (every "
+ + getRecurrenceSchedule().toString() + ")";
+ }
+ return " " + getDescription() + " " + "(" + getAssignee() + ")";
+ }
+}
diff --git a/src/main/java/Model_Classes/TaskReminder.java b/src/main/java/Model_Classes/TaskReminder.java
new file mode 100644
index 0000000000..26d07464e2
--- /dev/null
+++ b/src/main/java/Model_Classes/TaskReminder.java
@@ -0,0 +1,39 @@
+package Model_Classes;
+
+import java.util.Timer;
+import java.util.TimerTask;
+import java.awt.Toolkit;
+
+public class TaskReminder {
+ private Timer timer = new Timer();
+ private int duration;
+ private String description;
+
+ /**
+ * constructor for the TaskReminder class.
+ * @param description description of the reminder
+ * @param duration duration of the reminder
+ */
+ public TaskReminder(String description, int duration) {
+ this.duration = duration;
+ this.description = description;
+ }
+
+ /**
+ * schedules a timer to play a sound when the time is up.
+ */
+ public void start() {
+ timer.schedule(new TimerTask() {
+
+ public void run() {
+ playSound();
+ timer.cancel();
+ }
+
+ private void playSound() {
+ System.out.println(description + " is completed!!");
+ Toolkit.getDefaultToolkit().beep();
+ }
+ }, duration * 1000);
+ }
+}
diff --git a/src/main/java/Operations/CheckAnomaly.java b/src/main/java/Operations/CheckAnomaly.java
new file mode 100644
index 0000000000..45223c74c0
--- /dev/null
+++ b/src/main/java/Operations/CheckAnomaly.java
@@ -0,0 +1,213 @@
+package Operations;
+
+import Enums.TimeUnit;
+import Model_Classes.Meeting;
+import Model_Classes.Task;
+
+import java.util.ArrayList;
+import java.util.Date;
+
+/**
+ * This class checks if there are clashes in timings for meetings.
+ */
+public class CheckAnomaly {
+
+ /**
+ * Checks for tasks with the same description when adding a new task.
+ * @param task task we are checking
+ * @return current index if duplicate detected and -1 if no duplicate detected
+ */
+ public static int isDuplicate(Task task) {
+ String name = task.getDescription();
+ String assignee = task.getAssignee();
+ String date = task.getDate().toString();
+ for (int i = 0; i < TaskList.getCurrentList().size(); i++) {
+ boolean isSameDescription = TaskList.getCurrentList().get(i).getDescription().equals(name);
+ boolean isSameAssignee = TaskList.getCurrentList().get(i).getAssignee().equals(assignee);
+ boolean isSameDate = TaskList.getCurrentList().get(i).getDate().toString().equals(date);
+ boolean isSameClass = TaskList.getCurrentList().get(i).getClass().equals(task.getClass());
+ if (isSameDescription && isSameAssignee
+ && isSameClass && isSameDate) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks for tasks in the overdue list for duplicates.
+ * @param task task to be checked
+ * @return true if duplicate found in overdue list
+ */
+ static Boolean isDuplicateOverdue(Task task) {
+ String name = task.getDescription();
+ String assignee = task.getAssignee();
+ String date = task.getDate().toString();
+ ArrayList temp = OverdueList.getOverdueList();
+ for (Task value : temp) {
+ boolean isSameDescription = value.getDescription().equals(name);
+ boolean isSameAssignee = value.getAssignee().equals(assignee);
+ boolean isSameDate = value.getDate().toString().equals(assignee);
+ boolean isSameClass = value.getClass().equals(task.getClass());
+ if (isSameDescription && isSameAssignee
+ && isSameDate && isSameClass) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks time clashes in RoomShare for meetings.
+ * Checks first if the task is a meeting, then decides which check function
+ * to use depending on whether the meeting has a fixed duration.
+ * @param task task we are checking
+ * @return current index if there is a time clash, -1 if there is no clash.
+ */
+ public static int isTimeClash(Task task) {
+ if (task instanceof Meeting) {
+ if (((Meeting) task).isFixedDuration()) {
+ return isTimeDuration(task);
+ } else {
+ return isTime(task);
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks if the Meeting with fixed duration task has any clashes with any other meetings in the task list.
+ * @param task task we are checking
+ * @return current index if there are time clashes, -1 if there are no time clashes.
+ */
+ private static int isTimeDuration(Task task) {
+ ArrayList curr = TaskList.getCurrentList();
+ for (int i = 0; i < TaskList.getCurrentList().size(); i++) {
+ if (curr.get(i) instanceof Meeting) {
+ if (((Meeting) curr.get(i)).isFixedDuration() && isOverlap(curr.get(i), task)) {
+ return i;
+ } else if (!(((Meeting) curr.get(i)).isFixedDuration())
+ && isIntersect(curr.get(i).getDate(), task)) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks if the Meeting with no fixed duration has any clashes with any other tasks in the task list.
+ * @param task task we are checking for time clashes
+ * @return current index if there are time clashes, -1 if there are no time clashes.
+ */
+ private static int isTime(Task task){
+ Date at = task.getDate();
+ ArrayList curr = TaskList.getCurrentList();
+ // Goes down list of Tasks
+ for (int i = 0; i < TaskList.getCurrentList().size(); i++) {
+ // If task is a meeting, checks if it has a fixed duration
+ if (curr.get(i) instanceof Meeting) {
+ long check1 = curr.get(i).getDate().getTime() / 10000 * 10000;
+ long check2 = at.getTime() / 10000 * 10000;
+ if (((Meeting) curr.get(i)).isFixedDuration()) {
+ if (isIntersect(at, curr.get(i))) {
+ return i;
+ }
+ } else if (check1 == check2) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks if a timing clashes with the duration of another meeting.
+ * @param time Timing we are checking.
+ * @param task task we are checking.
+ * @return True if the two timings clash and False if there is no clash.
+ */
+ private static Boolean isIntersect(Date time, Task task) {
+ Date rangeTime = task.getDate();
+ if (rangeTime.getYear() == time.getYear()
+ && rangeTime.getMonth() == time.getMonth()
+ && rangeTime.getDay() == time.getDay()) {
+ long meetingTime = task.getDate().getTime();
+ long currTime = time.getTime();
+ long duration;
+ if (task instanceof Meeting) {
+ String durationAsString = ((Meeting) task).getDuration();
+ long taskDuration = Long.parseLong(durationAsString);
+ TimeUnit timeUnit = ((Meeting) task).getTimeUnit();
+ duration = timeToMilSeconds(taskDuration, timeUnit);
+ } else {
+ // task is a Leave
+ return false;
+ }
+ return currTime < meetingTime + duration && currTime >= meetingTime;
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the timings of two Meetings overlap.
+ * @param first First task input.
+ * @param second Second task input.
+ * @return True if there is an overlap and false if there is no overlap.
+ */
+ private static Boolean isOverlap(Task first, Task second) {
+ Date date1 = first.getDate();
+ Date date2 = second.getDate();
+ boolean isSameYear = date1.getYear() == date2.getYear();
+ boolean isSameMonth = date1.getMonth() == date2.getMonth();
+ boolean isSameDay = date1.getDay() == date2.getDay();
+ if (isSameYear && isSameMonth && isSameDay) {
+ long duration1;
+ long duration2;
+ if (first instanceof Meeting) {
+ String durationFirstString = ((Meeting) first).getDuration();
+ int durationFirst = Integer.parseInt(durationFirstString);
+ TimeUnit timeUnitFirst = ((Meeting) first).getTimeUnit();
+ duration1 = timeToMilSeconds(durationFirst, timeUnitFirst);
+ } else {
+ // task is a leave, no need to check leave
+ return false;
+ }
+ if (second instanceof Meeting) {
+ String durationSecondString = ((Meeting) second).getDuration();
+ int durationSecond = Integer.parseInt(durationSecondString);
+ TimeUnit timeUnitSecond = ((Meeting) second).getTimeUnit();
+ duration2 = timeToMilSeconds(durationSecond, timeUnitSecond);
+ } else {
+ // task is a leave, no need to check leave
+ return false;
+ }
+ long time1 = date1.getTime();
+ long time2 = date2.getTime();
+ boolean isOverlapTime1 = (time1 < time2 + duration2 && time1 >= time2);
+ boolean isOverlapTime2 = (time2 < time1 + duration1 && time2 >= time1);
+
+ return isOverlapTime1 || isOverlapTime2;
+ }
+ return false;
+ }
+
+ /**
+ * Converts time to milliseconds.
+ * @param duration duration of the Meeting.
+ * @param unit unit the duration of the Meeting is in.
+ * @return duration of Meeting in milliseconds.
+ */
+ private static long timeToMilSeconds(long duration, TimeUnit unit) {
+ switch (unit) {
+ case day:
+ return duration * 60 * 60 * 24 * 1000;
+ case hours:
+ return duration * 60 * 60 * 1000;
+ case minutes:
+ return duration * 60 * 1000;
+ default:
+ return duration;
+ }
+ }
+}
diff --git a/src/main/java/Operations/Help.java b/src/main/java/Operations/Help.java
new file mode 100644
index 0000000000..30b4dab112
--- /dev/null
+++ b/src/main/java/Operations/Help.java
@@ -0,0 +1,97 @@
+package Operations;
+
+import Enums.TaskType;
+
+public class Help {
+ private Ui ui = new Ui();
+
+ /**
+ * constructor for help class.
+ */
+ public Help() {
+ }
+
+ /**
+ * shows the help tips for the command specified by the keyword.
+ * @param keyword the command the user wants tot seek help on
+ */
+ public void showHelp(String keyword) {
+ TaskType taskType;
+ try {
+ taskType = TaskType.valueOf(keyword);
+ } catch (IllegalArgumentException e) {
+ taskType = TaskType.others;
+ }
+ switch (taskType) {
+ case bye:
+ ui.helpBye();
+ break;
+ case list:
+ ui.helperList();
+ break;
+ case done:
+ ui.helpDone();
+ break;
+ case delete:
+ ui.helpDelete();
+ break;
+ case removeoverdue:
+ ui.helpRemoveoverdue();
+ break;
+ case restore:
+ ui.helpRestore();
+ break;
+ case find:
+ ui.helpFind();
+ break;
+ case priority:
+ ui.helpPriority();
+ break;
+ case add:
+ ui.helpAdd();
+ break;
+ case snooze:
+ ui.helpSnooze();
+ break;
+ case reorder:
+ ui.helpReorder();
+ break;
+ case subtask:
+ ui.helpSubtask();
+ break;
+ case update:
+ ui.helpUpdate();
+ break;
+ case sort:
+ ui.helpSort();
+ break;
+ case log:
+ ui.helpLog();
+ break;
+ case completed:
+ ui.helpCompleted();
+ break;
+ case overdue:
+ ui.helpOverdue();
+ break;
+ case reschedule:
+ ui.helpReschedule();
+ break;
+ case show:
+ ui.helpShow();
+ break;
+ case reopen:
+ ui.helpReopen();
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * shows all commands that can be used with help.
+ */
+ public void helpCommandList() {
+ ui.helpList();
+ }
+}
diff --git a/src/main/java/Operations/ListRoutine.java b/src/main/java/Operations/ListRoutine.java
new file mode 100644
index 0000000000..e9f5c1bd66
--- /dev/null
+++ b/src/main/java/Operations/ListRoutine.java
@@ -0,0 +1,37 @@
+package Operations;
+
+import CustomExceptions.RoomShareException;
+import Model_Classes.ProgressBar;
+
+public class ListRoutine {
+ private TaskList taskList;
+ private OverdueList overdueList;
+ private Ui ui = new Ui();
+
+ /**
+ * constructor for the ListRoutine.
+ * @param taskList the task list to be listed using the list routine
+ */
+ public ListRoutine(TaskList taskList, OverdueList overdueList) {
+ this.taskList = taskList;
+ this.overdueList = overdueList;
+ }
+
+ /**
+ * the listing method to be used by ListRoutine.
+ * lists the tasks and the associated information, while showing the progress bar
+ */
+ public void list() {
+ ui.showSort();
+ ui.showList();
+ try {
+ taskList.list(overdueList);
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ }
+ int taskListSize = taskList.getSize();
+ int taskListDoneSize = taskList.getDoneSize();
+ ProgressBar progressBar = new ProgressBar(taskListSize, taskListDoneSize);
+ ui.showBar(progressBar.showBar());
+ }
+}
diff --git a/src/main/java/Operations/OverdueList.java b/src/main/java/Operations/OverdueList.java
new file mode 100644
index 0000000000..c581c78704
--- /dev/null
+++ b/src/main/java/Operations/OverdueList.java
@@ -0,0 +1,150 @@
+package Operations;
+
+import CustomExceptions.RoomShareException;
+import Enums.ExceptionType;
+import Model_Classes.Assignment;
+import Model_Classes.Task;
+
+import java.util.ArrayList;
+
+public class OverdueList {
+ private static ArrayList overdue;
+
+ /**
+ * A constructor for the overdueList class.
+ * Takes in an ArrayList of Task objects as a parameter.
+ * @param Overdue ArrayList of Task object to be operated on.
+ */
+ public OverdueList(ArrayList Overdue) {
+ OverdueList.overdue = Overdue;
+ }
+
+ /**
+ * Adds a Task to the Overdued task list.
+ * @param task Task that was overdue and added into the
+ * Overdued task list.
+ */
+ public void add(Task task) {
+ overdue.add(task);
+ }
+
+ /**
+ * Reschedules an overdue task that was in the overdued list to be placed back into
+ * the original task list for the user.
+ *
+ * @param idx index of the task in the Overdued task list that is being rescheduled.
+ * @throws RoomShareException if the index entered is not valid
+ */
+ public void reschedule(int[] idx, TaskList taskList) throws RoomShareException {
+ int[] index = idx.clone();
+ if (index.length == 1) {
+ boolean isNegativeIndex = index[0] < 0;
+ boolean isExceededIndex = index[0] >= overdue.size();
+ if (isNegativeIndex || isExceededIndex) {
+ System.out.println("This are your tasks in your Overdue list");
+ list();
+ throw new RoomShareException(ExceptionType.outOfBounds);
+ } else {
+ taskList.add(overdue.get(index[0]));
+ overdue.get(index[0]).setOverdue(false);
+ }
+ } else {
+ boolean isNegativeFirstIndex = index[0] < 0;
+ boolean isExceededFirstIndex = index[0] >= overdue.size();
+ boolean isNegativeSecondIndex = index[1] < 0;
+ boolean isExceededSecondIndex = index[1] >= overdue.size();
+ if (isNegativeFirstIndex || isExceededFirstIndex
+ || isNegativeSecondIndex || isExceededSecondIndex) {
+ throw new RoomShareException(ExceptionType.outOfBounds);
+ }
+ for (int i = index[0]; i <= index[1]; i++) {
+ taskList.add(overdue.get(i));
+ overdue.get(i).setOverdue(false);
+ }
+ }
+ for (int i = 0; i < index.length; i++) {
+ overdue.removeIf(n -> !n.getOverdue());
+ }
+ }
+
+ /**
+ * lists the tasks that are current in the overdued task list.
+ * @throws RoomShareException when the list is empty
+ */
+ public void list() throws RoomShareException {
+ if (overdue.size() == 0) {
+ throw new RoomShareException(ExceptionType.emptyList);
+ } else {
+ int listCount = 1;
+ for (Task output : overdue) {
+ System.out.println("\t" + listCount + ". " + output.toString());
+ showSubtasks(output);
+ listCount += 1;
+ }
+ }
+ }
+
+ /**
+ * Retrieve a task from the overdued task list.
+ * @param index the index of the task.
+ * @return the task at the specified index in the task list.
+ * @throws RoomShareException when the index specified is out of bounds.
+ */
+ public Task get(int index) throws RoomShareException {
+ try {
+ return overdue.get(index);
+ } catch (IndexOutOfBoundsException e) {
+ throw new RoomShareException(ExceptionType.outOfBounds);
+ }
+ }
+
+ /**
+ * removes overdue items from the list.
+ * supports ranged based deletion
+ * @param index array of indices of tasks to be removed
+ * @param deletedList list for temporary storage to dump the overdue items into
+ * @throws RoomShareException when the indices specified are out of bounds
+ */
+ public void remove(int[] index, TempDeleteList deletedList) throws RoomShareException {
+ int[] idx = index.clone();
+ if (idx.length == 1) {
+ boolean isNegativeIndex = index[0] < 0;
+ boolean isExceededIndex = index[0] >= overdue.size();
+ if (isNegativeIndex || isExceededIndex) {
+ throw new RoomShareException(ExceptionType.outOfBounds);
+ }
+ deletedList.add(overdue.get(idx[0]));
+ overdue.remove(idx[0]);
+ } else {
+ boolean isNegativeFirstIndex = index[0] < 0;
+ boolean isExceededFirstIndex = index[0] >= overdue.size();
+ boolean isNegativeSecondIndex = index[1] < 0;
+ boolean isExceededSecondIndex = index[1] >= overdue.size();
+ if (isNegativeFirstIndex || isExceededFirstIndex
+ || isNegativeSecondIndex || isExceededSecondIndex) {
+ throw new RoomShareException(ExceptionType.outOfBounds);
+ }
+ for (int i = idx[0]; idx[1] >= idx[0]; idx[1]--) {
+ deletedList.add(overdue.get(i));
+ overdue.remove(i);
+ }
+ }
+ }
+
+ /**
+ * gets the current overdue list.
+ * @return ArrayList of tasks representing the overdue list
+ */
+ public static ArrayList getOverdueList() {
+ return overdue;
+ }
+
+ private void showSubtasks(Task task) {
+ if (task instanceof Assignment && !(((Assignment) task).getSubTasks() == null)) {
+ ArrayList subTasks = ((Assignment) task).getSubTasks();
+ for (String subtask : subTasks) {
+ System.out.println("\t" + "\t" + "-" + subtask);
+ }
+ }
+ }
+}
diff --git a/src/main/java/Operations/Parser.java b/src/main/java/Operations/Parser.java
new file mode 100644
index 0000000000..49ae45d951
--- /dev/null
+++ b/src/main/java/Operations/Parser.java
@@ -0,0 +1,352 @@
+package Operations;
+
+import CustomExceptions.RoomShareException;
+import Enums.ExceptionType;
+import Enums.SortType;
+import Enums.TimeUnit;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.temporal.TemporalAdjusters;
+import java.util.Date;
+import java.util.Scanner;
+
+/**
+ * A class for handling all parsing for Duke. Makes sure that inputs by the user.
+ * are properly formatted as parameters for other classes.
+ */
+public class Parser {
+ private Scanner scanner = new Scanner(System.in);
+
+ /**
+ * Constructor for the Parser object.
+ */
+ public Parser() {
+ }
+
+ /**
+ * Returns the command that the user has given RoomShare.
+ * @return The command given by the user to RoomShare
+ */
+ public String getCommand() {
+ return scanner.next().toLowerCase().trim();
+ }
+
+ /**
+ * Return the line of command that the user has given Duke.
+ * @return The line of command given by the user to RoomShare
+ */
+ public String getCommandLine() {
+ return scanner.nextLine().toLowerCase().trim();
+ }
+
+ /**
+ * Returns the index number requested by the user for commands like 'snooze, update'.
+ * @param input the input the user has entered
+ * @return the index the user wishes to perform operations on.
+ * @throws RoomShareException when the format is invalid
+ */
+ public Integer getIndex(String input) throws RoomShareException {
+ try {
+ String[] arr = input.trim().split(" ");
+ return Integer.parseInt(arr[0]) - 1;
+ } catch (IllegalArgumentException e) {
+ throw new RoomShareException(ExceptionType.emptyIndex);
+ }
+ }
+
+ /**
+ * Return the first/second/... index number requested by the user for command like 'reorder'.
+ * @param input the input the user has entered
+ * @param ordinal the first/second/...
+ * @return the index the user wishes to perform operations on.
+ * @throws RoomShareException when the format is invalid
+ */
+ public Integer getIndex(String input, int ordinal) throws RoomShareException {
+ try {
+ String[] arr = input.trim().split(" ");
+ return Integer.parseInt(arr[ordinal]) - 1;
+ } catch (IllegalArgumentException | IndexOutOfBoundsException e) {
+ throw new RoomShareException(ExceptionType.wrongIndexFormat);
+ }
+ }
+
+ /**
+ * Returns the index number requested by the user for subTask.
+ * @return index Index the user wishes to assign subtasks to.
+ */
+ public Integer getIndexSubtask(String input) throws RoomShareException {
+ try {
+ String[] arr = input.trim().split(" ");
+ return Integer.parseInt(arr[0]) - 1;
+ } catch (IllegalArgumentException e) {
+ throw new RoomShareException(ExceptionType.wrongIndexFormat);
+ }
+ }
+
+ /**
+ * Return the sub-tasks list from the user's input.
+ * @param input the input the user has entered
+ * @return the sub-tasks list as a String
+ * @throws RoomShareException when there is no sub-tasks list
+ */
+ public String getSubTasks(String input) throws RoomShareException {
+ try {
+ String[] arr = input.trim().split(" ", 2);
+ return arr[1];
+ } catch (IndexOutOfBoundsException e) {
+ throw new RoomShareException(ExceptionType.emptySubTask);
+ }
+ }
+
+ /**
+ * Return a single index number or a range of index number requested by users for command 'done' and 'delete'.
+ * @return a single index or a range of index
+ */
+ public int[] getIndexRange(String input) throws RoomShareException {
+ String[] temp = input.trim().split("-",2);
+ try {
+ int[] index;
+ if (temp.length == 1) {
+ int tempIndex = Integer.parseInt(temp[0].trim()) - 1;
+ index = new int[]{tempIndex};
+ } else {
+ int tempIndex1 = Integer.parseInt(temp[0].trim()) - 1;
+ int tempIndex2 = Integer.parseInt(temp[1].trim()) - 1;
+ index = new int[]{tempIndex1, tempIndex2};
+ }
+ return index;
+ } catch (IllegalArgumentException e) {
+ throw new RoomShareException(ExceptionType.wrongIndexFormat);
+ }
+ }
+
+ /**
+ * Returns a Date object from a raw date that is stored as a String in any format.
+ * @param by Input String containing the date information.
+ * @return A Date object containing the appropriately formatted date.
+ * @throws RoomShareException if the input is uninterpretable.
+ */
+ Date formatDate(String by) throws RoomShareException {
+ Date date;
+ if (this.formatDateTomorrowToday(by) != null) {
+ date = this.formatDateTomorrowToday(by);
+ } else if (this.formatDateByDay(by) != null) {
+ date = this.formatDateByDay(by);
+ } else {
+ date = this.formatDateDDmmYY(by);
+ }
+ return date;
+ }
+
+
+ /**
+ * Returns a Date object from a raw date that is stored as a String in a DD/MM/YYYY HH:MM format.
+ * If the format of the input string is unacceptable, will throw a DukeException and will not return anything.
+ * @param by Input String containing the date information.
+ * @return A Date object containing the appropriately formatted date.
+ * @throws RoomShareException If by is not in dd/MM/yyyy HH:mm format
+ */
+ public Date formatDateDDmmYY(String by) throws RoomShareException {
+ try {
+ SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
+ format.setLenient(false);
+ Date date = format.parse(by);
+ date.setSeconds(0);
+ return date;
+ } catch (ParseException | IndexOutOfBoundsException | IllegalArgumentException e2) {
+ throw new RoomShareException(ExceptionType.wrongDateFormat);
+ }
+ }
+
+ /**
+ * Returns a Date object from a raw date that is stored as a String with special key words like "tomorrow, today".
+ * @param by Input String containing the date information.
+ * @return A Date object containing the appropriately formatted date.
+ */
+ private Date formatDateTomorrowToday(String by) {
+ try {
+ Date date = new Date();
+ String[] temp = by.split(" ");
+ String day = temp[0];
+ String[] time = temp[1].trim().split(":");
+ // validate hours and minute
+ SimpleDateFormat format = new SimpleDateFormat("HH:mm");
+ format.setLenient(false);
+ format.parse(temp[1].trim());
+ // extract hours and minutes
+ int hours = Integer.parseInt(time[0]);
+ int minutes = Integer.parseInt(time[1]);
+ date.setHours(hours);
+ date.setMinutes(minutes);
+ date.setSeconds(0);
+ if (day.toLowerCase().equals("tomorrow") || day.toLowerCase().equals("tmr")) {
+ date.setDate(date.getDate() + 1);
+ return date;
+ } else if (day.toLowerCase().equals("today") || day.toLowerCase().equals("tdy")) {
+ return date;
+ } else {
+ return null;
+ }
+ } catch (IndexOutOfBoundsException | IllegalArgumentException | ParseException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns a Date object from a raw date that is stored as a String with special key words like
+ * "next monday, this fri".
+ * @param by Input String containing the date information.
+ * @return A Date object containing the appropriately formatted date.
+ */
+ public Date formatDateByDay(String by) {
+ try {
+ LocalDate date = LocalDate.now();
+ DayOfWeek currentDayOfWeek = date.getDayOfWeek();
+ Date outputDate;
+ String[] temp = by.split(" ");
+ // validate hours and minute
+ SimpleDateFormat format = new SimpleDateFormat("HH:mm");
+ format.setLenient(false);
+ format.parse(temp[2].trim());
+ // Check if the user enter proper keyword "next" or "this"
+ if (!temp[0].toLowerCase().equals("next") && !temp[0].toLowerCase().equals("this")) {
+ return null;
+ }
+ // Check which day of the week the user input
+ String day = temp[1].trim();
+ DayOfWeek dayOfWeek;
+ switch (day.toLowerCase()) {
+ case "monday":
+ case "mon":
+ dayOfWeek = DayOfWeek.MONDAY;
+ break;
+
+ case "tuesday":
+ case "tues":
+ dayOfWeek = DayOfWeek.TUESDAY;
+ break;
+
+ case "wednesday":
+ case "wed":
+ dayOfWeek = DayOfWeek.WEDNESDAY;
+ break;
+
+ case "thursday":
+ case "thurs":
+ dayOfWeek = DayOfWeek.THURSDAY;
+ break;
+
+ case "friday":
+ case "fri":
+ dayOfWeek = DayOfWeek.FRIDAY;
+ break;
+
+ case "saturday":
+ case "sat":
+ dayOfWeek = DayOfWeek.SATURDAY;
+ break;
+
+ case "sunday":
+ case "sun":
+ dayOfWeek = DayOfWeek.SUNDAY;
+ break;
+
+ default:
+ return null;
+ }
+ if (temp[0].toLowerCase().equals("this")) {
+ date = date.with(TemporalAdjusters.nextOrSame(dayOfWeek));
+ } else {
+ if (currentDayOfWeek.getValue() < dayOfWeek.getValue()) {
+ date = date.with(TemporalAdjusters.next(dayOfWeek));
+ date = date.with(TemporalAdjusters.next(dayOfWeek));
+ } else {
+ date = date.with(TemporalAdjusters.next(dayOfWeek));
+ }
+ }
+ // Convert LocalDate object to Date object for storing compatibility
+ ZoneId defaultZoneId = ZoneId.systemDefault();
+ outputDate = Date.from(date.atStartOfDay(defaultZoneId).toInstant());
+ // Set hours and minute as specified
+ String[] time = temp[2].trim().split(":");
+ int hours = Integer.parseInt(time[0]);
+ int minutes = Integer.parseInt(time[1]);
+ outputDate.setHours(hours);
+ outputDate.setMinutes(minutes);
+ outputDate.setSeconds(0);
+ return outputDate;
+ } catch (IndexOutOfBoundsException | IllegalArgumentException | ParseException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the keyword to be searched for.
+ * @return key A string of the keyword to be searched for
+ */
+ public String getKey() {
+ return scanner.nextLine().trim();
+ }
+
+ /**
+ * Returns the amount of time the customer request to snooze.
+ * @return the amount of time the customer request to snooze
+ */
+ public int getAmount(String input) throws RoomShareException {
+ try {
+ String[] arr = input.trim().split(" ");
+ return Integer.parseInt(arr[1]);
+ } catch (IllegalArgumentException | IndexOutOfBoundsException e) {
+ throw new RoomShareException(ExceptionType.wrongTimeFormat);
+ }
+ }
+
+ /**
+ * Returns the unit of time the customer request to snooze.
+ * @return the unit of time the customer request to snooze
+ */
+ public TimeUnit getTimeUnit(String input) throws RoomShareException {
+ try {
+ String[] arr = input.trim().split(" ");
+ return TimeUnit.valueOf(arr[2]);
+ } catch (IllegalArgumentException | IndexOutOfBoundsException e) {
+ throw new RoomShareException(ExceptionType.wrongTimeFormat);
+ }
+
+ }
+
+
+
+ /**
+ * Returns the index of the task and priority the user wants to set it to.
+ * @return the index and priority of the task the user wants to set
+ */
+ public String[] getPriority() {
+ return scanner.nextLine().trim().split(" ", 2);
+ }
+
+ /**
+ * Gets the input and converts it into a sort type.
+ * @param input input of the sort type
+ * @return the input as an enum of sort type
+ * @throws RoomShareException when sort type specified is not valid
+ */
+ public SortType getSort(String input) throws RoomShareException {
+ try {
+ return SortType.valueOf(input.trim());
+ } catch (IllegalArgumentException e) {
+ throw new RoomShareException(ExceptionType.wrongSortFormat);
+ }
+ }
+
+ /**
+ * Closes the scanner used in Parser class.
+ */
+ public void close() {
+ scanner.close();
+ }
+}
diff --git a/src/main/java/Operations/RecurHandler.java b/src/main/java/Operations/RecurHandler.java
new file mode 100644
index 0000000000..3a7547fb70
--- /dev/null
+++ b/src/main/java/Operations/RecurHandler.java
@@ -0,0 +1,130 @@
+package Operations;
+
+import CustomExceptions.RoomShareException;
+import Enums.RecurrenceScheduleType;
+import Model_Classes.Assignment;
+import Model_Classes.Meeting;
+import Model_Classes.Task;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * This class deals with operations for Recurring Tasks.
+ * will perform operations such as add, list, find
+ * also checks for recurrence of tasks
+ */
+public class RecurHandler {
+ public static final String DATE_ERROR_SET_AS_NOT_DONE = "Error in parsing date, will be setting the task "
+ + "to not done instead";
+ private TaskList taskList;
+ private Parser parser = new Parser();
+
+ /**
+ * Constructor for RecurHandler class.
+ * @param recurringList The TaskList to be operated on using RecurHandler
+ */
+ public RecurHandler(TaskList recurringList) {
+ this.taskList = recurringList;
+ }
+
+ /**
+ * Checks for recurrences based on the date.
+ * if there is a recurrence, replaces the old recurring task with a new one
+ * new recurring task will have an updated recurrence date.
+ * Returns a boolean value that determines if there was any recurrence triggered.
+ * @return A boolean value where true indicates a recurrence was triggered, and false being otherwise.
+ */
+ public boolean checkRecurrence() throws RoomShareException {
+ LocalDateTime now = LocalDateTime.now();
+ DateTimeFormatter dateTimeFormatterNow = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
+ String currentTime = now.format(dateTimeFormatterNow);
+ int index = 0;
+ boolean isEdited = false;
+ for (Task check : TaskList.getCurrentList()) {
+ if (check.hasRecurring()) {
+ // task is a recurring task
+ RecurrenceScheduleType type;
+ String description = check.getDescription();
+ type = check.getRecurrenceSchedule();
+ // check if recurrence date has passed
+ if (dateHasPassedOthers(currentTime, check, isEdited)) {
+ if (check instanceof Assignment) {
+ Assignment recurringAssignment = new Assignment(description, getNewDate(check));
+ recurringAssignment.setRecurrenceSchedule(type);
+ recurringAssignment.setPriority(check.getPriority());
+ recurringAssignment.setAssignee(check.getAssignee());
+ taskList.replace(index, recurringAssignment);
+ isEdited = true;
+ } else {
+ Meeting recurringMeeting = new Meeting(description, getNewDate(check));
+ recurringMeeting.setRecurrenceSchedule(type);
+ recurringMeeting.setPriority(check.getPriority());
+ recurringMeeting.setAssignee(check.getAssignee());
+ taskList.replace(index, recurringMeeting);
+ isEdited = true;
+ }
+ }
+ }
+ // move on to next item in the task list
+ index += 1;
+ }
+ return isEdited;
+ }
+
+ /**
+ * Returns a new Date object with the date stored in the task object class
+ * If any error occurs, the Date object will be set to the current date instead.
+ * @param check Task object containing the Date information to be extracted
+ * @return newDate, containing a the date information of the task object class.
+ */
+ private Date getNewDate(Task check) {
+ Date newDate = new Date();
+ try {
+ Calendar calendar = Calendar.getInstance();
+ String date = new Storage().convertForStorage(check);
+ date = date.substring(0, 15);
+ Date storedDate = parser.formatDateDDmmYY(date);
+ calendar.setTime(storedDate);
+ if (check.getRecurrenceSchedule().equals(RecurrenceScheduleType.day)) {
+ calendar.add(Calendar.DAY_OF_MONTH, 1);
+ } else if (check.getRecurrenceSchedule().equals(RecurrenceScheduleType.week)) {
+ calendar.add(Calendar.WEEK_OF_MONTH, 1);
+ } else {
+ calendar.add(Calendar.MONTH, 1);
+ }
+ newDate = calendar.getTime();
+ } catch (RoomShareException e) {
+ System.out.println();
+ }
+ return newDate;
+ }
+
+ /**
+ * checks if the recurrence date has passed for a Meeting or Assignment object
+ * if date has passed, returns true
+ * if date has not passed, returns false.
+ * @param currentTime current time of the system as a string
+ * @param check Task to be time checked
+ * @param isEdited boolean variable describing if the task list has been edited in anyway
+ * @return isPassed boolean variable describing if the recurrence date has been passed.
+ */
+ private boolean dateHasPassedOthers(String currentTime, Task check, boolean isEdited) throws RoomShareException {
+ boolean isPassed = false;
+ try {
+ Date current = parser.formatDateDDmmYY(currentTime);
+ Date newDate = getNewDate(check);
+ if (newDate.compareTo(current) < 0) {
+ // date has passed
+ isPassed = true;
+ }
+ } catch (RoomShareException e) {
+ System.out.println(DATE_ERROR_SET_AS_NOT_DONE);
+ check.setDone(false);
+ isEdited = true;
+ }
+ return isPassed;
+ }
+}
diff --git a/src/main/java/Operations/Storage.java b/src/main/java/Operations/Storage.java
new file mode 100644
index 0000000000..7bba24948b
--- /dev/null
+++ b/src/main/java/Operations/Storage.java
@@ -0,0 +1,353 @@
+package Operations;
+
+import CustomExceptions.RoomShareException;
+import Enums.ExceptionType;
+import Enums.Priority;
+import Enums.RecurrenceScheduleType;
+import Enums.SaveType;
+import Enums.TimeUnit;
+import Model_Classes.Assignment;
+import Model_Classes.Leave;
+import Model_Classes.Meeting;
+import Model_Classes.Task;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+
+/**
+ * Performs storage operations such as writing and reading from a .txt file.
+ */
+public class Storage {
+
+ /**
+ * Constructor for the Storage class.
+ */
+ public Storage() {
+ }
+
+ /**
+ * Returns an ArrayList of Tasks from a .txt file.
+ * Extracts the relevant information from the data.txt file in Duke to create the tasks.
+ * Populates an ArrayList with these created tasks.
+ *
+ * @return taskArrayList An ArrayList of Tasks that is created from the .txt file.
+ * @throws RoomShareException If the file has mistakes in formatting.
+ * Creates and empty task list instead and returns the empty list.
+ */
+ public ArrayList loadFile(String fileName) throws RoomShareException {
+ ArrayList taskArrayList = new ArrayList<>();
+ try {
+ BufferedReader bufferedReader = new BufferedReader(new FileReader(fileName));
+ String line = "";
+ ArrayList tempList = new ArrayList<>();
+ while ((line = bufferedReader.readLine()) != null) {
+ tempList.add(line);
+ }
+ Parser parser = new Parser();
+ for (String list : tempList) {
+ String[] temp = list.split("#");
+
+ if (temp.length > 11) {
+ throw new RoomShareException(ExceptionType.loadError);
+ }
+ // Identify type of task
+ String scanType = temp[0].trim();
+ SaveType type;
+ try {
+ type = SaveType.valueOf(scanType);
+ } catch (IllegalArgumentException e) {
+ type = SaveType.empty;
+ }
+
+ String scanDone = temp[1].trim();
+ boolean done = scanDone.equals("y");
+
+ String scanPriority = temp[2].trim();
+ Priority priority;
+ try {
+ priority = Priority.valueOf(scanPriority);
+ } catch (IllegalArgumentException e) {
+ priority = Priority.low;
+ }
+
+ String description = temp[3].trim();
+
+ Date from = new Date();
+ Date to = new Date();
+ Date date = new Date();
+ if (temp[4].contains("-")) {
+ String[] dateArray = temp[4].trim().split("-");
+ String scanFromDate = dateArray[0].trim();
+ try {
+ from = parser.formatDateDDmmYY(scanFromDate);
+ } catch (RoomShareException e) {
+ System.out.println("error in loading file: date format error");
+ }
+ String scanToDate = dateArray[1].trim();
+ try {
+ to = parser.formatDateDDmmYY(scanToDate);
+ } catch (RoomShareException e) {
+ System.out.println("error in loading file: date format error");
+ }
+ } else {
+ String scanDate = temp[4].trim();
+ try {
+ date = parser.formatDateDDmmYY(scanDate);
+ } catch (RoomShareException e) {
+ System.out.println("error in loading file: date format error");
+ }
+ }
+
+ String scanRecurrence = temp[5].trim();
+ RecurrenceScheduleType recurrence = null;
+ try {
+ recurrence = RecurrenceScheduleType.valueOf(scanRecurrence);
+ } catch (IllegalArgumentException e) {
+ throw new RoomShareException(ExceptionType.loadError);
+ }
+
+ String user = temp[6].trim();
+
+ String scanIsFixedDuration = temp[7].trim();
+ boolean isFixedDuration = scanIsFixedDuration.equals("F");
+
+ String scanDuration = temp[8].trim();
+ int duration = 0;
+ try {
+ duration = Integer.parseInt(scanDuration);
+ } catch (NumberFormatException e) {
+ throw new RoomShareException(ExceptionType.loadError);
+ }
+
+ String scanUnit = temp[9].trim();
+ TimeUnit unit = null;
+ try {
+ unit = TimeUnit.valueOf(scanUnit);
+ } catch (IllegalArgumentException e) {
+ throw new RoomShareException(ExceptionType.loadError);
+ }
+ String scanSubTask = "";
+ if (temp.length > 10) {
+ scanSubTask = temp[10].trim();
+ }
+
+ if (type.equals(SaveType.A)) {
+ // Assignment type
+ Assignment assignment = new Assignment(description, date);
+ assignment.setPriority(priority);
+ assignment.setAssignee(user);
+ assignment.setRecurrenceSchedule(recurrence);
+ assignment.setDone(done);
+ if (!scanSubTask.equals("")) {
+ assignment.addSubTasks(scanSubTask);
+ }
+ taskArrayList.add(assignment);
+ } else if (type.equals(SaveType.L)) {
+ //Leave type
+ Leave leave = new Leave(description, user, from, to);
+ leave.setPriority(priority);
+ leave.setRecurrenceSchedule(recurrence);
+ taskArrayList.add(leave);
+ } else {
+ //Meeting type
+ if (isFixedDuration) {
+ Meeting meeting = new Meeting(description, date, duration, unit);
+ meeting.setPriority(priority);
+ meeting.setAssignee(user);
+ meeting.setRecurrenceSchedule(recurrence);
+ meeting.setDone(done);
+ taskArrayList.add(meeting);
+ } else {
+ Meeting meeting = new Meeting(description, date);
+ meeting.setRecurrenceSchedule(recurrence);
+ meeting.setPriority(priority);
+ meeting.setAssignee(user);
+ meeting.setDone(done);
+ taskArrayList.add(meeting);
+ }
+ }
+ }
+ } catch (IOException | IndexOutOfBoundsException e) {
+ throw new RoomShareException(ExceptionType.wrongFormat);
+ }
+ return (taskArrayList);
+ }
+
+ /**
+ * Rewrites the data.txt file with a task list.
+ * Formats all task information into a style that the loadFile() method is able to understand
+ * Writes all the formatted information into a data.txt file for storage
+ * Will not write any information if the there are mistakes in the ArrayList information.
+ *
+ * @param list ArrayList of Tasks to be stored on data.txt
+ * @throws RoomShareException If there are parsing errors in the ArrayList.
+ */
+ public void writeFile(ArrayList list, String fileName) throws RoomShareException {
+ try {
+ FileWriter fw = new FileWriter(fileName);
+ BufferedWriter writer = new BufferedWriter(fw);
+ for (Task s : list) {
+ String out = "";
+ String type = String.valueOf(s.toString().charAt(1));
+ String isDone = s.getDone() ? "y" : "n";
+ String priority = s.getPriority().toString();
+ String description = s.getDescription();
+ String date = convertForStorage(s);
+ String recurrence = s.getRecurrenceSchedule().toString();
+ String user = s.getAssignee();
+ if (s instanceof Assignment) {
+ out = type + "#" + isDone + "#"
+ + priority + "#" + description + "#"
+ + date + "#" + recurrence + "#"
+ + user + "#" + "N" + "#"
+ + "0" + "#" + "unDefined" + "#";
+ // Saves sub-tasks
+ if (!(((Assignment) s).getSubTasks() == null)) {
+ ArrayList subTasks = ((Assignment) s).getSubTasks();
+ for (String subTask : subTasks) {
+ out += subTask + ",";
+ }
+ }
+ out += "#";
+ } else if (s instanceof Leave) {
+ String leaveDate = convertForStorageLeave(s);
+ out = type + "#" + isDone + "#"
+ + priority + "#" + description + "#"
+ + leaveDate + "#" + recurrence + "#"
+ + user + "#" + "N" + "#"
+ + "0" + "#" + "unDefined" + "#" + "#";
+ } else if (s instanceof Meeting) {
+ if (((Meeting) s).isFixedDuration()) {
+ String duration = ((Meeting) s).getDuration();
+ String unit = ((Meeting) s).getTimeUnit().toString();
+ out = type + "#" + isDone + "#"
+ + priority + "#" + description + "#"
+ + date + "#" + recurrence + "#"
+ + user + "#" + "F" + "#"
+ + duration + "#" + unit + "#" + "#";
+ } else {
+ out = type + "#" + isDone + "#"
+ + priority + "#" + description + "#"
+ + date + "#" + recurrence + "#"
+ + user + "#" + "N" + "#"
+ + "0" + "#" + "unDefined" + "#" + "#";
+ }
+ }
+ writer.write(out);
+ writer.newLine();
+ }
+ writer.close();
+ } catch (IOException | ArrayIndexOutOfBoundsException e) {
+ throw new RoomShareException(ExceptionType.writeError);
+ }
+ }
+
+ /**
+ * Create a new text file and write all information of the current task list to it.
+ * @param list the current task list
+ * @throws RoomShareException when there is an error in writing the log file
+ */
+ public String writeLogFile(ArrayList list) throws RoomShareException {
+ String fileName = "log " + new Date().toString() + ".txt";
+ fileName = fileName.replaceAll(" ", "_").replaceAll(":","_");
+ String filePath = "logs\\" + fileName;
+ String folderName = "logs";
+ try {
+ File file = new File(filePath);
+ File folder = new File(folderName);
+ if (!folder.exists()) {
+ folder.mkdir();
+ }
+ file.createNewFile();
+ PrintWriter writer = new PrintWriter(filePath, StandardCharsets.UTF_8);
+ for (Task t : list) {
+ writer.println(t.toString());
+ }
+ writer.close();
+ } catch (IOException e) {
+ throw new RoomShareException(ExceptionType.logError);
+ }
+ return filePath;
+ }
+
+ /**
+ * Extracts and converts all the information in the task object for storage
+ * will format the time information for meeting and assignment tasks
+ * Additional formatting will be done for recurring tasks to include recurrence schedule
+ * returns a string with all the relevant information.
+ *
+ * @param task task object to be converted
+ * @return time A String containing all the relevant information
+ * @throws RoomShareException If there is any error in parsing the Date information.
+ */
+ public String convertForStorage(Task task) throws RoomShareException {
+ try {
+ String time = "";
+ String[] prelimSplit = task.toString().split("\\(");
+ String[] tempString = prelimSplit[2].split("\\s+");
+ String year = tempString[6].substring(0, tempString[6].length() - 1);
+ Date date = new SimpleDateFormat("MMM").parse(tempString[2]);
+ DateFormat dateFormat = new SimpleDateFormat("MM");
+ String month = dateFormat.format(date);
+ String[] timeArray = tempString[4].split(":", 3);
+ String day = tempString[3];
+ time = day + "/" + month + "/" + year + " " + timeArray[0] + ":" + timeArray[1];
+ return time;
+ } catch (ParseException e) {
+ throw new RoomShareException(ExceptionType.wrongFormat);
+ }
+ }
+
+ /**
+ * Extracts the time information from the leave class object for it to be able
+ * to store in the data file to be saved.
+ *
+ * @param task Task object to be converted.
+ * @return time A string with the correct formatting to be placed in the data file.
+ * @throws RoomShareException If there is any error in parsing the Date information.
+ */
+ public String convertForStorageLeave(Task task) throws RoomShareException {
+ try {
+ String time;
+ String[] prelimSplit = task.toString().split("\\(");
+ String[] tempString = prelimSplit[2].split("\\s+");
+
+ String fromYear = tempString[6].trim();
+ String toYear = tempString[13].trim().substring(0, tempString[13].length() - 1);
+
+ Date fromMonth = new SimpleDateFormat("MMM").parse(tempString[2]);
+ DateFormat dateFormatFromMonth = new SimpleDateFormat("MM");
+ String fromMth = dateFormatFromMonth.format(fromMonth);
+ Date toMonth = new SimpleDateFormat("MMM").parse(tempString[9]);
+ DateFormat dateFormatToMonth = new SimpleDateFormat("MM");
+ String toMth = dateFormatToMonth.format(toMonth);
+
+ String[] fromTimeArray = tempString[4].split(":", 3);
+ String[] toTimeArray = tempString[11].split(":", 3);
+
+ String fromDay = tempString[3];
+ String toDay = tempString[10];
+
+ time = fromDay + "/" + fromMth + "/" + fromYear
+ + " " + fromTimeArray[0] + ":" + fromTimeArray[1] + "-"
+ + toDay + "/" + toMth + "/" + toYear
+ + " " + toTimeArray[0] + ":" + toTimeArray[1];
+ return time;
+ } catch (ParseException e) {
+ throw new RoomShareException(ExceptionType.wrongFormat);
+ }
+ }
+}
+
+
diff --git a/src/main/java/Operations/TaskCreator.java b/src/main/java/Operations/TaskCreator.java
new file mode 100644
index 0000000000..d2d2e76030
--- /dev/null
+++ b/src/main/java/Operations/TaskCreator.java
@@ -0,0 +1,589 @@
+package Operations;
+
+import CustomExceptions.DuplicateException;
+import CustomExceptions.RoomShareException;
+import CustomExceptions.TimeClashException;
+import Enums.ExceptionType;
+import Enums.Priority;
+import Enums.RecurrenceScheduleType;
+import Enums.TimeUnit;
+import Model_Classes.*;
+import javafx.util.Pair;
+
+import java.util.ArrayList;
+import java.util.Date;
+
+public class TaskCreator {
+ private static final String UPDATED_DESCRIPTION_ERROR = "There is a formatting error in your updated description";
+ private static final String DURATION_FORMAT_ERROR = "There's a problem with the duration you've specified, default to no duration";
+ private static final String RECURRENCE_FORMAT_ERROR = "There seems to some mistake in your recurrence entry, will be setting recurrence as none";
+ private static final String STARTING_DATE_FORMAT_ERROR = "Wrong date format, starting date is set default to current date";
+ private static final String ENDING_DATE_FORMAT_ERROR = "Wrong date format, ending date is set default to current date";
+ public static final String PRIORITY_WILL_BE_SET_AS_LOW = "There seems to some mistake in your priority entry, will be setting priority as low";
+ private Parser parser;
+
+ /**
+ * Constructor for a TaskCreator.
+ */
+ public TaskCreator() {
+ parser = new Parser();
+ }
+
+ /**
+ * Extract the task type from the user's input.
+ * @param input user's input
+ * @return the task type
+ * @throws RoomShareException when the task type is invalid
+ */
+ public String extractType(String input) throws RoomShareException {
+ String[] typeArray = input.split("#");
+ String type;
+ if (typeArray.length != 1) {
+ type = typeArray[1].toLowerCase();
+ } else {
+ throw new RoomShareException(ExceptionType.emptyTaskType);
+ }
+ return type;
+ }
+
+ /**
+ * Extract the description of a task from user's input.
+ * @param input user's input
+ * @return the description of the task
+ * @throws RoomShareException when there's no description detected
+ */
+ public String extractDescription(String input) throws RoomShareException {
+ String[] descriptionArray = input.split("\\(");
+ String description;
+ if (descriptionArray.length != 1) {
+ String[] descriptionArray2 = descriptionArray[1].trim().split("\\)");
+ description = descriptionArray2[0].trim();
+ } else {
+ throw new RoomShareException(ExceptionType.emptyDescription);
+ }
+ if (hasSpecialCharacters(description)) {
+ throw new RoomShareException(ExceptionType.invalidInputString);
+ }
+ return description;
+ }
+
+ /**
+ * Extract the priority of a task from user's input.
+ * @param input user's input
+ * @return the priority of the task
+ */
+ public Priority extractPriority(String input) throws RoomShareException {
+ // check for errors in the raw input for misleading characters
+ int count = 0;
+ char[] inputAsChar = input.toCharArray();
+ for (char c: inputAsChar) {
+ if (c == '*') {
+ count++;
+ }
+ }
+ if (count == 1) {
+ throw new RoomShareException(ExceptionType.invalidInputString);
+ }
+ String[] priorityArray = input.split("\\*");
+ Priority priority;
+ if (priorityArray.length != 1) {
+ String inputPriority = priorityArray[1].trim();
+ try {
+ priority = Priority.valueOf(inputPriority);
+ } catch (IllegalArgumentException e) {
+ System.out.println(PRIORITY_WILL_BE_SET_AS_LOW);
+ priority = Priority.low;
+ }
+ } else {
+ priority = Priority.low;
+ }
+ return priority;
+ }
+
+ /**
+ * Extract the date and time of a task from user's input.
+ * @param input user's input
+ * @return the date and time of the task
+ * @throws RoomShareException when there is no date and time detected or the format of date and time is invalid
+ */
+ public ArrayList extractDate(String input) throws RoomShareException {
+ // counts the number of '&' tags to determine if the user input a single date or double dates
+ int count = 0;
+ char[] inputAsChar = input.toCharArray();
+ for (char c: inputAsChar) {
+ if (c == '&') {
+ count++;
+ }
+ }
+ String[] dateArray = input.trim().split("&");
+ ArrayList dates = new ArrayList<>();
+ Date currentDate = new Date();
+ if (count > 0) {
+ if (count <= 2) {
+ try {
+ String dateInput = dateArray[1].trim();
+ Date date;
+ date = parser.formatDate(dateInput);
+ if (date.before(currentDate)) {
+ // the input date is before the current date
+ throw new RoomShareException(ExceptionType.invalidDateError);
+ }
+ dates.add(date);
+ } catch (ArrayIndexOutOfBoundsException a) {
+ throw new RoomShareException(ExceptionType.emptyDate);
+ }
+ } else {
+ String fromInput = dateArray[1].trim();
+ String toInput = dateArray[2].trim();
+ Date from = new Date();
+ Date to = new Date();
+
+ try {
+ from = parser.formatDate(fromInput);
+ dates.add(from);
+ } catch (RoomShareException e) {
+ System.out.println(STARTING_DATE_FORMAT_ERROR);
+ dates.add(currentDate);
+ }
+ try {
+ to = parser.formatDate(toInput);
+ dates.add(to);
+ } catch (RoomShareException e) {
+ System.out.println(ENDING_DATE_FORMAT_ERROR);
+ }
+ if (from.before(currentDate)) {
+ // input date is before the current date
+ throw new RoomShareException(ExceptionType.invalidDateError);
+ }
+ if (to.before(from)) {
+ // the date is before the current date or is before the starting
+ // date of the leave
+ throw new RoomShareException(ExceptionType.invalidDateRange);
+ }
+ }
+ } else {
+ throw new RoomShareException(ExceptionType.emptyDate);
+ }
+ return dates;
+ }
+
+ /**
+ * Extract the assignee of a task from user's input.
+ * @param input user's input
+ * @return the name of the assignee
+ */
+ public String extractAssignee(String input) throws RoomShareException {
+ // check for errors in the raw input for misleading characters
+ int count = 0;
+ char[] inputAsChar = input.toCharArray();
+ for (char c: inputAsChar) {
+ if (c == '@') {
+ count++;
+ }
+ }
+ if (count == 1) {
+ throw new RoomShareException(ExceptionType.invalidInputString);
+ }
+ String[] assigneeArray = input.split("@");
+ String assignee;
+ if (assigneeArray.length != 1) {
+ assignee = assigneeArray[1].trim();
+ } else {
+ assignee = "everyone";
+ }
+ // check for special characters
+ if (hasSpecialCharacters(assignee)) {
+ throw new RoomShareException(ExceptionType.invalidInputString);
+ }
+ return assignee;
+ }
+
+ /**
+ * Extract the recurrence schedule of task from user's input.
+ * @param input user's input
+ * @return the recurrence schedule of the task
+ */
+ public RecurrenceScheduleType extractRecurrence(String input) throws RoomShareException {
+ // check for errors in the raw input for misleading characters
+ int count = 0;
+ char[] inputAsChar = input.toCharArray();
+ for (char c: inputAsChar) {
+ if (c == '%') {
+ count++;
+ }
+ }
+ if (count == 1) {
+ throw new RoomShareException(ExceptionType.invalidInputString);
+ }
+ String[] recurrenceArray = input.split("%");
+ RecurrenceScheduleType recurrence;
+ if (recurrenceArray.length != 1) {
+ try {
+ String inputRecurrence = recurrenceArray[1].trim();
+ recurrence = RecurrenceScheduleType.valueOf(inputRecurrence);
+ } catch (IllegalArgumentException | IndexOutOfBoundsException e) {
+ System.out.println(RECURRENCE_FORMAT_ERROR);
+ recurrence = RecurrenceScheduleType.none;
+ }
+ } else {
+ recurrence = RecurrenceScheduleType.none;
+ }
+
+ return recurrence;
+ }
+
+ /**
+ * Extract the duration of a task from user's input.
+ * @param input user's input
+ * @return the amount of time and unit of the duration as a Pair of Integer and TimeUnit
+ */
+ public Pair extractDuration(String input) throws RoomShareException {
+ // check for errors in the raw input for misleading characters
+ int count = 0;
+ char[] inputAsChar = input.toCharArray();
+ for (char c: inputAsChar) {
+ if (c == '^') {
+ count++;
+ }
+ }
+ if (count == 1) {
+ throw new RoomShareException(ExceptionType.invalidInputString);
+ }
+ String[] durationArray = input.split("\\^");
+ int duration;
+ TimeUnit unit;
+ if (durationArray.length != 1) {
+ try {
+ String[] inputDuration = durationArray[1].split(" ");
+ duration = Integer.parseInt(inputDuration[0].trim());
+ unit = TimeUnit.valueOf(inputDuration[1].trim());
+ } catch (IllegalArgumentException | ArrayIndexOutOfBoundsException e) {
+ System.out.println(DURATION_FORMAT_ERROR);
+ duration = 0;
+ unit = TimeUnit.unDefined;
+ }
+ } else {
+ duration = 0;
+ unit = TimeUnit.unDefined;
+ }
+
+ if (duration < 0) {
+ throw new RoomShareException(ExceptionType.negativeTimeAmount);
+ }
+ return new Pair<>(duration,unit);
+ }
+
+ /**
+ * Checks if input string has special flags used in the input format.
+ * @param input input to be checked
+ * @return a boolean value denoting if the input contains such flags
+ */
+ private boolean hasSpecialCharacters(String input) {
+ boolean isInvalid = false;
+ if (input.contains("#")) {
+ isInvalid = true;
+ } else if (input.contains("@")) {
+ isInvalid = true;
+ } else if (input.contains("!")) {
+ isInvalid = true;
+ } else if (input.contains("*")) {
+ isInvalid = true;
+ } else if (input.contains("^")) {
+ isInvalid = true;
+ } else if (input.contains("%")) {
+ isInvalid = true;
+ } else if (input.contains("&")) {
+ isInvalid = true;
+ } else if (input.contains("(")) {
+ isInvalid = true;
+ }
+ return isInvalid;
+ }
+
+ /**
+ * Extract the reminder flag of a task from user's input.
+ * @param input user's input
+ * @return the reminder flag of the task
+ */
+ public boolean extractReminder(String input) {
+ String[] reminderArray = input.split("!");
+ if (reminderArray.length != 1) {
+ return reminderArray[1].contains("R");
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Create a new task based on the description the user key in.
+ * @param input the description of the task
+ * @return a new Task object created based on the description
+ * @throws RoomShareException when there are some formatting errors
+ */
+ public Task create(String input) throws RoomShareException, DuplicateException, TimeClashException {
+ // extract the Task Type
+ String type = this.extractType(input);
+
+ // extract the priority
+ Priority priority = this.extractPriority(input);
+
+ // extract the description
+ String description = this.extractDescription(input);
+
+ // check for duplicates and time clashes
+ int duplicateCheck;
+ int timeClashCheck;
+
+ // extract date
+ ArrayList dates = this.extractDate(input);
+ Date date = new Date();
+ Date from = new Date();
+ Date to = new Date();
+
+ if (dates.size() == 1) {
+ date = dates.get(0);
+ } else {
+ from = dates.get(0);
+ to = dates.get(1);
+ }
+
+ // extract the assignee
+ String assignee = this.extractAssignee(input);
+
+ // extract recurrence schedule
+ RecurrenceScheduleType recurrence = this.extractRecurrence(input);
+
+ //extract duration
+ Pair durationAndUnit = this.extractDuration(input);
+ int duration = durationAndUnit.getKey();
+
+ TimeUnit unit = durationAndUnit.getValue();
+
+ //extract reminder
+ boolean remind = this.extractReminder(input);
+
+ if (type.equals("assignment")) {
+ Assignment assignment = new Assignment(description, date);
+ assignment.setPriority(priority);
+ assignment.setAssignee(assignee);
+ assignment.setRecurrenceSchedule(recurrence);
+ if (remind) {
+ TaskReminder taskReminder = new TaskReminder(description, duration);
+ taskReminder.start();
+ }
+ duplicateCheck = CheckAnomaly.isDuplicate(assignment);
+ if (duplicateCheck == -1) {
+ return assignment;
+ } else {
+ throw new DuplicateException(duplicateCheck);
+ }
+ } else if (type.equals("leave")) {
+ String user;
+ String[] leaveUserArray = input.split("@");
+ if (leaveUserArray.length != 1) {
+ user = leaveUserArray[1].trim();
+ } else {
+ throw new RoomShareException(ExceptionType.emptyUser);
+ }
+ Leave leave = new Leave(description, user, from, to);
+ leave.setPriority(priority);
+ leave.setRecurrenceSchedule(recurrence);
+ duplicateCheck = CheckAnomaly.isDuplicate(leave);
+ if (duplicateCheck == -1) {
+ return leave;
+ } else {
+ throw new DuplicateException(duplicateCheck);
+ }
+ } else if (type.equals("meeting")) {
+ if (remind) {
+ if (unit.equals(TimeUnit.unDefined)) {
+ // duration was not specified or not correctly input
+ Meeting meeting = new Meeting(description, date);
+ meeting.setPriority(priority);
+ meeting.setAssignee(assignee);
+ meeting.setRecurrenceSchedule(recurrence);
+ TaskReminder taskReminder = new TaskReminder(description, duration);
+ taskReminder.start();
+ duplicateCheck = CheckAnomaly.isDuplicate(meeting);
+ if (duplicateCheck == -1) {
+ timeClashCheck = CheckAnomaly.isTimeClash(meeting);
+ if (timeClashCheck == -1) {
+ return meeting;
+ } else {
+ throw new TimeClashException(timeClashCheck);
+ }
+ } else {
+ throw new DuplicateException(duplicateCheck);
+ }
+
+ } else {
+ Meeting meeting = new Meeting(description, date, duration, unit);
+ meeting.setPriority(priority);
+ meeting.setAssignee(assignee);
+ meeting.setRecurrenceSchedule(recurrence);
+ TaskReminder taskReminder = new TaskReminder(description, duration);
+ taskReminder.start();
+ duplicateCheck = CheckAnomaly.isDuplicate(meeting);
+ if (duplicateCheck == -1) {
+ timeClashCheck = CheckAnomaly.isTimeClash(meeting);
+ if (timeClashCheck == -1) {
+ return meeting;
+ } else {
+ throw new TimeClashException(timeClashCheck);
+ }
+ } else {
+ throw new DuplicateException(duplicateCheck);
+ }
+ }
+ } else {
+ if (unit.equals(TimeUnit.unDefined)) {
+ // duration was not specified or not correctly input
+ Meeting meeting = new Meeting(description, date);
+ meeting.setPriority(priority);
+ meeting.setAssignee(assignee);
+ meeting.setRecurrenceSchedule(recurrence);
+ duplicateCheck = CheckAnomaly.isDuplicate(meeting);
+ if (duplicateCheck == -1) {
+ timeClashCheck = CheckAnomaly.isTimeClash(meeting);
+ if (timeClashCheck == -1) {
+ return meeting;
+ } else {
+ throw new TimeClashException(timeClashCheck);
+ }
+ } else {
+ throw new DuplicateException(duplicateCheck);
+ }
+ } else {
+ Meeting meeting = new Meeting(description, date, duration, unit);
+ meeting.setPriority(priority);
+ meeting.setAssignee(assignee);
+ meeting.setRecurrenceSchedule(recurrence);
+ duplicateCheck = CheckAnomaly.isDuplicate(meeting);
+ if (duplicateCheck == -1) {
+ timeClashCheck = CheckAnomaly.isTimeClash(meeting);
+ if (timeClashCheck == -1) {
+ return meeting;
+ } else {
+ throw new TimeClashException(timeClashCheck);
+ }
+ } else {
+ throw new DuplicateException(duplicateCheck);
+ }
+ }
+ }
+ } else {
+ throw new RoomShareException(ExceptionType.wrongTaskType);
+ }
+ }
+
+ /**
+ * Update a task from the task list according to the user's input.
+ * @param input user's input
+ * @param oldTask the task to be updated
+ */
+ public void updateTask(String input, Task oldTask) throws RoomShareException {
+ boolean isNotUpdated = true;
+ boolean isSetToEveryone = false;
+ try {
+ if (input.contains("(") && input.contains(")")) {
+ String description = this.extractDescription(input);
+ oldTask.setDescription(description);
+ isNotUpdated = false;
+ }
+ } catch (RoomShareException e) {
+ System.out.println(UPDATED_DESCRIPTION_ERROR);
+ }
+
+ if (input.contains("&")) {
+ ArrayList dates = extractDate(input);
+ if (oldTask instanceof Leave && dates.size() == 2) {
+ Leave oldLeave = (Leave) oldTask;
+ Date start = dates.get(0);
+ Date end = dates.get(1);
+ oldLeave.setDate(start);
+ oldLeave.setStartDate(start);
+ oldLeave.setEndDate(end);
+ isNotUpdated = false;
+ } else {
+ Date date = dates.get(0);
+ if (oldTask instanceof Leave) {
+ Leave oldLeave = (Leave)oldTask;
+ oldLeave.setEndDate(date);
+ isNotUpdated = false;
+ } else {
+ oldTask.setDate(date);
+ isNotUpdated = false;
+ }
+ }
+ }
+
+ if (input.contains("*")) {
+ Priority priority = this.extractPriority(input);
+ oldTask.setPriority(priority);
+ isNotUpdated = false;
+ }
+
+ if (input.contains("@")) {
+ String assignee = null;
+ try {
+ assignee = this.extractAssignee(input);
+ } catch (RoomShareException e) {
+ assignee = "everyone";
+ }
+ if (assignee.equals("everyone")) {
+ isSetToEveryone = true;
+ }
+ oldTask.setAssignee(assignee);
+ if (oldTask instanceof Leave) {
+ Leave oldLeave = (Leave) oldTask;
+ oldLeave.setUser(assignee);
+ }
+ isNotUpdated = false;
+ }
+
+ if (input.contains("^") && oldTask instanceof Meeting) {
+ Pair durationAndUnit = this.extractDuration(input);
+ int duration = durationAndUnit.getKey();
+ TimeUnit unit = durationAndUnit.getValue();
+ Meeting oldMeeting = (Meeting) oldTask;
+ oldMeeting.setDuration(duration,unit);
+ isNotUpdated = false;
+ }
+
+ if (input.contains("%")) {
+ RecurrenceScheduleType recurrence = this.extractRecurrence(input);
+ oldTask.setRecurrenceSchedule(recurrence);
+ isNotUpdated = false;
+ }
+
+ // check if any field was updated at all
+ if (isNotUpdated) {
+ throw new RoomShareException(ExceptionType.invalidInputString);
+ }
+
+ if (isSetToEveryone) {
+ throw new RoomShareException(ExceptionType.assigneeSetToEveyone);
+ }
+ }
+
+ /**
+ * Updates the date of the overdue task.
+ *
+ * @param input user's input of the date
+ * @param overdueTask the task which date needs to be updated
+ */
+ public void rescheduleTask(String input, Task overdueTask) throws RoomShareException {
+ ArrayList dates = this.extractDate(input);
+ if (overdueTask instanceof Leave && dates.size() == 2) {
+ Leave oldLeave = (Leave) overdueTask;
+ Date start = dates.get(0);
+ Date end = dates.get(1);
+ oldLeave.setDate(start);
+ oldLeave.setStartDate(start);
+ oldLeave.setEndDate(end);
+ } else {
+ Date date = dates.get(0);
+ overdueTask.setDate(date);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/Operations/TaskList.java b/src/main/java/Operations/TaskList.java
new file mode 100644
index 0000000000..1da2121bc1
--- /dev/null
+++ b/src/main/java/Operations/TaskList.java
@@ -0,0 +1,557 @@
+package Operations;
+
+import CustomExceptions.RoomShareException;
+import Enums.ExceptionType;
+import Enums.Priority;
+import Enums.SortType;
+import Enums.TimeUnit;
+import Model_Classes.Assignment;
+import Model_Classes.Leave;
+import Model_Classes.Meeting;
+import Model_Classes.Task;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+
+/**
+ * A class to perform operations on the task list in Duke.
+ */
+public class TaskList {
+ private static final String COMPLETED_TASKS = "Completed Tasks:";
+ private static final String NO_SEARCH_RESULTS_TRY_ANOTHER_KEYWORD
+ = " Your search returned no results.... Try searching with another keyword!";
+ private static ArrayList tasks;
+ private static SortType sortType = SortType.priority;
+
+ /**
+ * Constructor for the TaskList class.
+ * takes in an ArrayList as the list of tasks to be operated on.
+ * @param tasks ArrayList of Task objects to be operated on.
+ */
+ public TaskList(ArrayList tasks) {
+ TaskList.tasks = tasks;
+ }
+
+ /**
+ * Adds a new task into the task list.
+ * @param newTask Task object to be added into the list of tasks
+ */
+ public void add(Task newTask) {
+ tasks.add(newTask);
+ sortTasks();
+ }
+
+ /**
+ * Deletes a task from the list. Task to be deleted is specified by the index that is input into this method
+ * Will not perform any operations if the index does not exist in the list.
+ * @param index Index of task in the list to be deleted
+ * @param deletedList temporary storage list for the deleted items so they can be restored
+ * @throws RoomShareException If the index cannot be found in the list of tasks.
+ */
+ public void delete(int[] index, TempDeleteList deletedList) throws RoomShareException {
+ int[] idx = index.clone();
+ if (idx.length == 1) {
+ boolean isNegativeIndex = idx[0] < 0;
+ boolean isExceededIndex = idx[0] >= tasks.size();
+ if (isNegativeIndex || isExceededIndex) {
+ throw new RoomShareException(ExceptionType.outOfBounds);
+ }
+ deletedList.add(tasks.get(idx[0]));
+ tasks.remove(idx[0]);
+ } else {
+ boolean isNegativeFirstIndex = idx[0] < 0;
+ boolean isExceededFirstIndex = idx[0] >= tasks.size();
+ boolean isNegativeSecondIndex = idx[1] < 0;
+ boolean isExceededSecondIndex = idx[1] >= tasks.size();
+ if (isNegativeFirstIndex || isExceededFirstIndex
+ || isNegativeSecondIndex || isExceededSecondIndex) {
+ throw new RoomShareException(ExceptionType.outOfBounds);
+ }
+ for (int i = idx[0]; idx[1] >= idx[0]; idx[1]--) {
+ deletedList.add(tasks.get(i));
+ tasks.remove(i);
+ }
+ }
+ }
+
+ /**
+ * Lists out all tasks in the current list in the order they were added into the list.
+ * shows all information related to the tasks
+ * hides completed tasks
+ * @throws RoomShareException when the list is empty
+ */
+ public void list(OverdueList overdueList) throws RoomShareException {
+ sortTasks();
+ if (tasks.size() != 0) {
+ int listCount = 1;
+ checkForOverdueTasks(overdueList);
+ checkForFinishedLeave();
+ for (Task output : tasks) {
+ if (!output.getDone() && !output.getOverdue()) {
+ String priorityLvl = indicatePriorityLevel(output);
+ System.out.println("\t" + listCount + ". " + output.toString() + priorityLvl);
+ showSubtasks(output);
+ }
+ listCount += 1;
+ }
+ } else {
+ throw new RoomShareException(ExceptionType.emptyList);
+ }
+ }
+
+ /**
+ * Lists out completed tasks in the list.
+ * @throws RoomShareException when there are no completed tasks
+ */
+ public void showCompleted() throws RoomShareException {
+ sortTasks();
+ System.out.println(COMPLETED_TASKS);
+ if (tasks.size() != 0) {
+ int listCount = 1;
+ for (Task output : tasks) {
+ if (output.getDone()) {
+ System.out.println("\t" + listCount + ". " + output.toString());
+ showSubtasks(output);
+ }
+ listCount += 1;
+ }
+ } else {
+ throw new RoomShareException(ExceptionType.emptyList);
+ }
+ }
+
+ /**
+ * Sets a task in the list as 'done' to mark that the user has completed the task.
+ * Will not perform any operations if the index does not exist in the list.
+ * @param index Index of the task to be marked as done.
+ * @throws RoomShareException If the index cannot be found in the list of tasks.
+ */
+ public void done(int[] index) throws RoomShareException {
+ if (index.length == 1) {
+ boolean isNegativeIndex = index[0] < 0;
+ boolean isExceededIndex = index[0] >= tasks.size();
+ if (isNegativeIndex || isExceededIndex) {
+ throw new RoomShareException(ExceptionType.outOfBounds);
+ }
+ tasks.get(index[0]).setDone(true);
+ } else {
+ boolean isNegativeFirstIndex = index[0] < 0;
+ boolean isExceededFirstIndex = index[0] >= tasks.size();
+ boolean isNegativeSecondIndex = index[1] < 0;
+ boolean isExceededSecondIndex = index[1] >= tasks.size();
+ if (isNegativeFirstIndex || isExceededFirstIndex
+ || isNegativeSecondIndex || isExceededSecondIndex) {
+ throw new RoomShareException(ExceptionType.outOfBounds);
+ }
+ for (int i = index[0]; i <= index[1]; i++) {
+ tasks.get(i).setDone(true);
+ }
+ }
+ }
+
+ /**
+ * Set a subtask from an assignment as done.
+ * @param input the String containing the index of the Assignment and subtask
+ * @throws RoomShareException if there are formatting error or the task entered is not an Assignment
+ */
+ public void doneSubTask(String input) throws RoomShareException {
+ int index;
+ int subTaskIndex;
+ try {
+ String[] arr = input.split(" ");
+ index = Integer.parseInt(arr[1]) - 1;
+ subTaskIndex = Integer.parseInt(arr[2]) - 1;
+ if (TaskList.get(index) instanceof Assignment) {
+ ((Assignment) TaskList.get(index)).doneSubtask(subTaskIndex);
+ } else {
+ throw new RoomShareException(ExceptionType.subTaskError);
+ }
+ } catch (IndexOutOfBoundsException | IllegalArgumentException e1) {
+ throw new RoomShareException(ExceptionType.wrongIndexFormat);
+ }
+ }
+
+ /**
+ * Searches for tasks that has the specified keyword and prints them to the console.
+ * Will prompt that the search has no results if keyword does not exist in the list.
+ * @param key Keyword of the search.
+ */
+ public void find(String key) {
+ int queryCount = 1;
+ for (Task query : tasks) {
+ if (query.toString().toLowerCase().contains(key.trim())) {
+ String priorityLevel = indicatePriorityLevel(query);
+ System.out.println("\t" + queryCount + ". " + query.toString() + priorityLevel);
+ showSubtasks(query);
+ queryCount += 1;
+ }
+ }
+ if (queryCount == 1) {
+ System.out.println(NO_SEARCH_RESULTS_TRY_ANOTHER_KEYWORD);
+ }
+ }
+
+ /**
+ * Returns the entire ArrayList of tasks.
+ * @return tasks The ArrayList of Task objects that is being operated on.
+ */
+ public static ArrayList getCurrentList() {
+ return tasks;
+ }
+
+ /**
+ * replaces the task at the specified index with a new task.
+ * @param index index of the task to be replaced
+ * @param replacement the replacement task
+ */
+ public void replace(int index, Task replacement) {
+ tasks.set(index, replacement);
+ }
+
+ /**
+ * Sets priority of task at an index to a new priority.
+ * @param info the information of the task index and the priority it should be set to
+ * @throws RoomShareException when the priority specified is wrong or index is out of bounds
+ */
+ public void setPriority(String[] info) throws RoomShareException {
+ try {
+ int index = Integer.parseInt(info[0]) - 1;
+ Priority priority = Priority.valueOf(info[1]);
+ tasks.get(index).setPriority(priority);
+ } catch (IllegalArgumentException a) {
+ throw new RoomShareException(ExceptionType.wrongPriority);
+ } catch (IndexOutOfBoundsException i) {
+ throw new RoomShareException(ExceptionType.outOfBounds);
+ }
+
+ }
+
+ /**
+ * Returns priority of the task in the form of an integer.
+ * high = 0, medium = 1, low = 2
+ * @param t task in which we are checking the value of
+ * @return integer value of the task's priority
+ */
+ private static int getValue(Task t) {
+ if (t.getPriority().equals(Priority.high)) {
+ return 0;
+ } else if (t.getPriority().equals(Priority.medium)) {
+ return 1;
+ } else {
+ return 2;
+ }
+ }
+
+ /**
+ * Changes taskList sort mode.
+ * @param sortType new sort mode
+ */
+ public static void changeSort(SortType sortType) {
+ TaskList.sortType = sortType;
+ sortTasks();
+ }
+
+ /**
+ * Sorts the list based on current sort mode.
+ * @throws IllegalArgumentException when the sort type is not of priority, alphabetical or by deadline
+ */
+ public static void sortTasks() {
+ switch (sortType) {
+ case priority:
+ comparePriority();
+ break;
+ case alphabetical:
+ compareAlphabetical();
+ break;
+ case deadline:
+ compareDeadline();
+ break;
+ case type:
+ compareType();
+ break;
+ default:
+ throw new IllegalStateException("Unexpected value: " + sortType);
+ }
+ }
+
+ /**
+ * Compare tasks based on priority.
+ */
+ private static void comparePriority() {
+ tasks.sort((task1, task2) -> {
+ if (task1.getDone() && !task2.getDone()) {
+ return 1;
+ } else if (task2.getDone() && !task1.getDone()) {
+ return -1;
+ } else {
+ return getValue(task1) - getValue(task2);
+ }
+ });
+ }
+
+ /**
+ * Compare tasks based on Alphabetical order.
+ */
+ private static void compareAlphabetical() {
+ tasks.sort((task1, task2) -> {
+ if (task1.getDone() && !task2.getDone()) {
+ return 1;
+ } else if (task2.getDone() && !task1.getDone()) {
+ return -1;
+ } else {
+ String name1 = task1.getDescription();
+ String name2 = task2.getDescription();
+ return name1.compareTo(name2);
+ }
+ });
+ }
+
+ /**
+ * Compare tasks based on Deadline.
+ */
+ private static void compareDeadline() {
+ tasks.sort((task1, task2) -> {
+ if (task1.getDone() && !task2.getDone()) {
+ return 1;
+ } else if (task2.getDone() && !task1.getDone()) {
+ return -1;
+ } else {
+ Date date1 = task1.getDate();
+ Date date2 = task2.getDate();
+ return (int) (date1.getTime() - date2.getTime());
+ }
+ });
+ }
+
+ /**
+ * Compare tasks based on Type.
+ */
+ private static void compareType() {
+ tasks.sort((task1, task2) -> {
+ if (task1 instanceof Meeting && !(task2 instanceof Meeting)) {
+ return -1;
+ } else if (task1 instanceof Assignment) {
+ if (task2 instanceof Meeting) {
+ return 1;
+ } else if (task2 instanceof Leave) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } else {
+ if (task2 instanceof Meeting || task2 instanceof Assignment) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ });
+ }
+
+ /**
+ * Reorder the positions of two tasks inside the task list.
+ * @param first the first task
+ * @param second the second task
+ */
+ public void reorder(int first, int second) throws RoomShareException {
+ try {
+ Collections.swap(tasks, first, second);
+ } catch (IndexOutOfBoundsException e) {
+ throw new RoomShareException(ExceptionType.outOfBounds);
+ }
+ }
+
+ /**
+ * Snooze a specific task indicated by user.
+ * @param index the index of the task to be snoozed
+ * @param amount the amount of time to snooze
+ * @param timeUnit unit for snooze time: month, day, hour, minute
+ * @throws IndexOutOfBoundsException when the specified index is not within the task list indices
+ */
+ public void snooze(int index, int amount, TimeUnit timeUnit) throws RoomShareException {
+ try {
+ switch (timeUnit) {
+ case month:
+ tasks.get(index).snoozeMonth(amount);
+ break;
+ case day:
+ tasks.get(index).snoozeDay(amount);
+ break;
+ case hours:
+ tasks.get(index).snoozeHour(amount);
+ break;
+ case minutes:
+ tasks.get(index).snoozeMinute(amount);
+ break;
+ default:
+ tasks.get(index).snoozeMinute(0);
+ break;
+ }
+ } catch (IndexOutOfBoundsException e) {
+ throw new RoomShareException(ExceptionType.outOfBounds);
+ }
+ }
+
+ /**
+ * Get the number of tasks inside the task list.
+ * @return the number of tasks inside the task list
+ */
+ int getSize() {
+ int count = 0;
+ for (Task t : tasks) {
+ if (!t.getOverdue() && !(t instanceof Leave)) {
+ count += 1;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Get the number of completed tasks inside the task list.
+ * @return the number of completed tasks inside the task list
+ */
+ int getDoneSize() {
+ int count = 0;
+ for (Task t: tasks) {
+ if (t.getDone() && !t.getOverdue() && !(t instanceof Leave)) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Retrieve a task from the list.
+ * @param index the index of the task
+ * @return the task at the specified index of the task list
+ * @throws RoomShareException when the index specified is out of bounds
+ */
+ public static Task get(int index) throws RoomShareException {
+ try {
+ return tasks.get(index);
+ } catch (IndexOutOfBoundsException e) {
+ throw new RoomShareException(ExceptionType.outOfBounds);
+ }
+ }
+
+ /**
+ * Returns current sort type of list.
+ * @return current sort type of list
+ */
+ static SortType getSortType() {
+ return sortType;
+ }
+
+ /**
+ * lists out all the tasks associated with a certain assignee.
+ * will include tasks that are tagged "everyone", since everyone includes the assignee
+ * @param user assignee to the tasks
+ * @throws RoomShareException when the list is empty
+ */
+ public int[] listTagged(String user) throws RoomShareException {
+ int listCount = 1;
+ int belongCount = 0;
+ int doneCount = 0;
+ for (Task output : tasks) {
+ boolean isSameUser = output.getAssignee().equals(user);
+ boolean isEveryone = output.getAssignee().equals("everyone");
+ if (isSameUser || isEveryone) {
+ belongCount += 1;
+ if (output.getDone()) {
+ doneCount += 1;
+ }
+ if (!output.getDone() && !output.getOverdue()) {
+ String priorityLvl = indicatePriorityLevel(output);
+ System.out.println("\t" + listCount + ". " + output.toString() + priorityLvl);
+ showSubtasks(output);
+ }
+ listCount += 1;
+ }
+ }
+ if (belongCount == 0) {
+ throw new RoomShareException(ExceptionType.emptyList);
+ }
+ return new int[]{belongCount, doneCount};
+ }
+
+ /**
+ * sets the tasks which are done to an undone state.
+ * @param index index of task
+ * @param date date the new deadline of the task
+ * @throws RoomShareException when the task selected is a Leave
+ */
+ public void reopen(int index, Date date) throws RoomShareException {
+ TaskList.get(index).setDate(date);
+ CheckAnomaly.isDuplicate(TaskList.get(index));
+ if (tasks.get(index) instanceof Meeting) {
+ CheckAnomaly.isTimeClash(TaskList.get(index));
+ }
+ TaskList.get(index).setDone(false);
+ }
+
+ /**
+ * checks for overdue tasks in the task list.
+ * removes from the current list if overdue, and adds it into the overdue list
+ * @param overdueList overdue list to be added into
+ */
+ private void checkForOverdueTasks(OverdueList overdueList) {
+ for (int i = 0; i < tasks.size(); i++) {
+ boolean isPassedCurrentDate = new Date().after(tasks.get(i).getDate());
+ boolean isNotALeave = !(tasks.get(i) instanceof Leave);
+ if (isPassedCurrentDate && isNotALeave) {
+ tasks.get(i).setOverdue(true);
+ boolean hasNoDuplicateOverdue = !CheckAnomaly.isDuplicateOverdue(tasks.get(i));
+ if (hasNoDuplicateOverdue) {
+ // no duplicates in overdue list
+ overdueList.add(tasks.get(i));
+ }
+ tasks.remove(tasks.get(i));
+ }
+ }
+ }
+
+ /**
+ * checks for finished leave in the task list.
+ * removes the finished leave if detected
+ */
+ private void checkForFinishedLeave() {
+ for (int i = 0; i < tasks.size(); i++) {
+ if (tasks.get(i) instanceof Leave && ((Leave) tasks.get(i)).getEndDate().before(new Date())) {
+ tasks.remove(tasks.get(i));
+ }
+ }
+ }
+
+ /**
+ * Shows the priority level of the task as String.
+ * number of stars indicates the priority level
+ * @param task task to be checked for priority level
+ * @return String containing the number of stars as the priority level
+ */
+ private String indicatePriorityLevel(Task task) {
+ Priority priority = task.getPriority();
+ String priorityLvl;
+ if (priority.equals(Priority.low)) {
+ priorityLvl = " *";
+ } else if (priority.equals(Priority.medium)) {
+ priorityLvl = " **";
+ } else {
+ priorityLvl = " ***";
+ }
+ return priorityLvl;
+ }
+
+ /**
+ * lists out the subtasks if the task is an Assignment.
+ * @param task task to be checked for subtasks.
+ */
+ private void showSubtasks(Task task) {
+ if (task instanceof Assignment && (((Assignment) task).getSubTasks() != null)) {
+ ArrayList subTasks = ((Assignment) task).getSubTasks();
+ for (String subtask : subTasks) {
+ System.out.println("\t" + "\t" + "- " + subtask);
+ }
+ }
+ }
+}
diff --git a/src/main/java/Operations/TempDeleteList.java b/src/main/java/Operations/TempDeleteList.java
new file mode 100644
index 0000000000..c4ea54e9fa
--- /dev/null
+++ b/src/main/java/Operations/TempDeleteList.java
@@ -0,0 +1,72 @@
+package Operations;
+
+import CustomExceptions.RoomShareException;
+import Enums.ExceptionType;
+import Model_Classes.Assignment;
+import Model_Classes.Task;
+
+import java.util.ArrayList;
+
+public class TempDeleteList {
+ private ArrayList tempDelete;
+
+ /**
+ * Constructor for the TempDeleteList Class.
+ * Takes in an ArrayList of Task objects as a parameter
+ * @param tempDelete ArrayList of Task objects to be operated on
+ */
+ public TempDeleteList(ArrayList tempDelete) {
+ this.tempDelete = tempDelete;
+ }
+
+ /**
+ * Adds a Task to the temporary deleted list.
+ * @param task Task that was deleted from the main list and
+ * has to be added into the temp delete list
+ */
+ public void add(Task task) {
+ tempDelete.add(task);
+ }
+
+ /**
+ * Restores a Task from the temp delete list into the main list.
+ * ALso removes the Task from the temp delete list
+ * if index is not valid, will show the temp delete list to help the
+ * user see the deleted items
+ * @param index index of the task in the temp delete list that is being restored
+ * @param taskList the main list to add the restored task back into
+ * @throws RoomShareException if the index entered is not valid
+ */
+ public void restore(int index, TaskList taskList) throws RoomShareException {
+ if (index < 0 || index > tempDelete.size() - 1) {
+ System.out.println("This are your tasks in the temp delete list");
+ list();
+ throw new RoomShareException(ExceptionType.outOfBounds);
+ } else {
+ taskList.add(tempDelete.get(index));
+ this.tempDelete.remove(index);
+ }
+ }
+
+ /**
+ * lists the tasks in the temp delete list.
+ * @throws RoomShareException when the list is empty
+ */
+ public void list() throws RoomShareException {
+ if (tempDelete.size() == 0) {
+ throw new RoomShareException(ExceptionType.emptyList);
+ } else {
+ int listCount = 1;
+ for (Task output : tempDelete) {
+ System.out.println("\t" + listCount + ". " + output.toString());
+ if (output instanceof Assignment && (((Assignment) output).getSubTasks() != null)) {
+ ArrayList subTasks = ((Assignment) output).getSubTasks();
+ for (String subtask : subTasks) {
+ System.out.println("\t" + "\t" + "-" + subtask);
+ }
+ }
+ listCount += 1;
+ }
+ }
+ }
+}
diff --git a/src/main/java/Operations/Ui.java b/src/main/java/Operations/Ui.java
new file mode 100644
index 0000000000..c4afb665c0
--- /dev/null
+++ b/src/main/java/Operations/Ui.java
@@ -0,0 +1,366 @@
+package Operations;
+
+import Enums.SortType;
+import Enums.TimeUnit;
+
+import java.io.IOException;
+
+/**
+ * Class to tell user about errors and completion of operations.
+ */
+public class Ui {
+ /**
+ * Constructor for Ui class.
+ */
+ public Ui() {
+ }
+
+ /**
+ * Shows the startup logo for RoomShare.
+ */
+ public void startUp() {
+ String logo = " &@\n"
+ + " #@&@@.\n"
+ + " #&& .@@,\n"
+ + " %&& %@,\n"
+ + " #@&@% %@#\n"
+ + " %&& @@@&&&&.\n"
+ + " &&& @@##/ @@@@@#\n"
+ + " (@ .@& .@@. &@@.\n"
+ + " /@% (@( * \n"
+ + " @@* #@%\n"
+ + " #@, @@#\n"
+ + " /* *@@\n"
+ + " %@. @@.\n"
+ + " #@@@&@*\n";
+ System.out.println("Hello from RoomShare!\n" + logo);
+ System.out.println("Enter 'help' if you require assistance");
+ }
+
+ /**
+ * Shows the list of help commands.
+ */
+ public void helpList() {
+ System.out.println("Here are a list of commands you can input: "
+ + "\n add "
+ + "\n list "
+ + "\n update "
+ + "\n done "
+ + "\n delete "
+ + "\n find "
+ + "\n snooze "
+ + "\n sort "
+ + "\n subtask "
+ + "\n restore "
+ + "\n priority "
+ + "\n reorder "
+ + "\n completed "
+ + "\n overdue "
+ + "\n reschedule "
+ + "\n show "
+ + "\n removeoverdue "
+ + "\n log "
+ + "\n bye \n"
+ + "For more information about a specific command you can \n"
+ + "Enter help followed by a command, eg. help add\n");
+ }
+
+ void helpAdd() {
+ System.out.println("Adds a Meeting or Assignment to the list\n");
+ System.out.println("You must specify the description, type of task, and time of the task");
+ System.out.println("Each field has a particular format of entry\n");
+ System.out.println("Type of task must be either meeting or assignment, wrapped in '#'\n"
+ + "\te.g #meeting# # assignment#\n");
+ System.out.println("Description must be wrapped in parentheses\n "
+ + "\te.g (description)\n");
+ System.out.println("Priority must be either high medium or low, wrapped in asterisks '*'\n "
+ + "\te.g *low*\n");
+ System.out.println("Time must be specified, wrapped in '&'\n"
+ + "\te.g &22/12/2019 18:00& &this friday 13:00& &next monday 14:00& &tmr 16:00&\n");
+ System.out.println("If time isn't specified, then the duration of the task must at least be specified\n");
+ System.out.println("Duration can be specified by wrapping in '^', "
+ + "in terms of number of hours or number of minutes");
+ System.out.println("\te.g ^2 hours^ ^1 minutes^\n");
+ System.out.println("Recurrence of the task can be specified by wrapping either days, weeks or months"
+ + "\nin '%'\n\te.g %day% %week% %month%\n");
+ System.out.println("Task can also be assigned to a name, by wrapping the name in '@'\n"
+ + "\te.g @Alice@\n");
+ System.out.println("You must specify the task type, description, and either time or duration");
+ System.out.println("The rest of the fields can still be changed later using other commands");
+ }
+
+ void helpDelete() {
+ System.out.println("Deletes the tasks in the index or the specified range");
+ System.out.println("\te.g delete 1");
+ System.out.println("\te.g delete 3 - 5");
+ }
+
+ void helperList() {
+ System.out.println("Shows the list of task that are currently in the Task list");
+ System.out.println("\teg. list");
+ }
+
+ void helpDone() {
+ System.out.println("Marks the specified task as done/completed");
+ System.out.println("\teg. done 1");
+ System.out.println("\teg. done 2 - 4");
+ }
+
+ void helpRestore() {
+ System.out.println("Restores a deleted task back into the task list based on its index");
+ System.out.println("\teg. restore 2");
+ }
+
+ void helpFind() {
+ System.out.println("Finds tasks in the task list based on keyword specified");
+ System.out.println("\teg. find maths");
+ System.out.println("\treturns all tasks that contains the 'maths' keyword");
+ }
+
+ void helpPriority() {
+ System.out.println("Changes the priority of the specified task");
+ System.out.println("\t3 levels of priority: 1 (High), 2 (Medium), 3 (Low)");
+ System.out.println("\teg. priority 1");
+ System.out.println("\tThis changes the priority of the task to high");
+ }
+
+ void helpSnooze() {
+ System.out.println("Snoozes a task for a specified amount of time");
+ System.out.println("Different time units include: hours, minutes");
+ System.out.println("\teg. snooze 1 2 hours");
+ System.out.println("\tThis snoozes task 1 for a period of 2 hours");
+ }
+
+ void helpReorder() {
+ System.out.println("Reorder 2 different tasks in the task list");
+ System.out.println("\teg. reorder 1 3");
+ System.out.println("\tThis will swap the order task 1 and task 3");
+ }
+
+
+ void helpSubtask() {
+ System.out.println("Adds subtasks to an assignment task type");
+ System.out.println("\teg. subtask 3 subtask1, subtask2");
+ System.out.println("\tThis will add 2 subtasks to the task at index 3, subtask1 and subtask2");
+ }
+
+ void helpUpdate() {
+ System.out.println("Updates the task details");
+ System.out.println("Fields that are updatable: ");
+ System.out.println("\tDescription: (new_description)");
+ System.out.println("\tDate Time: &20/09/2019 20:00&");
+ System.out.println("\tPriority: *high*");
+ System.out.println("\tDuration: ^3 hours^");
+ System.out.println("\tRecurrence: %day%");
+ System.out.println("\tAssignee: @joel@");
+ }
+
+ void helpSort() {
+ System.out.println("Sorts the tasks in the task list based on, deadline, priority and alphabetical order");
+ System.out.println("\teg. sort deadline");
+ System.out.println("\tThis will sort the tasks in the task list by their deadlines");
+ }
+
+ void helpLog() {
+ System.out.println("Logs the current task list into a saved file");
+ }
+
+ public void helpRemoveoverdue() {
+ System.out.println("Remove tasks from the overdue list if you do not want to reschedule it");
+ System.out.println("\teg. removeoverdue 2");
+ }
+
+ public void helpBye() {
+ System.out.println("Typing in 'bye' will exit the program");
+ }
+
+ public void helpCompleted() {
+ System.out.println("Shows the list of completed tasks");
+ }
+
+ public void helpOverdue() {
+ System.out.println("Shows the list of overdued tasks");
+ }
+
+ public void helpReschedule() {
+ System.out.println("Reschedules an overdued task by index to a later date by inputting a new date");
+ System.out.println("\teg. reschedule 1 &20/11/2019 10:00&");
+ System.out.println("This will reschedule the tasks specified by their index to the new date");
+ }
+
+ public void helpShow() {
+ System.out.println("Shows you the task tagged to each user in the task list");
+ System.out.println("\teg. show kelly");
+ System.out.println("This will list all the tasks assigned to kelly and everyone");
+ System.out.println("To show deleted tasks, you can type in 'show deleted'");
+ System.out.println("\te.g show deleted");
+ }
+
+ public void helpReopen() {
+ System.out.println("Re-opens a completed task from the completed task list");
+ System.out.println("\teg. reopen 6 &tmr 18:00&");
+ System.out.println("This will re-open the task at index 6 and with the specified date");
+ }
+
+ /**
+ * Prints a message telling the user that the task at the index has been deleted.
+ *
+ * @param index Index of task to be deleted.
+ */
+ public void showDeleted(int[] index) {
+ if (index.length == 1) {
+ System.out.println("Deleted task number " + (index[0] + 1) + "!");
+ } else {
+ System.out.println("Deleted task number " + (index[0] + 1) + " to " + (index[1] + 1) + " !");
+ }
+ }
+
+ /**
+ * Tells the user that the search operation is executing.
+ */
+ public void showFind() {
+ System.out.println("Searching for item in task list...");
+ }
+
+ /**
+ * Tells the user that the task of index has been done and the list has been updated.
+ */
+ public void showDone() {
+ System.out.println("Completed task! Your task list has been updated");
+ }
+
+ /**
+ * tells the user that a task has been added into the list.
+ */
+ public void showAdd() {
+ System.out.println("Your task has been added into the list!");
+ }
+
+ /**
+ * tells the user goodbye.
+ */
+ public void showBye() {
+ System.out.println("Goodbye!");
+ }
+
+ /**
+ * tells the user that RoomShare is listing the tasks.
+ */
+ void showList() {
+ System.out.println("Listing tasks in the common task list...");
+ }
+
+ /**
+ * Tells the user that an invalid command has been input into RoomShare.
+ */
+ public void showCommandError() {
+ System.out.println("Sorry, I don't understand this command...");
+ System.out.println("Try type \"help add\" for instructions on how to add new task");
+ System.out.println("\tType list, find, done, delete to perform operations on your todo list");
+ }
+
+ /**
+ * tells the user that recurring tasks have appeared.
+ */
+ public void showChangeInTaskList() {
+ System.out.println("You have some recurring tasks that need to be cleared, please check them:");
+ }
+
+ /**
+ * tells the user that the requested task has been snoozed.
+ */
+ public void showSnoozeComplete(int index, int amount, TimeUnit unit) {
+ System.out.println("Great I've snoozed task " + index + " by " + amount + " " + unit.name());
+ }
+
+ /**
+ * Provides user with instructions to prioritise task.
+ */
+ public void priorityInstruction() {
+ System.out.println("Enter task index followed by priority (high, medium, low)");
+ System.out.println("\te.g. 1 high");
+ }
+
+ /**
+ * Notifies the user that their task's priority has been set.
+ */
+ public void prioritySet() {
+ System.out.println("Your task's priority has been set");
+ }
+
+ /**
+ * Prompt user to enter the second index.
+ */
+ public void promptSecondIndex() {
+ System.out.println("Please enter the index to swap to");
+ }
+
+ public void showReordering() {
+ System.out.println("Reordering the task list...");
+ }
+
+ /**
+ * Show the message of an error encountered.
+ * @param e the encountered error
+ */
+ public void showError(Exception e) {
+ System.out.println(e);
+ }
+
+ public void showLogSuccess(String filePath) {
+ System.out.println("Log has been successfully written to " + filePath);
+ }
+
+ public void showUpdated(int index) {
+ System.out.println("Great! I've updated task " + index);
+ }
+
+ public static void clearScreen() throws IOException, InterruptedException {
+ new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor();
+ }
+
+ public void showBar(String bar) {
+ System.out.println(bar);
+ }
+
+ public void showChangeInPriority(SortType sortType) {
+ System.out.println("Your sorting preferences have been set to " + sortType.toString());
+ }
+
+ void showSort() {
+ System.out.print("sort: ");
+ if (TaskList.getSortType().equals(SortType.priority)) {
+ System.out.println("Priority");
+ } else if (TaskList.getSortType().equals(SortType.alphabetical)) {
+ System.out.println("Alphabetical");
+ } else if (TaskList.getSortType().equals(SortType.deadline)) {
+ System.out.println("Deadline");
+ } else {
+ System.out.println("Type");
+ }
+ }
+
+ public void showRestoreList() {
+ System.out.println("This are the items in your restore list");
+ }
+
+ public void showOverdueList() {
+ System.out.println("Here are your overdue tasks: ");
+ }
+
+ public void showTagged(String user) {
+ System.out.println("These are the tasks assigned to " + user + ":");
+ }
+
+ public void showTaggedPercentage(String user) {
+ System.out.println("The completion status for '" + user + "' is:");
+ }
+
+ public void showDeletedList() {
+ System.out.println("Here are the tasks that you have deleted and are in temporary storage");
+ }
+
+ public void showDoneList() {
+ System.out.println("These are the tasks that you have already done:");
+ }
+}
diff --git a/src/main/java/Operations/subTaskCreator.java b/src/main/java/Operations/subTaskCreator.java
new file mode 100644
index 0000000000..0577d51e14
--- /dev/null
+++ b/src/main/java/Operations/subTaskCreator.java
@@ -0,0 +1,74 @@
+package Operations;
+
+import CustomExceptions.RoomShareException;
+import Enums.ExceptionType;
+import Model_Classes.Assignment;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class subTaskCreator {
+ /**
+ * creates sub tasks for Assignments. Appends the information to the Assignment class.
+ * checks for duplicate subTasks
+ * throws RoomShareException if there are mistakes in the formatting of sub tasks
+ * @param index index of the task to add sub tasks to
+ * @param subTasks list of sub tasks to be added to the task
+ * @throws RoomShareException when the sub tasks are added to non assignment classes
+ */
+ public subTaskCreator(int index, String subTasks) throws RoomShareException {
+ boolean error = false;
+ if (TaskList.get(index) instanceof Assignment) {
+ ArrayList temp = new ArrayList<>(Arrays.asList(subTasks.trim().split(",")));
+
+ ArrayList subtasks = new ArrayList<>();
+
+ for (int i = 0; i < temp.size(); i++) {
+ temp.set(i, temp.get(i).trim());
+ if (hasSpecialCharacters(temp.get(i))) {
+ throw new RoomShareException(ExceptionType.invalidInputString);
+ }
+ boolean duplicate = false;
+ if (!subtasks.isEmpty()) {
+ for (String subtask : subtasks) {
+ if (temp.get(i).equals(subtask)) {
+ duplicate = true;
+ error = true;
+ break;
+ }
+ }
+ }
+ if (!duplicate) {
+ subtasks.add(temp.get(i));
+ }
+ }
+ ((Assignment) TaskList.getCurrentList().get(index)).addSubTasks(subtasks);
+ if (error) {
+ throw new RoomShareException(ExceptionType.duplicateSubtask);
+ }
+ } else {
+ throw new RoomShareException(ExceptionType.subTaskError);
+ }
+ }
+
+ private boolean hasSpecialCharacters(String input) {
+ boolean isInvalid = false;
+ if (input.contains("#")) {
+ isInvalid = true;
+ } else if (input.contains("@")) {
+ isInvalid = true;
+ } else if (input.contains("!")) {
+ isInvalid = true;
+ } else if (input.contains("*")) {
+ isInvalid = true;
+ } else if (input.contains("^")) {
+ isInvalid = true;
+ } else if (input.contains("%")) {
+ isInvalid = true;
+ } else if (input.contains("&")) {
+ isInvalid = true;
+ } else if (input.contains("(")) {
+ isInvalid = true;
+ }
+ return isInvalid;
+ }
+}
diff --git a/src/main/java/RoomShare.java b/src/main/java/RoomShare.java
new file mode 100644
index 0000000000..b111764d55
--- /dev/null
+++ b/src/main/java/RoomShare.java
@@ -0,0 +1,479 @@
+import CustomExceptions.DuplicateException;
+import CustomExceptions.RoomShareException;
+import CustomExceptions.TimeClashException;
+import Enums.ExceptionType;
+import Enums.SortType;
+import Enums.TaskType;
+import Enums.TimeUnit;
+import Model_Classes.ProgressBar;
+import Model_Classes.Task;
+import Operations.Help;
+import Operations.ListRoutine;
+import Operations.OverdueList;
+import Operations.Parser;
+import Operations.RecurHandler;
+import Operations.Storage;
+import Operations.TaskCreator;
+import Operations.TaskList;
+import Operations.TempDeleteList;
+import Operations.Ui;
+import Operations.subTaskCreator;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+
+/**
+ * Main class of the RoomShare program.
+ */
+public class RoomShare {
+ private Ui ui;
+ private Storage storage;
+ private TaskList taskList;
+ private OverdueList overdueList;
+ private Parser parser;
+ private TempDeleteList tempDeleteList;
+ private TaskCreator taskCreator;
+ private Help help;
+ private ListRoutine listRoutine;
+
+ /**
+ * Constructor of a RoomShare class. Creates all necessary objects and collections for RoomShare to run
+ * Also loads the ArrayList of tasks from the data.txt file
+ */
+ private RoomShare() throws RoomShareException {
+ ui = new Ui();
+ help = new Help();
+ ui.startUp();
+ storage = new Storage();
+ parser = new Parser();
+ taskCreator = new TaskCreator();
+ ArrayList tempStorage = new ArrayList<>();
+ tempDeleteList = new TempDeleteList(tempStorage);
+
+ try {
+ taskList = new TaskList(storage.loadFile("data.txt"));
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ ArrayList emptyList = new ArrayList<>();
+ taskList = new TaskList(emptyList);
+ }
+ try {
+ overdueList = new OverdueList(storage.loadFile("overdue.txt"));
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ ArrayList emptyList = new ArrayList<>();
+ overdueList = new OverdueList(emptyList);
+ }
+ listRoutine = new ListRoutine(taskList, overdueList);
+ RecurHandler recurHandler = new RecurHandler(taskList);
+ if (recurHandler.checkRecurrence()) {
+ ui.showChangeInTaskList();
+ taskList.list(overdueList);
+ }
+ listRoutine.list();
+ }
+
+ /**
+ * Deals with the operation flow of RoomShare.
+ */
+ private void run() throws RoomShareException, IOException, InterruptedException {
+ boolean isExit = false;
+ while (!isExit) {
+ TaskType type;
+ try {
+ String command = parser.getCommand();
+ type = TaskType.valueOf(command);
+ } catch (IllegalArgumentException e) {
+ type = TaskType.others;
+ }
+ switch (type) {
+ case help:
+ Ui.clearScreen();
+ ui.startUp();
+ help.helpCommandList();
+ help.showHelp(parser.getCommandLine());
+ break;
+
+ case bye:
+ isExit = true;
+ try {
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ }
+ try {
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ }
+ parser.close();
+ ui.showBye();
+ break;
+
+ case list:
+ Ui.clearScreen();
+ ui.startUp();
+ listRoutine.list();
+ break;
+
+ case done:
+ Ui.clearScreen();
+ ui.startUp();
+ try {
+ String input = parser.getCommandLine().trim();
+ if (input.split(" ")[0].equals("subtask")) {
+ taskList.doneSubTask(input);
+ } else {
+ int[] index = parser.getIndexRange(input);
+ taskList.done(index);
+ ui.showDone();
+ }
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ } finally {
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ listRoutine.list();
+ break;
+
+ case delete:
+ Ui.clearScreen();
+ ui.startUp();
+ try {
+ String input = parser.getCommandLine().trim();
+ int[] index = parser.getIndexRange(input);
+ taskList.delete(index, tempDeleteList);
+ ui.showDeleted(index);
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ } finally {
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ listRoutine.list();
+ break;
+
+ case removeoverdue:
+ Ui.clearScreen();
+ ui.startUp();
+ try {
+ String input = parser.getCommandLine().trim();
+ int[] index = parser.getIndexRange(input);
+ overdueList.remove(index, tempDeleteList);
+ ui.showDeleted(index);
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ } finally {
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ listRoutine.list();
+ break;
+
+ case restore:
+ Ui.clearScreen();
+ ui.startUp();
+ ui.showRestoreList();
+ try {
+ String input = parser.getCommandLine().trim();
+ tempDeleteList.list();
+ int restoreIndex = parser.getIndex(input);
+ tempDeleteList.restore(restoreIndex, taskList);
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ } finally {
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ listRoutine.list();
+ break;
+
+ case find:
+ Ui.clearScreen();
+ ui.startUp();
+ listRoutine.list();
+ ui.showFind();
+ taskList.find(parser.getKey().toLowerCase());
+ break;
+
+ case priority:
+ Ui.clearScreen();
+ ui.startUp();
+ boolean success = true;
+ try {
+ taskList.setPriority(parser.getPriority());
+ } catch (RoomShareException e) {
+ success = false;
+ ui.showError(e);
+ ui.priorityInstruction();
+ } finally {
+ if (success) {
+ TaskList.sortTasks();
+ ui.prioritySet();
+ }
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ listRoutine.list();
+ break;
+
+ case add:
+ Ui.clearScreen();
+ ui.startUp();
+ try {
+ String input = parser.getCommandLine().trim();
+ taskList.add(taskCreator.create(input));
+ ui.showAdd();
+ } catch (RoomShareException | DuplicateException | TimeClashException e) {
+ ui.showError(e);
+ } finally {
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ listRoutine.list();
+ break;
+
+ case snooze:
+ Ui.clearScreen();
+ ui.startUp();
+ try {
+ String input = parser.getCommandLine().trim();
+ int index = parser.getIndex(input);
+ int amount = parser.getAmount(input);
+ TimeUnit timeUnit = parser.getTimeUnit(input);
+ if (amount < 0) {
+ throw new RoomShareException(ExceptionType.negativeTimeAmount);
+ }
+ taskList.snooze(index, amount, timeUnit);
+ ui.showSnoozeComplete(index + 1, amount, timeUnit);
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ } finally {
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ listRoutine.list();
+ break;
+
+ case reorder:
+ Ui.clearScreen();
+ ui.startUp();
+ try {
+ String input = parser.getCommandLine().trim();
+ int firstIndex = parser.getIndex(input, 0);
+ int secondIndex = parser.getIndex(input, 1);
+ taskList.reorder(firstIndex, secondIndex);
+ ui.showReordering();
+ } catch (RoomShareException e) {
+ ui.showError(e);;
+ } finally {
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ listRoutine.list();
+ break;
+
+ case subtask:
+ Ui.clearScreen();
+ ui.startUp();
+ try {
+ String input = parser.getCommandLine().trim();
+ int index = parser.getIndexSubtask(input);
+ String subTasks = parser.getSubTasks(input);
+ new subTaskCreator(index, subTasks);
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ } finally {
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ listRoutine.list();
+ break;
+
+ case update:
+ Ui.clearScreen();
+ ui.startUp();
+ try {
+ String input = parser.getCommandLine().trim();
+ int index = parser.getIndex(input);
+ Task oldTask = TaskList.get(index);
+ taskCreator.updateTask(input,oldTask);
+ ui.showUpdated(index + 1);
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ } finally {
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ listRoutine.list();
+ break;
+
+ case sort:
+ Ui.clearScreen();
+ ui.startUp();
+ SortType sortType;
+ try {
+ String input = parser.getCommandLine().trim();
+ sortType = parser.getSort(input);
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ sortType = SortType.priority;
+ } finally {
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ TaskList.changeSort(sortType);
+ ui.showChangeInPriority(sortType);
+ listRoutine.list();
+ break;
+
+ case log:
+ Ui.clearScreen();
+ ui.startUp();
+ listRoutine.list();
+ try {
+ String filePath = storage.writeLogFile(TaskList.getCurrentList());
+ ui.showLogSuccess(filePath);
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ } finally {
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ break;
+
+ case completed:
+ Ui.clearScreen();
+ ui.startUp();
+ listRoutine.list();
+ try {
+ taskList.showCompleted();
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ } finally {
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ break;
+
+ case overdue:
+ Ui.clearScreen();
+ ui.startUp();
+ listRoutine.list();
+ ui.showOverdueList();
+ try {
+ overdueList.list();
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ }
+ try {
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ }
+ break;
+
+ case reschedule:
+ Ui.clearScreen();
+ ui.startUp();
+ try {
+ overdueList.list();
+ String input = parser.getCommandLine();
+ String[] range = input.split(" ");
+ int[] indexes = parser.getIndexRange(range[0]);
+ if (indexes.length != 1) {
+ for (int i = indexes[0]; i <= indexes[1]; i++) {
+ Task oldTask = overdueList.get(i);
+ taskCreator.rescheduleTask(input, oldTask);
+ ui.showUpdated(i + 1);
+ }
+ } else {
+ Task oldTask = overdueList.get(indexes[0]);
+ taskCreator.rescheduleTask(input, oldTask);
+ ui.showUpdated(indexes[0] + 1);
+ }
+ overdueList.reschedule(indexes, taskList);
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ } finally {
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ listRoutine.list();
+ break;
+
+ case show:
+ Ui.clearScreen();
+ ui.startUp();
+ try {
+ String input = parser.getCommandLine().trim();
+ if (input.equals("deleted")) {
+ ui.showDeletedList();
+ try {
+ tempDeleteList.list();
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ }
+ } else {
+ ui.showTagged(input);
+ int[] doneArray = taskList.listTagged(input);
+ ui.showTaggedPercentage(input);
+ ProgressBar progressBar = new ProgressBar(doneArray[0], doneArray[1]);
+ ui.showBar(progressBar.showBar());
+ }
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ } finally {
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ }
+ break;
+
+ case reopen:
+ Ui.clearScreen();
+ ui.startUp();
+ try {
+ String input = parser.getCommandLine();
+ int index = parser.getIndex(input);
+ ArrayList date = taskCreator.extractDate(input);
+ taskList.reopen(index,date.get(0));
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ }
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ listRoutine.list();
+ ui.showDoneList();
+ taskList.showCompleted();
+ break;
+
+ default:
+ Ui.clearScreen();
+ ui.startUp();
+ listRoutine.list();
+ ui.showCommandError();
+ storage.writeFile(TaskList.getCurrentList(), "data.txt");
+ try {
+ storage.writeFile(OverdueList.getOverdueList(), "overdue.txt");
+ } catch (RoomShareException e) {
+ ui.showError(e);
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Main function of RoomShare.
+ * Creates a new instance of RoomShare class
+ * @param args command line arguments
+ * @throws RoomShareException Custom exception class within RoomShare program
+ */
+ public static void main(String[] args) throws RoomShareException, IOException, InterruptedException {
+ new RoomShare().run();
+ System.exit(0);
+ }
+}
diff --git a/src/test/java/AssignmentTest.java b/src/test/java/AssignmentTest.java
new file mode 100644
index 0000000000..6e31a0093a
--- /dev/null
+++ b/src/test/java/AssignmentTest.java
@@ -0,0 +1,56 @@
+import Enums.Priority;
+import Enums.RecurrenceScheduleType;
+import Model_Classes.Assignment;
+import org.junit.jupiter.api.Test;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+public class AssignmentTest {
+ private static SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
+ private static Date date;
+
+ static {
+ try {
+ date = format.parse("22/12/2019 18:00");
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private Assignment assignment = new Assignment("description", date);
+
+ @Test
+ void getDescription() {
+ assertEquals(assignment.getDescription(), "description");
+ }
+
+ @Test
+ void getDate() {
+ assertEquals(assignment.getDate().toString(), "Sun Dec 22 18:00:00 SGT 2019");
+ }
+
+ @Test
+ void getDone() {
+ assertFalse(assignment.getDone());
+ }
+
+ @Test
+ void getPriority() {
+ assertEquals(assignment.getPriority(), Priority.low);
+ }
+
+ @Test
+ void getAssignee() {
+ assertEquals(assignment.getAssignee(), "everyone");
+ }
+
+ @Test
+ void getRecurrenceSchedule() {
+ assertEquals(assignment.getRecurrenceSchedule(), RecurrenceScheduleType.none);
+ }
+}
diff --git a/src/test/java/CheckAnomalyTest.java b/src/test/java/CheckAnomalyTest.java
new file mode 100644
index 0000000000..3d6a7ef5ba
--- /dev/null
+++ b/src/test/java/CheckAnomalyTest.java
@@ -0,0 +1,66 @@
+import CustomExceptions.RoomShareException;
+import Enums.TimeUnit;
+import Model_Classes.Assignment;
+import Model_Classes.Meeting;
+import Operations.CheckAnomaly;
+import Operations.Parser;
+import Operations.Storage;
+import Operations.TaskList;
+import org.junit.jupiter.api.Test;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class CheckAnomalyTest {
+ private static final Parser parser = new Parser();
+ private static final Storage storage = new Storage();
+ private static Meeting meeting1, meeting2, meeting3, meeting4, meeting5;
+ private static Assignment assignment1, assignment2;
+ private static Date at1, at2, at3, at4, at5, at6, at7;
+ private static TaskList taskList;
+
+ static {
+ try {
+ at1 = parser.formatDateDDmmYY("12/12/2019 17:00");
+ at2 = parser.formatDateDDmmYY("12/12/2019 19:00");
+ at3 = parser.formatDateDDmmYY("12/12/2019 10:00");
+ at4 = parser.formatDateDDmmYY("12/12/2019 09:00");
+ at5 = parser.formatDateDDmmYY("21/12/2019 13:00");
+ at6 = parser.formatDateDDmmYY("22/12/2019 13:00");
+ at7 = parser.formatDateDDmmYY("25/12/2019 13:00");
+ taskList = new TaskList(storage.loadFile("test.txt"));
+ meeting1 = new Meeting("test1", at1, 2, TimeUnit.hours);
+ meeting2 = new Meeting("test2", at2);
+ meeting3 = new Meeting("test3", at3);
+ meeting4 = new Meeting("test4", at4, 2, TimeUnit.hours);
+ meeting5 = new Meeting("test5", at5);
+ assignment1 = new Assignment("test6", at6);
+ assignment1.setAssignee("harry");
+ assignment2 = new Assignment("test6", at7);
+ assignment2.setAssignee("harry");
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void durationClashOverlap() { assertEquals(0, new CheckAnomaly().isTimeClash(meeting1)); }
+
+ @Test
+ public void durationClashIntersect() { assertEquals(0, new CheckAnomaly().isTimeClash(meeting2)); }
+
+ @Test
+ public void fixedClashIntersect() { assertEquals(1, new CheckAnomaly().isTimeClash(meeting3)); }
+
+ @Test
+ public void fixedClashOverlap() { assertEquals(1, new CheckAnomaly().isTimeClash(meeting4)); }
+
+ @Test
+ public void noClash() { assertEquals(-1, new CheckAnomaly().isTimeClash(meeting5)); }
+
+ @Test
+ public void duplicateClash() { assertEquals(3, new CheckAnomaly().isDuplicate(assignment1)); }
+
+ @Test
+ public void noDuplicate() { assertEquals(-1, new CheckAnomaly().isTimeClash(assignment2)); }
+}
\ No newline at end of file
diff --git a/src/test/java/LeaveTest.java b/src/test/java/LeaveTest.java
new file mode 100644
index 0000000000..9c5047ef7b
--- /dev/null
+++ b/src/test/java/LeaveTest.java
@@ -0,0 +1,64 @@
+import Enums.Priority;
+import Enums.RecurrenceScheduleType;
+import Model_Classes.Leave;
+import org.junit.jupiter.api.Test;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+public class LeaveTest {
+ private static SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
+ private static Date from;
+ private static Date to;
+ private static String user = "user";
+
+ static {
+ try {
+ from = format.parse("22/12/2019 18:00");
+ to = format.parse("24/12/2019 22:00");
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private Leave leave = new Leave("description", user, from, to);
+
+ @Test
+ void getDescription() {
+ assertEquals(leave.getDescription(), "description");
+ }
+
+ @Test
+ void getStartDate() {
+ assertEquals(leave.getStartDate().toString(), "Sun Dec 22 18:00:00 SGT 2019");
+ }
+
+ @Test
+ void getEndDate() {
+ assertEquals(leave.getEndDate().toString(), "Tue Dec 24 22:00:00 SGT 2019");
+ }
+
+ @Test
+ void getAssignee() {
+ assertEquals(leave.getAssignee(), "user");
+ }
+
+ @Test
+ void getPriority() {
+ assertEquals(leave.getPriority(), Priority.low);
+ }
+
+ @Test
+ void getDone() {
+ assertFalse(leave.getDone());
+ }
+
+ @Test
+ void getRecurrenceSchedule() {
+ assertEquals(leave.getRecurrenceSchedule(), RecurrenceScheduleType.none);
+ }
+}
diff --git a/src/test/java/MeetingTest.java b/src/test/java/MeetingTest.java
new file mode 100644
index 0000000000..f426081391
--- /dev/null
+++ b/src/test/java/MeetingTest.java
@@ -0,0 +1,79 @@
+import CustomExceptions.RoomShareException;
+import Enums.Priority;
+import Enums.RecurrenceScheduleType;
+import Enums.TimeUnit;
+import Model_Classes.Meeting;
+import org.junit.jupiter.api.Test;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class MeetingTest {
+ private static SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
+ private static Date date;
+
+ static {
+ try {
+ date = format.parse("22/12/2019 18:00");
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ private static Meeting meeting1 = new Meeting("description", date);
+ private static Meeting meeting2 = new Meeting("description", date, 2, TimeUnit.hours);
+
+ @Test
+ void getDescription() {
+ assertEquals(meeting1.getDescription(), "description");
+ assertEquals(meeting2.getDescription(), "description");
+ }
+
+ @Test
+ void getDone() {
+ assertFalse(meeting1.getDone());
+ try {
+ meeting2.setDone(true);
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ assertTrue(meeting2.getDone());
+ }
+
+ @Test
+ void getDate() {
+ assertEquals(meeting1.getDate().toString(), "Sun Dec 22 18:00:00 SGT 2019" );
+ }
+
+ @Test
+ void getPriority() {
+ assertEquals(meeting1.getPriority(), Priority.low);
+ meeting2.setPriority(Priority.high);
+ assertEquals(meeting2.getPriority(), Priority.high);
+ }
+
+ @Test
+ void getAssignee() {
+ assertEquals(meeting1.getAssignee(), "everyone");
+ meeting2.setAssignee("john");
+ assertEquals(meeting2.getAssignee(), "john");
+ }
+
+ @Test
+ void getTimeUnit() {
+ assertEquals(meeting2.getTimeUnit(), TimeUnit.hours);
+ }
+
+ @Test
+ void getDuration() {
+ assertEquals(meeting2.getDuration(), "2");
+ }
+
+ @Test
+ void getRecurrenceSchedule() {
+ assertEquals(meeting1.getRecurrenceSchedule(), RecurrenceScheduleType.none);
+ assertEquals(meeting2.getRecurrenceSchedule(), RecurrenceScheduleType.none);
+ }
+}
diff --git a/src/test/java/OverdueListTest.java b/src/test/java/OverdueListTest.java
new file mode 100644
index 0000000000..be9848ec5f
--- /dev/null
+++ b/src/test/java/OverdueListTest.java
@@ -0,0 +1,89 @@
+import CustomExceptions.RoomShareException;
+import Model_Classes.Assignment;
+import Model_Classes.Leave;
+import Model_Classes.Meeting;
+import Operations.OverdueList;
+import Operations.TaskList;
+import Operations.TempDeleteList;
+import org.junit.jupiter.api.Test;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class OverdueListTest {
+ private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
+ private Date date1;
+ private Date date2;
+ private Date date3;
+ private Date date4;
+
+ {
+ try {
+ date1 = format.parse("22/12/2019 18:00");
+ date2 = format.parse("23/12/2019 18:00");
+ date3 = format.parse("24/12/2019 18:00");
+ date4 = format.parse("25/12/2019 18:00");
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private Assignment assignment1 = new Assignment("assignment1", date1);
+ private Assignment assignment2 = new Assignment("assignment2", date2);
+ private Meeting meeting1 = new Meeting("meeting1", date3);
+ private Meeting meeting2 = new Meeting("meeting2", date4);
+ private OverdueList overdueList = new OverdueList(new ArrayList<>());
+
+ @Test
+ void add() {
+ overdueList.add(assignment1);
+ overdueList.add(assignment2);
+ overdueList.add(meeting1);
+ overdueList.add(meeting2);
+ try {
+ assertEquals("[A] assignment1 (everyone) (by: Sun Dec 22 18:00:00 SGT 2019)", overdueList.get(0).toString());
+ assertEquals("[A] assignment2 (everyone) (by: Mon Dec 23 18:00:00 SGT 2019)", overdueList.get(1).toString());
+ assertEquals("[M] meeting1 (everyone) (on: Tue Dec 24 18:00:00 SGT 2019)", overdueList.get(2).toString());
+ assertEquals("[M] meeting2 (everyone) (on: Wed Dec 25 18:00:00 SGT 2019)", overdueList.get(3).toString());
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void reschedule() {
+ overdueList.add(assignment1);
+ overdueList.add(meeting1);
+ overdueList.add(assignment2);
+ overdueList.add(meeting2);
+ int[] index = {0, 1};
+ try {
+ overdueList.reschedule(index, new TaskList(new ArrayList<>()));
+ assertEquals("[A] assignment2 (everyone) (by: Sun Dec 22 18:00:00 SGT 2019)\n" +
+ "[M] meeting2 (everyone) (by: Sun Dec 22 18:00:00 SGT 2019)", overdueList.get(0).toString() + "\n" + overdueList.get(1).toString());
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void remove() {
+ overdueList.add(assignment1);
+ overdueList.add(meeting1);
+ overdueList.add(assignment2);
+ overdueList.add(meeting2);
+ int[] index = {0, 1};
+ try {
+ overdueList.remove(index, new TempDeleteList(new ArrayList<>()));
+ assertEquals("[A] assignment2 (everyone) (by: Mon Dec 23 18:00:00 SGT 2019)\n" +
+ "[M] meeting2 (everyone) (on: Wed Dec 25 18:00:00 SGT 2019)", overdueList.get(0).toString() + "\n" + overdueList.get(1).toString());
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/test/java/ProgressBarTest.java b/src/test/java/ProgressBarTest.java
new file mode 100644
index 0000000000..0629ae5491
--- /dev/null
+++ b/src/test/java/ProgressBarTest.java
@@ -0,0 +1,17 @@
+import Model_Classes.*;
+import Operations.TaskList;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class ProgressBarTest {
+ private float total = 5;
+ private float done = 5;
+
+ private ProgressBar pg = new ProgressBar(total, done);
+
+ @Test
+ void showBar() {
+ assertEquals(pg.showBar(), "[= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =] 100.0%");
+ }
+}
diff --git a/src/test/java/RecurHandlerTest.java b/src/test/java/RecurHandlerTest.java
new file mode 100644
index 0000000000..64fdc68806
--- /dev/null
+++ b/src/test/java/RecurHandlerTest.java
@@ -0,0 +1,2 @@
+public class RecurHandlerTest {
+}
diff --git a/src/test/java/StorageTest.java b/src/test/java/StorageTest.java
new file mode 100644
index 0000000000..26df68dcc0
--- /dev/null
+++ b/src/test/java/StorageTest.java
@@ -0,0 +1,85 @@
+import CustomExceptions.RoomShareException;
+import Enums.TimeUnit;
+import Model_Classes.Assignment;
+import Model_Classes.Leave;
+import Model_Classes.Meeting;
+import Model_Classes.Task;
+import Operations.Storage;
+import org.junit.jupiter.api.Test;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class StorageTest {
+ private static SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
+ private static Date date, to, dateTest, dateTest2, dateTest3, dateTest4;
+ static {
+ try {
+ date = format.parse("22/12/2019 18:00");
+ to = format.parse("24/12/2019 18:00");
+ dateTest = format.parse("12/12/2019 18:00");
+ dateTest2 = format.parse("12/12/2019 10:00");
+ dateTest3 = format.parse("12/12/2019 21:00");
+ dateTest4 = format.parse("22/12/2019 13:00");
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private ArrayList al = new ArrayList<>();
+// private static TaskList tl1 = new TaskList(new ArrayList());
+ private Assignment ts = new Assignment("assign", date);
+ private Meeting ts1 = new Meeting("meet", date);
+ private Leave ts2 = new Leave("leave", "user", date, to);
+ private Storage storage = new Storage();
+ private Meeting meetingTest = new Meeting("test1", dateTest, 2, TimeUnit.hours);
+ private Meeting meetingTest2 = new Meeting("test2", dateTest2);
+ private Assignment assignmentTest = new Assignment("subtasks", dateTest3);
+ private Assignment assignmentTest2 = new Assignment("test6", dateTest4);
+
+ private static String[] GetStringArray(ArrayList arr)
+ {
+
+ // declaration and initialise String Array
+ String[] str = new String[arr.size()];
+ int i =0;
+ // ArrayList to Array Conversion
+ for (Task s : arr) {
+
+ // Assign each value to String array
+ str[i] = s.toString();
+ i++;
+ }
+ return str;
+ }
+ @Test
+ void loadFile() throws RoomShareException {
+ String fileName = "test.txt";
+ ArrayList altest = storage.loadFile(fileName);
+ assignmentTest2.setAssignee("harry");
+ al.add(meetingTest);
+ al.add(meetingTest2);
+ al.add(assignmentTest);
+ al.add(assignmentTest2);
+ ts1.setDone(true);
+ String[] str = GetStringArray(altest);
+ String[] str1 = GetStringArray(al);
+
+ assertEquals(str[0] + str[1] + str[2] + str[3],
+ str1[0] + str1[1] + str1[2] + str[3]);
+ }
+
+ @Test
+ void convertForStorage() throws RoomShareException {
+ assertEquals("22/12/2019 18:00", storage.convertForStorage(ts1));
+ }
+
+ @Test
+ void convertForStorageLeave() throws RoomShareException {
+ assertEquals("22/12/2019 18:00-24/12/2019 18:00", storage.convertForStorageLeave(ts2));
+ }
+}
diff --git a/src/test/java/TaskCreatorTest.java b/src/test/java/TaskCreatorTest.java
new file mode 100644
index 0000000000..9a48f0698b
--- /dev/null
+++ b/src/test/java/TaskCreatorTest.java
@@ -0,0 +1,224 @@
+import CustomExceptions.DuplicateException;
+import CustomExceptions.RoomShareException;
+import CustomExceptions.TimeClashException;
+import Enums.Priority;
+import Enums.RecurrenceScheduleType;
+import Enums.TimeUnit;
+import Model_Classes.Leave;
+import Model_Classes.Meeting;
+import Operations.TaskCreator;
+import javafx.util.Pair;
+import org.junit.jupiter.api.Test;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class TaskCreatorTest {
+ private static TaskCreator taskCreator = new TaskCreator();
+ private static String input1 = "add #meeting# (description) &22/12/2019 18:00& *high* %week% " +
+ "@john@ ^2 hours^ !R!";
+ private static String input2 = "add #meeting# (description) &23/12/2019 18:00&";
+ private static String input3 = "add #leave# (description) &24/12/2019 18:00&25/12/2019 18:00& @Harry@";
+ private static String updates = "update 1 (another description) &22/12/2020 19:00& *medium* %day% " +
+ "@bob@ ^120 minutes^";
+
+ @Test
+ void extractDescription() {
+ try {
+ assertEquals(taskCreator.extractDescription(input1), "description");
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void extractDate() {
+ SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
+ Date date1 = new Date();
+ Date date2 = new Date();
+ Date date3 = new Date();
+ try {
+ date1 = format.parse("22/12/2019 18:00");
+ date2 = format.parse("24/12/2019 18:00");
+ date3 = format.parse("25/12/2019 18:00");
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ ArrayList dates = new ArrayList<>();
+ ArrayList dates2 = new ArrayList<>();
+ dates2.add(date2);
+ dates2.add(date3);
+ dates.add(date1);
+ try {
+ assertEquals(taskCreator.extractDate(input1), dates);
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ try {
+ assertEquals(taskCreator.extractDate(input3), dates2);
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void extractType() {
+ try {
+ assertEquals(taskCreator.extractType(input1), "meeting");
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ try {
+ assertEquals(taskCreator.extractType(input2), "meeting");
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ try {
+ assertEquals(taskCreator.extractType(input3), "leave");
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void extractPriority() {
+ try {
+ assertEquals(taskCreator.extractPriority(input1), Priority.high);
+ assertEquals(taskCreator.extractPriority(input2), Priority.low);
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void extractAssignee() {
+ try {
+ assertEquals(taskCreator.extractAssignee(input1), "john");
+ assertEquals(taskCreator.extractAssignee(input2), "everyone");
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void extractRecurrence() {
+ try {
+ assertEquals(taskCreator.extractRecurrence(input1), RecurrenceScheduleType.week);
+ assertEquals(taskCreator.extractRecurrence(input2), RecurrenceScheduleType.none);
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void extractDuration() {
+ Pair pair = new Pair<>(2, TimeUnit.hours);
+ Pair pair2 = new Pair<>(0, TimeUnit.unDefined);
+ try {
+ assertEquals(taskCreator.extractDuration(input1), pair);
+ assertEquals(taskCreator.extractDuration(input2), pair2);
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void extractReminder() {
+ assertTrue(taskCreator.extractReminder(input1));
+ assertFalse(taskCreator.extractReminder(input2));
+ }
+
+ @Test
+ void create() {
+ Pair pair = new Pair<>(2, TimeUnit.hours);
+ Pair pair2 = new Pair<>(0, TimeUnit.unDefined);
+ SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
+ Date date1 = new Date();
+ Date date2 = new Date();
+ Date date3 = new Date();
+ Date date4 = new Date();
+ try {
+ date1 = format.parse("22/12/2019 18:00");
+ date2 = format.parse("23/12/2019 18:00");
+ date3 = format.parse("24/12/2019 18:00");
+ date4 = format.parse("25/12/2019 18:00");
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ try {
+ Meeting meeting1 = (Meeting) taskCreator.create(input1);
+ assertFalse(meeting1.getDone());
+ assertEquals(meeting1.getRecurrenceSchedule(), RecurrenceScheduleType.week);
+ assertEquals(meeting1.getDuration(), "2");
+ assertEquals(meeting1.getTimeUnit(), TimeUnit.hours);
+ assertEquals(meeting1.getAssignee(), "john");
+ assertEquals(meeting1.getDate(), date1);
+ assertEquals(meeting1.getPriority(), Priority.high);
+ assertEquals(meeting1.getDescription(), "description");
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ } catch (DuplicateException e) {
+ e.printStackTrace();
+ } catch (TimeClashException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ Meeting meeting2 = (Meeting) taskCreator.create(input2);
+ assertFalse(meeting2.getDone());
+ assertFalse(meeting2.isFixedDuration());
+ assertEquals(meeting2.getDescription(), "description");
+ assertEquals(meeting2.getPriority(), Priority.low);
+ assertEquals(meeting2.getDate(), date2);
+ assertEquals(meeting2.getAssignee(), "everyone");
+ assertEquals(meeting2.getTimeUnit(), TimeUnit.unDefined);
+ assertEquals(meeting2.getDuration(), "0");
+ assertEquals(meeting2.getRecurrenceSchedule(), RecurrenceScheduleType.none);
+ } catch (RoomShareException | DuplicateException | TimeClashException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ Leave leave = (Leave) taskCreator.create(input3);
+ assertFalse(leave.getDone());
+ assertFalse(leave.hasRecurring());
+ assertEquals(leave.getAssignee(), "Harry");
+ assertEquals(leave.getEndDate(), date4);
+ assertEquals(leave.getStartDate(), date3);
+ assertEquals(leave.getDescription(), "description");
+ assertEquals(leave.getPriority(), Priority.low);
+ assertEquals(leave.getRecurrenceSchedule(), RecurrenceScheduleType.none);
+ } catch (RoomShareException | DuplicateException | TimeClashException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void updateTask() {
+ try {
+ SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
+ Date newDate = format.parse("22/12/2020 19:00");
+
+ Meeting meeting = (Meeting) taskCreator.create(input1);
+ taskCreator.updateTask(updates,meeting);
+ assertFalse(meeting.getDone());
+ assertEquals(meeting.getDescription(), "another description");
+ assertEquals(meeting.getDate(),newDate);
+ assertEquals(meeting.getPriority(), Priority.medium);
+ assertEquals(meeting.getAssignee(), "bob");
+ assertEquals(meeting.getDuration(), "120");
+ assertEquals(meeting.getTimeUnit(), TimeUnit.minutes);
+ assertEquals(meeting.getRecurrenceSchedule(), RecurrenceScheduleType.day);
+ } catch (RoomShareException | ParseException e) {
+ e.printStackTrace();
+ } catch (DuplicateException e) {
+ e.printStackTrace();
+ } catch (TimeClashException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/test/java/TaskListTest.java b/src/test/java/TaskListTest.java
new file mode 100644
index 0000000000..01f50d70ee
--- /dev/null
+++ b/src/test/java/TaskListTest.java
@@ -0,0 +1,136 @@
+import CustomExceptions.RoomShareException;
+import Enums.Priority;
+import Enums.TimeUnit;
+import Model_Classes.Assignment;
+import Operations.TaskList;
+import org.junit.jupiter.api.Test;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class TaskListTest {
+ private SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
+ private Date date1;
+ private Date date2;
+ private Date date3;
+ private Date date4;
+ {
+ try {
+ date1 = format.parse("22/12/2019 18:00");
+ date2 = format.parse("22/12/2019 18:00");
+ date3 = format.parse("22/12/2019 18:00");
+ date4 = format.parse("22/12/2019 18:00");
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private Assignment assignment1 = new Assignment("task1", date1);
+ private Assignment assignment2 = new Assignment("task2", date2);
+ private Assignment assignment3 = new Assignment ("as1", date3);
+ private Assignment assignment4 = new Assignment("as2", date4);
+ private TaskList taskList = new TaskList(new ArrayList<>());
+
+ @Test
+ void add() {
+ taskList.add(assignment1);
+ taskList.add(assignment2);
+ taskList.add(assignment3);
+ taskList.add(assignment4);
+ try {
+ assertEquals("[A] task1 (everyone) (by: Sun Dec 22 18:00:00 SGT 2019)", taskList.get(0).toString());
+ assertEquals("[A] task2 (everyone) (by: Sun Dec 22 18:00:00 SGT 2019)", taskList.get(1).toString());
+ assertEquals("[A] as1 (everyone) (by: Sun Dec 22 18:00:00 SGT 2019)", taskList.get(2).toString());
+ assertEquals("[A] as2 (everyone) (by: Sun Dec 22 18:00:00 SGT 2019)", taskList.get(3).toString());
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void done() {
+ taskList.add(assignment1);
+ taskList.add(assignment2);
+ int[] array = {0, 1};
+ try {
+ taskList.done(array);
+ assertEquals("[A] task1 (everyone) (by: Sun Dec 22 18:00:00 SGT 2019)\n" +
+ "[A] task2 (everyone) (by: Sun Dec 22 18:00:00 SGT 2019)",
+ taskList.get(0).toString()+ "\n" + taskList.get(1).toString());
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void find() {
+ taskList.add(assignment1);
+ taskList.find("task");
+ try {
+ assertEquals("[A] task1 (everyone) (by: Sun Dec 22 18:00:00 SGT 2019)", taskList.get(0).toString());
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void setPriority() {
+ taskList.add(assignment1);
+ String[] array = {"1", "high"};
+ try {
+ taskList.setPriority(array);
+ assertEquals(taskList.get(0).getPriority(), Priority.high);
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void reorder() {
+ taskList.add(assignment1);
+ taskList.add(assignment2);
+ try {
+ taskList.reorder(0, 1);
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ try {
+ assertEquals("[A] task2 (everyone) (by: Sun Dec 22 18:00:00 SGT 2019)\n" +
+ "[A] task1 (everyone) (by: Sun Dec 22 18:00:00 SGT 2019)", taskList.get(0).toString() + "\n" + taskList.get(1).toString());
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void replace() {
+ taskList.add(assignment1);
+ taskList.replace(0, assignment2);
+ try {
+ assertEquals("[A] task2 (everyone) (by: Sun Dec 22 18:00:00 SGT 2019)", taskList.get(0).toString());
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ void snooze() {
+ taskList.add(assignment1);
+ taskList.add(assignment2);
+ taskList.add(assignment3);
+ try {
+ taskList.snooze(0, 1, TimeUnit.hours);
+ taskList.snooze(1,10, TimeUnit.minutes);
+ taskList.snooze(2, 1, TimeUnit.day);
+ assertEquals("[A] task1 (everyone) (by: Sun Dec 22 19:00:00 SGT 2019)", taskList.get(0).toString());
+ assertEquals("[A] task2 (everyone) (by: Sun Dec 22 18:10:00 SGT 2019)", taskList.get(1).toString());
+ assertEquals("[A] as1 (everyone) (by: Mon Dec 23 18:00:00 SGT 2019)", taskList.get(2).toString());
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/TempDeleteListTest.java b/src/test/java/TempDeleteListTest.java
new file mode 100644
index 0000000000..ecbed793dc
--- /dev/null
+++ b/src/test/java/TempDeleteListTest.java
@@ -0,0 +1,2 @@
+public class TempDeleteListTest {
+}
diff --git a/src/test/java/subTaskCreatorTest.java b/src/test/java/subTaskCreatorTest.java
new file mode 100644
index 0000000000..d0a076ab7a
--- /dev/null
+++ b/src/test/java/subTaskCreatorTest.java
@@ -0,0 +1,37 @@
+import CustomExceptions.RoomShareException;
+import Model_Classes.Assignment;
+import Operations.*;
+import Operations.subTaskCreator;
+import org.junit.jupiter.api.Test;
+
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class subTaskCreatorTest {
+ private static final Parser parser = new Parser();
+ private static final Storage storage = new Storage();
+ private static TaskList taskList;
+ private static Date by;
+ private static Assignment assignment;
+
+ static {
+ try {
+ taskList = new TaskList(storage.loadFile("test.txt"));
+ by = parser.formatDateDDmmYY("12/12/2019 17:00");
+ assignment = new Assignment("test", by);
+ taskList.add(assignment);
+ new subTaskCreator(3, "one,two");
+ } catch (RoomShareException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void testSubtask() {
+ String one = ((Assignment) TaskList.getCurrentList().get(3)).getSubTasks().get(0);
+ String two = ((Assignment) TaskList.getCurrentList().get(3)).getSubTasks().get(1);
+ assertEquals(one, "one");
+ assertEquals(two, "two");
+ }
+}
\ No newline at end of file
diff --git a/test.txt b/test.txt
new file mode 100644
index 0000000000..f63d4738ee
--- /dev/null
+++ b/test.txt
@@ -0,0 +1,4 @@
+M#n#low#test1#12/12/2019 18:00#none#everyone#F#2#hours##
+M#n#low#test2#12/12/2019 10:00#none#everyone#N#0#unDefined##
+A#n#low#subtasks#12/12/2019 21:00#none#everyone#N#0#unDefined##
+A#n#low#test6#22/12/2019 13:00#none#harry#N#0#unDefined##
\ No newline at end of file
diff --git a/text-ui-test/EXPECTED.txt b/text-ui-test/EXPECTED.txt
new file mode 100644
index 0000000000..c7c91965c1
--- /dev/null
+++ b/text-ui-test/EXPECTED.txt
@@ -0,0 +1,8 @@
+Hello from
+ ____ _
+| _ \ _ _| | _____
+| | | | | | | |/ / _ \
+| |_| | |_| | < __/
+|____/ \__,_|_|\_\___|
+
+How may I serve you?
\ No newline at end of file
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
new file mode 100644
index 0000000000..b023018cab
--- /dev/null
+++ b/text-ui-test/input.txt
@@ -0,0 +1 @@
+bye
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
new file mode 100644
index 0000000000..320f4d78f6
--- /dev/null
+++ b/text-ui-test/runtest.bat
@@ -0,0 +1,21 @@
+@ECHO OFF
+
+REM create bin directory if it doesn't exist
+if not exist ..\bin mkdir ..\bin
+
+REM delete output from previous run
+del ACTUAL.TXT
+
+REM compile the code into the bin folder
+javac -cp ..\src -Xlint:none -d ..\bin ..\src\main\java\RoomShare.java
+IF ERRORLEVEL 1 (
+ echo ********** BUILD FAILURE **********
+ exit /b 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 RoomShare < input.txt > ACTUAL.TXT
+
+REM compare the output to the expected output
+FC ACTUAL.TXT EXPECTED.TXT
\ No newline at end of file
diff --git a/tutorials/gradleTutorial.md b/tutorials/gradleTutorial.md
index 08292b118d..0adfb02eb5 100644
--- a/tutorials/gradleTutorial.md
+++ b/tutorials/gradleTutorial.md
@@ -30,10 +30,10 @@ As a developer, you write a _build file_ that describes the project. A build fil
git checkout master
git merge gradle
```
-1. Open the `build.gradle` file in an editor. Update the following code block to point to the main class (i.e., the one containing the `main` method) of your application. The code below assumes your main class is `seedu.duke.Duke`
+1. Open the `build.gradle` file in an editor. Update the following code block to point to the main class (i.e., the one containing the `main` method) of your application. The code below assumes your main class is `seedu.duke.RoomShare`
```groovy
application {
- mainClassName = "seedu.duke.Duke"
+ mainClassName = "seedu.duke.RoomShare"
}
```
1. To check if Gradle has been added to the project correctly, open a terminal window, navigate to the root directory of your project and run the command `gradlew run`. This should result in Gradle running the main method of your project.
@@ -146,7 +146,7 @@ By convention, java tests belong in `src/test/java` folder. Create a new `test/j
src
├─main
│ └─java
-│ └─seedu/duke/Duke.java
+│ └─seedu/duke/RoomShare.java
└─test
└─java
└─seedu/duke/DukeTest.java
diff --git a/tutorials/javaFxTutorialPart1.md b/tutorials/javaFxTutorialPart1.md
index 561daeca43..0722d2176c 100644
--- a/tutorials/javaFxTutorialPart1.md
+++ b/tutorials/javaFxTutorialPart1.md
@@ -44,7 +44,7 @@ javafx {
## Writing your first program
-As customary, let’s start off with a simple “Hello World” program. Modify your `Duke` class to extend `javafx.application.Application`. This requires you to override the `Application#start()` method and provide a concrete implementation. Notice that the method signature for `Application#start()` has a parameter `Stage`. This is the _primary stage_ that JavaFX provides.
+As customary, let’s start off with a simple “Hello World” program. Modify your `RoomShare` class to extend `javafx.application.Application`. This requires you to override the `Application#start()` method and provide a concrete implementation. Notice that the method signature for `Application#start()` has a parameter `Stage`. This is the _primary stage_ that JavaFX provides.
```java
import javafx.application.Application;
@@ -52,7 +52,7 @@ import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
-public class Duke extends Application {
+public class RoomShare extends Application {
// ...
@@ -80,7 +80,7 @@ import javafx.application.Application;
*/
public class Launcher {
public static void main(String[] args) {
- Application.launch(Duke.class, args);
+ Application.launch(RoomShare.class, args);
}
}
```
diff --git a/tutorials/javaFxTutorialPart2.md b/tutorials/javaFxTutorialPart2.md
index f24a0cd6ad..b6d447c634 100644
--- a/tutorials/javaFxTutorialPart2.md
+++ b/tutorials/javaFxTutorialPart2.md
@@ -1,8 +1,8 @@
-# JavaFX Tutorial Part 2 - Creating a GUI for Duke
+# JavaFX Tutorial Part 2 - Creating a GUI for RoomShare
-In this tutorial, we will be creating a GUI for Duke from scratch based on the following mockup.
+In this tutorial, we will be creating a GUI for RoomShare from scratch based on the following mockup.
-![Mockup for Duke](assets/DukeMockup.png)
+![Mockup for RoomShare](assets/DukeMockup.png)
## JavaFX controls
@@ -34,7 +34,7 @@ But how do we get the exact layout we want in the UI? JavaFX provides that funct
One way to obtain the layout in the mockup is as follows.
-![Duke's layout](assets/DukeSceneGraph.png)
+![RoomShare's layout](assets/DukeSceneGraph.png)
To get that layout, we create a new `AnchorPane` and add our controls to it. Similarly, we create a new `VBox` to hold the contents of the `ScrollPane`. The code should look something like this:
@@ -49,7 +49,7 @@ import javafx.scene.layout.VBox;
import javafx.stage.Stage;
-public class Duke extends Application {
+public class RoomShare extends Application {
private ScrollPane scrollPane;
private VBox dialogContainer;
@@ -88,7 +88,7 @@ public class Duke extends Application {
Run the application and you should see something like this:
-![Duke's raw layout](assets/RawLayout.png)
+![RoomShare's raw layout](assets/RawLayout.png)
That is not what we were expecting, what did we forget to do?
@@ -106,7 +106,7 @@ Add the following code to the bottom of the `start` method. You'll have to add `
//...
//Step 2. Formatting the window to look as expected
- stage.setTitle("Duke");
+ stage.setTitle("RoomShare");
stage.setResizable(false);
stage.setMinHeight(600.0);
stage.setMinWidth(400.0);
@@ -141,7 +141,7 @@ Add the following code to the bottom of the `start` method. You'll have to add `
Run the application again. It should now look like this:
-![Duke's Final layout](assets/FinalLayout.png)
+![RoomShare's Final layout](assets/FinalLayout.png)
## Exercises
diff --git a/tutorials/javaFxTutorialPart3.md b/tutorials/javaFxTutorialPart3.md
index a9e1bdddd3..5b0f8b70e3 100644
--- a/tutorials/javaFxTutorialPart3.md
+++ b/tutorials/javaFxTutorialPart3.md
@@ -8,7 +8,7 @@ Rather than to do everything in one try, let’s iterate and build up towards ou
JavaFX has an _event-driven architecture style_. As such, we programmatically define _handler_ methods to execute as a response to certain _events_. When an event is detected, JavaFX will call the respective handlers.
-For Duke, there are two events that we want to respond to, namely the user pressing `Enter` in the `TextField` and left-clicking the `Button`. These are the `onAction` event for the `TextField` and the `onMouseClicked` event for the `Button`.
+For RoomShare, there are two events that we want to respond to, namely the user pressing `Enter` in the `TextField` and left-clicking the `Button`. These are the `onAction` event for the `TextField` and the `onMouseClicked` event for the `Button`.
For now, let’s have the application add a new `Label` with the text from the `TextField`. Update the `Main` class as follows. You'll need to add an `import javafx.scene.control.Label;` too.
```java
@@ -103,7 +103,7 @@ import javafx.scene.image.ImageView;
```
Next, add two images to the `main/resources/images` folder.
-For this tutorial, we have two images `DaUser.png` and `DaDuke.png` to represent the user avatar and Duke's avatar respectively but you can use any image you want.
+For this tutorial, we have two images `DaUser.png` and `DaDuke.png` to represent the user avatar and RoomShare's avatar respectively but you can use any image you want.
Image|Filename
---|---
@@ -112,7 +112,7 @@ Image|Filename
```java
-public class Duke extends Application {
+public class RoomShare extends Application {
// ...
private Image user = new Image(this.getClass().getResourceAsStream("/images/DaUser.png"));
private Image duke = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png"));
@@ -124,7 +124,7 @@ Add a new method to handle user input:
```java
/**
* Iteration 2:
- * Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to
+ * Creates two dialog boxes, one echoing user input and the other containing RoomShare's reply and then appends them to
* the dialog container. Clears the user input after processing.
*/
private void handleUserInput() {
@@ -142,7 +142,7 @@ private void handleUserInput() {
* Replace this stub with your completed method.
*/
private String getResponse(String input) {
- return "Duke heard: " + input;
+ return "RoomShare heard: " + input;
}
```
@@ -170,7 +170,7 @@ Run the program and see how it works.
## Iteration 3 – Adding custom behavior to DialogBox
-One additional benefit of defining a custom control is that we can add behavior specific to our `DialogBox`. Let’s add a method to flip a dialog box such that the image on the left to differentiate between user input and Duke’s output.
+One additional benefit of defining a custom control is that we can add behavior specific to our `DialogBox`. Let’s add a method to flip a dialog box such that the image on the left to differentiate between user input and RoomShare’s output.
```java
/**
@@ -224,7 +224,7 @@ Run the application and play around with it.
![DialogBoxes Iteration 3](assets/DialogBoxesIteration3.png)
Congratulations!
-You have successfully implemented a fully functional GUI for Duke!
+You have successfully implemented a fully functional GUI for RoomShare!
## Exercises
diff --git a/tutorials/javaFxTutorialPart4.md b/tutorials/javaFxTutorialPart4.md
index 0e0ab280c4..176bec9432 100644
--- a/tutorials/javaFxTutorialPart4.md
+++ b/tutorials/javaFxTutorialPart4.md
@@ -29,7 +29,7 @@ FXML is a XML-based language that allows us to define our user interface. Proper
The FXML snippet define a TextField similar to the one that we programmatically defined previous in Tutorial 2. Notice how concise FXML is compared to the plain Java version.
-Let's return to Duke and convert it to use FXML instead.
+Let's return to RoomShare and convert it to use FXML instead.
# Rebuilding the Scene using FXML
@@ -101,7 +101,7 @@ We will get to that later.
## Using Controllers
-As part of the effort to separate the code handling Duke's logic and UI, let's _refactor_ the UI-related code to its own class.
+As part of the effort to separate the code handling RoomShare's logic and UI, let's _refactor_ the UI-related code to its own class.
We call these UI classes _controllers_.
Let's implement the `MainWindow` controller class that we specified in `MainWindow.fxml`.
@@ -128,7 +128,7 @@ public class MainWindow extends AnchorPane {
@FXML
private Button sendButton;
- private Duke duke;
+ private RoomShare duke;
private Image userImage = new Image(this.getClass().getResourceAsStream("/images/DaUser.png"));
private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png"));
@@ -138,12 +138,12 @@ public class MainWindow extends AnchorPane {
scrollPane.vvalueProperty().bind(dialogContainer.heightProperty());
}
- public void setDuke(Duke d) {
+ public void setDuke(RoomShare d) {
duke = d;
}
/**
- * Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to
+ * Creates two dialog boxes, one echoing user input and the other containing RoomShare's reply and then appends them to
* the dialog container. Clears the user input after processing.
*/
@FXML
@@ -168,7 +168,7 @@ Similarly, methods like private methods like `handleUserInput` can be used in FX
## Using FXML in our application
-Let's create a new `Main` class as the bridge between the existing logic in `Duke` and the UI in `MainWindow`.
+Let's create a new `Main` class as the bridge between the existing logic in `RoomShare` and the UI in `MainWindow`.
**Main.java**
```java
@@ -182,11 +182,11 @@ import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
/**
- * A GUI for Duke using FXML.
+ * A GUI for RoomShare using FXML.
*/
public class Main extends Application {
- private Duke duke = new Duke();
+ private RoomShare duke = new RoomShare();
@Override
public void start(Stage stage) {
diff --git a/tutorials/textUiTestingTutorial.md b/tutorials/textUiTestingTutorial.md
index f397d76aef..e95f70f105 100644
--- a/tutorials/textUiTestingTutorial.md
+++ b/tutorials/textUiTestingTutorial.md
@@ -13,7 +13,7 @@
del ACTUAL.TXT
REM compile the code into the bin folder
- javac -cp ..\src -Xlint:none -d ..\bin ..\src\main\java\Duke.java
+ javac -cp ..\src -Xlint:none -d ..\bin ..\src\main\java\RoomShare.java
IF ERRORLEVEL 1 (
echo ********** BUILD FAILURE **********
exit /b 1
@@ -21,7 +21,7 @@
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 RoomShare < input.txt > ACTUAL.TXT
REM compare the output to the expected output
FC ACTUAL.TXT EXPECTED.TXT
@@ -44,14 +44,14 @@
fi
# compile the code into the bin folder, terminates if error occurred
- if ! javac -cp ../src -Xlint:none -d ../bin ../src/main/java/Duke.java
+ if ! javac -cp ../src -Xlint:none -d ../bin ../src/main/java/RoomShare.java
then
echo "********** BUILD FAILURE **********"
exit 1
fi
# run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT
- java -classpath ../bin Duke < input.txt > ACTUAL.TXT
+ java -classpath ../bin RoomShare < input.txt > ACTUAL.TXT
# compare the output to the expected output
diff ACTUAL.TXT EXPECTED.TXT
diff --git a/ui-mockup.png b/ui-mockup.png
new file mode 100644
index 0000000000..5a40aa7a70
Binary files /dev/null and b/ui-mockup.png differ