diff --git a/.classpath b/.classpath
new file mode 100644
index 000000000..b6cbb3c39
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/.project b/.project
new file mode 100644
index 000000000..5bfb5bc84
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+
+
+ ip
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/data/save.txt b/data/save.txt
new file mode 100644
index 000000000..fd7182a7d
--- /dev/null
+++ b/data/save.txt
@@ -0,0 +1,2 @@
+D|1|write book|1999/03/12 1200
+T|0|read book
diff --git a/docs/README.md b/docs/README.md
index 8077118eb..c6b83c7f6 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,29 +1,211 @@
# User Guide
-## Features
-### Feature-ABC
+ |___ | | | |_____| / / -- \ \
+ / / | | / / | | | |
+ / / | | / / | | | |
+ / /___ | | /_/__ | | -- | |
+ |_____| | | |_____| \ \____/ /
-Description of the feature.
+Zizo is a desktop app for managing tasks, optimized for use via a Command Line Interface (CLI).
+If you can type fast, Zizo can get your task management done faster than traditional GUI apps.
+## Features
-### Feature-XYZ
+### Add Todo
-Description of the feature.
+Adds a **Todo** task
-## Usage
+### Add Event
+
+Adds an **Event** task
+
+### Add Deadline
+
+Adds a **Deadline** task
+
+### List
+
+Show all the tasks in a ordered list
+### Done
+
+Mark a specific task as completed
+### Delete
+
+Remove a specific task from the tasks list
+### Show Date
+
+Show all tasks with the given deadline
+### Find
+
+Search for a tasks given a keyword
+### Terminate
-### `Keyword` - Describe action
+Ends the program
-Describe the action and its outcome.
+## Usage
+
+### `todo` - Adds a todo task to the tasks list
Example of usage:
-`keyword (optional arguments)`
+`todo Read a book`
+
+
+###Expected output
+```
+____________________________________________________________
+
+Got it. I've added this task:
+[T][ ]Read a book
+Now you have 1 tasks in the list.
+____________________________________________________________
+```
+### `deadline` - Adds a deadline task to the tasks list
+
+
+Example of usage:
+
+`deadline Read a book /by 2021/09/25 1800`
+
+
+###Expected output
+```
+____________________________________________________________
+
+Got it. I've added this task:
+[D][ ]Read a book (by: 25 Sep 2021, 6 00 PM)
+Now you have 1 tasks in the list.
+____________________________________________________________
+```
+### `event` - Adds a event task to the tasks list
+
+
+Example of usage:
+
+`event Read a book /at 2021/09/25 1800`
+
+###Expected output
+```
+____________________________________________________________
+
+Got it. I've added this task:
+[E][ ]Read a book (by: 25 Sep 2021, 6 00 PM)
+Now you have 1 tasks in the list.
+____________________________________________________________
+```
+### `list` - Shows a list of tasks
+
+
+Example of usage:
+
+`list`
+
+
+###Expected output
+```
+____________________________________________________________
+
+Here are the task in your list:
+1.[D][ ]Read a book (by: 25 Sep 2021, 6 00 PM)
+____________________________________________________________
+```
+### `done` - Mark a task as done
+
+Selects which task base on its index in the list to mark as done
+
+Format: done (Task index)
+* Index must be a positive integer
+
+Example of usage:
+
+`done 1`
Expected outcome:
+```
+ Here are the task in your list:
+1. [D][X]Read a book (by: 25 Sep 2021, 6 00 PM)
+```
+
+###Expected output
+```
+____________________________________________________________
+
+Nice! task is done
+____________________________________________________________
+```
+
+### `delete` - Delete task
+
+Selects which task to delete based on its index in the tasks list
+
+Format: delete (Task Index)
+* Index must be a positive integer
+
+
+Example of usage:
+
+`delete 1`
+
+
+###Expected output
+```
+____________________________________________________________
+Noted. I've removed this task:
+[D][X]Read a book (by: 25 Sep 2021, 6 00 PM)
+Now you have 0 tasks in the list.
+____________________________________________________________
+```
+
+### `show date` Show tasks based on date
+
+Show tasks with the specific deadline
+
+Example of usage:
+
+`show date (date in yyyy/MM/dd format)`
+
+`show date 2012/12/12`
+
+
+###Expected output
+```
+____________________________________________________________
+Here are the all the task in your list to be done by:13 Mar 1999
+[E][X] collect book (at: 13 Mar 1999, 01 00 PM)
+____________________________________________________________
+```
+
+### `find` - Search for a task
+
+Show tasks with the specific deadline
+
+Example of usage:
+
+`find (keyword of task)`
+
+`find book`
+
+###Expected output
+```
+____________________________________________________________
+Here are the all the task in your list with keyword: book
+1.[D][ ] write book (by: 12 Mar 1999, 12 00 PM)
+2.[T][ ] read book
+
+____________________________________________________________
+____________________________________________
+```
+### `Bye` - Ends the program
+
+End the program
+
+Example of usage:
-Description of the outcome.
+`bye`
+###Expected output
```
-expected output
+____________________________________________________________
+chat again next time!
+____________________________________________________________
```
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 000000000..c4192631f
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1 @@
+theme: jekyll-theme-cayman
\ No newline at end of file
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..6e864153e
--- /dev/null
+++ b/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: duke.Duke
+
diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java
new file mode 100644
index 000000000..217c7bea9
--- /dev/null
+++ b/src/main/java/duke/Duke.java
@@ -0,0 +1,63 @@
+package duke;
+
+import duke.command.Command;
+import duke.exception.DukeException;
+import duke.parser.Parser;
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+import java.io.FileNotFoundException;
+import java.util.Locale;
+import java.util.Scanner;
+
+
+public class Duke {
+ private static final String fileDir = "./data";
+ private static final String fileName = "./data/save.txt";
+ private final Storage storage;
+ private TaskList task;
+ private final Ui ui;
+
+
+ /**
+ * Initialise all classes and load save file if it exists otherwise create a new save file
+ *
+ * @param fileName The name of the save file
+ * @param fileDir The directory of the save file
+ */
+ public Duke(String fileName, String fileDir) {
+ storage = new Storage(fileName, fileDir);
+ ui = new Ui();
+ try {
+ task = new TaskList(storage.items);
+ storage.load(task);
+ } catch (FileNotFoundException e) {
+ ui.showSaveFileError();
+ storage.create();
+ task = new TaskList(storage.items);
+ }
+ }
+ private void run() {
+ Scanner in = new Scanner(System.in);
+ boolean isExit = false;
+ while (!isExit) {
+ try {
+ String fullCommand = ui.readCommand(in).toLowerCase(Locale.ROOT);
+ Command c = Parser.parse(fullCommand);
+ boolean hasError = Parser.verifyCommand(task, c, ui);
+ if (hasError) {
+ throw new DukeException();
+ }
+ c.execute(task, ui, storage);
+ isExit = c.isExit();
+ } catch (DukeException e) {
+ ui.showError();
+ }
+ }
+ storage.save();
+ ui.printEndMessage();
+ }
+ public static void main(String[] args) {
+ new Duke(fileName, fileDir).run();
+ }
+}
diff --git a/src/main/java/duke/command/AddCommand.java b/src/main/java/duke/command/AddCommand.java
new file mode 100644
index 000000000..efc3aaa5e
--- /dev/null
+++ b/src/main/java/duke/command/AddCommand.java
@@ -0,0 +1,4 @@
+package duke.command;
+
+public class AddCommand {
+}
diff --git a/src/main/java/duke/command/Command.java b/src/main/java/duke/command/Command.java
new file mode 100644
index 000000000..065fcaeeb
--- /dev/null
+++ b/src/main/java/duke/command/Command.java
@@ -0,0 +1,145 @@
+package duke.command;
+import duke.storage.Storage;
+import duke.tasklist.TaskList;
+import duke.tasklist.task.Task;
+import duke.ui.Ui;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+public class Command {
+ private static final int CMD_NOT_FOUND = 0;
+ private static final int CMD_TODO = 1;
+ private static final int CMD_EVENT = 2;
+ private static final int CMD_DEADLINE = 3;
+ private static final int CMD_LIST = 4;
+ private static final int CMD_DONE = 5;
+ private static final int CMD_DELETE = 6;
+ private static final int CMD_SHOW_DATE = 7;
+ private static final int CMD_FIND = 8;
+ private static final int CMD_TERMINATE = 0;
+ private static final String TODO = "todo";
+ private static final String EVENT = "event";
+ private static final String DEADLINE = "deadline";
+ private static final int INDEX_NUM_DONE = 5;
+ private static final int INDEX_NUM_DELETE = 7;
+ private static final String BY = "/by";
+ private static final String AT = "/at";
+ private static final String SHOW_DATE = "show date";
+ private static final String FIND = "find";
+
+ protected int command;
+ protected boolean isExit = false;
+ protected String userInput;
+
+ public Command() {
+ this.command = CMD_NOT_FOUND;
+ }
+ public void setCommand(int command) {
+ this.command = command;
+ }
+ public void setUserInput(String userInput) {
+ this.userInput = userInput;
+
+ }
+ public String getUserInput() {
+ return this.userInput;
+ }
+ public int getCommand() {
+ return this.command;
+ }
+ /**
+ * Executes the command based on the command type
+ *
+ * @param tasks An object that contains the list of tasks
+ * @param storage An object to allow saving and loading of the list of tasks
+ * @param ui An object to interacts with the user
+ */
+ public void execute(TaskList tasks, Ui ui, Storage storage) {
+ int taskCount = tasks.getTaskCount();
+ String[] userInputs;
+ switch (command) {
+ case CMD_TODO:
+ tasks.addTodo(storage.items, userInput.replace(TODO, "").trim());
+ tasks.loadTaskCount(storage.items);
+ ui.addTaskMessage(tasks, storage.items.get(taskCount));
+ break;
+ case CMD_EVENT:
+ userInputs = userInput.split(AT);
+ tasks.addEvent(storage.items, userInputs[0].trim().replace(EVENT, "").trim(), userInputs[1].trim());
+ tasks.loadTaskCount(storage.items);
+ ui.addTaskMessage(tasks, storage.items.get(taskCount));
+ break;
+ case CMD_DEADLINE:
+ userInputs = userInput.split(BY);
+ tasks.addDeadline(storage.items, userInputs[0].trim().replace(DEADLINE, "").trim(), userInputs[1].trim());
+ tasks.loadTaskCount(storage.items);
+ ui.addTaskMessage(tasks, storage.items.get(taskCount));
+ break;
+ case CMD_LIST:
+ int j = 1;
+ System.out.println(Ui.border);
+ System.out.println("Here are the task in your list:");
+ for (Task item : storage.items) {
+ if (item != null) {
+ System.out.print(j + ".");
+ System.out.println(item);
+ j++;
+ }
+ }
+ break;
+ case CMD_SHOW_DATE:
+ int index = 1;
+ LocalDate deadline = LocalDate.parse(userInput.replace(SHOW_DATE, "").trim(), DateTimeFormatter.ofPattern("yyyy/MM/dd"));
+ System.out.println(Ui.border);
+ System.out.println("Here are the all the task in your list to be done by:" + deadline.format(DateTimeFormatter.ofPattern("dd MMM yyyy")));
+ for (Task item : storage.items) {
+ if (!(item.getDate().contains("empty")) && item.getDeadline().isEqual(deadline)) {
+ System.out.print(index + ".");
+ System.out.println(item);
+ index++;
+ }
+ }
+ break;
+ case CMD_FIND:
+ index = 1;
+ String key = userInput.replace(FIND, "").trim();
+ System.out.println(Ui.border);
+ System.out.println("Here are the all the task in your list with keyword: " + key);
+ for (Task item : storage.items) {
+ if (item.getDescription().contains(key)) {
+ System.out.print(index + ".");
+ System.out.println(item);
+ index++;
+ }
+ }
+ break;
+ case CMD_DONE:
+ int dividerPosition = userInput.indexOf(" ") + 1;
+ int endPosition = userInput.length();
+ if (endPosition > INDEX_NUM_DONE) {
+ String num = userInput.substring(dividerPosition, endPosition);
+ int taskNum = Integer.parseInt(num) - 1;
+ storage.items.get(taskNum).markDone();
+ ui.showLine();
+ System.out.println("Nice! task is done " + '\n');
+ ui.showLine();
+ }
+ break;
+ case CMD_DELETE:
+ dividerPosition = userInput.indexOf(" ") + 1;
+ endPosition = userInput.length();
+ if (endPosition > INDEX_NUM_DELETE) {
+ String num = userInput.substring(dividerPosition, endPosition);
+ int taskNum = Integer.parseInt(num) - 1;
+ tasks.removeItem(ui, storage.items, taskNum);
+ }
+ break;
+ case CMD_TERMINATE:
+ isExit = true;
+ break;
+ }
+ }
+ public boolean isExit() {
+ return this.isExit;
+ }
+}
diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java
new file mode 100644
index 000000000..38b5d9e01
--- /dev/null
+++ b/src/main/java/duke/command/DeleteCommand.java
@@ -0,0 +1,4 @@
+package duke.command;
+
+public class DeleteCommand {
+}
diff --git a/src/main/java/duke/command/FindCommand.java b/src/main/java/duke/command/FindCommand.java
new file mode 100644
index 000000000..e45b2d3a6
--- /dev/null
+++ b/src/main/java/duke/command/FindCommand.java
@@ -0,0 +1,4 @@
+package duke.command;
+
+public class FindCommand {
+}
diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java
new file mode 100644
index 000000000..74e12fc53
--- /dev/null
+++ b/src/main/java/duke/command/ListCommand.java
@@ -0,0 +1,4 @@
+package duke.command;
+
+public class ListCommand {
+}
diff --git a/src/main/java/duke/command/ShowDateCommand.java b/src/main/java/duke/command/ShowDateCommand.java
new file mode 100644
index 000000000..acc9bd6ec
--- /dev/null
+++ b/src/main/java/duke/command/ShowDateCommand.java
@@ -0,0 +1,4 @@
+package duke.command;
+
+public class ShowDateCommand {
+}
diff --git a/src/main/java/duke/exception/CommandDoesNotExistException.java b/src/main/java/duke/exception/CommandDoesNotExistException.java
new file mode 100644
index 000000000..c3c6f33a0
--- /dev/null
+++ b/src/main/java/duke/exception/CommandDoesNotExistException.java
@@ -0,0 +1,4 @@
+package duke.exception;
+
+public class CommandDoesNotExistException extends Exception {
+}
diff --git a/src/main/java/duke/exception/CommandInvalidException.java b/src/main/java/duke/exception/CommandInvalidException.java
new file mode 100644
index 000000000..e6cb9ee3e
--- /dev/null
+++ b/src/main/java/duke/exception/CommandInvalidException.java
@@ -0,0 +1,4 @@
+package duke.exception;
+
+public class CommandInvalidException extends Exception {
+}
diff --git a/src/main/java/duke/exception/DateDoesNotExistException.java b/src/main/java/duke/exception/DateDoesNotExistException.java
new file mode 100644
index 000000000..28918e340
--- /dev/null
+++ b/src/main/java/duke/exception/DateDoesNotExistException.java
@@ -0,0 +1,4 @@
+package duke.exception;
+
+public class DateDoesNotExistException extends Exception {
+}
diff --git a/src/main/java/duke/exception/DukeException.java b/src/main/java/duke/exception/DukeException.java
new file mode 100644
index 000000000..6464da39f
--- /dev/null
+++ b/src/main/java/duke/exception/DukeException.java
@@ -0,0 +1,4 @@
+package duke.exception;
+
+public class DukeException extends Exception {
+}
diff --git a/src/main/java/duke/exception/EmptyDescriptionException.java b/src/main/java/duke/exception/EmptyDescriptionException.java
new file mode 100644
index 000000000..5f6a65836
--- /dev/null
+++ b/src/main/java/duke/exception/EmptyDescriptionException.java
@@ -0,0 +1,4 @@
+package duke.exception;
+
+public class EmptyDescriptionException extends Exception{
+}
diff --git a/src/main/java/duke/exception/FindIsEmptyException.java b/src/main/java/duke/exception/FindIsEmptyException.java
new file mode 100644
index 000000000..04859def0
--- /dev/null
+++ b/src/main/java/duke/exception/FindIsEmptyException.java
@@ -0,0 +1,4 @@
+package duke.exception;
+
+public class FindIsEmptyException extends Exception {
+}
diff --git a/src/main/java/duke/exception/ShowDateIsEmptyException.java b/src/main/java/duke/exception/ShowDateIsEmptyException.java
new file mode 100644
index 000000000..18d532507
--- /dev/null
+++ b/src/main/java/duke/exception/ShowDateIsEmptyException.java
@@ -0,0 +1,4 @@
+package duke.exception;
+
+public class ShowDateIsEmptyException extends Exception {
+}
diff --git a/src/main/java/duke/exception/WrongDateFormatException.java b/src/main/java/duke/exception/WrongDateFormatException.java
new file mode 100644
index 000000000..13458314a
--- /dev/null
+++ b/src/main/java/duke/exception/WrongDateFormatException.java
@@ -0,0 +1,4 @@
+package duke.exception;
+
+public class WrongDateFormatException extends Exception {
+}
diff --git a/src/main/java/duke/parser/Parser.java b/src/main/java/duke/parser/Parser.java
new file mode 100644
index 000000000..773bc5f88
--- /dev/null
+++ b/src/main/java/duke/parser/Parser.java
@@ -0,0 +1,201 @@
+package duke.parser;
+
+import duke.command.Command;
+import duke.exception.*;
+import duke.tasklist.TaskList;
+import duke.ui.Ui;
+
+public class Parser {
+ private static final int LENGTH_OF_DONE = 4;
+ private static final int LENGTH_OF_TODO = 4;
+ private static final int LENGTH_OF_FIND = 4;
+ private static final int LEN_OF_YEAR = 4;
+ private static final int LENGTH_OF_EVENT = 5;
+ private static final int LENGTH_OF_DELETE = 6;
+ private static final int LENGTH_OF_DEADLINE = 8;
+ private static final int LENGTH_OF_SHOW_DATE = 9;
+ private static final int TOTAL_NUM_MONTH = 12;
+ private static final int TOTAL_NUM_DAY = 31;
+ private static final int MIN_SPLIT_SIZE = 2;
+ private static final int CMD_NOT_FOUND = -1;
+ private static final int CMD_TODO = 1;
+ private static final int CMD_EVENT = 2;
+ private static final int CMD_DEADLINE = 3;
+ private static final int CMD_LIST = 4;
+ private static final int CMD_DONE = 5;
+ private static final int CMD_DELETE = 6;
+ private static final int CMD_SHOW_DATE = 7;
+ private static final int CMD_FIND = 8;
+ private static final int CMD_TERMINATE = 0;
+ private static final String LIST = "list";
+ private static final String SHOW_DATE = "show date";
+ private static final String TODO = "todo";
+ private static final String EVENT = "event";
+ private static final String DEADLINE = "deadline";
+ private static final String DONE = "done";
+ private static final String FIND = "find";
+ private static final String BYE = "bye";
+ private static final String DELETE = "delete";
+ private static final String BY = "/by";
+ private static final String AT = "/at";
+
+ private static boolean isInvalid(TaskList task, String line, String key) {
+ if (!line.split(key)[1].trim().isEmpty()) {
+ if (Integer.parseInt(line.split(key)[1].trim()) > task.getTaskCount()) {
+ return true;
+ }
+ }
+ return (line.length() <= LENGTH_OF_EVENT);
+ }
+
+ /**
+ * Extracts the command parameter from the user input
+ *
+ * @param fullCommand Input provided by user
+ * @return Command object of the given command
+ */
+ public static Command parse(String fullCommand) {
+ Command c;
+ c = new Command();
+ c.setUserInput(fullCommand);
+ if (fullCommand.matches(LIST)) {
+ c.setCommand(CMD_LIST);
+ } else if (fullCommand.length() > LENGTH_OF_DONE && fullCommand.substring(0, LENGTH_OF_DONE).contains(DONE)) {
+ c.setCommand(CMD_DONE);
+ } else if (fullCommand.length() >= LENGTH_OF_TODO && fullCommand.substring(0, LENGTH_OF_TODO).contains(TODO)) {
+ c.setCommand(CMD_TODO);
+ } else if (fullCommand.length() >= LENGTH_OF_EVENT && fullCommand.substring(0, LENGTH_OF_EVENT).contains(EVENT)) {
+ c.setCommand(CMD_EVENT);
+ } else if (fullCommand.length() >= LENGTH_OF_DEADLINE && fullCommand.substring(0, LENGTH_OF_DEADLINE).contains(DEADLINE)) {
+ c.setCommand(CMD_DEADLINE);
+ } else if (fullCommand.length() >= LENGTH_OF_DELETE && fullCommand.substring(0, LENGTH_OF_DELETE).contains(DELETE)) {
+ c.setCommand(CMD_DELETE);
+ } else if (fullCommand.length() >= LENGTH_OF_SHOW_DATE && fullCommand.substring(0, LENGTH_OF_SHOW_DATE).contains(SHOW_DATE)) {
+ c.setCommand(CMD_SHOW_DATE);
+ } else if (fullCommand.length() >= LENGTH_OF_FIND && fullCommand.substring(0, LENGTH_OF_FIND).contains(FIND)) {
+ c.setCommand(CMD_FIND);
+ } else if (fullCommand.matches(BYE)) {
+ c.setCommand(CMD_TERMINATE);
+ } else {
+ c.setCommand(CMD_NOT_FOUND);
+ }
+ return c;
+ }
+
+ /**
+ * Verify the if command is valid
+ *
+ * @param task List of task so far
+ * @param c Command object to access and execute the command
+ * @param ui Ui object to interact with the user
+ * @return boolean value true if command is valid
+ */
+ public static boolean verifyCommand(TaskList task, Command c, Ui ui) {
+ String userInput = c.getUserInput();
+ switch (c.getCommand()) {
+ case CMD_TODO:
+ try {
+ if (userInput.length() <= LENGTH_OF_TODO + 1) {
+ throw new EmptyDescriptionException();
+ }
+ } catch (EmptyDescriptionException e) {
+ ui.printEmptyDescriptionError(TODO);
+ return true;
+ }
+ return false;
+ case CMD_EVENT:
+ try {
+ String[] keys = userInput.replace(EVENT, "").split(AT);
+ if (keys.length < MIN_SPLIT_SIZE || keys[0].isBlank() || keys[1].isBlank()) {
+ throw new EmptyDescriptionException();
+ }
+ } catch (EmptyDescriptionException e) {
+ ui.printEmptyDescriptionError(EVENT);
+ return true;
+ }
+ return false;
+ case CMD_DEADLINE:
+ try {
+ String[] keys = userInput.replace(DEADLINE, "").split(BY);
+ if (keys.length < MIN_SPLIT_SIZE || keys[0].isBlank() || keys[1].isBlank()) {
+ throw new EmptyDescriptionException();
+ }
+ } catch (EmptyDescriptionException e) {
+ ui.printEmptyDescriptionError(DEADLINE);
+ return true;
+ }
+ return false;
+ case CMD_SHOW_DATE:
+ String key = userInput.replace(SHOW_DATE, "");
+ try {
+ if (key.isBlank()) {
+ throw new ShowDateIsEmptyException();
+ }
+ } catch (ShowDateIsEmptyException e) {
+ ui.printEmptyDateError();
+ return true;
+ }
+ try {
+ if (Integer.parseInt(key.split("/")[1].trim()) > TOTAL_NUM_MONTH) {
+ throw new WrongDateFormatException();
+ }
+ if (Integer.parseInt(key.split("/")[2].trim()) > TOTAL_NUM_DAY) {
+ throw new WrongDateFormatException();
+ }
+ } catch (WrongDateFormatException e) {
+ ui.printWrongDateFormatError();
+ return true;
+ }
+ try {
+ if (key.split("/")[0].trim().length() < LEN_OF_YEAR) {
+ throw new WrongDateFormatException();
+ }
+ } catch (WrongDateFormatException e) {
+ ui.printWrongDateFormatError();
+ return true;
+ }
+ return false;
+ case CMD_FIND:
+ try {
+ key = userInput.replace(FIND, "");
+ if (key.isBlank()) {
+ throw new FindIsEmptyException();
+ }
+ } catch (FindIsEmptyException e) {
+ ui.printFindFieldEmpty();
+ return true;
+ }
+ return false;
+ case CMD_DONE:
+ try {
+ if (isInvalid(task, userInput, DONE)) {
+ throw new CommandInvalidException();
+ }
+ } catch (CommandInvalidException e) {
+ ui.printCommandIsInvalid();
+ return true;
+ }
+ return false;
+ case CMD_DELETE:
+ try {
+ if (isInvalid(task, userInput, DELETE)) {
+ throw new CommandInvalidException();
+ }
+ } catch (CommandInvalidException e) {
+ ui.printCommandIsInvalid();
+ return true;
+ }
+ return false;
+ case CMD_LIST:
+ case CMD_TERMINATE:
+ return false;
+ default:
+ try {
+ throw new CommandDoesNotExistException();
+ } catch (CommandDoesNotExistException e) {
+ ui.printCommandDoesNotExist();
+ return true;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/storage/Storage.java b/src/main/java/duke/storage/Storage.java
new file mode 100644
index 000000000..71c45d63b
--- /dev/null
+++ b/src/main/java/duke/storage/Storage.java
@@ -0,0 +1,111 @@
+package duke.storage;
+
+import duke.tasklist.TaskList;
+import duke.tasklist.task.Task;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+
+public class Storage {
+ protected String fileName;
+ protected String fileDir;
+ public final ArrayList items = new ArrayList<>();
+
+
+ /**
+ * @param fileDir the directory of the save file
+ * @param fileName the name of the save file
+ */
+ public Storage(String fileName, String fileDir) {
+ this.fileDir = fileDir;
+ this.fileName = fileName;
+ }
+
+ /**
+ * Check and create save folder and save file if it does not exist
+ *
+ */
+ public void create() {
+ File saveFile = new File(fileName);
+ File saveDir = new File(fileDir);
+ if (saveDir.mkdirs()) {
+ System.out.println("Successfully created save dir");
+ } else {
+ System.out.println("Save folder already exists.");
+ }
+ try {
+ if (saveFile.createNewFile()) {
+ System.out.println("Successfully created save file");
+ } else {
+ System.out.println("Save file already exists");
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Save the current list of tasks to save file
+ *
+ */
+ public void save() {
+ Task[] saveLists = new Task[items.size()];
+ items.toArray(saveLists);
+ try {
+ FileWriter fw = new FileWriter(fileName);
+ for (Task saveList : saveLists) {
+ fw.write(saveList.toString().charAt(1) + "|");
+ fw.write(saveList.getStatus() + "|" + saveList.getDescription());
+ if (!saveList.getDate().equals("empty")) {
+ fw.write("|" + saveList.getDate());
+ }
+ fw.write("\n");
+ }
+ System.out.println("Automatically saved to " + fileName);
+ fw.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Loads the tasks list from save file
+ *
+ */
+ public void load(TaskList task) throws FileNotFoundException {
+ File saveFile = new File(fileName);
+ Scanner s = new Scanner(saveFile);
+ while (s.hasNext()) {
+ String[] chars = s.nextLine().split("\\|");
+ String type = chars[0].trim();
+ String status = chars[1].trim();
+ String description = chars[2].trim();
+ switch (type) {
+ case "E":
+ String date = chars[3].trim();
+ task.addEvent(items, description, date);
+ if (status.equals("1")) {
+ items.get(task.getTaskCount()).markDone();
+ }
+ break;
+ case "D":
+ date = chars[3].trim();
+ task.addDeadline(items, description, date);
+ if (status.equals("1")) {
+ items.get(task.getTaskCount()).markDone();
+ }
+ break;
+ case "T":
+ task.addTodo(items, description);
+ break;
+ }
+ }
+ task.loadTaskCount(items);
+ System.out.println("Save file successfully loaded");
+ }
+
+}
diff --git a/src/main/java/duke/tasklist/TaskList.java b/src/main/java/duke/tasklist/TaskList.java
new file mode 100644
index 000000000..1558c8b92
--- /dev/null
+++ b/src/main/java/duke/tasklist/TaskList.java
@@ -0,0 +1,72 @@
+package duke.tasklist;
+import duke.tasklist.task.Task;
+import duke.tasklist.task.Deadlines;
+import duke.tasklist.task.Todo;
+import duke.tasklist.task.Events;
+import duke.ui.Ui;
+import java.util.ArrayList;
+
+public class TaskList {
+
+ protected int taskCount;
+
+ /**
+ * @param items The list of tasks stored in an ArrayList
+ */
+ public TaskList(ArrayList items) {
+ loadTaskCount(items);
+ }
+
+ public int getTaskCount() {
+ return taskCount;
+ }
+
+ public void loadTaskCount(ArrayList items) {
+ this.taskCount = items.size();
+ }
+
+ /**
+ * Create a new Event object and add it to the tasks list
+ *
+ * @param items list of items stored in an ArrayList
+ * @param description task description input by user
+ * @param at the deadline for the event input by the user
+ */
+ public void addEvent(ArrayList items, String description, String at) {
+ Events newEvent = new Events(description, at);
+ items.add(taskCount, newEvent);
+ }
+
+ /**
+ * Create a new Deadline object and add it to the tasks list
+ *
+ * @param items list of items stored in an ArrayList
+ * @param description task description input by user
+ * @param by the date for the deadline input by the user
+ */
+ public void addDeadline(ArrayList items, String description, String by) {
+ Deadlines newDeadline = new Deadlines(description, by);
+ items.add(taskCount, newDeadline);
+ }
+
+ /**
+ * Create a new Todo object and add it to the tasks list
+ *
+ * @param items list of items stored in an ArrayList
+ * @param description task description input by user
+ *
+ */
+ public void addTodo(ArrayList items, String description) {
+ Todo newTodo = new Todo(description);
+ items.add(taskCount, newTodo);
+ }
+
+ public void removeItem(Ui ui, ArrayList items, int taskNum) {
+ taskCount--;
+ ui.removeTaskMessage(items.get(taskNum), taskCount);
+ items.remove(taskNum);
+ }
+
+}
+
+
diff --git a/src/main/java/duke/tasklist/task/Deadlines.java b/src/main/java/duke/tasklist/task/Deadlines.java
new file mode 100644
index 000000000..883055da4
--- /dev/null
+++ b/src/main/java/duke/tasklist/task/Deadlines.java
@@ -0,0 +1,52 @@
+package duke.tasklist.task;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+public class Deadlines extends Task {
+ protected String by;
+ protected LocalDate date;
+ protected LocalTime time;
+
+ /**
+ * @param description The description of the task given by the user
+ * @param by the deadline given by the user for the task
+ */
+ public Deadlines(String description, String by) {
+ super(description);
+ this.by = by;
+ this.date = LocalDate.parse(by.split(" ")[0], DateTimeFormatter.ofPattern("yyyy/MM/dd"));
+ this.time = LocalTime.parse(readTime(by));
+
+ }
+ /**
+ * Reformat the time parameter input to one that is readable by the library
+ *
+ * @param str is the string input by the user after '/by'
+ * @return a string that is reformatted to the right format for LocalTime.parse()
+ */
+ private String readTime(String str) {
+ String hour = str.split(" ")[1].substring(0, 2);
+ String colon = ":";
+ String minutes = str.split(" ")[1].substring(2, 4);
+ return hour.concat(colon).concat(minutes);
+ }
+ @Override
+ public String getDate() {
+ return this.by;
+ }
+ private String formatDate(LocalDate date) {
+ return date.format(DateTimeFormatter.ofPattern("dd MMM yyyy"));
+ }
+ private String formatTime(LocalTime time) {
+ return time.format(DateTimeFormatter.ofPattern("hh mm a"));
+ }
+ @Override
+ public LocalDate getDeadline() {
+ return this.date;
+ }
+ public String toString() {
+ return "[D]" + super.toString() + " (by: " + formatDate(this.date) + ", " + formatTime(this.time) + ")";
+ }
+}
+
diff --git a/src/main/java/duke/tasklist/task/Events.java b/src/main/java/duke/tasklist/task/Events.java
new file mode 100644
index 000000000..843c55485
--- /dev/null
+++ b/src/main/java/duke/tasklist/task/Events.java
@@ -0,0 +1,52 @@
+package duke.tasklist.task;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+public class Events extends Task {
+ protected String at;
+ protected LocalDate date;
+ protected LocalTime time;
+
+ /**
+ * @param description The description of the task given by the user
+ * @param at the deadline given by the user for the task
+ */
+ public Events(String description, String at) {
+ super(description);
+ this.at = at;
+ this.date = LocalDate.parse(at.split(" ")[0], DateTimeFormatter.ofPattern("yyyy/MM/dd"));
+ this.time = LocalTime.parse(readTime(at));
+ }
+ /**
+ * Reformat the time parameter input to one that is readable by the library
+ *
+ * @param str is the string input by the user after '/at'
+ * @return a string that is reformatted to the right format for LocalTime.parse()
+ */
+ private String readTime(String str) {
+ String hour = str.split(" ")[1].substring(0, 2);
+ String colon = ":";
+ String minutes = str.split(" ")[1].substring(2, 4);
+ return hour.concat(colon).concat(minutes);
+ }
+ @Override
+ public String getDate() {
+ return this.at;
+ }
+ private String formatDate(LocalDate date) {
+ return date.format(DateTimeFormatter.ofPattern("dd MMM yyyy"));
+ }
+
+ private String formatTime(LocalTime time) {
+ return time.format(DateTimeFormatter.ofPattern("hh mm a"));
+ }
+ @Override
+ public LocalDate getDeadline() {
+ return this.date;
+ }
+ public String toString() {
+ return "[E]" + super.toString() + " (at: " + formatDate(this.date) + ", " + formatTime(this.time) + ")";
+ }
+}
diff --git a/src/main/java/duke/tasklist/task/Task.java b/src/main/java/duke/tasklist/task/Task.java
new file mode 100644
index 000000000..177ddb176
--- /dev/null
+++ b/src/main/java/duke/tasklist/task/Task.java
@@ -0,0 +1,42 @@
+package duke.tasklist.task;
+
+import java.time.LocalDate;
+
+public class Task {
+ protected String description;
+ protected boolean isDone;
+
+ /**
+ * @param description The description of the task given by the user
+ */
+ public Task(String description) {
+ this.description = description;
+ this.isDone = false;
+ }
+
+ public String getStatusIcon() {
+
+ return (isDone ? "X" : " ");
+ }
+ public String getDescription() {
+
+ return this.description;
+ }
+ public String getStatus() {
+ return (isDone ? "1" : "0");
+ }
+ public String getDate() {
+ return "empty";
+ }
+
+ public LocalDate getDeadline() {
+ return null;
+ }
+ public void markDone() {
+
+ this.isDone = true;
+ }
+ public String toString() {
+ return "[" + getStatusIcon() + "] " + getDescription();
+ }
+}
diff --git a/src/main/java/duke/tasklist/task/Todo.java b/src/main/java/duke/tasklist/task/Todo.java
new file mode 100644
index 000000000..ee004a042
--- /dev/null
+++ b/src/main/java/duke/tasklist/task/Todo.java
@@ -0,0 +1,15 @@
+package duke.tasklist.task;
+
+public class Todo extends Task {
+
+ /**
+ * @param description The description of the task given by the user
+ */
+ public Todo(String description) {
+ super(description);
+ }
+
+ public String toString() {
+ return "[T]" + super.toString();
+ }
+}
diff --git a/src/main/java/duke/ui/Ui.java b/src/main/java/duke/ui/Ui.java
new file mode 100644
index 000000000..b957b706b
--- /dev/null
+++ b/src/main/java/duke/ui/Ui.java
@@ -0,0 +1,94 @@
+package duke.ui;
+
+import duke.tasklist.TaskList;
+import duke.tasklist.task.Task;
+import java.util.Scanner;
+
+public class Ui {
+ private static final String logo =
+ " _____ ___ _____ ______\n"
+ + "|___ | | | |_____| / / -- \\ \\ \n"
+ + " / / | | / / | | | | \n"
+ + " / / | | / / | | | |\n"
+ + " / /___ | | /_/__ | | -- | |\n"
+ + "|_____| | | |_____| \\ \\____/ /\n";
+ public static final String border = "____________________________________________________________\n";
+
+ /**
+ * Check and create save folder and save file if it does not exist
+ *
+ */
+ public void showLine() {
+ System.out.println(border);
+ }
+ public void showError() {
+ System.out.println("Error occurred! Please try again.");
+ }
+ public void showSaveFileError() {
+ System.out.println("Could not find existing save file!");
+ }
+ public void printStartMessage() {
+ System.out.println(logo);
+ System.out.println(border + "Hi bro, my name is Zizo");
+ System.out.println("What do you want?\n" + border);
+ System.out.println("Type bye to exit\n" + border);
+ }
+ public void printEndMessage() {
+ System.out.println(border);
+ System.out.println("chat again next time!\n" + border);
+ }
+ public void addTaskMessage(TaskList tasks, Task task) {
+ int taskCount = tasks.getTaskCount();
+ System.out.println(border);
+ System.out.println("Got it. I've added this task:");
+ System.out.println(task);
+ System.out.println("Now you have " + taskCount + " tasks in the list.");
+ System.out.println(border);
+ }
+ public void removeTaskMessage(Task task, int taskCount) {
+ System.out.println(border);
+ System.out.println("Noted. I've removed this task:");
+ System.out.println(task);
+ System.out.println("Now you have " + taskCount + " tasks in the list.");
+ System.out.println(border);
+ }
+ public void printEmptyDescriptionError(String command) {
+ System.out.println(border);
+ System.out.println("\uD83D\uDE00 " + "OOPS!!! The description of a " + command + " cannot be empty.");
+ System.out.println(border);
+ }
+ public void printCommandDoesNotExist() {
+ System.out.println(border);
+ System.out.println("\uD83D\uDE00 " + "OOPS!!! I'm sorry, but I don't know what that means :-(");
+ System.out.println(border);
+ }
+ public void printCommandIsInvalid() {
+ System.out.println(border);
+ System.out.println("\uD83D\uDE00 " + "OOPS!!! I'm sorry, the command is invalid.");
+ System.out.println(border);
+ }
+ public void printEmptyDateError() {
+ System.out.println(border);
+ System.out.println("\uD83D\uDE00 " + "OOPS!!! I'm sorry, please input the date you would like to search for " +
+ "in yyyy/mm/dd format" );
+ System.out.println(border);
+ }
+ public void printFindFieldEmpty() {
+ System.out.println(border);
+ System.out.println("\uD83D\uDE00 " + "OOPS!!! I'm sorry, please input a keyword for the task " +
+ "you would like to search for");
+ System.out.println(border);
+ }
+ public void printWrongDateFormatError() {
+ System.out.println(border);
+ System.out.println("\uD83D\uDE00 " + "OOPS!!! I'm sorry, please input the correct date format: " +
+ "yyyy/dd/mm");
+ System.out.println(border);
+ }
+ public String readCommand(Scanner in) {
+ return in.nextLine();
+ }
+ public Ui() {
+ printStartMessage();
+ }
+}
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e..c53b9a459 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,72 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
+ _____ ___ _____ ______
+|___ | | | |_____| / / -- \ \
+ / / | | / / | | | |
+ / / | | / / | | | |
+ / /___ | | /_/__ | | -- | |
+|_____| | | |_____| \ \____/ /
+____________________________________________________________
+Hi bro, my name is Echo
+What do you want?
+____________________________________________________________
+
+Type bye to exit
+____________________________________________________________
+
+____________________________________________________________
+
+Got it. I've added this task:
+[E][ ]CCA (at: Tues & Thurs)
+Now you have 1 tasks in the list.
+____________________________________________________________
+
+____________________________________________________________
+
+Got it. I've added this task:
+[D][ ]CS2113T (by: Thursday 2359)
+Now you have 2 tasks in the list.
+____________________________________________________________
+
+____________________________________________________________
+
+Got it. I've added this task:
+[T][ ]CFG1002
+Now you have 3 tasks in the list.
+____________________________________________________________
+
+____________________________________________________________
+
+Here is your list
+1.[E][ ]CCA (at: Tues & Thurs)
+2.[D][ ]CS2113T (by: Thursday 2359)
+3.[T][ ]CFG1002
+____________________________________________________________
+
+____________________________________________________________
+Nice! task is done
+____________________________________________________________
+
+____________________________________________________________
+
+Here is your list
+1.[E][X]CCA (at: Tues & Thurs)
+2.[D][ ]CS2113T (by: Thursday 2359)
+3.[T][ ]CFG1002
+____________________________________________________________
+
+____________________________________________________________
+Nice! task is done
+____________________________________________________________
+
+____________________________________________________________
+
+Here is your list
+1.[E][X]CCA (at: Tues & Thurs)
+2.[D][X]CS2113T (by: Thursday 2359)
+3.[T][ ]CFG1002
+____________________________________________________________
+
+____________________________________________________________
+
+chat again next time!
+____________________________________________________________
\ No newline at end of file
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb..edcf35c89 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,9 @@
+event CCA /at Tues & Thurs
+deadline CS2113T /by Thursday 2359
+todo CFG1002
+list
+done 1
+list
+done 2
+list
+bye
\ No newline at end of file
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
index 087374464..e798e0298 100644
--- a/text-ui-test/runtest.bat
+++ b/text-ui-test/runtest.bat
@@ -4,10 +4,10 @@ REM create bin directory if it doesn't exist
if not exist ..\bin mkdir ..\bin
REM delete output from previous run
-if exist ACTUAL.TXT del ACTUAL.TXT
+del ACTUAL.TXT
REM compile the code into the bin folder
-javac -cp ..\src\main\java -Xlint:none -d ..\bin ..\src\main\java\*.java
+javac -cp ..\src\main\java\ -Xlint:none -d ..\bin ..\src\main\java\duke\*.java
IF ERRORLEVEL 1 (
echo ********** BUILD FAILURE **********
exit /b 1
@@ -18,4 +18,4 @@ REM run the program, feed commands from input.txt file and redirect the output t
java -classpath ..\bin Duke < input.txt > ACTUAL.TXT
REM compare the output to the expected output
-FC ACTUAL.TXT EXPECTED.TXT
+FC ACTUAL.TXT EXPECTED.TXT
\ No newline at end of file
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
deleted file mode 100644
index c9ec87003..000000000
--- a/text-ui-test/runtest.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env bash
-
-# create bin directory if it doesn't exist
-if [ ! -d "../bin" ]
-then
- mkdir ../bin
-fi
-
-# delete output from previous run
-if [ -e "./ACTUAL.TXT" ]
-then
- rm ACTUAL.TXT
-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
-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
-
-# convert to UNIX format
-cp EXPECTED.TXT EXPECTED-UNIX.TXT
-dos2unix ACTUAL.TXT EXPECTED-UNIX.TXT
-
-# compare the output to the expected output
-diff ACTUAL.TXT EXPECTED-UNIX.TXT
-if [ $? -eq 0 ]
-then
- echo "Test result: PASSED"
- exit 0
-else
- echo "Test result: FAILED"
- exit 1
-fi
\ No newline at end of file