diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
new file mode 100644
index 0000000000..7951f3a6c4
--- /dev/null
+++ b/config/checkstyle/checkstyle.xml
@@ -0,0 +1,398 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml
new file mode 100644
index 0000000000..135ea49ee0
--- /dev/null
+++ b/config/checkstyle/suppressions.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
index 8077118ebe..a8fe4fc3eb 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -2,28 +2,98 @@
## Features
-### Feature-ABC
+### Adding a ToDo task: `todo`
-Description of the feature.
+Adds a ToDo task to the task list.
-### Feature-XYZ
+Format: `todo TASK_DESCRIPTION`
-Description of the feature.
+Example: `todo read book`
-## Usage
+### Adding a Deadline task: `deadline`
-### `Keyword` - Describe action
+Adds a Deadline task to the task list.
-Describe the action and its outcome.
+Format: `deadline TASK_DESCRIPTION /by DATE`
-Example of usage:
+Example: `deadline return book /by 10/02/2024 1100`
-`keyword (optional arguments)`
+See [dateformat](https://github.com/tehkokhoe/ip/tree/master/docs#viewing-accepted-date-formats-dateformat) for accepted formats for date input.
+
+### Adding an Event task: `event`
+
+Adds an Event task to the task list.
+
+Format: `event TASK_DESCRIPTION /at START_DATE[-END_DATE]`
+
+Example:
+- `event book fair /at 09/11/2022 1200-1300`
+- `event lunch date /at 07/08/2022 1300`
+- `event dinner date /at 04/12/2022`
+
+See [dateformat](https://github.com/tehkokhoe/ip/tree/master/docs#viewing-accepted-date-formats-dateformat) for accepted formats for date input.
+
+### Viewing your task list: `list`
+
+Displays your task list.
+
+### Marking a task as done: `mark`
+
+Marks a task as done in your task list.
+
+format: `mark INDEX`
+
+Example: `mark 1`
+
+Expected outcome:
+```
+Nice! I've marked this task as done:
+ [T][X] read book
+```
+
+### Marking a task as not done: `unmark`
+
+Marks a task as not done in your task list.
+
+format: `unmark INDEX`
+
+Example: `unmark 2`
Expected outcome:
+```
+OK, I've marked this task as not done yet:
+ [T][ ] eat fish
+```
+
+### Deleting a task: `delete`
+
+Deletes a task in your task list.
-Description of the outcome.
+format: `delete INDEX`
+Example: `delete 3`
+
+Expected outcome:
```
-expected output
+Noted. I've removed this task:
+ [T][ ] run
+Now you have 2 task(s) in the list
```
+
+### Finding tasks with specific keyword: `find`
+
+Finds tasks that contains a keyword in the list.
+
+format: `find KEYWORD`
+
+Example: `find book`
+
+Expected outcome:
+```
+Here are the matching tasks in your list:
+ 1. [T][X] read book
+```
+
+### Viewing accepted date formats: `dateformat`
+
+Displays a list of available date formats for input.
diff --git a/docs/Ui.png b/docs/Ui.png
new file mode 100644
index 0000000000..eb18bb2737
Binary files /dev/null and b/docs/Ui.png differ
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000000..3397c9a492
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1 @@
+theme: jekyll-theme-architect
\ 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 5d313334cc..0000000000
--- a/src/main/java/Duke.java
+++ /dev/null
@@ -1,10 +0,0 @@
-public class Duke {
- public static void main(String[] args) {
- String logo = " ____ _ \n"
- + "| _ \\ _ _| | _____ \n"
- + "| | | | | | | |/ / _ \\\n"
- + "| |_| | |_| | < __/\n"
- + "|____/ \\__,_|_|\\_\\___|\n";
- System.out.println("Hello from\n" + logo);
- }
-}
diff --git a/src/main/java/duke/Command.java b/src/main/java/duke/Command.java
new file mode 100644
index 0000000000..226b907397
--- /dev/null
+++ b/src/main/java/duke/Command.java
@@ -0,0 +1,58 @@
+package duke;
+
+public enum Command {
+ BYE {
+ public boolean isRunning() {
+ return false;
+ }
+ },
+ LIST {
+ public boolean isRunning() {
+ return true;
+ }
+ },
+ MARK {
+ public boolean isRunning() {
+ return true;
+ }
+ },
+ UNMARK {
+ public boolean isRunning() {
+ return true;
+ }
+ },
+ TODO {
+ public boolean isRunning() {
+ return true;
+ }
+ },
+ DEADLINE {
+ public boolean isRunning() {
+ return true;
+ }
+ },
+ EVENT {
+ public boolean isRunning() {
+ return true;
+ }
+ },
+ DELETE {
+ public boolean isRunning() {
+ return true;
+ }
+ },
+ DATEFORMAT {
+ public boolean isRunning() {
+ return true;
+ }
+ },
+ FIND {
+ public boolean isRunning() {
+ return true;
+ }
+ };
+
+ public abstract boolean isRunning();
+}
+
+
diff --git a/src/main/java/duke/Deadline.java b/src/main/java/duke/Deadline.java
new file mode 100644
index 0000000000..7b630458e9
--- /dev/null
+++ b/src/main/java/duke/Deadline.java
@@ -0,0 +1,56 @@
+package duke;
+
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.DateTimeFormatterBuilder;
+import org.joda.time.format.DateTimeParser;
+
+public class Deadline extends Task {
+ private String byString;
+ private DateTime byDate;
+
+ /**
+ * Constructs a {@link Task} that has a date associated to it. The date
+ * associated is normally the date that the {@link Task} should be finished.
+ *
+ * @param task the description of the task.
+ * @param byString the due date of the task.
+ */
+ public Deadline(String task, String byString) {
+ super(task);
+ this.byString = byString;
+
+ try {
+ DateTimeParser[] dateParsers = {
+ DateTimeFormat.forPattern("d/MM/yyyy").getParser(),
+ DateTimeFormat.forPattern("yyyy-MM-dd").getParser(),
+ DateTimeFormat.forPattern("HHmm").getParser(),
+ DateTimeFormat.forPattern("d/MM/yyyy HHmm").getParser(),
+ DateTimeFormat.forPattern("yyyy-MM-dd HHmm").getParser(),
+ };
+ DateTimeFormatter formatter = new DateTimeFormatterBuilder().append(null, dateParsers).toFormatter();
+ DateTime date = formatter.parseDateTime(byString);
+ this.byDate = date;
+ } catch (UnsupportedOperationException e) {
+ this.byDate = null;
+ } catch (IllegalArgumentException e) {
+ this.byDate = null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ if (this.byDate == null) {
+ return "[D]" + super.toString() + " (by: " + byString + ")";
+ } else {
+ String formattedDate = DateTimeFormat.forPattern("MMM dd yyyy h:mm a").print(byDate);
+ return "[D]" + super.toString() + " (by: " + formattedDate + ")";
+ }
+ }
+
+ @Override
+ public String toRecord() {
+ return "D | " + super.toRecord() + " | " + byString;
+ }
+}
diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java
new file mode 100644
index 0000000000..eb10417f49
--- /dev/null
+++ b/src/main/java/duke/Duke.java
@@ -0,0 +1,146 @@
+package duke;
+
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.control.TextField;
+import javafx.scene.image.Image;
+import javafx.scene.layout.VBox;
+
+public class Duke {
+ private ScrollPane scrollPane;
+ private VBox dialogContainer;
+ private TextField userInput;
+ private Button sendButton;
+ private Scene scene;
+ private Image user = new Image(this.getClass().getResourceAsStream("/images/DaUser.png"));
+ private Image duke = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png"));
+ private UI ui;
+ private Storage storage;
+ private TaskList tasks;
+
+ /**
+ * Constructs an instance of the main program, by setting up the
+ * {@link UI}, {@link Storage}, and loads the existing {@link TaskList}
+ * or creates a new {@link TaskList} if one does not already exist.
+ */
+ public Duke() {
+ ui = new UI();
+ storage = new Storage();
+ try {
+ tasks = new TaskList(storage.load());
+ } catch (DukeException e) {
+ ui.showLoadingError(e.getMessage());
+ tasks = new TaskList();
+ }
+ }
+
+ /**
+ * Displays start screen. Runs program and keeps the program running until
+ * user exits. Accepts user input while running.
+ */
+ public void run() {
+ ui.startScreen();
+ boolean isRunning = true;
+ while (isRunning) {
+ String[] inputs = Parser.parseInput(ui);
+ UI.startLine();
+
+ try {
+ Command cmd = Parser.parseCommand(inputs);
+ this.execute(cmd, inputs);
+ isRunning = cmd.isRunning();
+ } catch (IllegalArgumentException e) {
+ ui.showError(UI.getIndent() + "Invalid Command: " + inputs[0]);
+ }
+
+ UI.endLine();
+ }
+ }
+
+ public static void main(String[] args) {
+ new Duke().run();
+ }
+
+ /**
+ * Executes {@link Command} with inputs given and returns a response.
+ *
+ * @param cmd one of the commands given in the enum {@link Command}.
+ * @param inputs the user input the has been split into command and description.
+ * @return the response after executing command.
+ * @see Command
+ */
+ public String execute(Command cmd, String[] inputs) {
+ try {
+ String result = "";
+ switch (cmd) {
+ case BYE:
+ ui.byeDisplay();
+ assert result == "";
+ break;
+ case LIST:
+ result = tasks.list();
+ assert result != "";
+ break;
+ case MARK:
+ result = tasks.mark(inputs);
+ storage.save(tasks.getTasks());
+ assert result != "";
+ break;
+ case UNMARK:
+ result = tasks.unmark(inputs);
+ storage.save(tasks.getTasks());
+ assert result != "";
+ break;
+ case TODO:
+ result = tasks.addToDo(inputs);
+ storage.save(tasks.getTasks());
+ assert result != "";
+ break;
+ case DEADLINE:
+ result = tasks.addDeadline(inputs);
+ storage.save(tasks.getTasks());
+ assert result != "";
+ break;
+ case EVENT:
+ result = tasks.addEvent(inputs);
+ storage.save(tasks.getTasks());
+ assert result != "";
+ break;
+ case DELETE:
+ result = tasks.delete(inputs);
+ storage.save(tasks.getTasks());
+ assert result != "";
+ break;
+ case DATEFORMAT:
+ result = ui.showDateFormats();
+ assert result != "";
+ break;
+ case FIND:
+ result = tasks.find(inputs);
+ assert result != "";
+ break;
+ default:
+ throw new IllegalStateException(UI.getIndent() + "Unexpected value: " + cmd);
+ }
+ return result;
+ } catch (NumberFormatException e) {
+ return ui.showError(UI.getIndent() + "☹ OOPS!!! Task number given is not suitable");
+ } catch (DukeException | IllegalStateException e) {
+ return ui.showError(e.getMessage());
+ } catch (IllegalArgumentException e) {
+ return ui.showError(UI.getIndent() + "Invalid command: " + cmd);
+ }
+ }
+
+ public String getResponse(String input) {
+ String[] inputs = Parser.parseGuiInput(input);
+ try {
+ Command cmd = Parser.parseCommand(inputs);
+ assert cmd == Command.valueOf(inputs[0]);
+ return this.execute(cmd, inputs);
+ } catch (IllegalArgumentException e) {
+ return ui.showError(UI.getIndent() + "Invalid Command: " + inputs[0]);
+ }
+ }
+}
diff --git a/src/main/java/duke/DukeDialogBox.java b/src/main/java/duke/DukeDialogBox.java
new file mode 100644
index 0000000000..a6289f18b8
--- /dev/null
+++ b/src/main/java/duke/DukeDialogBox.java
@@ -0,0 +1,54 @@
+package duke;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.HBox;
+
+public class DukeDialogBox extends HBox {
+ @FXML
+ private Label dialog;
+ @FXML
+ private ImageView displayPicture;
+
+ /**
+ * An example of a custom control using FXML.
+ * This control represents a dialog box consisting of an ImageView to represent the speaker's face and a label
+ * containing text from the speaker.
+ */
+ public DukeDialogBox(String text, Image img) {
+ try {
+ FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource("/view/DukeDialogBox.fxml"));
+ fxmlLoader.setController(this);
+ fxmlLoader.setRoot(this);
+ fxmlLoader.load();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ dialog.setText(text);
+ displayPicture.setImage(img);
+ }
+
+ private void flip() {
+ ObservableList tmp = FXCollections.observableArrayList(this.getChildren());
+ Collections.reverse(tmp);
+ getChildren().setAll(tmp);
+ setAlignment(Pos.TOP_LEFT);
+ }
+
+ public static DukeDialogBox getDukeDialog(String text, Image img) {
+ var db = new DukeDialogBox(text, img);
+ db.flip();
+ return db;
+ }
+}
diff --git a/src/main/java/duke/DukeException.java b/src/main/java/duke/DukeException.java
new file mode 100644
index 0000000000..3fcd0f5ea8
--- /dev/null
+++ b/src/main/java/duke/DukeException.java
@@ -0,0 +1,7 @@
+package duke;
+
+public class DukeException extends Exception {
+ public DukeException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/duke/Event.java b/src/main/java/duke/Event.java
new file mode 100644
index 0000000000..428db28a19
--- /dev/null
+++ b/src/main/java/duke/Event.java
@@ -0,0 +1,78 @@
+package duke;
+
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.DateTimeFormatterBuilder;
+import org.joda.time.format.DateTimeParser;
+
+public class Event extends Task {
+ private String atString;
+ private DateTime[] atDate;
+
+ /**
+ * Constructs a {@link Task} that have dates associated to it. The date
+ * associated is normally the date that the {@link Task} occurs and ends.
+ *
+ * @param task the description of the task.
+ * @param atString the start date and end date of the task.
+ */
+ public Event(String task, String atString) {
+ super(task);
+ this.atString = atString;
+ String[] arr = atString.split("\\s*-\\s*", 2);
+
+ try {
+ DateTimeParser[] dateParsers = {
+ DateTimeFormat.forPattern("d/MM/yyyy").getParser(),
+ DateTimeFormat.forPattern("yyyy-MM-dd").getParser(),
+ DateTimeFormat.forPattern("HHmm").getParser(),
+ DateTimeFormat.forPattern("d/MM/yyyy HHmm").getParser(),
+ DateTimeFormat.forPattern("yyyy-MM-dd HHmm").getParser(),
+ };
+ DateTimeFormatter formatter = new DateTimeFormatterBuilder().append(null, dateParsers).toFormatter();
+ atDate = new DateTime[2];
+
+ for (int i = 0; i < 2; i++) {
+ DateTime date = formatter.parseDateTime(arr[i]);
+ this.atDate[i] = date;
+ }
+ } catch (UnsupportedOperationException e) {
+ this.atDate[0] = null;
+ this.atDate[1] = null;
+ } catch (IllegalArgumentException e) {
+ this.atDate[0] = null;
+ this.atDate[1] = null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ String formattedDate = "";
+ if (this.atDate[0] == null && this.atDate[1] == null) {
+ return "[E]" + super.toString() + " (at: " + atString + ")";
+ } else if (this.atDate[0] != null && this.atDate[1] != null) {
+ if (this.atDate[1].isAfter(this.atDate[0])) {
+ formattedDate = DateTimeFormat.forPattern("MMM dd yyyy h:mm a").print(atDate[0])
+ + " - " + DateTimeFormat.forPattern("MMM dd yyyy h:mm a").print(atDate[1]);
+ } else {
+ formattedDate = DateTimeFormat.forPattern("MMM dd yyyy h:mm a").print(atDate[0])
+ + " - " + DateTimeFormat.forPattern("h:mm a").print(atDate[1]);
+ }
+ } else if (this.atDate[0] == null) {
+ String[] arr = atString.split("\\s+-\\s+", 2);
+ formattedDate = arr[0] + "-"
+ + DateTimeFormat.forPattern("MMM dd yyyy h:mm a").print(atDate[1]);
+ } else {
+ String[] arr = atString.split("\\s+-\\s+", 2);
+ formattedDate = DateTimeFormat.forPattern("MMM dd yyyy h:mm a").print(atDate[0])
+ + "-" + arr[1];
+ }
+ return "[E]" + super.toString() + " (at: " + formattedDate + ")";
+ }
+
+ @Override
+ public String toRecord() {
+ return "E | " + super.toRecord() + " | " + atString;
+ }
+}
diff --git a/src/main/java/duke/FastReader.java b/src/main/java/duke/FastReader.java
new file mode 100644
index 0000000000..6fe42a1ebb
--- /dev/null
+++ b/src/main/java/duke/FastReader.java
@@ -0,0 +1,55 @@
+package duke;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.StringTokenizer;
+
+public class FastReader {
+ private BufferedReader br;
+ private StringTokenizer st;
+
+ /**
+ * Constructs a reader that uses {@link BufferedReader}.
+ * @author Rishabh Mahrsee, GeeksforGeeks
+ */
+ public FastReader() {
+ br = new BufferedReader(new InputStreamReader(System.in));
+ }
+
+ String next() {
+ while (st == null || !st.hasMoreElements()) {
+ try {
+ st = new StringTokenizer(br.readLine());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return st.nextToken();
+ }
+
+ int nextInt() {
+ return Integer.parseInt(next());
+ }
+
+ long nextLong() {
+ return Long.parseLong(next());
+ }
+
+ double nextDouble() {
+ return Double.parseDouble(next());
+ }
+
+ String nextLine() {
+ String str = "";
+
+ try {
+ str = br.readLine();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return str;
+ }
+}
diff --git a/src/main/java/duke/Launcher.java b/src/main/java/duke/Launcher.java
new file mode 100644
index 0000000000..e4ef6b4628
--- /dev/null
+++ b/src/main/java/duke/Launcher.java
@@ -0,0 +1,12 @@
+package duke;
+
+import javafx.application.Application;
+
+/**
+ * A launcher class to workaround classpath issues.
+ */
+public class Launcher {
+ public static void main(String[] args) {
+ Application.launch(Main.class, args);
+ }
+}
diff --git a/src/main/java/duke/Main.java b/src/main/java/duke/Main.java
new file mode 100644
index 0000000000..355e04241d
--- /dev/null
+++ b/src/main/java/duke/Main.java
@@ -0,0 +1,27 @@
+package duke;
+
+import java.io.IOException;
+
+import javafx.application.Application;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Scene;
+import javafx.scene.layout.AnchorPane;
+import javafx.stage.Stage;
+
+public class Main extends Application {
+ private Duke duke = new Duke();
+
+ @Override
+ public void start(Stage stage) {
+ try {
+ FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml"));
+ AnchorPane ap = fxmlLoader.load();
+ Scene scene = new Scene(ap);
+ stage.setScene(scene);
+ fxmlLoader.getController().setDuke(duke);
+ stage.show();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/duke/MainWindow.java b/src/main/java/duke/MainWindow.java
new file mode 100644
index 0000000000..d6a93b5f33
--- /dev/null
+++ b/src/main/java/duke/MainWindow.java
@@ -0,0 +1,59 @@
+package duke;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.control.TextField;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.VBox;
+
+public class MainWindow extends AnchorPane {
+ @FXML
+ private ScrollPane scrollPane;
+ @FXML
+ private VBox dialogContainer;
+ @FXML
+ private TextField userInput;
+ @FXML
+ private Button sendButton;
+ @FXML
+ private Pane user;
+ @FXML
+ private ImageView userPic;
+ @FXML
+ private Label userText;
+
+ private Duke duke;
+
+ private Image userImage = new Image(this.getClass().getResourceAsStream("/images/DaUser.png"));
+ private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png"));
+
+ /**
+ * Initializes the GUI.
+ */
+ @FXML
+ public void initialize() {
+ scrollPane.vvalueProperty().bind(dialogContainer.heightProperty());
+ userPic.setImage(userImage);
+ }
+
+ public void setDuke(Duke d) {
+ duke = d;
+ }
+
+ @FXML
+ private void handleUserInput() {
+ String input = userInput.getText();
+ String response = duke.getResponse(input);
+ userText.setText(input);
+ dialogContainer.getChildren().addAll(
+ DukeDialogBox.getDukeDialog(response, dukeImage)
+ );
+ userInput.clear();
+ }
+}
+
diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java
new file mode 100644
index 0000000000..a3fdb78dec
--- /dev/null
+++ b/src/main/java/duke/Parser.java
@@ -0,0 +1,224 @@
+package duke;
+
+import java.util.ArrayList;
+
+public class Parser {
+ /**
+ * Returns a command by detecting the command in the user input.
+ *
+ * @param inputs user input that has been seperated into command and description.
+ * @return the command from user input.
+ * @throws IllegalArgumentException If command is not found in enum {@link Command}.
+ * @see Command
+ */
+ public static Command parseCommand(String[] inputs) throws IllegalArgumentException {
+ Command cmd = Command.valueOf(inputs[0].toUpperCase());
+ return cmd;
+ }
+
+ /**
+ * Returns index of list that should be marked.
+ *
+ * @param tasks the list of tasks saved.
+ * @param inputs user input that has been seperated into command and description.
+ * @return the index of the task in the list that should be marked.
+ * @throws DukeException If index is not given, index given is not an integer or index > size
+ * of task list.
+ * @see Task
+ */
+ public static int parseMarkIndex(ArrayList tasks, String[] inputs) throws DukeException {
+ if (inputs.length < 2) {
+ throw new DukeException(UI.getIndent() + "☹ OOPS!!! I don't know what to mark");
+ }
+
+ int markIndex = Integer.parseInt(inputs[1]);
+
+ if (markIndex > tasks.size()) {
+ throw new DukeException(UI.getIndent() + "☹ OOPS!!! I don't see your task");
+ }
+
+ return markIndex;
+ }
+
+ /**
+ * Returns index of list that should be unmarked.
+ *
+ * @param tasks the list of tasks saved.
+ * @param inputs user input that has been seperated into command and description.
+ * @return the index of the task in the list that should be unmarked.
+ * @throws DukeException If index is not given, index given is not an integer or index > size
+ * of task list.
+ * @see Task
+ */
+ public static int parseUnmarkIndex(ArrayList tasks, String[] inputs) throws DukeException {
+ if (inputs.length < 2) {
+ throw new DukeException(UI.getIndent() + "☹ OOPS!!! I don't know what to mark");
+ }
+
+ int unmarkIndex = Integer.parseInt(inputs[1]);
+
+ if (unmarkIndex > tasks.size()) {
+ throw new DukeException(UI.getIndent() + "☹ OOPS!!! I don't see your task");
+ }
+
+ return unmarkIndex;
+ }
+
+ /**
+ * Check if description of {@link ToDo} is empty.
+ *
+ * @param inputs user input that has been seperated into command and description.
+ * @throws DukeException If input length < 2.
+ */
+ public static void checkToDoDescription(String[] inputs) throws DukeException {
+ if (inputs.length < 2) {
+ throw new DukeException(UI.getIndent() + "☹ OOPS!!! The description of a todo cannot be empty");
+ }
+ }
+
+ /**
+ * Check if description of {@link Deadline} is empty.
+ *
+ * @param inputs user input that has been seperated into command and description.
+ * @throws DukeException If input length < 2.
+ */
+ public static void checkDeadlineDescription(String[] inputs) throws DukeException {
+ if (inputs.length < 2) {
+ throw new DukeException(UI.getIndent() + "☹ OOPS!!! The description of a deadline cannot be empty");
+ }
+ }
+
+ /**
+ * Returns a {@link String} array that separates the task description and the date.
+ *
+ * @param inputs user input that has been seperated into command and description.
+ * @return the description of the task seperated into task description and the date.
+ * @throws DukeException If date is not given or {@link Deadline} input is not in the right
+ * format.
+ */
+ public static String[] splitDeadlineDate(String[] inputs) throws DukeException {
+ String[] splitByDate = inputs[1].split(" /by ");
+
+ if (splitByDate.length < 2) {
+ throw new DukeException(UI.getIndent() + "☹ OOPS!!! I don't know when your task is due");
+ }
+
+ return splitByDate;
+ }
+
+ /**
+ * Check if description of {@link Event} is empty.
+ *
+ * @param inputs user input that has been seperated into command and description.
+ * @throws DukeException If input length < 2.
+ */
+ public static void checkEventDescription(String[] inputs) throws DukeException {
+ if (inputs.length < 2) {
+ throw new DukeException(UI.getIndent() + "☹ OOPS!!! The description of an event cannot be empty");
+ }
+ }
+
+ /**
+ * Returns a {@link String} array that separates the task description and the dates.
+ *
+ * @param inputs user input that has been seperated into command and description.
+ * @return the description of the task seperated into task description and the dates.
+ * @throws DukeException If dates are not given or {@link Event} input is not in the
+ * right format.
+ */
+ public static String[] splitEventDate(String[] inputs) throws DukeException {
+ String[] splitAtDate = inputs[1].split(" /at ");
+
+ if (splitAtDate.length < 2) {
+ throw new DukeException(UI.getIndent() + "☹ OOPS!!! I don't know when your event happens");
+ }
+
+ return splitAtDate;
+ }
+
+ /**
+ * Returns the index of the list to delete.
+ *
+ * @param inputs user input that has been seperated into command and description.
+ * @param tasks list of tasks saved.
+ * @return the index of the task in the list to delete.
+ * @throws DukeException If index is not given, index given is not an integer or index > size
+ * of task list.
+ */
+ public static int parseDeleteIndex(String[] inputs, ArrayList tasks) throws DukeException {
+ if (inputs.length < 2) {
+ throw new DukeException(UI.getIndent() + "☹ OOPS!!! I don't know what to delete");
+ }
+
+ int removeNum = Integer.parseInt(inputs[1]);
+
+ if (removeNum > tasks.size()) {
+ throw new DukeException(UI.getIndent() + "☹ OOPS!!! I don't see your task");
+ }
+
+ return removeNum;
+ }
+
+ /**
+ * Returns a {@link String} array with the command and description seperated.
+ *
+ * @param ui the user interface that accepts user input.
+ * @return the array with command and description seperated.
+ */
+ public static String[] parseInput(UI ui) {
+ String in = ui.read();
+ String[] inputs = in.split(" ", 2);
+ return inputs;
+ }
+
+ /**
+ * Returns a {@link String} array with the command and description seperated.
+ *
+ * @param input the user input.
+ * @return the array with command and description seperated.
+ */
+ public static String[] parseGuiInput(String input) {
+ String[] inputs = input.split(" ", 2);
+ return inputs;
+ }
+
+ /**
+ * Returns a Task object by parsing entry from saved file.
+ *
+ * @param entry a task string in the form saved in file.
+ * @return the Task object that represents the entry inserted.
+ */
+ public static Task parseEntry(String entry) {
+ String[] display = entry.split(" \\| ");
+ Task task = new Task();
+
+ if (display[0].equals("T")) {
+ task = new ToDo(display[2]);
+ } else if (display[0].equals("D")) {
+ task = new Deadline(display[2], display[3]);
+ } else if (display[0].equals("E")) {
+ task = new Event(display[2], display[3]);
+ }
+
+ if (display[1].equals("1")) {
+ task.setDone();
+ }
+
+ return task;
+ }
+
+ /**
+ * Returns the keyword in the user input.
+ *
+ * @param input the user input.
+ * @return the keyword associated with find command.
+ * @throws DukeException If keyword is not given.
+ */
+ public static String parseKeyword(String[] input) throws DukeException {
+ if (input.length < 2) {
+ throw new DukeException(UI.getIndent() + "☹ OOPS!!! I don't know what keyword to look for");
+ }
+
+ return input[1];
+ }
+}
diff --git a/src/main/java/duke/Storage.java b/src/main/java/duke/Storage.java
new file mode 100644
index 0000000000..d10689fca5
--- /dev/null
+++ b/src/main/java/duke/Storage.java
@@ -0,0 +1,89 @@
+package duke;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+
+public class Storage {
+ public Storage() {
+ }
+
+ /**
+ * Saves the task list in a file.
+ *
+ * @param tasks list of tasks saved.
+ */
+ public void save(ArrayList tasks) {
+ String working = System.getProperty("user.dir");
+ Path path = Paths.get(working, "data");
+ path.toFile().mkdirs();
+ File file = new File(path + "/duke.txt");
+
+ try {
+ file.createNewFile();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ BufferedWriter writer = new BufferedWriter(new FileWriter(file));
+ StringBuilder output = new StringBuilder();
+
+ for (int i = 0; i < tasks.size(); i++) {
+ output.append(tasks.get(i)).append("\n");
+ }
+
+ writer.write(output.toString());
+ writer.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Returns data out of saved file as an {@link ArrayList}.
+ *
+ * @return the list of entries retrieved from save file.
+ * @throws DukeException If file could not be used or created.
+ */
+ public ArrayList load() throws DukeException {
+ String working = System.getProperty("user.dir");
+ Path path = Paths.get(working, "data");
+ path.toFile().mkdirs();
+ File file = new File(path + "/duke.txt");
+
+ try {
+ file.createNewFile();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new DukeException("Saved task list could not be loaded");
+ }
+
+ ArrayList input = new ArrayList<>();
+
+ try {
+ BufferedReader reader = new BufferedReader(new FileReader(file));
+ String entry = reader.readLine();
+
+ while (entry != null) {
+ input.add(entry);
+ entry = reader.readLine();
+ }
+
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ throw new DukeException("Saved task list could not be loaded");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return input;
+ }
+}
diff --git a/src/main/java/duke/Task.java b/src/main/java/duke/Task.java
new file mode 100644
index 0000000000..522062d9dc
--- /dev/null
+++ b/src/main/java/duke/Task.java
@@ -0,0 +1,79 @@
+package duke;
+
+public class Task {
+ private String task;
+ private boolean isDone;
+
+ public Task() {
+ this.isDone = false;
+ }
+
+ /**
+ * Constructs a task.
+ *
+ * Task is initialized as not done.
+ *
+ * @param task the task description.
+ * @return the index of the task in the list to delete.
+ * @throws DukeException If index is not given, index given is not an integer or index > size
+ * of task list.
+ */
+ public Task(String task) {
+ this.task = task;
+ this.isDone = false;
+ }
+
+ public String getTask() {
+ return task;
+ }
+
+ public void setDone() {
+ this.isDone = true;
+ }
+
+ public void setUndone() {
+ this.isDone = false;
+ }
+
+ @Override
+ public int hashCode() {
+ return task.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof Task) {
+ Task toCompare = (Task) other;
+ return this.task.equals(toCompare.getTask());
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ String temp;
+ if (this.isDone) {
+ temp = "X";
+ } else {
+ temp = " ";
+ }
+ return "[" + temp + "] " + this.task;
+ }
+
+ /**
+ * Returns a {@link String} representing a {@link Task} in the form convenient for record.
+ *
+ * @return the text representing the task to record in save file.
+ */
+ public String toRecord() {
+ int temp;
+
+ if (this.isDone) {
+ temp = 1;
+ } else {
+ temp = 0;
+ }
+
+ return temp + " | " + this.task;
+ }
+}
diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java
new file mode 100644
index 0000000000..9dcbfe8ebb
--- /dev/null
+++ b/src/main/java/duke/TaskList.java
@@ -0,0 +1,160 @@
+package duke;
+
+import java.util.ArrayList;
+
+public class TaskList {
+ private ArrayList tasks;
+ private ArrayList display;
+
+ /**
+ * Constructs a list of tasks and converts entries in save file to a list of {@link Task}
+ * objects.
+ *
+ * @param tasks list of tasks saved.
+ */
+ public TaskList(ArrayList tasks) {
+ this.tasks = tasks;
+ this.display = new ArrayList<>();
+
+ for (int i = 0; i < tasks.size(); i++) {
+ display.add(Parser.parseEntry(tasks.get(i)));
+ }
+ }
+
+ public TaskList() {
+ this.tasks = new ArrayList();
+ }
+
+ public ArrayList getTasks() {
+ return tasks;
+ }
+
+ public String list() {
+ return UI.listDisplay(display);
+ }
+
+ /**
+ * Marks a task, and returns a response.
+ *
+ * @param inputs the user input that has been seperated into command and index.
+ * @return the response after marking a task.
+ * @throws DukeException If index is not given, index given is not an integer or
+ * index > size of task list.
+ */
+ public String mark(String[] inputs) throws DukeException {
+ int markIndex = Parser.parseMarkIndex(display, inputs);
+ display.get(markIndex - 1).setDone();
+ tasks.set(markIndex - 1, display.get(markIndex - 1).toRecord());
+ return UI.markDisplay(display.get(markIndex - 1));
+ }
+
+ /**
+ * Unmarks a task and returns a response.
+ *
+ * @param inputs the user input that has been seperated into command and index.
+ * @return the response after unmarking a task.
+ * @throws DukeException If index is not given, index given is not an integer or
+ * index > size of task list.
+ */
+ public String unmark(String[] inputs) throws DukeException {
+ int unmarkIndex = Parser.parseUnmarkIndex(display, inputs);
+ display.get(unmarkIndex - 1).setUndone();
+ tasks.set(unmarkIndex - 1, display.get(unmarkIndex - 1).toRecord());
+ return UI.unmarkDisplay(display.get(unmarkIndex - 1));
+ }
+
+ /**
+ * Adds a {@link ToDo} {@link Task} and returns a response.
+ *
+ * @param inputs the user input that has been seperated into command and description.
+ * @return the response after adding the to do task to the list.
+ * @throws DukeException If input length < 2.
+ */
+ public String addToDo(String[] inputs) throws DukeException {
+ Parser.checkToDoDescription(inputs);
+ Task toDo = new ToDo(inputs[1]);
+ if (this.isDuplicate(toDo)) {
+ return UI.duplicateDisplay(toDo);
+ }
+ display.add(toDo);
+ tasks.add(toDo.toRecord());
+ return UI.toDoDisplay(toDo, display);
+ }
+
+ /**
+ * Adds a {@link Deadline} {@link Task} and returns a response.
+ *
+ * @param inputs the user input that has been seperated into command and description.
+ * @return the response after adding the deadline task to the list.
+ * @throws DukeException If input length < 2.
+ */
+ public String addDeadline(String[] inputs) throws DukeException {
+ Parser.checkDeadlineDescription(inputs);
+ String[] splitByDate = Parser.splitDeadlineDate(inputs);
+ String byDate = splitByDate[1];
+ Task deadline = new Deadline(splitByDate[0], byDate);
+ if (this.isDuplicate(deadline)) {
+ return UI.duplicateDisplay(deadline);
+ }
+ display.add(deadline);
+ tasks.add(deadline.toRecord());
+ return UI.deadlineDisplay(deadline, display);
+ }
+
+ /**
+ * Adds a {@link Event} {@link Task} and returns a response.
+ *
+ * @param inputs user input that has been seperated into command and description.
+ * @return the response after adding the event task to the list.
+ * @throws DukeException If input length < 2.
+ */
+ public String addEvent(String[] inputs) throws DukeException {
+ Parser.checkEventDescription(inputs);
+ String[] splitAtDate = Parser.splitEventDate(inputs);
+ String atDate = splitAtDate[1];
+ Task event = new Event(splitAtDate[0], atDate);
+ if (this.isDuplicate(event)) {
+ return UI.duplicateDisplay(event);
+ }
+ display.add(event);
+ tasks.add(event.toRecord());
+ return UI.eventDisplay(event, display);
+ }
+
+ /**
+ * Delete a task from the task list and returns a response.
+ *
+ * @param inputs user input that has been seperated into command and index.
+ * @return the response after deleting a task from the list.
+ * @throws DukeException If index is not given, index given is not an integer or
+ * index > size of task list.
+ */
+ public String delete(String[] inputs) throws DukeException {
+ int deleteIndex = Parser.parseDeleteIndex(inputs, display);
+ Task deletedTask = display.remove(deleteIndex - 1);
+ tasks.remove(deleteIndex - 1);
+ return UI.deleteDisplay(deletedTask, display);
+ }
+
+ /**
+ * Find a task from the task list and return a response
+ *
+ * @param inputs user input that has been seperated into command and keyword.
+ * @return the response after finding a task from the list.
+ * @throws DukeException If keyword is not given.
+ */
+ public String find(String[] inputs) throws DukeException {
+ String keyword = Parser.parseKeyword(inputs);
+ ArrayList foundTasks = new ArrayList<>();
+ for (int i = 0; i < tasks.size(); i++) {
+ if (tasks.get(i).contains(keyword)) {
+ foundTasks.add(display.get(i));
+ }
+ }
+ return UI.findDisplay(foundTasks);
+ }
+
+ public boolean isDuplicate(Task task) {
+ return display.contains(task);
+ }
+}
diff --git a/src/main/java/duke/ToDo.java b/src/main/java/duke/ToDo.java
new file mode 100644
index 0000000000..dde24cacfb
--- /dev/null
+++ b/src/main/java/duke/ToDo.java
@@ -0,0 +1,17 @@
+package duke;
+
+public class ToDo extends Task {
+ public ToDo(String task) {
+ super(task);
+ }
+
+ @Override
+ public String toString() {
+ return "[T]" + super.toString();
+ }
+
+ @Override
+ public String toRecord() {
+ return "T | " + super.toRecord();
+ }
+}
diff --git a/src/main/java/duke/UI.java b/src/main/java/duke/UI.java
new file mode 100644
index 0000000000..bf50368470
--- /dev/null
+++ b/src/main/java/duke/UI.java
@@ -0,0 +1,250 @@
+package duke;
+
+import java.util.ArrayList;
+
+public class UI {
+ private static final String[] dateFormat = {"d/MM/yyyy", "yyyy-MM-dd", "HHmm", "d/MM/yyyy HHmm", "yyyy-MM-dd HHmm"};
+ private static final String INDENT = " ";
+ private static final String SPACE = " ";
+ private FastReader fr;
+
+ public UI() {
+ fr = new FastReader();
+ }
+
+ /**
+ * Prints the starting screen
+ */
+ public void startScreen() {
+ String logo = " ____ _ \n"
+ + "| _ \\ _ _| | _____ \n"
+ + "| | | | | | | |/ / _ \\\n"
+ + "| |_| | |_| | < __/\n"
+ + "|____/ \\__,_|_|\\_\\___|\n";
+ System.out.println("Hello from\n" + logo);
+ System.out.println(INDENT + "____________________________________________________________");
+ System.out.println(INDENT + "Hello! I'm Duke");
+ System.out.println(INDENT + "What can I do for you?");
+ System.out.println(INDENT + "____________________________________________________________");
+ }
+
+ public String read() {
+ return fr.nextLine();
+ }
+
+ public static void startLine() {
+ System.out.println(INDENT + "____________________________________________________________");
+ }
+
+ public static void endLine() {
+ System.out.println(INDENT + "____________________________________________________________");
+ }
+
+ public void byeDisplay() {
+ System.out.println(INDENT + "Bye. Hope to see you again soon!");
+ }
+
+ /**
+ * Returns the list of tasks.
+ *
+ * @param tasks the list of tasks.
+ * @return the response of list command.
+ */
+ public static String listDisplay(ArrayList tasks) {
+ String response = "";
+ for (int i = 0; i < tasks.size(); i++) {
+ if (i == 0) {
+ response += "Here are the tasks in your list:\n";
+ System.out.println(INDENT + "Here are the tasks in your list:");
+ }
+
+ response += String.format(SPACE + "%d. %s\n", i + 1, tasks.get(i));
+ System.out.printf(INDENT + SPACE + "%d. %s\n", i + 1, tasks.get(i));
+ }
+
+ if (tasks.size() == 0) {
+ response += "There's nothing in your list\n";
+ System.out.println(INDENT + "There's nothing in your list");
+ }
+
+ return response;
+ }
+
+ /**
+ * Returns marked task.
+ *
+ * @param task the marked task.
+ * @return the response to mark command.
+ */
+ public static String markDisplay(Task task) {
+ String response = "";
+ response += "Nice! I've marked this task as done:\n";
+ System.out.println(INDENT + "Nice! I've marked this task as done:");
+ response += String.format(SPACE + "%s\n", task);
+ System.out.println(INDENT + SPACE + task);
+ return response;
+ }
+
+ /**
+ * Returns unmarked task.
+ *
+ * @param task the unmarked task.
+ * @return the response to unmark command.
+ */
+ public static String unmarkDisplay(Task task) {
+ String response = "";
+ response += "OK, I've marked this task as not done yet:\n";
+ System.out.println(INDENT + "OK, I've marked this task as not done yet:");
+ response += String.format(SPACE + "%s\n", task);
+ System.out.println(INDENT + SPACE + task);
+ return response;
+ }
+
+ public static String getIndent() {
+ return INDENT;
+ }
+
+ public static String getSpace() {
+ return SPACE;
+ }
+
+ /**
+ * Returns added {@link ToDo} {@link Task}.
+ *
+ * @param toDo the added toDo task.
+ * @param tasks the list of tasks.
+ * @return the response to todo command.
+ */
+ public static String toDoDisplay(Task toDo, ArrayList tasks) {
+ String response = "";
+ response += "Got it. I've added this task:\n";
+ System.out.println(INDENT + "Got it. I've added this task:");
+ response += String.format(SPACE + "%s\n", toDo);
+ System.out.println(INDENT + SPACE + toDo);
+ response += String.format("Now you have %d task(s) in the list\n", tasks.size());
+ System.out.printf(INDENT + "Now you have %d task(s) in the list\n", tasks.size());
+ return response;
+ }
+
+ /**
+ * Returns added {@link Deadline} {@link Task}.
+ *
+ * @param deadline the added deadline task.
+ * @param tasks the list of tasks.
+ * @return the response to deadline command.
+ */
+ public static String deadlineDisplay(Task deadline, ArrayList tasks) {
+ String response = "";
+ response += "Got it. I've added this task:\n";
+ System.out.println(INDENT + "Got it. I've added this task:");
+ response += String.format(SPACE + "%s\n", deadline);
+ System.out.println(INDENT + SPACE + deadline);
+ response += String.format("Now you have %d task(s) in the list\n", tasks.size());
+ System.out.printf(INDENT + "Now you have %d task(s) in the list\n", tasks.size());
+ return response;
+ }
+
+ /**
+ * Returns added {@link Event} {@link Task}.
+ *
+ * @param event the added event task.
+ * @param tasks the list of tasks.
+ * @return the response to event command.
+ */
+ public static String eventDisplay(Task event, ArrayList tasks) {
+ String response = "";
+ response += "Got it. I've added this task:\n";
+ System.out.println(INDENT + "Got it. I've added this task:");
+ response += String.format(SPACE + "%s\n", event);
+ System.out.println(INDENT + SPACE + event);
+ response += String.format("Now you have %d task(s) in the list\n", tasks.size());
+ System.out.printf(INDENT + "Now you have %d task(s) in the list\n", tasks.size());
+ return response;
+ }
+
+ /**
+ * Returns deleted task.
+ *
+ * @param deletedTask the deleted task.
+ * @param tasks the list of tasks.
+ * @return the response to delete command.
+ */
+ public static String deleteDisplay(Task deletedTask, ArrayList tasks) {
+ String response = "";
+ response += "Noted. I've removed this task:\n";
+ System.out.println(INDENT + "Noted. I've removed this task:");
+ response += String.format(SPACE + "%s\n", deletedTask);
+ System.out.println(INDENT + SPACE + deletedTask);
+ response += String.format("Now you have %d task(s) in the list\n", tasks.size());
+ System.out.printf(INDENT + "Now you have %d task(s) in the list\n", tasks.size());
+ return response;
+ }
+
+ /**
+ * Returns loading error message.
+ *
+ * @param e the error message.
+ * @return the loading error message.
+ */
+ public String showLoadingError(String e) {
+ System.out.println(e);
+ return e;
+ }
+
+ /**
+ * Returns error message.
+ *
+ * @param e the error message.
+ * @return the error message.
+ */
+ public String showError(String e) {
+ System.out.println(e);
+ return e;
+ }
+
+ /**
+ * Returns a list of viable date formats for user input.
+ *
+ * @return the response for dateformat command.
+ */
+ public String showDateFormats() {
+ String response = "";
+
+ for (String s : dateFormat) {
+ response += s + "\n";
+ System.out.println(s);
+ }
+
+ return response;
+ }
+
+ /**
+ * Return found tasks.
+ *
+ * @param found the list of found tasks containing keyword.
+ * @return the response to find command.
+ */
+ public static String findDisplay(ArrayList found) {
+ String response = "";
+ if (found.size() < 1) {
+ System.out.println(INDENT + "I couldn't find any task with that keyword");
+ return "I couldn't find any task with that keyword";
+ }
+
+ response += "Here are the matching tasks in your list:\n";
+ System.out.println(INDENT + "Here are the matching tasks in your list:");
+ int i = 1;
+
+ for (Task task : found) {
+ response += String.format(SPACE + "%d. %s\n", i, task);
+ System.out.printf(INDENT + SPACE + "%d. %s\n", i, task);
+ i += 1;
+ }
+
+ return response;
+ }
+
+ public static String duplicateDisplay(Task task) {
+ return String.format("You already have task\n %s\non your list", task);
+ }
+}
diff --git a/src/main/resources/images/DaDuke.png b/src/main/resources/images/DaDuke.png
new file mode 100644
index 0000000000..d893658717
Binary files /dev/null and b/src/main/resources/images/DaDuke.png differ
diff --git a/src/main/resources/images/DaUser.png b/src/main/resources/images/DaUser.png
new file mode 100644
index 0000000000..3c82f45461
Binary files /dev/null and b/src/main/resources/images/DaUser.png differ
diff --git a/src/main/resources/view/DukeDialogBox.fxml b/src/main/resources/view/DukeDialogBox.fxml
new file mode 100644
index 0000000000..3d5055f8ac
--- /dev/null
+++ b/src/main/resources/view/DukeDialogBox.fxml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
new file mode 100644
index 0000000000..0c05e039d7
--- /dev/null
+++ b/src/main/resources/view/MainWindow.fxml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/duke/CommandTest.java b/src/test/java/duke/CommandTest.java
new file mode 100644
index 0000000000..9487653bb5
--- /dev/null
+++ b/src/test/java/duke/CommandTest.java
@@ -0,0 +1,15 @@
+package duke;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+class CommandTest {
+ @Test
+ @DisplayName("BYE command quits program")
+ void byeQuit() {
+ Command cmd = Parser.parseCommand(new String[] {"bye"});
+ assertFalse(cmd.isRunning());
+ }
+}
diff --git a/src/test/java/duke/ParserTest.java b/src/test/java/duke/ParserTest.java
new file mode 100644
index 0000000000..7ec5119ac3
--- /dev/null
+++ b/src/test/java/duke/ParserTest.java
@@ -0,0 +1,16 @@
+package duke;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class ParserTest {
+ @Test
+ @DisplayName("Invalid Command")
+ void executeInvalidCommand() {
+ assertThrows(IllegalArgumentException.class, () -> {
+ Parser.parseCommand(new String[] {"chicken", "little"});
+ });
+ }
+}
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e7..a6e87d6d6f 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -5,3 +5,127 @@ Hello from
| |_| | |_| | < __/
|____/ \__,_|_|\_\___|
+ ____________________________________________________________
+ Hello! I'm Duke
+ What can I do for you?
+ ____________________________________________________________
+ ____________________________________________________________
+ There's nothing in your list
+ ____________________________________________________________
+ ____________________________________________________________
+ ☹ OOPS!!! The description of a todo cannot be empty
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [T][ ] read book
+ Now you have 1 task(s) in the list
+ ____________________________________________________________
+ ____________________________________________________________
+ ☹ OOPS!!! The description of a deadline cannot be empty
+ ____________________________________________________________
+ ____________________________________________________________
+ ☹ OOPS!!! I don't know when your task is due
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [D][ ] return book (by: June 6th)
+ Now you have 2 task(s) in the list
+ ____________________________________________________________
+ ____________________________________________________________
+ ☹ OOPS!!! The description of an event cannot be empty
+ ____________________________________________________________
+ ____________________________________________________________
+ ☹ OOPS!!! I don't know when your event happens
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [E][ ] project meeting (at: Aug 6th 2-4pm)
+ Now you have 3 task(s) in the list
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [T][ ] join sports club
+ Now you have 4 task(s) in the list
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [T][ ] borrow book
+ Now you have 5 task(s) in the list
+ ____________________________________________________________
+ ____________________________________________________________
+ ☹ OOPS!!! I don't know what to mark
+ ____________________________________________________________
+ ____________________________________________________________
+ ☹ OOPS!!! I don't see your task
+ ____________________________________________________________
+ ____________________________________________________________
+ ☹ OOPS!!! Task number given is not suitable
+ ____________________________________________________________
+ ____________________________________________________________
+ Nice! I've marked this task as done:
+ [T][X] read book
+ ____________________________________________________________
+ ____________________________________________________________
+ Nice! I've marked this task as done:
+ [T][X] join sports club
+ ____________________________________________________________
+ ____________________________________________________________
+ Here are the tasks in your list:
+ 1. [T][X] read book
+ 2. [D][ ] return book (by: June 6th)
+ 3. [E][ ] project meeting (at: Aug 6th 2-4pm)
+ 4. [T][X] join sports club
+ 5. [T][ ] borrow book
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [D][ ] return book (by: Sunday)
+ Now you have 6 task(s) in the list
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [E][ ] project meeting (at: Mon 2-4pm)
+ Now you have 7 task(s) in the list
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [D][ ] do homework (by: no idea :-p)
+ Now you have 8 task(s) in the list
+ ____________________________________________________________
+ ____________________________________________________________
+ ☹ OOPS!!! I don't know what to delete
+ ____________________________________________________________
+ ____________________________________________________________
+ ☹ OOPS!!! I don't see your task
+ ____________________________________________________________
+ ____________________________________________________________
+ Noted. I've removed this task:
+ [D][ ] do homework (by: no idea :-p)
+ Now you have 7 task(s) in the list
+ ____________________________________________________________
+ ____________________________________________________________
+ Noted. I've removed this task:
+ [E][ ] project meeting (at: Mon 2-4pm)
+ Now you have 6 task(s) in the list
+ ____________________________________________________________
+ ____________________________________________________________
+ Noted. I've removed this task:
+ [D][ ] return book (by: Sunday)
+ Now you have 5 task(s) in the list
+ ____________________________________________________________
+ ____________________________________________________________
+ Here are the tasks in your list:
+ 1. [T][X] read book
+ 2. [D][ ] return book (by: June 6th)
+ 3. [E][ ] project meeting (at: Aug 6th 2-4pm)
+ 4. [T][X] join sports club
+ 5. [T][ ] borrow book
+ ____________________________________________________________
+ ____________________________________________________________
+ Noted. I've removed this task:
+ [E][ ] project meeting (at: Aug 6th 2-4pm)
+ Now you have 4 task(s) in the list
+ ____________________________________________________________
+ ____________________________________________________________
+ Bye. Hope to see you again soon!
+ ____________________________________________________________
\ No newline at end of file
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb2..41ee8df05f 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,28 @@
+list
+todo
+todo read book
+deadline
+deadline return book
+deadline return book /by June 6th
+event
+event project meeting
+event project meeting /at Aug 6th 2-4pm
+todo join sports club
+todo borrow book
+mark
+mark 6
+mark a
+mark 1
+mark 4
+list
+deadline return book /by Sunday
+event project meeting /at Mon 2-4pm
+deadline do homework /by no idea :-p
+delete
+delete 9
+delete 8
+delete 7
+delete 6
+list
+delete 3
+bye