diff --git a/README.md b/README.md
index 8715d4d91..ddafa165e 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,132 @@
-# Duke project template
-
-This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.
-
-## Setting up in Intellij
-
-Prerequisites: JDK 11, update Intellij to the most recent version.
-
-1. Open Intellij (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project first)
-1. Open the project into Intellij as follows:
- 1. Click `Open`.
- 1. Select the project directory, and click `OK`.
- 1. If there are any further prompts, accept the defaults.
-1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
- In the same dialog, set the **Project language level** field to the `SDK default` option.
-3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output:
- ```
- Hello from
- ____ _
- | _ \ _ _| | _____
- | | | | | | | |/ / _ \
- | |_| | |_| | < __/
- |____/ \__,_|_|\_\___|
- ```
+# Sinep User Guide
+A CLI Chatbot to track and manage tasks.
+***
+
+## Features
+***
+
+### 1. Add a Todo Task
+
+Adds a task of type TODO to the list. This is for tasks that do not have a deadline.
+
+Format : ``` todo DESCRIPTION ```
+
+Example command: `todo study tonight`
+Example output:
+```
+Added to Task List:
+[T][ ] study tonight
+```
+
+
+### 2. Add a Deadline Task
+
+Adds a task of type DEADLINE to the list. This is for tasks that has one deadline.
+
+Format : ``` deadline DESCRIPTION /by DEADLINE ```
+
+Example command: `deadline study /by tonight`
+Example output:
+```
+Added to Task List:
+[D][ ] study (by: tonight)
+```
+
+
+### 3. Add an Event Task
+
+Adds a task of type EVENT to the list. This is for tasks that has a time period.
+
+Format : ``` event DESCRIPTION /from START_DATE /to END_DATE ```
+
+Example command: `event study /from 22-03-24 /to 23-03-24`
+Example output:
+```
+Added to Task List:
+[E][ ] study (from: 22-03-24 to: 23-03-24)
+```
+
+
+### 4. Mark Task
+
+Marks a task as done.
+
+Format : ``` mark INDEX ```
+
+Example command: `mark 1`
+Example output:
+```
+Got it! Task 1 marked as done:
+[X] study
+```
+
+
+### 5. Unmark Task
+
+Marks a task as undone.
+
+Format : ``` unmark INDEX ```
+
+Example command: `unmark 1`
+Example output:
+```
+Got it! Task 1 unmarked as done:
+[ ] study
+```
+
+
+### 6. Delete Task
+
+Delete a task from the list.
+
+Format : ``` delete INDEX ```
+
+Example command: `delete 1`
+Example output:
+```
+Noted. I have removed this task:
+[T][0] study
+Now you have 7 tasks left.
+```
+
+
+### 7. Find Task
+
+Find a task from the list.
+
+Format : ``` find KEYWORD ```
+
+Example command: `Find study`
+Example output:
+```
+Here are the matching tasks in your list:
+1.[T][ ] study
+```
+
+
+### 8. List
+
+Gives a list of current tasks
+
+Format : ``` list ```
+
+Example command: `list`
+Example output:
+```
+Here are the current tasks in your list:
+1.[T][ ] study
+```
+
+
+### 9. Exit Programme
+
+Exit the Programme
+
+Format : ``` byer ```
+
+Example command: `bye`
+Example output:
+```
+Bye. Hope to see you again soon!
+```
+
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 000000000..a388517ae
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,42 @@
+plugins {
+ id 'java'
+ id 'application'
+ id 'com.github.johnrengelman.shadow' version '7.1.2'
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.10.0'
+ testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.10.0'
+}
+
+test {
+ useJUnitPlatform()
+
+ testLogging {
+ events "passed", "skipped", "failed"
+
+ showExceptions true
+ exceptionFormat "full"
+ showCauses true
+ showStackTraces true
+ showStandardStreams = false
+ }
+}
+
+application {
+ mainClass.set("seedu.duke.Duke")
+}
+
+shadowJar {
+ archiveBaseName = "duke"
+ archiveClassifier = null
+ dependsOn("distZip", "distTar")
+}
+
+run{
+ standardInput = System.in
+}
diff --git a/docs/README.md b/docs/README.md
index 8077118eb..ddafa165e 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,29 +1,132 @@
-# User Guide
+# Sinep User Guide
+A CLI Chatbot to track and manage tasks.
+***
-## Features
+## Features
+***
-### Feature-ABC
+### 1. Add a Todo Task
-Description of the feature.
+Adds a task of type TODO to the list. This is for tasks that do not have a deadline.
-### Feature-XYZ
+Format : ``` todo DESCRIPTION ```
-Description of the feature.
+Example command: `todo study tonight`
+Example output:
+```
+Added to Task List:
+[T][ ] study tonight
+```
+
+
+### 2. Add a Deadline Task
+
+Adds a task of type DEADLINE to the list. This is for tasks that has one deadline.
+
+Format : ``` deadline DESCRIPTION /by DEADLINE ```
+
+Example command: `deadline study /by tonight`
+Example output:
+```
+Added to Task List:
+[D][ ] study (by: tonight)
+```
+
+
+### 3. Add an Event Task
+
+Adds a task of type EVENT to the list. This is for tasks that has a time period.
+
+Format : ``` event DESCRIPTION /from START_DATE /to END_DATE ```
+
+Example command: `event study /from 22-03-24 /to 23-03-24`
+Example output:
+```
+Added to Task List:
+[E][ ] study (from: 22-03-24 to: 23-03-24)
+```
+
+
+### 4. Mark Task
+
+Marks a task as done.
+
+Format : ``` mark INDEX ```
+
+Example command: `mark 1`
+Example output:
+```
+Got it! Task 1 marked as done:
+[X] study
+```
+
-## Usage
+### 5. Unmark Task
-### `Keyword` - Describe action
+Marks a task as undone.
-Describe the action and its outcome.
+Format : ``` unmark INDEX ```
-Example of usage:
+Example command: `unmark 1`
+Example output:
+```
+Got it! Task 1 unmarked as done:
+[ ] study
+```
+
+
+### 6. Delete Task
+
+Delete a task from the list.
+
+Format : ``` delete INDEX ```
+
+Example command: `delete 1`
+Example output:
+```
+Noted. I have removed this task:
+[T][0] study
+Now you have 7 tasks left.
+```
+
+
+### 7. Find Task
+
+Find a task from the list.
+
+Format : ``` find KEYWORD ```
+
+Example command: `Find study`
+Example output:
+```
+Here are the matching tasks in your list:
+1.[T][ ] study
+```
+
+
+### 8. List
+
+Gives a list of current tasks
+
+Format : ``` list ```
+
+Example command: `list`
+Example output:
+```
+Here are the current tasks in your list:
+1.[T][ ] study
+```
+
-`keyword (optional arguments)`
+### 9. Exit Programme
-Expected outcome:
+Exit the Programme
-Description of the outcome.
+Format : ``` byer ```
+Example command: `bye`
+Example output:
```
-expected output
+Bye. Hope to see you again soon!
```
+
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..033e24c4c
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 000000000..66c01cfeb
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 000000000..fcb6fca14
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,248 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ 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
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 000000000..6689b85be
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,92 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 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!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java
deleted file mode 100644
index 5d313334c..000000000
--- 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/ExceptionHandling/InvalidCommandException.java b/src/main/java/ExceptionHandling/InvalidCommandException.java
new file mode 100644
index 000000000..448507c5a
--- /dev/null
+++ b/src/main/java/ExceptionHandling/InvalidCommandException.java
@@ -0,0 +1,6 @@
+package ExceptionHandling;
+
+
+public class InvalidCommandException extends Exception{
+ //empty class because the output is customised based on when it is called
+}
diff --git a/src/main/java/ExceptionHandling/InvalidCommandMessageException.java b/src/main/java/ExceptionHandling/InvalidCommandMessageException.java
new file mode 100644
index 000000000..d9c267b24
--- /dev/null
+++ b/src/main/java/ExceptionHandling/InvalidCommandMessageException.java
@@ -0,0 +1,5 @@
+package ExceptionHandling;
+
+public class InvalidCommandMessageException extends Exception {
+ //empty class because the output is customised based on when it is called
+}
diff --git a/src/main/java/ExceptionHandling/InvalidTaskIndexException.java b/src/main/java/ExceptionHandling/InvalidTaskIndexException.java
new file mode 100644
index 000000000..20ca03efe
--- /dev/null
+++ b/src/main/java/ExceptionHandling/InvalidTaskIndexException.java
@@ -0,0 +1,5 @@
+package ExceptionHandling;
+
+public class InvalidTaskIndexException extends Exception{
+ //empty class because the output is customised based on when it is called
+}
diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..912c607bb
--- /dev/null
+++ b/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: Sinep.Sinep
+
diff --git a/src/main/java/Parser/CommandParse.java b/src/main/java/Parser/CommandParse.java
new file mode 100644
index 000000000..2e287da8b
--- /dev/null
+++ b/src/main/java/Parser/CommandParse.java
@@ -0,0 +1,69 @@
+package Parser;
+
+public class CommandParse {
+
+ /**
+ * Parses the event command string from a line read from the task list file.
+ *
+ * @param nextLine The string line of task read from the task list file.
+ * @return The command string for an event task, formatted as "description /from startTime /to endTime".
+ */
+ public static String getEventCommand(String nextLine) {
+ int startDescription = nextLine.indexOf("[E]") + 6;
+ int endDescription = nextLine.indexOf(" (from:");
+ String description = nextLine.substring(startDescription, endDescription).trim();
+ String fromKeyword = "(from: ";
+ String toKeyword = " to:";
+ int start = nextLine.indexOf(fromKeyword) + fromKeyword.length();
+ int end = nextLine.indexOf(toKeyword);
+ String fromTime = nextLine.substring(start, end).trim();
+ String startKeyword = "to: ";
+ int start1 = nextLine.indexOf(startKeyword) + startKeyword.length();
+ int end1 = nextLine.lastIndexOf(')');
+ String toTime = nextLine.substring(start1, end1).trim();
+ String command;
+ command = description + " /from " + fromTime + " /to " + toTime;
+ return command;
+ }
+
+ /**
+ * Parses the deadline command string from a line read from the task list file.
+ *
+ * @param nextLine The string line read from the task list file.
+ * @return The command string for a deadline task, formatted as "description /by dateTime".
+ */
+ public static String getDeadlineCommand(String nextLine) {
+ int startDescription = nextLine.indexOf("[D]") + 6;
+ int endDescription = nextLine.indexOf(" (by:");
+ String description = nextLine.substring(startDescription, endDescription).trim();
+ String keyword = "(by: ";
+ int start = nextLine.indexOf(keyword) + keyword.length();
+ int end = nextLine.lastIndexOf(')');
+
+ String dateTime = nextLine.substring(start, end).trim();
+ String command;
+ command = description + " /by " + dateTime;
+ return command;
+ }
+
+ /**
+ * Extracts the todo command description from an input string.
+ *
+ * @param input The input string containing the todo command.
+ * @return The description of the todo task.
+ */
+ public static String getTodoCommand(String input) {
+ return input.replace("todo ", "");
+ }
+
+ /**
+ * Extracts the todo task description from a line read from the task list file.
+ *
+ * @param nextLine The string line read from the task list file.
+ * @return The description of the todo task.
+ */
+
+ public static String getTodoString(String nextLine) {
+ return nextLine.substring(6).trim();
+ }
+}
diff --git a/src/main/java/Sinep/Sinep.java b/src/main/java/Sinep/Sinep.java
new file mode 100644
index 000000000..e744a6f92
--- /dev/null
+++ b/src/main/java/Sinep/Sinep.java
@@ -0,0 +1,34 @@
+package Sinep;
+
+import Storage.StorageCommand;
+import TaskList.HandleTask;
+import TaskList.Task;
+import UI.CommandUI;
+
+import java.util.ArrayList;
+import java.util.Scanner;
+import java.io.IOException;
+
+
+public class Sinep {
+ public static final String FILE_PATH = "src/main/java/Sinep/Sinep.txt";
+ public static ArrayList taskList = new ArrayList<>();
+
+ /**
+ * The main method that initializes the application, loads existing tasks, and processes user input, then save tasks.
+ *
+ * @param args Command-line arguments(not used).
+ * @throws IOException If there is an issue with loading or saving tasks to the file.
+ */
+ public static void main(String[] args) throws IOException {
+ StorageCommand.loadTaskFile(taskList);
+ Scanner scanner = new Scanner(System.in);
+ CommandUI.printGreeting();
+ while (true) {
+ String input = scanner.nextLine();
+ String command = input.split(" ", 2)[0]; // Get the first word of the input as the command
+ if (HandleTask.taskCommands(command, scanner, input)) return;
+ StorageCommand.saveTasks(taskList);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/Storage/StorageCommand.java b/src/main/java/Storage/StorageCommand.java
new file mode 100644
index 000000000..fcff1bbff
--- /dev/null
+++ b/src/main/java/Storage/StorageCommand.java
@@ -0,0 +1,124 @@
+package Storage;
+
+import Parser.CommandParse;
+import Sinep.Sinep;
+import TaskList.*;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+public class StorageCommand {
+
+ /**
+ * Loads tasks from a file and populates them into the provided taskList.
+ *
+ * @param taskList The list to populate with the loaded tasks.
+ * @throws IOException If there is an issue accessing the file.
+ */
+ public static void loadTaskFile(ArrayList taskList) throws IOException {
+ File taskFile = new File(Sinep.FILE_PATH);
+ if (!taskFile.exists()) {
+ try {
+ File parentDir = taskFile.getParentFile();
+ if (!parentDir.exists() && parentDir.mkdirs()) {
+ // Create the directory if it doesn't exist
+ throw new IOException("Failed to create directory " + parentDir.getAbsolutePath());
+ }
+ File dataFile = new File(Sinep.FILE_PATH);
+ if (!dataFile.getParentFile().exists()) {
+ Files.createDirectories(dataFile.getParentFile().toPath());
+ }
+ } catch (IOException e) {
+ System.out.println("An error occurred while trying to create the file: " + e.getMessage());
+ return; // Exit the method if file creation fails
+ }
+ }
+ try {
+ Scanner scanner = new Scanner(taskFile);
+ int counter = 0;
+ while (scanner.hasNext()) {
+ String nextLine = scanner.nextLine();
+ if (nextLine.startsWith("[T]")) {
+ String description = CommandParse.getTodoString(nextLine);
+ taskList.add(new Todo(description));
+ if (nextLine.charAt(4) == 'X') {
+ Task markingTask = taskList.get(counter);
+ markingTask.markAsDone();
+ }
+ } else if (nextLine.startsWith("[D]")) {
+ String command = CommandParse.getDeadlineCommand(nextLine);
+ taskList.add(new Deadline(command));
+ if (nextLine.charAt(4) == 'X') {
+ Task markingTask = taskList.get(counter);
+ markingTask.markAsDone();
+ }
+ } else {
+ String command = CommandParse.getEventCommand(nextLine);
+ taskList.add(new Event(command));
+ if (nextLine.charAt(4) == 'X') {
+ Task markingTask = taskList.get(counter);
+ markingTask.markAsDone();
+ }
+ }
+ counter++;
+ }
+ } catch (FileNotFoundException e) {
+ File parentDir = taskFile.getParentFile();
+ if (!parentDir.exists() && parentDir.mkdirs()) {
+ throw new IOException("File not found.");
+ }
+ }
+ }
+
+ /**
+ * Writes text to a file, with an option to append or overwrite the file.
+ *
+ * @param textToAdd The text to be written to the file.
+ * @param isAppend If true, the text will be appended to the file; if false, the file will be overwritten.
+ * @throws IOException If there is an issue writing to the file.
+ */
+ protected static void writeToFile(String textToAdd, boolean isAppend) throws IOException {
+ File taskFile = new File(Sinep.FILE_PATH);
+ if (!taskFile.getParentFile().exists() && taskFile.getParentFile().mkdirs()) {
+ throw new IOException("File not found."); // This will create the directory if it doesn't exist
+ }
+ FileWriter fw = new FileWriter(Sinep.FILE_PATH, isAppend);
+ fw.write(textToAdd + System.lineSeparator());
+ fw.close();
+ }
+
+ /**
+ * Saves the current state of the task list to a file.
+ *
+ * @param taskList The list of tasks to save.
+ */
+ public static void saveTasks(ArrayList taskList) {
+ if (taskList.isEmpty()) {
+ try {
+ writeToFile("", false);
+ } catch (IOException e) {
+ System.out.println("Error saving your file. IO issues.");
+ }
+ } else {
+ try {
+ writeToFile(taskList.get(0).toString(), false);
+ } catch (IOException e) {
+ System.out.println("Error saving your file. IO issues.");
+ }
+ int i = 1;
+ while (i < taskList.size()) {
+ try {
+ writeToFile(taskList.get(i).toString(), true);
+ i += 1;
+ } catch (IOException e) {
+ System.out.println("Error saving your file. IO issues.");
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/TaskList/Deadline.java b/src/main/java/TaskList/Deadline.java
new file mode 100644
index 000000000..ebefa1137
--- /dev/null
+++ b/src/main/java/TaskList/Deadline.java
@@ -0,0 +1,60 @@
+package TaskList;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+public class Deadline extends Task {
+ protected String rawDateTime;
+ protected LocalDate dateTime;
+ private static final DateTimeFormatter INPUT_FORMATTER = DateTimeFormatter.ofPattern("d-M-yyyy");
+ private static final DateTimeFormatter INPUT_FORMATTER2 = DateTimeFormatter.ofPattern("MMMM d yyyy");
+ private static final DateTimeFormatter OUTPUT_FORMATTER = DateTimeFormatter.ofPattern("MMMM d yyyy");
+ private String warningMessage;
+
+ /**
+ * Constructs a new Deadline with the specified description and parses the due date.
+ *
+ * @param description Description and date of the deadline in the format "description /by dd-MM-yyyy".
+ */
+ public Deadline(String description) {
+ super(description);
+ String[] descriptionParts = description.split("/by ", 2);
+ this.description = descriptionParts.length >= 1 ? descriptionParts[0].trim() : "";
+ if (descriptionParts.length > 1) {
+ this.rawDateTime = descriptionParts[1].trim(); // Store the raw date string
+ try {
+ this.dateTime = LocalDate.parse(this.rawDateTime, INPUT_FORMATTER);
+ } catch (DateTimeParseException e1) {
+ try {
+ this.dateTime = LocalDate.parse(this.rawDateTime, INPUT_FORMATTER2);
+ } catch (DateTimeParseException e2) {
+ this.warningMessage = "Advice: " + this.rawDateTime + " is an invalid date format. Please use 'dd-MM-yyyy' or 'MMMM d yyyy'.";
+ this.dateTime = null; // Ensure dateTime is null if parsing fails
+ }
+ }
+ } else {
+ this.rawDateTime = "";
+ }
+ }
+
+ /**
+ * Retrieves the warning message generated during the construction of this deadline.
+ *
+ * @return The warning message if the date was invalid, otherwise null.
+ */
+ public String getWarningMessage() {
+ return warningMessage;
+ }
+
+ /**
+ * Returns a string representation of the deadline, including its status icon,
+ * description, and due date.
+ *
+ * @return A string representation of the deadline task.
+ */
+ @Override
+ public String toString() {
+ String dateTimeString = (dateTime != null ) ? dateTime.format(OUTPUT_FORMATTER) : this.rawDateTime;
+ return "[D]" + getStatusIcon() + " " + this.description + " (by: " + dateTimeString + ")";
+ }
+}
diff --git a/src/main/java/TaskList/Event.java b/src/main/java/TaskList/Event.java
new file mode 100644
index 000000000..089e3c6ce
--- /dev/null
+++ b/src/main/java/TaskList/Event.java
@@ -0,0 +1,76 @@
+package TaskList;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+public class Event extends Task {
+ protected String rawStartDateTime;
+ protected String rawEndDateTime;
+ protected LocalDate startDateTime;
+ protected LocalDate endDateTime;
+ private static final DateTimeFormatter INPUT_FORMATTER = DateTimeFormatter.ofPattern("d-M-yyyy");
+ private static final DateTimeFormatter INPUT_FORMATTER2 = DateTimeFormatter.ofPattern("MMMM d yyyy");
+ private static final DateTimeFormatter OUTPUT_FORMATTER = DateTimeFormatter.ofPattern("MMMM d yyyy");
+
+ private String warningMessage;
+
+ /**
+ * Constructs an Event with a specified description including its start and end times.
+ *
+ * @param description Description of the event, including "/from" and "/to" time markers.
+ */
+ public Event(String description) {
+ super(description);
+ try {
+ String[] givenTimeline = description.split("/from ", 2);
+ this.description = givenTimeline.length >= 1 ? givenTimeline[0].trim() : "";
+ if (givenTimeline.length > 1) {
+ String[] startEnd = givenTimeline[1].split(" /to ", 2);
+ this.rawStartDateTime = startEnd.length > 0 ? startEnd[0].trim() : "";
+ this.rawEndDateTime = startEnd.length > 0 ? startEnd[1].trim() : "";
+ try {
+ this.startDateTime = LocalDate.parse(this.rawStartDateTime, INPUT_FORMATTER);
+ this.endDateTime = LocalDate.parse(this.rawEndDateTime, INPUT_FORMATTER);
+ } catch (DateTimeParseException e1) {
+ try {
+ this.startDateTime = LocalDate.parse(this.rawStartDateTime, INPUT_FORMATTER2);
+ this.endDateTime = LocalDate.parse(this.rawEndDateTime, INPUT_FORMATTER2);
+ } catch (DateTimeParseException e2) {
+ this.startDateTime = null;
+ this.endDateTime = null;
+ this.warningMessage = "Advice: " + this.rawStartDateTime + " and " + this.rawEndDateTime +
+ " are invalid date formats. Please use 'dd-MM-yyyy' or 'MMMM d yyyy'.";
+ }
+ }
+
+ } else {
+ this.rawStartDateTime = "";
+ this.rawEndDateTime = "";
+ }
+ } catch (Exception e) {
+ this.rawStartDateTime = "";
+ this.rawEndDateTime = "";
+ }
+ }
+
+ /**
+ * Gets the warning message generated during construction if the date format was invalid.
+ *
+ * @return Warning message if date was invalid, null otherwise.
+ */
+ public String getWarningMessage() {
+ return warningMessage;
+ }
+
+ /**
+ * Returns a string representation of the event, including its status icon, description,
+ * and formatted start and end times.
+ *
+ * @return A string representation of the event.
+ */
+ @Override
+ public String toString() {
+ String startDateTimeString = (this.startDateTime != null ) ? this.startDateTime.format(OUTPUT_FORMATTER) : this.rawStartDateTime;
+ String endDateTimeString = (this.endDateTime != null ) ? this.endDateTime.format(OUTPUT_FORMATTER) : this.rawEndDateTime;
+ return "[E]" + getStatusIcon() + " " + this.description + " (from: " + startDateTimeString + " to: " + endDateTimeString + ")";
+ }
+}
diff --git a/src/main/java/TaskList/HandleTask.java b/src/main/java/TaskList/HandleTask.java
new file mode 100644
index 000000000..ff6624a43
--- /dev/null
+++ b/src/main/java/TaskList/HandleTask.java
@@ -0,0 +1,261 @@
+package TaskList;
+
+import ExceptionHandling.InvalidCommandException;
+import ExceptionHandling.InvalidCommandMessageException;
+import ExceptionHandling.InvalidTaskIndexException;
+import Parser.CommandParse;
+import UI.BackboneUI;
+import UI.CommandUI;
+import UI.ExceptionUI;
+import java.util.Objects;
+import java.util.Scanner;
+import static Sinep.Sinep.taskList;
+
+public class HandleTask {
+
+ /**
+ * Processes the task-related commands and updates the task list accordingly.
+ *
+ * @param command The task command to execute.
+ * @param scanner The scanner object for user input.
+ * @param input The user input string.
+ * @return True if the "bye" command is issued, otherwise false.
+ */
+ public static boolean taskCommands(String command, Scanner scanner, String input) {
+ switch (command) {
+ case "bye":
+ return byeCommand(scanner);
+ case "list":
+ CommandUI.printList();
+ break;
+ case "mark":
+ markCommand(input);
+ break;
+ case "unmark":
+ unmarkCommand(input);
+ break;
+ case "todo":
+ todoCommand(input);
+ break;
+ case "deadline":
+ deadlineCommand(input);
+ break;
+ case "event":
+ eventCommand(input);
+ break;
+ case "delete":
+ deleteCommand(input);
+ break;
+ case "find":
+ findTask(input.split(" ", 2)[1]);
+ break;
+ default:
+ try {
+ throw new InvalidCommandException();
+ } catch (InvalidCommandException e) {
+ ExceptionUI.printInvalidCommand();
+ }
+ }
+ return false;
+ }
+
+ private static void deleteCommand(String input) {
+ try {
+ deleteTask(input);
+ } catch (InvalidTaskIndexException | InvalidCommandMessageException e) {
+ ExceptionUI.printInvalidDeleteIndex();
+ }
+ }
+
+ private static void eventCommand(String input) {
+ try {
+ addEvent(input);
+ } catch (InvalidCommandMessageException e) {
+ ExceptionUI.printInvalidEventMessage();
+ }
+ }
+
+ private static void deadlineCommand(String input) {
+ try {
+ addDeadline(input);
+ } catch (InvalidCommandMessageException e) {
+ ExceptionUI.printInvalidDeadlineMessage();
+ }
+ }
+
+ private static void todoCommand(String input) {
+ try {
+ addTodo(input);
+ } catch (InvalidCommandMessageException e) {
+ ExceptionUI.printInvalidTodoMessage();
+ }
+ }
+
+ private static void unmarkCommand(String input) {
+ try {
+ unmarkList(input);
+ } catch (InvalidTaskIndexException e){
+ ExceptionUI.printInvalidTaskIndex();
+ }
+ }
+
+ private static void markCommand(String input) {
+ try {
+ markList(input);
+ } catch (InvalidTaskIndexException e){
+ ExceptionUI.printInvalidTaskIndex();
+ }
+ }
+
+ private static boolean byeCommand(Scanner scanner) {
+ CommandUI.printBye();
+ scanner.close();
+ return true;
+ }
+
+ /**
+ * Searches for tasks that contain the given keyword and prints them.
+ *
+ * @param keyword The keyword to search for in task descriptions.
+ */
+ public static void findTask(String keyword) {
+ System.out.println(BackboneUI.line);
+ System.out.println("Here are the matching tasks in your list:");
+
+ int taskNumber = 1;
+ for (Task task : taskList) {
+ if (task.description.contains(keyword)) {
+ System.out.println(taskNumber + "." + task);
+ taskNumber++;
+ }
+ }
+ if (Objects.equals(taskNumber, 1)) {
+ System.out.println("Sorry, the task does not exist!");
+ }
+
+ System.out.println(BackboneUI.line);
+ }
+
+ /**
+ * Deletes a task from the task list based on the given input index.
+ *
+ * @param input The input string containing the index of the task to delete.
+ * @throws InvalidTaskIndexException If the task index is invalid.
+ * @throws InvalidCommandMessageException If the input command message is invalid.
+ */
+ public static void deleteTask(String input) throws InvalidTaskIndexException, InvalidCommandMessageException {
+ if (Objects.equals(input, "delete")) {
+ throw new InvalidCommandMessageException();
+ }
+ int taskIndex = Integer.parseInt(input.substring(7)) - 1;
+ if (taskIndex >= taskList.size()) {
+ throw new InvalidTaskIndexException();
+ }
+ CommandUI.printDelete(taskIndex);
+ }
+
+ /**
+ * Marks a task as done based on the given input index.
+ *
+ * @param input The input string containing the index of the task to mark as done.
+ * @throws InvalidTaskIndexException If the task index is invalid.
+ */
+ public static void markList(String input) throws InvalidTaskIndexException {
+ int taskIndex = Integer.parseInt(input.substring(5)) - 1;
+ if (taskIndex >= taskList.size()) {
+ throw new InvalidTaskIndexException();
+ }
+ Task markingTask = taskList.get(taskIndex);
+ markingTask.markAsDone();
+ CommandUI.printMark(taskIndex, markingTask);
+ }
+
+ /**
+ * Unmarks a task as done based on the given input index.
+ *
+ * @param input The input string containing the index of the task to unmark as done.
+ * @throws InvalidTaskIndexException If the task index is invalid.
+ */
+ public static void unmarkList(String input) throws InvalidTaskIndexException {
+ int taskIndex = Integer.parseInt(input.substring(7)) - 1;
+ if (taskIndex >= taskList.size()) {
+ throw new InvalidTaskIndexException();
+ }
+ Task markingTask = taskList.get(taskIndex);
+ markingTask.unmarkAsDone();
+ CommandUI.printUnmark(taskIndex, markingTask);
+ }
+
+ /**
+ * Adds a new Todo task to the task list based on the given description.
+ *
+ * @param input The input string containing the description of the Todo task.
+ * @throws InvalidCommandMessageException If the input command message is invalid.
+ */
+ public static void addTodo(String input) throws InvalidCommandMessageException {
+ if (Objects.equals(input, "todo")) {
+ throw new InvalidCommandMessageException();
+ }
+ String actualDescription = CommandParse.getTodoCommand(input);
+ Todo newTodo = new Todo(actualDescription);
+ taskList.add(newTodo);
+ CommandUI.todoAddMessage(newTodo);
+ }
+
+ /**
+ * Adds a new Deadline task to the task list based on the given description.
+ *
+ * @param input The input string containing the description of the Deadline task.
+ * @throws InvalidCommandMessageException If the input command message is invalid.
+ */
+ public static void addDeadline(String input) throws InvalidCommandMessageException{
+ boolean containsDeadline = input.contains("/by");
+ if (Objects.equals(input, "deadline") || !containsDeadline) {
+ throw new InvalidCommandMessageException();
+ }
+ String actualDescription = input.replace("deadline ", "");
+ String[] inputParts = actualDescription.split("/by", 2);
+ if (Objects.equals(inputParts[0], "") || Objects.equals(inputParts[1], "")) {
+ throw new InvalidCommandMessageException();
+ }
+ Deadline newDeadline = new Deadline(actualDescription);
+ taskList.add(newDeadline);
+
+ CommandUI.commandDeadlineMessage(newDeadline);
+
+ }
+
+ /**
+ * Adds a new Event task to the task list based on the given description.
+ *
+ * @param input The input string containing the description of the Event task.
+ * @throws InvalidCommandMessageException If the input command message is invalid.
+ */
+ public static void addEvent(String input) throws InvalidCommandMessageException{
+ boolean containStart = input.contains("/from");
+ Event newEvent = getEvent(input, containStart);
+ taskList.add(newEvent);
+ CommandUI.commandEventMessage(newEvent);
+ }
+
+ /**
+ * Helper method to create an Event task from the given input.
+ *
+ * @param input The input string containing the description of the Event task.
+ * @param containStart A flag indicating whether the input contains a start date/time.
+ * @return The created Event task.
+ * @throws InvalidCommandMessageException If the input command message is invalid.
+ */
+ private static Event getEvent(String input, boolean containStart) throws InvalidCommandMessageException {
+ boolean containEnd = input.contains("/to");
+ if (Objects.equals(input, "event") || !containStart || !containEnd) {
+ throw new InvalidCommandMessageException();
+ }
+ String actualDescription = input.replace("event ", "");
+ String[] inputParts = actualDescription.split("/from|/to", 3);
+ if (Objects.equals(inputParts[0], "") || Objects.equals(inputParts[1], "") || Objects.equals(inputParts[2], "")) {
+ throw new InvalidCommandMessageException();
+ }
+ return new Event(actualDescription);
+ }
+}
diff --git a/src/main/java/TaskList/Task.java b/src/main/java/TaskList/Task.java
new file mode 100644
index 000000000..d7ac49cba
--- /dev/null
+++ b/src/main/java/TaskList/Task.java
@@ -0,0 +1,49 @@
+package TaskList;
+
+public class Task {
+ public String description;
+ protected boolean isDone;
+
+ /**
+ * Creates a new Task with the specified description.
+ *
+ * @param description The description of the task.
+ */
+ public Task(String description) {
+ this.description = description;// Description of the task
+ this.isDone = false;//Completion status of the task(True: Done, False: Undone)
+ }
+
+ /**
+ * Retrieves the status icon indicating whether the task is done.
+ *
+ * @return A string representing the status icon. "[X]" if the task is done, "[ ]" otherwise.
+ */
+ public String getStatusIcon() {
+ return (isDone ? "[X]" : "[ ]");// mark tasks that are done with X, else empty space
+ }
+
+ /**
+ * Marks the task as done by setting its completion status to true.
+ */
+ public void markAsDone() {
+ isDone = true;
+ }
+
+ /**
+ * Unmarks the task as done by setting its completion status to false.
+ */
+ public void unmarkAsDone() {
+ isDone = false;
+ }
+
+ /**
+ * Returns a string representation of the task, combining its status icon and description.
+ *
+ * @return A string representation of the task.
+ */
+ public String toString() {
+ return getStatusIcon() + " " + this.description; //combine the status and task description for easier listing
+ }
+
+}
diff --git a/src/main/java/TaskList/Todo.java b/src/main/java/TaskList/Todo.java
new file mode 100644
index 000000000..492049f30
--- /dev/null
+++ b/src/main/java/TaskList/Todo.java
@@ -0,0 +1,12 @@
+package TaskList;
+
+public class Todo extends Task {
+ public Todo(String description) {
+ super(description);
+ this.description = description.trim();
+ }
+ @Override
+ public String toString() {
+ return "[T]" + getStatusIcon() + " " + this.description;
+ }
+}
diff --git a/src/main/java/UI/BackboneUI.java b/src/main/java/UI/BackboneUI.java
new file mode 100644
index 000000000..6549f2b52
--- /dev/null
+++ b/src/main/java/UI/BackboneUI.java
@@ -0,0 +1,6 @@
+package UI;
+
+public class BackboneUI {
+ public static String line = "_____________________________________________________________________";
+ public static String newLine = System.lineSeparator();
+}
diff --git a/src/main/java/UI/CommandUI.java b/src/main/java/UI/CommandUI.java
new file mode 100644
index 000000000..b0e04d11c
--- /dev/null
+++ b/src/main/java/UI/CommandUI.java
@@ -0,0 +1,109 @@
+package UI;
+
+import Sinep.Sinep;
+import TaskList.Deadline;
+import TaskList.Event;
+import TaskList.Task;
+import TaskList.Todo;
+
+public class CommandUI {
+ public static void printGreeting() {
+ final String greeting = "Hello! I'm Sinep, your personal chatbot!\n"
+ + "What can I do for you today?";
+ System.out.println(BackboneUI.line + BackboneUI.newLine + greeting + BackboneUI.newLine + BackboneUI.line);
+ }
+
+ public static void printBye() {
+ final String bye = "Bye. Hope to see you again soon!";
+ System.out.println(BackboneUI.line + BackboneUI.newLine + bye + BackboneUI.newLine + BackboneUI.line);
+
+ }
+
+ public static void printList() {
+ System.out.println(BackboneUI.line);
+ System.out.println("Here are the current tasks in your list:");
+ if (Sinep.taskList.isEmpty()) {
+ System.out.println("Great job! You have no tasks!");
+ } else {
+ for (int i = 0; i < Sinep.taskList.size(); i++) {
+ System.out.println((i + 1) + "." + Sinep.taskList.get(i));
+ }
+ }
+ System.out.println(BackboneUI.line);
+ }
+
+
+ /**
+ * Prints a message indicating a Todo task has been added.
+ *
+ * @param newTodo The Todo task that has been added.
+ */
+ public static void todoAddMessage(Todo newTodo) {
+ System.out.println(BackboneUI.line + BackboneUI.newLine + "Added to task list:" + BackboneUI.newLine + newTodo);
+ System.out.println("Now you have " + Sinep.taskList.size() + " tasks in the list." + BackboneUI.newLine + BackboneUI.line);
+ }
+
+ /**
+ * Prints a message indicating a Deadline task has been added, along with any warning messages.
+ *
+ * @param message The Deadline task that has been added.
+ */
+ public static void commandDeadlineMessage(Deadline message) {
+ String warningMessage = message.getWarningMessage();
+ String realMessage = message.toString();
+ System.out.println(BackboneUI.line + BackboneUI.newLine +
+ (warningMessage != null ? warningMessage + BackboneUI.newLine : "") +
+ "Added to task list:" + BackboneUI.newLine + realMessage);
+ System.out.println("Now you have " + Sinep.taskList.size() + " tasks in the list." + BackboneUI.newLine + BackboneUI.line);
+ }
+
+ /**
+ * Prints a message indicating an Event task has been added, along with any warning messages.
+ *
+ * @param message The Event task that has been added.
+ */
+ public static void commandEventMessage(Event message) {
+ String warningMessage = message.getWarningMessage();
+ String realMessage = message.toString();
+ System.out.println(BackboneUI.line + BackboneUI.newLine +
+ (warningMessage != null ? warningMessage + BackboneUI.newLine : "") +
+ "Added to task list:" + BackboneUI.newLine + realMessage);
+ System.out.println("Now you have " + Sinep.taskList.size() + " tasks in the list." + BackboneUI.newLine + BackboneUI.line);
+ }
+
+ /**
+ * Prints a message indicating a task has been marked as not done.
+ *
+ * @param taskIndex The index of the task that has been unmarked.
+ * @param markingTask The task that has been unmarked.
+ */
+ public static void printUnmark(int taskIndex, Task markingTask) {
+ System.out.println(BackboneUI.line + BackboneUI.newLine + "Got it! Task " + (taskIndex + 1) + " marked as undone:");
+ System.out.println(markingTask.getStatusIcon() + " " + markingTask.description + BackboneUI.newLine + BackboneUI.line);
+ }
+
+ /**
+ * Prints a message indicating a task has been marked as done.
+ *
+ * @param taskIndex The index of the task that has been marked.
+ * @param markingTask The task that has been marked.
+ */
+ public static void printMark(int taskIndex, Task markingTask) {
+ System.out.println(BackboneUI.line + BackboneUI.newLine + "Got it! Task " + (taskIndex + 1) + " marked as done:");
+ System.out.println(markingTask.getStatusIcon() + " " + markingTask.description + BackboneUI.newLine + BackboneUI.line);
+ }
+
+ /**
+ * Prints a message indicating a task has been deleted.
+ *
+ * @param taskIndex The index of the task that has been deleted.
+ */
+ public static void printDelete(int taskIndex) {
+ System.out.println(BackboneUI.line);
+ System.out.println("Noted. I have removed this task:");
+ Task removedTask = Sinep.taskList.remove(taskIndex);
+ System.out.println(removedTask);
+ System.out.println("Now you have " + Sinep.taskList.size() + " tasks left.");
+ System.out.println(BackboneUI.line);
+ }
+}
diff --git a/src/main/java/UI/ExceptionUI.java b/src/main/java/UI/ExceptionUI.java
new file mode 100644
index 000000000..8b1979711
--- /dev/null
+++ b/src/main/java/UI/ExceptionUI.java
@@ -0,0 +1,27 @@
+package UI;
+
+public class ExceptionUI {
+ public static void printInvalidCommand() {
+ System.out.println("Please enter a valid command: todo, deadline or event");
+ }
+
+ public static void printInvalidDeleteIndex() {
+ System.out.println("The delete command is invalid" + BackboneUI.newLine + BackboneUI.line);
+ }
+
+ public static void printInvalidEventMessage() {
+ System.out.println("The event command is invalid" + BackboneUI.newLine + BackboneUI.line);
+ }
+
+ public static void printInvalidDeadlineMessage() {
+ System.out.println("The deadline command is invalid" + BackboneUI.newLine + BackboneUI.line);
+ }
+
+ public static void printInvalidTodoMessage() {
+ System.out.println("The todo command message is invalid" + BackboneUI.newLine + BackboneUI.line);
+ }
+
+ public static void printInvalidTaskIndex() {
+ System.out.println("The task you are trying to edit does not exist!" + BackboneUI.newLine + BackboneUI.line);
+ }
+}
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e..d0c21ee98 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,82 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
-
+_____________________________________________________________________
+Hello! I'm Sinep, your personal chatbot!
+What can I do for you today?
+_____________________________________________________________________
+_____________________________________________________________________
+Here are the current tasks in your list:
+Great job! You have no tasks!
+_____________________________________________________________________
+Please enter a valid command: todo, deadline or event
+_____________________________________________________________________
+Added to task list:
+[T][ ] study for EE2211
+Now you have 1 tasks in the list.
+_____________________________________________________________________
+_____________________________________________________________________
+Here are the current tasks in your list:
+1.[T][ ] study for EE2211
+_____________________________________________________________________
+_____________________________________________________________________
+Added to task list:
+[D][ ] finish assignment1 /by 10 June 2024 (by: 10 June 2024)
+Now you have 2 tasks in the list.
+_____________________________________________________________________
+_____________________________________________________________________
+Here are the current tasks in your list:
+1.[T][ ] study for EE2211
+2.[D][ ] finish assignment1 /by 10 June 2024 (by: 10 June 2024)
+_____________________________________________________________________
+_____________________________________________________________________
+Added to task list:
+[E][ ] hair for hope /from 10 June 2024 /to 20 June 2024 (from: 10 June 2024 to: 20 June 2024)
+Now you have 3 tasks in the list.
+_____________________________________________________________________
+_____________________________________________________________________
+Here are the current tasks in your list:
+1.[T][ ] study for EE2211
+2.[D][ ] finish assignment1 /by 10 June 2024 (by: 10 June 2024)
+3.[E][ ] hair for hope /from 10 June 2024 /to 20 June 2024 (from: 10 June 2024 to: 20 June 2024)
+_____________________________________________________________________
+_____________________________________________________________________
+Got it! Task 1 marked as done:
+[X] study for EE2211
+_____________________________________________________________________
+_____________________________________________________________________
+Here are the current tasks in your list:
+1.[T][X] study for EE2211
+2.[D][ ] finish assignment1 /by 10 June 2024 (by: 10 June 2024)
+3.[E][ ] hair for hope /from 10 June 2024 /to 20 June 2024 (from: 10 June 2024 to: 20 June 2024)
+_____________________________________________________________________
+_____________________________________________________________________
+Got it! Task 3 marked as done:
+[X] hair for hope /from 10 June 2024 /to 20 June 2024
+_____________________________________________________________________
+_____________________________________________________________________
+Here are the current tasks in your list:
+1.[T][X] study for EE2211
+2.[D][ ] finish assignment1 /by 10 June 2024 (by: 10 June 2024)
+3.[E][X] hair for hope /from 10 June 2024 /to 20 June 2024 (from: 10 June 2024 to: 20 June 2024)
+_____________________________________________________________________
+_____________________________________________________________________
+Got it! Task 2 marked as undone:
+[ ] finish assignment1 /by 10 June 2024
+_____________________________________________________________________
+_____________________________________________________________________
+Here are the current tasks in your list:
+1.[T][X] study for EE2211
+2.[D][ ] finish assignment1 /by 10 June 2024 (by: 10 June 2024)
+3.[E][X] hair for hope /from 10 June 2024 /to 20 June 2024 (from: 10 June 2024 to: 20 June 2024)
+_____________________________________________________________________
+_____________________________________________________________________
+Got it! Task 3 marked as undone:
+[ ] hair for hope /from 10 June 2024 /to 20 June 2024
+_____________________________________________________________________
+_____________________________________________________________________
+Here are the current tasks in your list:
+1.[T][X] study for EE2211
+2.[D][ ] finish assignment1 /by 10 June 2024 (by: 10 June 2024)
+3.[E][ ] hair for hope /from 10 June 2024 /to 20 June 2024 (from: 10 June 2024 to: 20 June 2024)
+_____________________________________________________________________
+_____________________________________________________________________
+Bye. Hope to see you again soon!
+_____________________________________________________________________
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb..209e83e71 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,17 @@
+list
+study
+todo study for EE2211
+list
+deadline finish assignment1 /by 10 June 2024
+list
+event hair for hope /from 10 June 2024 /to 20 June 2024
+list
+mark 1
+list
+mark 3
+list
+unmark 2
+list
+unmark 3
+list
+bye
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
old mode 100644
new mode 100755
index c9ec87003..6998ee3a6
--- a/text-ui-test/runtest.sh
+++ b/text-ui-test/runtest.sh
@@ -1,5 +1,6 @@
#!/usr/bin/env bash
+
# create bin directory if it doesn't exist
if [ ! -d "../bin" ]
then
@@ -13,19 +14,19 @@ then
fi
# compile the code into the bin folder, terminates if error occurred
-if ! javac -cp ../src/main/java -Xlint:none -d ../bin ../src/main/java/*.java
+if ! javac -cp ../src/main/java -Xlint:none -d ../bin ../src/main/java/Sinep/*.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 Sinep < input.txt > ACTUAL.TXT
# convert to UNIX format
cp EXPECTED.TXT EXPECTED-UNIX.TXT
dos2unix ACTUAL.TXT EXPECTED-UNIX.TXT
-
+echo "test"
# compare the output to the expected output
diff ACTUAL.TXT EXPECTED-UNIX.TXT
if [ $? -eq 0 ]