diff --git a/README.md b/README.md
index 8715d4d91..3fe1f9bd9 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Duke project template
+# chatbot.Duke project template
This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.
@@ -13,7 +13,7 @@ Prerequisites: JDK 11, update Intellij to the most recent version.
1. If there are any further prompts, accept the defaults.
1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
In the same dialog, set the **Project language level** field to the `SDK default` option.
-3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output:
+3. After that, locate the `src/main/java/chatbot.Duke.java` file, right-click it, and choose `Run chatbot.Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output:
```
Hello from
____ _
diff --git a/data.txt b/data.txt
new file mode 100644
index 000000000..0dccabe2d
--- /dev/null
+++ b/data.txt
@@ -0,0 +1,3 @@
+true| concert | aer | thurs
+false| Homework | Friday
+false|event concert |now| thwn
diff --git a/docs/README.md b/docs/README.md
index 8077118eb..4436e9420 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -2,28 +2,117 @@
## Features
-### Feature-ABC
+### Feature: Add Todo, Deadline or Event
-Description of the feature.
+Use app to record todos, deadlines and events with a custom user description for each added entry. Deadlines support due dates and events support start and end dates. Todos, deadlines and events can be removed as well.
-### Feature-XYZ
+Can also search for tasks with keywords from their task description.
+
+### Feature: Mark/unmark
+
+Use app to mark/unmark todos/deadlines/events as done or not done yet.
+
+### Feature: Find
+
+Use app to find todos/deadlines/events by searching the task list for the relavent keyword in their descriptions
+
+### Feature: List
+
+List all todos, deadlines and events.
+
+### Feature: Save
+
+Todos, deadlines and events are saved in between running the program.
-Description of the feature.
## Usage
-### `Keyword` - Describe action
+### `todo`/`deadline`/`event` - Add todo, deadline or event
+
+How to add a Todo:
+
+todo [description]
+
+
+How to add a Deadline:
+
+deadline [description] /by [due date]
+
+
+How to add an Event:
+
+event [description] /from [start date] /to [end date]
-Describe the action and its outcome.
Example of usage:
-`keyword (optional arguments)`
+`deadline Homework /by Friday`
+
+Expected outcome:
+
+Adds a new deadline with description "go to school" with due date of "Friday"
+
+```
+Created new Deadline:
+ Homework (by: Friday)
+```
+
+### `mark`/`unmark` - Mark/unmark todo, deadline or event
+
+Mark/unmark a todo/event/deadline as done or not done yet using the mark/unmark keyword:
+
+mark [item position in list]
+
+unmark [item position in list]
+
+
+Example of usage:
+
+`mark 1`
+
+Expected outcome:
+
+Marks todo/deadline/event in position 1 of list as done
+
+```
+Marked as done:
+ Homework
+```
+
+### `list` - Lists all todos, deadlines and events
+
+Example of usage:
+
+`list`
Expected outcome:
-Description of the outcome.
+```
+[D][X] Homework (by: Friday)
+```
+
+### `find` - Lists all todos, deadlines and events that contain search term in the description
+
+find [search term]
+
+Example of usage:
+
+`find Homework`
+
+Expected outcome:
+
+```
+[D][X] Homework (by: Friday)
+```
+
+### `bye` - Exits program
+
+Example of usage:
+
+`bye`
+
+Expected outcome:
```
-expected output
+Bye. Hope to see you again soon!
```
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/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..70897dd5d
--- /dev/null
+++ b/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: chatbot.Duke
+
diff --git a/src/main/java/chatbot/Duke.java b/src/main/java/chatbot/Duke.java
new file mode 100644
index 000000000..aff7fcc81
--- /dev/null
+++ b/src/main/java/chatbot/Duke.java
@@ -0,0 +1,157 @@
+package chatbot;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+import exception.FattyException;
+import tasks.Task;
+
+/**
+ * This is the chatbot class. This contains an array of Task objects and contains functions to handle them.
+ */
+
+public class Duke {
+ public static ArrayList taskList;
+ private static Storage storage;
+ private static Ui ui;
+ private static Parser parser;
+
+ public Duke() {
+ taskList = new ArrayList<>();
+ ui = new Ui();
+ parser = new Parser();
+ storage = new Storage();
+ }
+
+ /**
+ * Main function creates new Duke object and calls run method
+ * @param args
+ * @throws FattyException
+ */
+ public static void main(String[] args) throws FattyException, IOException {
+ new Duke().run();
+ }
+
+ /**
+ * Run function executes the main while loop of the program
+ * @throws FattyException
+ */
+ public static void run() throws FattyException, IOException {
+
+ try {
+ storage.load();
+ } catch (IOException e) {
+ System.out.println(e.toString());
+ }
+
+ ui.printWelcomeMessage();
+
+ Scanner scanner = new Scanner(System.in);
+
+ while(true) {
+ String inputMessage = scanner.nextLine();
+
+ if (inputMessage.equals("bye")) {
+ ui.printGoodbyeMessage();
+ break;
+ }
+
+ try {
+ String keyword = parser.getKeyword(inputMessage);
+
+ switch (keyword) {
+ case "list":
+ list();
+ break;
+ case "mark":
+ mark(parser.getIndex(inputMessage));
+ break;
+ case "unmark":
+ unmark(parser.getIndex(inputMessage));
+ break;
+ case "delete":
+ delete(parser.getIndex(inputMessage));
+ break;
+ case "find":
+ find(parser.getSearchField(inputMessage));
+ break;
+ case "create":
+ Task newTask = parser.getTask(inputMessage);
+ taskList.add(parser.getTask(inputMessage));
+ ui.printNewTaskMessage();
+ newTask.show();
+ ui.printDivider();
+ break;
+ }
+
+ storage.save();
+
+ } catch (FattyException e) {
+ ui.printDivider();
+ System.out.println(e.toString());
+ ui.printDivider();
+ continue;
+ }
+ }
+ }
+
+ private static void add(Task task) {
+ taskList.add(task);
+ }
+
+ private static void delete(int index) throws FattyException {
+ if(index <= 0 || index > taskList.size()) {
+ throw new FattyException ("Please enter a valid index");
+ }
+
+ ui.printDeleteMessage();
+ taskList.get(index - 1).show();
+ ui.printDivider();
+
+ taskList.remove(index - 1);
+ }
+
+ private static void list() {
+ ui.printListMessage();
+
+ for(int i = 0; i < taskList.size(); i++) {
+ taskList.get(i).show();
+ }
+
+ ui.printDivider();
+ }
+
+ private static void mark(int index) throws FattyException {
+ if(index <= 0 || index > taskList.size()) {
+ throw new FattyException ("Please enter a valid index");
+ }
+
+ taskList.get(index - 1).mark();
+ }
+
+ private static void unmark(int index) throws FattyException {
+ if(index <= 0 || index > taskList.size()) {
+ throw new FattyException ("Please enter a valid index");
+ }
+
+ taskList.get(index - 1).unmark();
+ }
+
+ private static void find(String keyword) {
+ boolean found = false;
+
+ for(int i = 0; i < taskList.size(); i++) {
+ if(taskList.get(i).getDescription().contains(keyword)) {
+ taskList.get(i).show();
+ found = true;
+ }
+ }
+
+ if(found) {
+ ui.printFoundMessage();
+ } else {
+ ui.printNotFoundMessage();
+ }
+ }
+}
diff --git a/src/main/java/chatbot/Parser.java b/src/main/java/chatbot/Parser.java
new file mode 100644
index 000000000..c2f801336
--- /dev/null
+++ b/src/main/java/chatbot/Parser.java
@@ -0,0 +1,111 @@
+package chatbot;
+
+import exception.FattyException;
+import tasks.Task;
+import tasks.Deadline;
+import tasks.Event;
+import tasks.ToDo;
+
+/**
+ * This is the parser class.
+ * It handles all the user inputs and interprets them for the chat bot.
+ */
+
+public class Parser {
+ /**
+ * This is the function that returns the function type
+ * Functions that are implemented as private methods in the Duke class are returned as is
+ * If tasks are added, "create" is returned instead
+ * @param inputMessage
+ * @return
+ * @throws FattyException
+ */
+ public String getKeyword(String inputMessage) throws FattyException {
+ String keyword = inputMessage.split(" ")[0];
+
+ switch(keyword){
+ case "list":
+ case "mark":
+ case "unmark":
+ case "delete":
+ case "find":
+ return keyword;
+ case "todo":
+ case "deadline":
+ case "event":
+ return "create";
+ default:
+ throw new FattyException("Please enter a valid keyword");
+ }
+ }
+
+ /**
+ * Returns the index for commands that target a specific task
+ * @param inputMessage
+ * @return
+ * @throws FattyException
+ * @throws NumberFormatException
+ */
+ public int getIndex(String inputMessage) throws FattyException, NumberFormatException {
+ String[] parts = inputMessage.split(" ");
+
+ if(parts.length != 2) {
+ throw new FattyException("Please have correct input format");
+ }
+
+ try {
+ return Integer.parseInt(parts[1]);
+ } catch (NumberFormatException e) {
+ throw new FattyException("Please have correct input format");
+ }
+ }
+
+ public String getSearchField(String inputMessage) {
+ return inputMessage.substring(4).trim();
+ }
+
+ /**
+ * Returns a Task object to the main Duke chatbot class.
+ * Handles the creation of the task and parsing of the input message
+ * @param inputMessage
+ * @return
+ * @throws FattyException
+ */
+ public Task getTask(String inputMessage) throws FattyException {
+ String keyword = inputMessage.split(" ")[0];
+
+ switch(keyword){
+ case "todo":
+ return parseToDo(inputMessage);
+ case "deadline":
+ return parseDeadline(inputMessage);
+ case "event":
+ return parseEvent(inputMessage);
+ default:
+ return new Task("dummy", false);
+ }
+ }
+ private Task parseToDo(String inputMessage){
+ return new ToDo(inputMessage, false);
+ }
+
+ private Task parseDeadline(String inputMessage) throws FattyException {
+ String[] parts = inputMessage.split("/by");
+
+ if(parts.length != 2) {
+ throw new FattyException("Missing fields detected");
+ }
+
+ return new Deadline(parts, false);
+ }
+
+ private Task parseEvent(String inputMessage) throws FattyException {
+ String[] parts = inputMessage.split("/from | /to");
+
+ if(parts.length != 3) {
+ throw new FattyException("Missing fields detected");
+ }
+
+ return new Event(parts, false);
+ }
+}
diff --git a/src/main/java/chatbot/Storage.java b/src/main/java/chatbot/Storage.java
new file mode 100644
index 000000000..5aaf350e8
--- /dev/null
+++ b/src/main/java/chatbot/Storage.java
@@ -0,0 +1,93 @@
+package chatbot;
+
+import java.io.IOException;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.FileReader;
+import java.io.BufferedReader;
+
+import exception.FattyException;
+import tasks.Task;
+import tasks.ToDo;
+import tasks.Event;
+import tasks.Deadline;
+
+/**
+ * This is the storage class.
+ * It handles the storing of data between sessions.
+ */
+
+public class Storage {
+ private File file;
+
+ public Storage() {
+ this.file = new File("data.txt");
+ }
+
+ /**
+ * Method to save taskList information to file
+ * Called every time there is an update to the taskList
+ */
+ public void save() {
+ try (FileWriter fileWriter = new FileWriter("data.txt")) {
+ for (int i = 0; i < Duke.taskList.size(); i++) {
+ Task task = Duke.taskList.get(i);
+ String description = task.getDescription();
+ String isDone = task.getDone();
+
+ if (task instanceof ToDo) {
+ fileWriter.write(isDone + "|" + description + "\n");
+ continue;
+ }
+
+ String time = task.getTime();
+ fileWriter.write(isDone + "|" + description + "|" + time + "\n");
+ }
+ } catch (IOException e) {
+ System.out.println("Error writing file");
+ }
+ }
+
+ /**
+ * Loads information from the save file to the program
+ * Called on program startup
+ * Creates new file if the save file does not exist
+ * Throws format exceptions if the save file has been corrupted
+ * @throws IOException
+ * @throws FattyException
+ */
+ public void load() throws IOException, FattyException {
+ if (!this.file.exists()) {
+ try {
+ this.file.createNewFile();
+ } catch (IOException e) {
+ System.out.println("File creation failed");
+ }
+ } else {
+ try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ String [] words = line.split("\\|");
+
+ for(int i = 0; i < words.length; i++) {
+ words[i] = words[i].trim();
+ }
+
+ boolean isDone = words[0].equals("true");
+
+ if (words.length == 2) {
+ Duke.taskList.add(new ToDo(words[1], isDone));
+ } else if (words.length == 3) {
+ String [] args = {words[1], words[2]};
+ Duke.taskList.add(new Deadline(args, isDone));
+ } else if(words.length == 4) {
+ String [] args = {words[1], words[2], words[3]};
+ Duke.taskList.add(new Event(args, isDone));
+ } else {
+ throw new FattyException("Save file corrupted.");
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/chatbot/Ui.java b/src/main/java/chatbot/Ui.java
new file mode 100644
index 000000000..14fcdffe6
--- /dev/null
+++ b/src/main/java/chatbot/Ui.java
@@ -0,0 +1,60 @@
+package chatbot;
+
+import java.util.ArrayList;
+
+import tasks.Task;
+
+/**
+ * This is the user interface class.
+ * It handles the printing of all cosmetics and user messages.
+ * Each type of user message is implemented in its own public method
+ */
+
+public class Ui {
+ public void printDivider() {
+ System.out.println("------------------------------------");
+ }
+
+ public void printWelcomeMessage() {
+ printDivider();
+ System.out.println("Welcome to TheChattyFatty chatbot!");
+ printDivider();
+ }
+
+ public void printGoodbyeMessage() {
+ printDivider();
+ System.out.println("Goodbye!");
+ printDivider();
+ }
+
+ public void printNotFoundMessage() {
+ printDivider();
+ System.out.println("Task not found.");
+ printDivider();
+ }
+
+ public void printFoundMessage() {
+ printDivider();
+ System.out.println("Found the above tasks.");
+ printDivider();
+ }
+
+ public void printListMessage() {
+ printDivider();
+ System.out.println("Here are your results:");
+ }
+
+ public void printNewTaskMessage() {
+ printDivider();
+ System.out.println("Successfully created:");
+ }
+
+ public void printDeleteMessage() {
+ printDivider();
+ System.out.println("Successfully deleted:");
+ }
+
+ public void printTask(Task t) {
+ t.show();
+ }
+}
diff --git a/src/main/java/exception/FattyException.java b/src/main/java/exception/FattyException.java
new file mode 100644
index 000000000..b827c5348
--- /dev/null
+++ b/src/main/java/exception/FattyException.java
@@ -0,0 +1,12 @@
+package exception;
+
+/**
+ * This is the exception class.
+ * It contains the custom exception that is thrown by the chatbot.
+ */
+
+public class FattyException extends Exception{
+ public FattyException(String errorMessage) {
+ super(errorMessage);
+ }
+}
diff --git a/src/main/java/tasks/Deadline.java b/src/main/java/tasks/Deadline.java
new file mode 100644
index 000000000..fed7eb893
--- /dev/null
+++ b/src/main/java/tasks/Deadline.java
@@ -0,0 +1,30 @@
+/**
+ * This is the deadline class which contains a description as well as a due date. It inherits from the task class
+ */
+
+package tasks;
+
+public class Deadline extends Task{
+ private String deadline;
+ public Deadline(String[] parts, boolean isDone){
+ super(parts[0], isDone);
+ this.deadline = parts[1];
+ }
+
+ @Override
+ public String getTime(){
+ return deadline;
+ }
+
+ @Override
+ public void show(){
+ System.out.print("[D][");
+ if(isDone){
+ System.out.print("X");
+ }
+ else{
+ System.out.print(" ");
+ }
+ System.out.println("] " + description + " (by: " + deadline + ")");
+ }
+}
diff --git a/src/main/java/tasks/Event.java b/src/main/java/tasks/Event.java
new file mode 100644
index 000000000..645e79554
--- /dev/null
+++ b/src/main/java/tasks/Event.java
@@ -0,0 +1,34 @@
+/**
+ * This is the Event class which contains a task description, event start time and event end time.
+ * It inherits from the task class.
+ */
+
+package tasks;
+
+public class Event extends Task{
+ private String start;
+ private String end;
+
+ public Event(String[] parts, boolean isDone){
+ super(parts[0], isDone);
+ this.start = parts[1];
+ this.end = parts[2];
+ }
+
+ @Override
+ public String getTime(){
+ return start + "|" + end;
+ }
+
+ @Override
+ public void show(){
+ System.out.print("[D][");
+ if(isDone){
+ System.out.print("X");
+ }
+ else{
+ System.out.print(" ");
+ }
+ System.out.println("] " + description + " (from:" + start + " to:" + end + ")");
+ }
+}
diff --git a/src/main/java/tasks/Task.java b/src/main/java/tasks/Task.java
new file mode 100644
index 000000000..76a49e262
--- /dev/null
+++ b/src/main/java/tasks/Task.java
@@ -0,0 +1,51 @@
+/**
+ * This is the task class which is the base class for todo, deadline and event classes.
+ * All task class objects can be marked as done or not done yet
+ */
+
+package tasks;
+
+public class Task{
+ protected String description;
+ protected boolean isDone;
+
+ public Task(String description, boolean isDone){
+ this.description = description;
+ this.isDone = isDone;
+ }
+
+ public void show(){
+ System.out.print("[?][");
+ if(isDone){
+ System.out.print("X");
+ }
+ else{
+ System.out.print(" ");
+ }
+ System.out.println("] " + description);
+ }
+
+ public void mark(){
+ isDone = true;
+ System.out.println("Marked as done:");
+ System.out.println(description);
+ }
+
+ public void unmark(){
+ isDone = false;
+ System.out.println("Marked as not done yet:");
+ System.out.println(description);
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getDone() {
+ return Boolean.toString(isDone);
+ }
+
+ public String getTime(){
+ return "";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/tasks/ToDo.java b/src/main/java/tasks/ToDo.java
new file mode 100644
index 000000000..26957268e
--- /dev/null
+++ b/src/main/java/tasks/ToDo.java
@@ -0,0 +1,23 @@
+/**
+ * This is the ToDo class which contains task description only. It inherits from the Task class.
+ */
+
+package tasks;
+
+public class ToDo extends Task{
+ public ToDo(String description, boolean isDone){
+ super(description, isDone);
+ }
+
+ @Override
+ public void show(){
+ System.out.print("[T][");
+ if(isDone){
+ System.out.print("X");
+ }
+ else{
+ System.out.print(" ");
+ }
+ System.out.println("] " + description);
+ }
+}
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
index 087374464..4be53bdd5 100644
--- a/text-ui-test/runtest.bat
+++ b/text-ui-test/runtest.bat
@@ -15,7 +15,7 @@ IF ERRORLEVEL 1 (
REM no error here, errorlevel == 0
REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT
-java -classpath ..\bin Duke < input.txt > ACTUAL.TXT
+java -classpath ..\bin chatbot.Duke < input.txt > ACTUAL.TXT
REM compare the output to the expected output
FC ACTUAL.TXT EXPECTED.TXT
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
index c9ec87003..d1673aa74 100644
--- a/text-ui-test/runtest.sh
+++ b/text-ui-test/runtest.sh
@@ -13,7 +13,7 @@ then
fi
# compile the code into the bin folder, terminates if error occurred
-if ! javac -cp ../src/main/java -Xlint:none -d ../bin ../src/main/java/*.java
+if ! javac -cp /Users/apple/Desktop/CS2113/ip/src/main/java -Xlint:none -d ../bin ../src/main/java/*.java
then
echo "********** BUILD FAILURE **********"
exit 1