diff --git a/.gitignore b/.gitignore
index f69985ef1f..f2d4270f7b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,4 +14,4 @@ src/main/resources/docs/
bin/
/text-ui-test/ACTUAL.txt
-text-ui-test/EXPECTED-UNIX.TXT
+text-ui-test/EXPECTED.TXT
diff --git a/data/duke.txt b/data/duke.txt
new file mode 100644
index 0000000000..5ac06b2bf1
--- /dev/null
+++ b/data/duke.txt
@@ -0,0 +1,3 @@
+[D][✘] d2 (by: Year.2015, Month.FEBRUARY, Day.20, Time: h.6, m.30)
+[D][✘] e1 (by: Year.2015, Month.FEBRUARY, Day.20, Time: h.6, m.30)
+[T][✘] task4
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/Duke.java b/src/main/java/Duke/Duke.java
new file mode 100644
index 0000000000..e725c52048
--- /dev/null
+++ b/src/main/java/Duke/Duke.java
@@ -0,0 +1,99 @@
+package Duke;
+
+import Duke.DukeException.DeadlineNullException;
+import Duke.DukeException.EventNullException;
+import Duke.DukeException.TodoNullException;
+import Duke.command.Command;
+import Duke.parser.Parser;
+import Duke.storage.Storage;
+import Duke.taskList.TaskList;
+import Duke.ui.UI;
+
+import java.time.Month;
+
+import static Duke.ui.UI.DOUBLEINDENTATION;
+import static Duke.ui.UI.printStatement;
+
+public class Duke {
+
+ private Storage storage;
+ private TaskList tasks;
+ private UI ui;
+
+ public Duke(String filePath) {
+ ui = new UI();
+ storage = new Storage(filePath);
+ //try {
+ tasks = new TaskList(storage.load());
+ /*} catch (DukeException e) {
+ ui.showLoadingError();
+ tasks = new TaskList();
+ }*/
+ }
+
+ public void run() {
+ ui.showWelcome();
+ boolean isExit = false;
+ int numberOfTasks = storage.loadNumberOfTasks();
+ while (!isExit) {
+ //try {
+ String fullCommand = ui.readCommand();
+ ui.showLine(); // show the divider line ("_______")
+ Command c;
+ if(fullCommand.contains("todo")) {
+ c = Parser.parseTodoCommand(fullCommand, numberOfTasks);
+ numberOfTasks++;
+ } else if(fullCommand.contains("deadline")){
+ c = Parser.parseDeadlineCommand(fullCommand, numberOfTasks);
+ numberOfTasks++;
+ } else if(fullCommand.contains("event")) {
+ c = Parser.parseEventCommand(fullCommand, numberOfTasks);
+ numberOfTasks++;
+ } else if(fullCommand.contains("help")) {
+ c = Parser.parseHelpCommand(numberOfTasks);
+ } else if(fullCommand.contains("list")){
+ c = Parser.parseListCommand(numberOfTasks);
+ } else if(fullCommand.contains("find")) {
+ c = Parser.parseFindCommand(fullCommand.substring(fullCommand.indexOf("find")+4).trim(),
+ numberOfTasks);
+ } else if(fullCommand.contains("done")) {
+ c = Parser.parseDoneCommand(fullCommand, numberOfTasks);
+ } else if(fullCommand.contains("delete")) {
+ c = Parser.parseDeleteCommand(fullCommand, numberOfTasks);
+ if(c.description.length() != 0) {
+ numberOfTasks--;
+ }
+ } else if(fullCommand.contains("bye")){
+ c = Parser.parseExitCommand(numberOfTasks);
+ } else {
+ c = Parser.parseExceptionCommand(numberOfTasks);
+ }
+ try{
+ c.execute(tasks, ui, storage);
+ c.sava(tasks, ui, storage);
+ isExit = c.isExit();
+ } catch (NullPointerException e) {
+ numberOfTasks--;
+ } catch (TodoNullException e) {
+ printStatement(DOUBLEINDENTATION +
+ "☹ OOPS!!! The description of a todo cannot be empty.\n");
+ tasks.remove(numberOfTasks-1);
+ numberOfTasks--;
+ } catch (DeadlineNullException e) {
+ numberOfTasks--;
+ } catch (EventNullException e) {
+ numberOfTasks--;
+ }
+
+ /*} catch (DukeException e) {
+ ui.showError(e.getMessage());
+ } finally {
+ ui.showLine();
+ }*/
+ }
+ }
+
+ public static void main(String[] args) {
+ new Duke("/Users/yuqiao/Desktop/CS2113T/ip/data/duke.txt").run();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/Duke/DukeException/DeadlineNullException.java b/src/main/java/Duke/DukeException/DeadlineNullException.java
new file mode 100644
index 0000000000..be6faa2379
--- /dev/null
+++ b/src/main/java/Duke/DukeException/DeadlineNullException.java
@@ -0,0 +1,4 @@
+package Duke.DukeException;
+
+public class DeadlineNullException extends Exception {
+}
diff --git a/src/main/java/Duke/DukeException/EventNullException.java b/src/main/java/Duke/DukeException/EventNullException.java
new file mode 100644
index 0000000000..4fdbf71de1
--- /dev/null
+++ b/src/main/java/Duke/DukeException/EventNullException.java
@@ -0,0 +1,4 @@
+package Duke.DukeException;
+
+public class EventNullException extends Throwable {
+}
diff --git a/src/main/java/Duke/DukeException/InvalidStorageFilePathException.java b/src/main/java/Duke/DukeException/InvalidStorageFilePathException.java
new file mode 100644
index 0000000000..71781ccb83
--- /dev/null
+++ b/src/main/java/Duke/DukeException/InvalidStorageFilePathException.java
@@ -0,0 +1,10 @@
+package Duke.DukeException;
+
+/**
+ * build InvalidStorageNullException extending Exception.
+ */
+public class InvalidStorageFilePathException extends Exception {
+ public InvalidStorageFilePathException(String s) {
+ }
+ //no other code needed
+}
diff --git a/src/main/java/Duke/DukeException/TodoNullException.java b/src/main/java/Duke/DukeException/TodoNullException.java
new file mode 100644
index 0000000000..f9bb43a8a2
--- /dev/null
+++ b/src/main/java/Duke/DukeException/TodoNullException.java
@@ -0,0 +1,8 @@
+package Duke.DukeException;
+
+/**
+ * build TodoNullException extending Exception.
+ */
+public class TodoNullException extends Exception {
+ //no other code needed
+}
diff --git a/src/main/java/Duke/command/Command.java b/src/main/java/Duke/command/Command.java
new file mode 100644
index 0000000000..a3b49f3375
--- /dev/null
+++ b/src/main/java/Duke/command/Command.java
@@ -0,0 +1,53 @@
+package Duke.command;
+
+import Duke.DukeException.DeadlineNullException;
+import Duke.DukeException.EventNullException;
+import Duke.DukeException.TodoNullException;
+import Duke.storage.Storage;
+import Duke.taskList.TaskList;
+import Duke.ui.UI;
+
+/**
+ * Represents a Command with description and numberOfTasks.
+ * Is it an abstracted type.
+ */
+public class Command {
+ public String description;
+ protected int numberOfTasks = 0;
+
+ public Command(String description, int numberOfTasks) {
+ this.description = description;
+ this.numberOfTasks = numberOfTasks;
+ }
+
+ /**
+ * Execute the Command.
+ */
+ public void execute(TaskList tasks, UI ui, Storage storage) throws TodoNullException, DeadlineNullException, EventNullException {
+ }
+
+ /**
+ * Execute the save function.
+ * Save the changed taskList into the file
+ */
+ public void sava(TaskList tasks, UI ui, Storage storage){
+
+ }
+
+ /**
+ * Return a boolean variable indicating whether the command
+ * is an ExitCommand.
+ * If it is, return true. Else wise, return false.
+ *
+ * @return Boolean variable indicating whether the command
+ * is an ExitCommand.
+ */
+ public boolean isExit() {
+ if(description == "bye") {
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/Duke/command/DeadlineCommand.java b/src/main/java/Duke/command/DeadlineCommand.java
new file mode 100644
index 0000000000..d5049a3db9
--- /dev/null
+++ b/src/main/java/Duke/command/DeadlineCommand.java
@@ -0,0 +1,58 @@
+package Duke.command;
+
+import Duke.DukeException.DeadlineNullException;
+import Duke.DukeException.EventNullException;
+import Duke.DukeException.TodoNullException;
+import Duke.storage.Storage;
+import Duke.task.Deadline;
+import Duke.taskList.TaskList;
+import Duke.ui.UI;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeParseException;
+
+import static Duke.ui.UI.*;
+
+/**
+ * Represents a DeadlineCommand with description and numberOfTasks.
+ * A deadline
object corresponds to a TodoCommand
+ * with the description and due time extracted from what entered by users.
+ */
+public class DeadlineCommand extends Command {
+ protected LocalDateTime by;
+
+ public DeadlineCommand(String description, int numberOfTasks, String by) {
+ super(description, numberOfTasks);
+ try {
+ this.by = LocalDateTime.parse(by);
+ } catch (DateTimeParseException e) {
+ printStatement(DOUBLEINDENTATION + "☹ OOPS!!! The time entered is not in the format(yyyy-mm-dd).\n");
+ }
+ }
+
+ /**
+ * Override: Execute the Command.
+ * add a new Deadline into the taskList.
+ */
+ @Override
+ public void execute(TaskList tasks, UI ui, Storage storage) throws TodoNullException, DeadlineNullException,
+ EventNullException {
+ super.execute(tasks, ui, storage);
+ if(this.by.toString().length() == 0 && this.by.toString().length() == 0){
+ throw new DeadlineNullException();
+ }
+ tasks.add(new Deadline(this.description, this.by));
+ ui.printStatement(DOUBLEINDENTATION + "Got it. I've added this task:\n"
+ + TRIPLEINDENTATION + tasks.get(numberOfTasks - 1).toString() + "\n" + DOUBLEINDENTATION
+ + "Now you have " + (numberOfTasks) + " tasks in the list.\n");
+ }
+
+ /**
+ * Execute the save function.
+ * Save the changed taskList into the file
+ */
+ @Override
+ public void sava(TaskList tasks, UI ui, Storage storage){
+ Storage.save(tasks, numberOfTasks);
+ }
+}
diff --git a/src/main/java/Duke/command/DeleteCommand.java b/src/main/java/Duke/command/DeleteCommand.java
new file mode 100644
index 0000000000..770843951f
--- /dev/null
+++ b/src/main/java/Duke/command/DeleteCommand.java
@@ -0,0 +1,45 @@
+package Duke.command;
+
+import Duke.storage.Storage;
+import Duke.taskList.TaskList;
+import Duke.ui.UI;
+
+import static Duke.ui.UI.*;
+
+/**
+ * Represents a DeleteCommand with description and numberOfTasks.
+ * A delete
object corresponds to a DeleteCommand
+ * with the description extracted from what entered by users,
+ * which is the index of the task users intend to delete.
+ */
+public class DeleteCommand extends Command {
+ public DeleteCommand(String description, int numberOfTasks) {
+ super(description, numberOfTasks);
+ }
+
+ /**
+ * Override: Execute the Command.
+ * Delete the task with entered index.
+ * Print out the delete message.
+ */
+ @Override
+ public void execute(TaskList tasks, UI ui, Storage storage){
+ try {
+ printStatement(DOUBLEINDENTATION + "Noted. I've removed this task: \n" +
+ TRIPLEINDENTATION + tasks.get(Integer.parseInt(this.description)-1).toString() + "\n" +
+ DOUBLEINDENTATION + "Now you have " + (numberOfTasks-1) + " tasks in the list.\n");
+ tasks.remove(Integer.parseInt(this.description)-1);
+ } catch (NumberFormatException e) {
+ printStatement(DOUBLEINDENTATION + "☹ OOPS!!! You did not indicate which task to delete.\n");
+ }
+ }
+
+ /**
+ * Execute the save function.
+ * Save the changed taskList into the file
+ */
+ @Override
+ public void sava(TaskList tasks, UI ui, Storage storage){
+ Storage.save(tasks, numberOfTasks-1);
+ }
+}
diff --git a/src/main/java/Duke/command/DoneCommand.java b/src/main/java/Duke/command/DoneCommand.java
new file mode 100644
index 0000000000..191754793e
--- /dev/null
+++ b/src/main/java/Duke/command/DoneCommand.java
@@ -0,0 +1,46 @@
+package Duke.command;
+
+import Duke.storage.Storage;
+import Duke.taskList.TaskList;
+import Duke.ui.UI;
+
+import static Duke.ui.UI.*;
+
+/**
+ * Represents a DoneCommand with description and numberOfTasks.
+ * A done
object corresponds to a DoneCommand
+ * with the description extracted from what entered by users,
+ * which is the index of the task users intend to mark as done.
+ */
+public class DoneCommand extends Command {
+ public DoneCommand(String description, int numberOfTasks) {
+ super(description, numberOfTasks);
+ }
+
+ /**
+ * Override: Execute the Command.
+ * Mark the task with the entered index as done.
+ * Print out the done message.
+ */
+ @Override
+ public void execute(TaskList tasks, UI ui, Storage storage){
+ try {
+ tasks.get(Integer.parseInt(this.description)- 1).markAsDone();
+ printStatement(DOUBLEINDENTATION + "Nice! I've marked this task as done: \n"
+ + TRIPLEINDENTATION + tasks.get(Integer.parseInt(this.description) - 1).toString() + "\n");
+ } catch (NumberFormatException e) {
+ printStatement(DOUBLEINDENTATION + "☹ OOPS!!! You did not indicate which task is done.\n");
+ } catch (IndexOutOfBoundsException e) {
+ printStatement(DOUBLEINDENTATION + "☹ OOPS!!! The index is out of the list boundary.\n");
+ }
+ }
+
+ /**
+ * Execute the save function.
+ * Save the changed taskList into the file
+ */
+ @Override
+ public void sava(TaskList tasks, UI ui, Storage storage){
+ Storage.save(tasks, numberOfTasks);
+ }
+}
diff --git a/src/main/java/Duke/command/EventCommand.java b/src/main/java/Duke/command/EventCommand.java
new file mode 100644
index 0000000000..d9321aceb8
--- /dev/null
+++ b/src/main/java/Duke/command/EventCommand.java
@@ -0,0 +1,54 @@
+package Duke.command;
+
+import Duke.DukeException.DeadlineNullException;
+import Duke.DukeException.EventNullException;
+import Duke.DukeException.TodoNullException;
+import Duke.storage.Storage;
+import Duke.task.Event;
+import Duke.taskList.TaskList;
+import Duke.ui.UI;
+
+import java.time.LocalDateTime;
+
+import static Duke.ui.UI.DOUBLEINDENTATION;
+import static Duke.ui.UI.TRIPLEINDENTATION;
+
+/**
+ * Represents an EventCommand with description and numberOfTasks.
+ * A event
object corresponds to a TodoCommand
+ * with the description and happening time extracted from what entered by users.
+ */
+public class EventCommand extends Command {
+ protected LocalDateTime at;
+
+ public EventCommand(String description, int numberOfTasks, String at) {
+ super(description, numberOfTasks);
+ this.at = LocalDateTime.parse(at);
+ }
+
+ /**
+ * Override: Execute the Command.
+ * add a new Event into the taskList.
+ */
+ @Override
+ public void execute(TaskList tasks, UI ui, Storage storage) throws TodoNullException, DeadlineNullException,
+ EventNullException {
+ super.execute(tasks, ui, storage);
+ if(this.at.toString().length() == 0 && this.at.toString().length() == 0){
+ throw new EventNullException();
+ }
+ tasks.add(new Event(this.description, this.at));
+ ui.printStatement(DOUBLEINDENTATION + "Got it. I've added this task:\n"
+ + TRIPLEINDENTATION + tasks.get(numberOfTasks - 1).toString() + "\n" + DOUBLEINDENTATION
+ + "Now you have " + (numberOfTasks) + " tasks in the list.\n");
+ }
+
+ /**
+ * Execute the save function.
+ * Save the changed taskList into the file
+ */
+ @Override
+ public void sava(TaskList tasks, UI ui, Storage storage){
+ Storage.save(tasks, numberOfTasks);
+ }
+}
diff --git a/src/main/java/Duke/command/ExceptionCommand.java b/src/main/java/Duke/command/ExceptionCommand.java
new file mode 100644
index 0000000000..3d7fb7f58b
--- /dev/null
+++ b/src/main/java/Duke/command/ExceptionCommand.java
@@ -0,0 +1,27 @@
+package Duke.command;
+
+import Duke.storage.Storage;
+import Duke.taskList.TaskList;
+import Duke.ui.UI;
+
+import static Duke.ui.UI.DOUBLEINDENTATION;
+import static Duke.ui.UI.printStatement;
+
+/**
+ * Represents an ExceptionCommand with description and numberOfTasks.
+ * It indicates that there are no corresponding functions in this Duke.
+ */
+public class ExceptionCommand extends Command {
+ public ExceptionCommand(String description, int numberOfTasks) {
+ super(description, numberOfTasks);
+ }
+
+ /**
+ * Override: Execute the Command.
+ * Print out the wrong message.
+ */
+ @Override
+ public void execute(TaskList tasks, UI ui, Storage storage) {
+ printStatement(DOUBLEINDENTATION + ui.WRONGMESSAGE);
+ }
+}
diff --git a/src/main/java/Duke/command/ExitCommand.java b/src/main/java/Duke/command/ExitCommand.java
new file mode 100644
index 0000000000..6e15639769
--- /dev/null
+++ b/src/main/java/Duke/command/ExitCommand.java
@@ -0,0 +1,23 @@
+package Duke.command;
+
+import Duke.storage.Storage;
+import Duke.taskList.TaskList;
+import Duke.ui.UI;
+
+/**
+ * Represents an ExitCommand with description and numberOfTasks.
+ */
+public class ExitCommand extends Command {
+ public ExitCommand(String description, int numberOfTasks) {
+ super(description, numberOfTasks);
+ }
+
+ /**
+ * Override: Execute the Command.
+ * Print out the Exit message and exit.
+ */
+ @Override
+ public void execute(TaskList tasks, UI ui, Storage storage) {
+ ui.printStatement(ui.BYE);
+ }
+}
diff --git a/src/main/java/Duke/command/FindCommand.java b/src/main/java/Duke/command/FindCommand.java
new file mode 100644
index 0000000000..f997a92328
--- /dev/null
+++ b/src/main/java/Duke/command/FindCommand.java
@@ -0,0 +1,26 @@
+package Duke.command;
+
+import Duke.storage.Storage;
+import Duke.taskList.TaskList;
+import Duke.ui.UI;
+
+import static Duke.ui.UI.*;
+
+public class FindCommand extends Command {
+ public FindCommand(String description, int numberOfTasks) {
+ super(description, numberOfTasks);
+ }
+
+ @Override
+ public void execute(TaskList tasks, UI ui, Storage storage) {
+ System.out.print(HORIZONTALLINE);
+ System.out.println(INDENTATION + "Here is yuqiaoluolong's Duke: \n" +
+ " Here are the matching tasks in your list:");
+ for(int i = 0; i < numberOfTasks; i++){
+ if(tasks.get(i).toString().contains(description)) {
+ System.out.println(DOUBLEINDENTATION + (i + 1) + "." + tasks.get(i).toString());
+ }
+ }
+ System.out.println(HORIZONTALLINE);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/Duke/command/HelpCommand.java b/src/main/java/Duke/command/HelpCommand.java
new file mode 100644
index 0000000000..4976bfbd18
--- /dev/null
+++ b/src/main/java/Duke/command/HelpCommand.java
@@ -0,0 +1,32 @@
+package Duke.command;
+
+import Duke.storage.Storage;
+import Duke.taskList.TaskList;
+import Duke.ui.UI;
+
+import static Duke.ui.UI.DOUBLEINDENTATION;
+import static Duke.ui.UI.TRIPLEINDENTATION;
+
+public class HelpCommand extends Command {
+ public HelpCommand(String description, int numberOfTasks) {
+ super(description, numberOfTasks);
+ }
+
+ @Override
+ public void execute(TaskList tasks, UI ui, Storage storage) {
+ UI.printStatement(DOUBLEINDENTATION + "Hello, below is the explanation of the functions:\n"
+ + TRIPLEINDENTATION + "1. you can add todo tasks follwed by the description\n"
+ + TRIPLEINDENTATION + "example: todo task1 --> [T][✘] task1\n"
+ + TRIPLEINDENTATION + "2. you can add deadlines followed by the description and the due time\n"
+ + TRIPLEINDENTATION + "example: deadline d2 /by 2015-02-20T06:30:00 --> " +
+ "[D][✘] d2 (by: Year.2015, Month.FEBRUARY, Day.20, Time: h.6, m.30)\n"
+ + TRIPLEINDENTATION + "3. you can add events followed by the description and the happening time\n"
+ + TRIPLEINDENTATION + "example: event e2 /by 2015-02-20T06:30:00 --> " +
+ "[E][✘] e2 (by: Year.2015, Month.FEBRUARY, Day.20, Time: h.6, m.30)\n"
+ + TRIPLEINDENTATION + "4. you can view all the tasks by typing \" list\" \n"
+ + TRIPLEINDENTATION + "5. you can search for the tasks containing some words\n"
+ + TRIPLEINDENTATION + "example: find book --> Duke will show all the tasks related with book\n"
+ + TRIPLEINDENTATION + "6. you can mark one task as done by byping \"done\" followed its number\n"
+ + TRIPLEINDENTATION + "7. you can delete one task as done by byping \"delete\" followed its number\n");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/Duke/command/ListCommand.java b/src/main/java/Duke/command/ListCommand.java
new file mode 100644
index 0000000000..55356ad6a2
--- /dev/null
+++ b/src/main/java/Duke/command/ListCommand.java
@@ -0,0 +1,32 @@
+package Duke.command;
+
+import Duke.storage.Storage;
+import Duke.taskList.TaskList;
+import Duke.ui.UI;
+
+import static Duke.ui.UI.*;
+
+/**
+ * Represents a ListCommand with description and numberOfTasks.
+ */
+public class ListCommand extends Command {
+ public ListCommand(String description, int numberOfTasks) {
+ super(description, numberOfTasks);
+ }
+
+ /**
+ * Override: Execute the Command.
+ * Print out all the tasks in the taskList.
+ */
+ @Override
+ public void execute(TaskList tasks, UI ui, Storage storage) {
+ System.out.print(HORIZONTALLINE);
+ System.out.println(INDENTATION + "Here is yuqiaoluolong's Duke: \n" +
+ " Here are the tasks in your list:");
+ for(int i = 0; i < numberOfTasks; i++){
+ System.out.println(DOUBLEINDENTATION + (i+1) + "." + tasks.get(i).toString());
+ }
+ System.out.println(HORIZONTALLINE);
+ }
+}
+
diff --git a/src/main/java/Duke/command/TodoCommand.java b/src/main/java/Duke/command/TodoCommand.java
new file mode 100644
index 0000000000..10b9223666
--- /dev/null
+++ b/src/main/java/Duke/command/TodoCommand.java
@@ -0,0 +1,50 @@
+package Duke.command;
+
+import Duke.DukeException.DeadlineNullException;
+import Duke.DukeException.EventNullException;
+import Duke.DukeException.TodoNullException;
+import Duke.storage.Storage;
+import Duke.task.Todo;
+import Duke.taskList.TaskList;
+import Duke.ui.UI;
+
+import static Duke.ui.UI.DOUBLEINDENTATION;
+import static Duke.ui.UI.TRIPLEINDENTATION;
+
+/**
+ * Represents a TodoCommand with description and numberOfTasks.
+ * A todo
object corresponds to a TodoCommand
+ * with the description extracted from what entered by users.
+ */
+public class TodoCommand extends Command {
+
+ public TodoCommand(String description, int numberOfTasks) {
+ super(description, numberOfTasks);
+ }
+
+ /**
+ * Override: Execute the Command.
+ * add a new Todo into the taskList.
+ */
+ @Override
+ public void execute(TaskList tasks, UI ui, Storage storage) throws TodoNullException, DeadlineNullException,
+ EventNullException {
+ super.execute(tasks, ui, storage);
+ tasks.add(new Todo(this.description));
+ if(tasks.get(numberOfTasks-1).description.length() == 0){
+ throw new TodoNullException();
+ }
+ ui.printStatement(DOUBLEINDENTATION + "Got it. I've added this task:\n"
+ + TRIPLEINDENTATION + tasks.get(numberOfTasks - 1).toString() + "\n" + DOUBLEINDENTATION
+ + "Now you have " + (numberOfTasks) + " tasks in the list.\n");
+ }
+
+ /**
+ * Execute the save function.
+ * Save the changed taskList into the file
+ */
+ @Override
+ public void sava(TaskList tasks, UI ui, Storage storage){
+ Storage.save(tasks, numberOfTasks);
+ }
+}
diff --git a/src/main/java/Duke/parser/Parser.java b/src/main/java/Duke/parser/Parser.java
new file mode 100644
index 0000000000..990b1fbd3a
--- /dev/null
+++ b/src/main/java/Duke/parser/Parser.java
@@ -0,0 +1,128 @@
+package Duke.parser;
+
+import Duke.command.*;
+
+import static Duke.ui.UI.DOUBLEINDENTATION;
+import static Duke.ui.UI.printStatement;
+
+/**
+ * parse the command entered into different format
+ * for methods to take in
+ */
+public class Parser {
+
+ /**
+ * Returns TodolineCommand with the description
+ * extracted from the fullCommand
+ *
+ * @param fullCommand Command entered by users.
+ * @param numberOfTasks Number of tasks.
+ * @return TodolineCommand with the description.
+ */
+ public static TodoCommand parseTodoCommand(String fullCommand, int numberOfTasks) {
+ String description = fullCommand.substring(fullCommand.indexOf("todo")+4).trim();
+ if(description =="") {
+ return null;
+ }
+ return new TodoCommand(description, numberOfTasks);
+ }
+
+ /**
+ * Returns DeadlineCommand with the description and due time
+ * extracted from the fullCommand
+ *
+ * @param fullCommand Command entered by users.
+ * @param numberOfTasks Number of tasks.
+ * @return DeadlineCommand with the description and due time.
+ */
+ public static DeadlineCommand parseDeadlineCommand(String fullCommand, int numberOfTasks) {
+ try {
+ return new DeadlineCommand(fullCommand.substring(fullCommand.indexOf("deadline") + 8,
+ fullCommand.indexOf("/")).trim(), numberOfTasks,
+ fullCommand.substring(fullCommand.indexOf("/") + 3).trim());
+ } catch (StringIndexOutOfBoundsException e) {
+ printStatement(DOUBLEINDENTATION + "☹ OOPS!!! There is nothing following \"deadline\".\n");
+ }
+ return null;
+ }
+
+ /**
+ * Returns EventCommand with the description and happening time
+ * extracted from the fullCommand
+ *
+ * @param fullCommand Command entered by users.
+ * @param numberOfTasks Number of tasks.
+ * @return EventCommand with the description and happening time.
+ */
+ public static EventCommand parseEventCommand(String fullCommand, int numberOfTasks) {
+ try {
+ return new EventCommand(fullCommand.substring(fullCommand.indexOf("event")+5,
+ fullCommand.indexOf("/")).trim(), numberOfTasks,
+ fullCommand.substring(fullCommand.indexOf("/")+3).trim());
+ } catch (StringIndexOutOfBoundsException e) {
+ printStatement(DOUBLEINDENTATION + "☹ OOPS!!! There is nothing following \"event\".\n");
+ }
+ return null;
+ }
+
+ /**
+ * Returns ListCommand with the description of "list"
+ *
+ * @param numberOfTasks Number of tasks.
+ * @return ListCommand with the description of "list".
+ */
+ public static Command parseListCommand(int numberOfTasks) {
+ return new ListCommand("list", numberOfTasks);
+ }
+ /**
+ * Returns ListCommand with the description of "bye"
+ *
+ * @param numberOfTasks Number of tasks.
+ * @return ListCommand with the description of "bye".
+ */
+ public static Command parseExitCommand(int numberOfTasks) {
+ return new ExitCommand("bye", numberOfTasks);
+ }
+
+ /**
+ * Returns DoneCommand with the description which is the index of tasks to change to done
+ * and extracted from the fullCommand.
+ *
+ * @param fullCommand Command entered by users
+ * @param numberOfTasks Number of tasks.
+ * @return DoneCommand with the description of the index of tasks to change to done.
+ */
+ public static Command parseDoneCommand(String fullCommand, int numberOfTasks) {
+ return new DoneCommand(fullCommand.replace("done", " ").trim(), numberOfTasks);
+ }
+
+ /**
+ * Returns DeleteCommand with the description which is the index of tasks to delete
+ * and extracted from the fullCommand.
+ *
+ * @param fullCommand Command entered by users
+ * @param numberOfTasks Number of tasks.
+ * @return DeleteCommand with the description that is the index of tasks to delete.
+ */
+ public static Command parseDeleteCommand(String fullCommand, int numberOfTasks) {
+ return new DeleteCommand(fullCommand.replace("delete", " ").trim(), numberOfTasks);
+ }
+
+ /**
+ * Returns Exception Command with the description "exception"
+ *
+ * @param numberOfTasks Number of tasks.
+ * @return Exception Command with the description "exception"
+ */
+ public static Command parseExceptionCommand(int numberOfTasks) {
+ return new ExceptionCommand("exception", numberOfTasks);
+ }
+
+ public static Command parseFindCommand(String index, int numberOfTasks) {
+ return new FindCommand(index, numberOfTasks);
+ }
+
+ public static Command parseHelpCommand(int numberOfTasks) {
+ return new HelpCommand("help", numberOfTasks);
+ }
+}
diff --git a/src/main/java/Duke/storage/Storage.java b/src/main/java/Duke/storage/Storage.java
new file mode 100644
index 0000000000..a13b0f5cd4
--- /dev/null
+++ b/src/main/java/Duke/storage/Storage.java
@@ -0,0 +1,187 @@
+package Duke.storage;
+
+import Duke.DukeException.InvalidStorageFilePathException;
+import Duke.task.Deadline;
+import Duke.task.Event;
+import Duke.task.Task;
+import Duke.task.Todo;
+import Duke.taskList.TaskList;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalDateTime;
+import java.time.Month;
+import java.time.format.DateTimeParseException;
+import java.util.ArrayList;
+
+import static Duke.ui.UI.INDENTATION;
+import static Duke.ui.UI.printStatement;
+
+/**
+ * Represents a class saving the tasklist to a file and load the content from it.
+ */
+public class Storage {
+ public static final String DEFAULT_STORAGE_FILEPATH = "/Users/yuqiao/Desktop/CS2113T/ip/data/duke.txt";
+ public static Path path = Path.of(DEFAULT_STORAGE_FILEPATH);
+
+ public Storage(String filePath) /*throws InvalidStorageFilePathException*/ {
+ path = Paths.get(filePath);
+ if (!isValidPath(path)) {
+ try {
+ throw new InvalidStorageFilePathException("Storage file should end with '.txt'");
+ } catch (InvalidStorageFilePathException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Returns a boolean variable indicating whethe the path is valid or not
+ *
+ * @param filePath Path of the file to be tested.
+ * @return the validity of the filePath.
+ */
+ private static boolean isValidPath(Path filePath) {
+ return filePath.toString().endsWith(".txt");
+ }
+
+ /**
+ * save the changed task list into the file
+ *
+ * @param tasks Task list to save
+ * @param numberOfTasks Number of the tasks in the task list.
+ */
+ public static void save(TaskList tasks, int numberOfTasks) {
+ String text = "";
+ for(int i = 0; i
+ *
+ * @return Task list containing tasks inside the
+ * file of the type ArrayList
+ */
+ public ArrayList load(){
+ ArrayList tasklist = new ArrayList<>();
+ try {
+ for (String encodedTask : Files.readAllLines(path)) {
+ if(encodedTask.contains("D")) {
+ int year, dayOfMonth, hour, minute;
+ Month month;
+ try{
+ year =Integer.parseInt(encodedTask.substring(encodedTask.indexOf("Year") + 5,
+ encodedTask.indexOf("Month") - 2));
+ month = Month.valueOf(encodedTask.substring(encodedTask.indexOf("Month") + 6,
+ encodedTask.indexOf("Day") - 2));
+ dayOfMonth = Integer.parseInt(encodedTask.substring(encodedTask.indexOf("Day") + 4,
+ encodedTask.indexOf("Time") - 2));
+ hour = Integer.parseInt(encodedTask.substring(encodedTask.lastIndexOf("h") + 2,
+ encodedTask.lastIndexOf("m") - 2));
+ minute = Integer.parseInt(encodedTask.substring(encodedTask.lastIndexOf("m") + 2,
+ encodedTask.indexOf(")")));
+ tasklist.add(new Deadline(getDescriptiongFromFile(encodedTask),
+ LocalDateTime.of(year, month, dayOfMonth, hour, minute)));
+ } catch (DateTimeParseException e) {
+ tasklist.remove(tasklist.size()-1);
+ printStatement(INDENTATION + "☹ OOPS!!! There are time entered wrongly in the text file.\n" +
+ INDENTATION + "Please delete them.\n");
+ }
+ if(encodedTask.contains("\u2713")) {
+ tasklist.get(tasklist.size()-1).markAsDone();
+ }
+ } else if(encodedTask.contains("E")) {
+ int year, dayOfMonth, hour, minute;
+ Month month;
+ try {
+ year =Integer.parseInt(encodedTask.substring(encodedTask.indexOf("Year") + 5,
+ encodedTask.indexOf("Month") - 2));
+ month = Month.valueOf(encodedTask.substring(encodedTask.indexOf("Month") + 6,
+ encodedTask.indexOf("Day") - 2));
+ dayOfMonth = Integer.parseInt(encodedTask.substring(encodedTask.indexOf("Day") + 4,
+ encodedTask.indexOf("Time") - 2));
+ hour = Integer.parseInt(encodedTask.substring(encodedTask.lastIndexOf("h") + 2,
+ encodedTask.lastIndexOf("m") - 2));
+ minute = Integer.parseInt(encodedTask.substring(encodedTask.lastIndexOf("m") + 2,
+ encodedTask.indexOf(")")));
+ tasklist.add(new Event(getDescriptiongFromFile(encodedTask),
+ LocalDateTime.of(year, month, dayOfMonth, hour, minute)));
+ } catch (DateTimeParseException e) {
+ tasklist.remove(tasklist.size()-1);
+ printStatement(INDENTATION + "☹ OOPS!!! There are time entered wrongly in the text file.\n" +
+ INDENTATION + "Please delete them.\n");
+ }
+ if(encodedTask.contains("\u2713")) {
+ tasklist.get(tasklist.size()-1).markAsDone();
+ }
+ } else {
+ tasklist.add(new Todo(getDescriptiongFromFile(encodedTask)));
+ if(encodedTask.contains("\u2713")) {
+ tasklist.get(tasklist.size()-1).markAsDone();
+ }
+ }
+ }
+ return tasklist;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the description of a task as a String variable.
+ * extracted from the inputCommand
+ *
+ * @param inputCommand Command entered by users.
+ * @return Description of a task as a String variable.
+ */
+ public static String getDescriptiongFromFile(String inputCommand) {
+ if(inputCommand.contains(":")){
+ return inputCommand.substring(inputCommand.lastIndexOf("]") + 1, inputCommand.indexOf((":"))-4).trim();
+ } else {
+ return inputCommand.substring(inputCommand.lastIndexOf("]") + 1).trim();
+ }
+ }
+
+ /**
+ * Returns the number of tasks inside the file when loading
+ *
+ * @return Number of tasks inside the file.
+ */
+ public int loadNumberOfTasks(){
+ int number = 0;
+ try {
+ for (int i = 0; i< Files.readAllLines(path).size(); i++) {
+ number++;
+ }
+ return number;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return -1;
+ }
+}
+
diff --git a/src/main/java/Duke/task/Deadline.java b/src/main/java/Duke/task/Deadline.java
new file mode 100644
index 0000000000..bf17032ee2
--- /dev/null
+++ b/src/main/java/Duke/task/Deadline.java
@@ -0,0 +1,26 @@
+package Duke.task;
+
+import java.time.LocalDateTime;
+
+/**
+ * Represents a Deadline Task. Adeadline
corresponds to a task
+ * described by description ,isDone, and by.
+ */
+public class Deadline extends Task {
+
+ protected LocalDateTime by;
+
+ public Deadline(String description, LocalDateTime by) {
+ super(description);
+ this.by = by;
+ }
+
+ /**
+ * Override: convert the task to a String in a certain format
+ */
+ @Override
+ public String toString() {
+ return "[D]" + super.toString() + " (by: Year." + by.getYear() +", Month." + by.getMonth()
+ + ", Day." + by.getDayOfMonth() +", Time: h." + by.getHour() +", m." + by.getMinute() + ")";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/Duke/task/Event.java b/src/main/java/Duke/task/Event.java
new file mode 100644
index 0000000000..144688ea0e
--- /dev/null
+++ b/src/main/java/Duke/task/Event.java
@@ -0,0 +1,26 @@
+package Duke.task;
+
+import java.time.LocalDateTime;
+
+/**
+ * Represents a Event Task. Aevent
corresponds to a task
+ * described by description ,isDone, and at.
+ */
+public class Event extends Task {
+
+ protected LocalDateTime at;
+
+ public Event(String description, LocalDateTime at){
+ super(description);
+ this.at = at;
+ }
+
+ /**
+ * Override: convert the task to a String in a certain format
+ */
+ @Override
+ public String toString() {
+ return "[E]" + super.toString() + " (at: Year." + at.getYear() +", Month." + at.getMonth()
+ + ", Day." + at.getDayOfMonth() +", Time: h." + at.getHour() +", m." + at.getMinute() + ")";
+ }
+}
diff --git a/src/main/java/Duke/task/Task.java b/src/main/java/Duke/task/Task.java
new file mode 100644
index 0000000000..2d06198c6a
--- /dev/null
+++ b/src/main/java/Duke/task/Task.java
@@ -0,0 +1,32 @@
+package Duke.task;
+
+/**
+ * Represents a Task. It is an abstract type
+ */
+public class Task {
+ public String description;
+ public boolean isDone;
+
+ public Task(String description) {
+ this.description = description;
+ this.isDone = false;
+ }
+
+ /**
+ * mark the task as done.
+ */
+ public void markAsDone(){
+ this.isDone = true;
+ }
+
+ public String getStatusIcon() {
+ return (isDone ? "\u2713" : "\u2718"); //return tick or X symbols
+ }
+
+ /**
+ * convert the task to a String in a certain format
+ */
+ public String toString() {
+ return "[" + this.getStatusIcon() + "] " + this.description;
+ }
+}
diff --git a/src/main/java/Duke/task/Todo.java b/src/main/java/Duke/task/Todo.java
new file mode 100644
index 0000000000..ad910fd702
--- /dev/null
+++ b/src/main/java/Duke/task/Todo.java
@@ -0,0 +1,20 @@
+package Duke.task;
+
+/**
+ * Represents a Todo Task. Atodo
corresponds to a task
+ * described by description and isDone.
+ */
+public class Todo extends Task {
+
+ public Todo(String description){
+ super(description);
+ }
+
+ /**
+ * Override: convert the task to a String in a certain format
+ */
+ @Override
+ public String toString() {
+ return "[T]" + super.toString();
+ }
+}
diff --git a/src/main/java/Duke/taskList/TaskList.java b/src/main/java/Duke/taskList/TaskList.java
new file mode 100644
index 0000000000..0b32a6baac
--- /dev/null
+++ b/src/main/java/Duke/taskList/TaskList.java
@@ -0,0 +1,47 @@
+package Duke.taskList;
+
+import Duke.task.Task;
+
+import java.util.ArrayList;
+
+/**
+ * Represents an ArrayList of Task.
+ */
+public class TaskList {
+ private static ArrayList taskList = new ArrayList<>();
+
+ public TaskList() {
+ }
+
+ public TaskList(ArrayList tasks) {
+ for(int i=0; i< tasks.size(); i++){
+ taskList.add(tasks.get(i));
+ }
+ }
+
+ /**
+ * add one element to the taskList
+ */
+ public void add(Task oneTask){
+ taskList.add(oneTask);
+ }
+
+ /**
+ * get the element in the taskList with entered index
+ *
+ * @param index the index of the element in taskList that we want.
+ * @return the element of type Task
+ */
+ public Task get(int index){
+ return taskList.get(index);
+ }
+
+ /**
+ * remove one element in the taskList with entered index
+ *
+ * @param i the index of the element in taskList that we want to remove.
+ */
+ public void remove(int i) {
+ taskList.remove(i);
+ }
+}
diff --git a/src/main/java/Duke/ui/UI.java b/src/main/java/Duke/ui/UI.java
new file mode 100644
index 0000000000..6fadc7ca1d
--- /dev/null
+++ b/src/main/java/Duke/ui/UI.java
@@ -0,0 +1,75 @@
+package Duke.ui;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.Scanner;
+
+/**
+ * Represents a ui
+ * Contains the common constant Strings and methods
+ */
+public class UI {
+ private static final String LS = System.lineSeparator();
+ public static final int MAX_NUM_TASKS = 100;
+ public static final String INDENTATION = " ";
+ public static final String DOUBLEINDENTATION = INDENTATION + " ";
+ public static final String TRIPLEINDENTATION = DOUBLEINDENTATION + " ";
+ public static final String HORIZONTALLINE = INDENTATION
+ + "<------------------------------------------------------------>\n";
+ public final String LOGO = TRIPLEINDENTATION + " ____ _ \n"
+ + TRIPLEINDENTATION + "| _ \\ _ _| | _____ \n"
+ + TRIPLEINDENTATION + "| | | | | | | |/ / _ \\\n"
+ + TRIPLEINDENTATION + "| |_| | |_| | < __/\n"
+ + TRIPLEINDENTATION + "|____/ \\__,_|_|\\_\\___|\n";
+ public final String GREET = INDENTATION + " Hello! I'm Duke\n"
+ + INDENTATION + " What can I do for you? (type\"help\" to get explanation)\n";
+ public final String BYE = INDENTATION + " Bye. Hope to see you again soon!\n";
+ public final String WRONGMESSAGE = "☹ OOPS!!! I'm sorry, but I don't know what that means :-(\n";
+
+ private final Scanner in;
+ private final PrintStream out;
+ public UI() {
+ this(System.in, System.out);
+ }
+
+ public UI(InputStream in, PrintStream out) {
+ this.in = new Scanner(in);
+ this.out = out;
+ }
+
+ /**
+ * print out the input String
+ * @param statement The String need to print.
+ */
+ public static void printStatement(String statement) {
+ System.out.println(HORIZONTALLINE + INDENTATION + "Here is yuqiaoluolong's Duke: \n"
+ + statement + HORIZONTALLINE);
+ }
+
+ /**
+ * print out the Welcome message
+ */
+ public void showWelcome() {
+ printStatement(TRIPLEINDENTATION + "Hello from\n" + LOGO);
+ printStatement(GREET);
+ }
+
+ /**
+ * Returns what is entered by users as a String variable.
+ *
+ * @return inputcommand.
+ */
+
+ public String readCommand(){
+ String input = in.nextLine();
+ return input;
+ }
+
+ /**
+ * Show a line.
+ */
+ public void showLine(){
+ System.out.printf(LS);
+ }
+
+}
diff --git a/text-ui-test/ACTUAL.TXT b/text-ui-test/ACTUAL.TXT
new file mode 100644
index 0000000000..97e74e8523
--- /dev/null
+++ b/text-ui-test/ACTUAL.TXT
@@ -0,0 +1,21 @@
+ <------------------------------------------------------------>
+ Here is yuqiaoluolong's Duke:
+Hello from
+ ____ _
+| _ \ _ _| | _____
+| | | | | | | |/ / _ \
+| |_| | |_| | < __/
+|____/ \__,_|_|\_\___|
+ <------------------------------------------------------------>
+
+ <------------------------------------------------------------>
+ Here is yuqiaoluolong's Duke:
+ Hello! I'm Duke
+ What can I do for you?
+ <------------------------------------------------------------>
+
+ <------------------------------------------------------------>
+ Here is yuqiaoluolong's Duke:
+ Bye. Hope to see you again soon!
+ <------------------------------------------------------------>
+
diff --git a/text-ui-test/EXPECTED-UNIX.TXT b/text-ui-test/EXPECTED-UNIX.TXT
new file mode 100644
index 0000000000..0b3737bbe0
--- /dev/null
+++ b/text-ui-test/EXPECTED-UNIX.TXT
@@ -0,0 +1,21 @@
+ <------------------------------------------------------------>
+ Here is yuqiaoluolong's Duke:
+Hello from
+ ____ _
+| _ \ _ _| | _____
+| | | | | | | |/ / _ \
+| |_| | |_| | < __/
+|____/ \__,_|_|\_\___|
+ <------------------------------------------------------------>
+
+ <------------------------------------------------------------>
+ Here is yuqiaoluolong's Duke:
+ Hello! I'm Duke
+ What can I do for you?
+ <------------------------------------------------------------>
+
+ <------------------------------------------------------------>
+ Here is yuqiaoluolong's Duke:
+ Bye. Hope to see you again soon!
+ <------------------------------------------------------------>
+
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e7..0b3737bbe0 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,21 @@
+ <------------------------------------------------------------>
+ Here is yuqiaoluolong's Duke:
Hello from
- ____ _
-| _ \ _ _| | _____
+ ____ _
+| _ \ _ _| | _____
| | | | | | | |/ / _ \
| |_| | |_| | < __/
|____/ \__,_|_|\_\___|
+ <------------------------------------------------------------>
+
+ <------------------------------------------------------------>
+ Here is yuqiaoluolong's Duke:
+ Hello! I'm Duke
+ What can I do for you?
+ <------------------------------------------------------------>
+
+ <------------------------------------------------------------>
+ Here is yuqiaoluolong's Duke:
+ Bye. Hope to see you again soon!
+ <------------------------------------------------------------>
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb2..b023018cab 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1 @@
+bye
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
index e169618a34..d47aa28099 100644
--- a/text-ui-test/runtest.sh
+++ b/text-ui-test/runtest.sh
@@ -13,7 +13,7 @@ then
fi
# compile the code into the bin folder, terminates if error occurred
-if ! javac -cp ../src -Xlint:none -d ../bin ../src/main/java/Duke.java
+if ! javac -cp ../src -Xlint:none -d ../bin ../src/main/java/*.java
then
echo "********** BUILD FAILURE **********"
exit 1