tasks) {
+ String description = line.substring(0, line.indexOf("")).trim();
+ Todo currTodo = new Todo(description);
+ String priority = line.substring(line.indexOf("
") + 3,line.indexOf("")).trim();
+ currTodo.setPriority(priority);
+ tasks.add(currTodo);
+ String savedNotes = line.substring(line.indexOf("") + 3);
+ if (savedNotes.charAt(0) == '1'){
+ savedNotes = savedNotes.substring(1);
+ String[] notesToBeAdded;
+ notesToBeAdded = savedNotes.split("@",0);
+ for (String item : notesToBeAdded) {
+ tasks.get(tasks.size() - 1).addNotes(item);
+ }
+ }
+ }
+
+
+ /**
+ * Adds an event into the list without generating messages,
+ * to be used when loading from save data.
+ *
+ * @param line The line of input from the save file
+ * @param tasks The array list of tasks
+ */
+ static void loadEvent(String line, ArrayList tasks) {
+ String description = line.substring(0, line.indexOf("/from")).trim();
+ String start = line.substring(line.indexOf("/from") + 5, line.indexOf("/to")).trim();
+ String end = line.substring(line.indexOf("/to") + 3, line.indexOf("")).trim();
+ String priority = line.substring(line.indexOf("
") + 3, line.indexOf("
") + 4).trim();
+ Event currEvent = new Event(description, start, end);
+ currEvent.setPriority(priority);
+ tasks.add(currEvent);
+ String savedNotes = line.substring(line.indexOf("") + 3);
+ if (savedNotes.charAt(0) == '1'){
+ savedNotes = savedNotes.substring(1);
+ String[] notesToBeAdded;
+ notesToBeAdded = savedNotes.split("@",0);
+ for (String item : notesToBeAdded) {
+ tasks.get(tasks.size() - 1).addNotes(item);
+ }
+ }
+ }
+
+ static void loadRecurringEvent(String line, ArrayList tasks) {
+ String description = line.substring(0, line.indexOf("/from")).trim();
+ String start = line.substring(line.indexOf("/from") + 5, line.indexOf("/to")).trim();
+ String end = line.substring(line.indexOf("/to") + 3, line.indexOf("")).trim();
+ String priority = line.substring(line.indexOf("
") + 3, line.indexOf("/day")).trim();
+ DayOfWeek day = DayOfWeek.valueOf(line.substring(line.indexOf("/day") + 4).trim());
+ RecurringEvent currEvent = new RecurringEvent(description, start, end, day);
+ currEvent.setPriority(priority);
+ tasks.add(currEvent);
+ }
+
+ /**
+ * Adds a schoolClass to the list without generating messages,
+ * to be used when loading from save data.
+ *
+ * @param line The line of input from the user
+ * @param classes The priority queue of school classes
+ */
+ static void loadSchoolClass(String line, PriorityQueue classes) {
+ String description = line.substring(0, line.indexOf("/class")).trim();
+ String className = line.substring(line.indexOf("/class") + 6, line.indexOf("/day")).trim();
+ DayOfWeek day = DayOfWeek.valueOf(line.substring(line.indexOf("/day") + 4, line.indexOf("/from")).trim());
+ String startString = line.substring(line.indexOf("/from") + 5, line.indexOf("/to")).trim();
+ String endString = line.substring(line.indexOf("/to") + 3).trim();
+ SchoolClass currSchoolClass = new SchoolClass(className, description, day, startString, endString);
+
+ TaskList.checkClassOver(day, endString, currSchoolClass);
+ classes.add(currSchoolClass);
+ }
+
+ /**
+ * Adds a deadline into the list without generating messages,
+ * to be used when loading from save data.
+ *
+ * @param line The line of input from the save file
+ * @param tasks The array list of tasks
+ */
+ static void loadDeadline(String line, ArrayList tasks) {
+ String description = line.substring(0, line.indexOf("/by")).trim();
+ String deadline = line.substring(line.indexOf("/by") + 3, line.indexOf("")).trim();
+ String priority = line.substring(line.indexOf("
") + 3, line.indexOf("
") + 4).trim();
+ Deadline currDeadline = new Deadline(description, deadline);
+ currDeadline.setPriority(priority);
+ tasks.add(currDeadline);
+ String savedNotes = line.substring(line.indexOf("") + 3);
+ if (savedNotes.charAt(0) == '1'){
+ savedNotes = savedNotes.substring(1);
+ String[] notesToBeAdded;
+ notesToBeAdded = savedNotes.split("@",0);
+ for (String item : notesToBeAdded) {
+ tasks.get(tasks.size() - 1).addNotes(item);
+ }
+ }
+ }
+
+ /**
+ * Adds a RecurringDeadline to the list when loading from save data
+ *
+ * @param line The line of input from save file
+ * @param tasks the array list of tasks
+ */
+ static void loadRecurringDeadline(String line, ArrayList tasks) {
+ String description = line.substring(0, line.indexOf("/by")).trim();
+ String deadline = line.substring(line.indexOf("/by") + 3, line.indexOf("")).trim();
+ String priority = line.substring(line.indexOf("
") + 3, line.indexOf("/day")).trim();
+ DayOfWeek day = DayOfWeek.valueOf(line.substring(line.indexOf("/day") + 4).trim());
+ RecurringDeadline currDeadline = new RecurringDeadline(description, deadline, day);
+ currDeadline.setPriority(priority);
+ tasks.add(currDeadline);
+ }
+
+ /**
+ * Load the task status of a task from the save data
+ *
+ * @param tasks The array list of tasks
+ * @param doneStatus The done status of the current task
+ */
+ static void loadTaskStatus(ArrayList tasks, String doneStatus) {
+ int taskNumber = Task.getTaskCount();
+ if (doneStatus.equals("1")) {
+ tasks.get(taskNumber).markAsDone();
+ } else {
+ tasks.get(taskNumber).markAsNotDone();
+ }
+ }
+
+ /**
+ * Saves the tasks in the list to the save file
+ *
+ * @param tasks The array list of tasks
+ */
+ static void save(ArrayList tasks, PriorityQueue classes) throws IOException {
+ File f = new File(SAVEPATH);
+ if (f.exists()) {
+ f.delete();
+ }
+ f.createNewFile();
+
+ // Saving the task list to the save file
+ FileWriter fw = new FileWriter(SAVEPATH);
+ for (Task currTask : tasks) {
+ fw.write(currTask.toSaveString());
+ }
+ fw.close();
+
+ // Saving the class schedule to the save file
+ FileWriter fw2 = new FileWriter(SAVEPATH, true);
+ PriorityQueue temp = new PriorityQueue(classes);
+ while (!temp.isEmpty()) {
+ fw2.write(temp.poll().toSaveString());
+ }
+ fw2.close();
+ }
+
+ /**
+ * Try to save, shows error message if saving fails
+ *
+ * @param tasks The array list of tasks
+ */
+ static void trySave(ArrayList tasks, PriorityQueue classes) {
+ try {
+ save(tasks, classes);
+ } catch (IOException e) {
+ System.out.println("Saving error.");
+ }
+ }
+
+ /**
+ * Load the save data
+ *
+ * @param tasks The array list of tasks
+ */
+ static void load(ArrayList tasks, PriorityQueue classes) throws IOException,
+ IndexOutOfBoundsException {
+ File folder = new File(SAVEFOLDER);
+ if (!folder.exists()) {
+ new File(SAVEFOLDER).mkdir();
+ }
+
+ File f = new File(SAVEPATH);
+ if (!f.exists()) {
+ f.createNewFile();
+ }
+
+ Scanner s = new Scanner(f);
+ while (s.hasNext()) {
+ String line = s.nextLine();
+ String[] formattedInput = line.split(" ");
+ String doneStatus = formattedInput[0];
+ String command = "";
+ for (int i = 1; i < formattedInput.length; i++) {
+ command += formattedInput[i];
+ command += " ";
+ }
+ try {
+ loadTask(command, tasks, classes, doneStatus);
+ } catch (IndexOutOfBoundsException e) {
+ FileWriter fw = new FileWriter(SAVEPATH);
+ throw new IndexOutOfBoundsException();
+ }
+ }
+ }
+
+ /**
+ * Try to load the save data, shows error message if loading fails
+ *
+ * @param tasks The array list of tasks
+ */
+ static void tryLoad(ArrayList tasks, PriorityQueue classes) {
+ try {
+ load(tasks, classes);
+ } catch (IOException e) {
+ Ui.loadingErrorMessage();
+ } catch (IndexOutOfBoundsException e) {
+ Ui.loadingErrorMessage();
+ }
+ }
+}
diff --git a/src/main/java/seedu/duck/TaskList.java b/src/main/java/seedu/duck/TaskList.java
new file mode 100644
index 0000000000..0f04b15f83
--- /dev/null
+++ b/src/main/java/seedu/duck/TaskList.java
@@ -0,0 +1,799 @@
+package seedu.duck;
+
+import seedu.duck.exception.*;
+import seedu.duck.task.*;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.time.DayOfWeek;
+import java.time.format.DateTimeParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.PriorityQueue;
+import java.util.Scanner;
+
+/**
+ * Contains operations to make changes to the list of tasks or the class schedule
+ */
+public class TaskList {
+ private static final int DESCRIPTION_OFFSET = 12;
+ private static final int DEADLINE_OFFSET = 9;
+ private static final int FROM_OFFSET = 5;
+ private static final int TO_OFFSET = 3;
+ private static final int DAY_OFFSET = 4;
+ private static final int BY_OFFSET = 3;
+
+ static void addTask(String line, ArrayList tasks, PriorityQueue classes) {
+ if (line.contains("/by")) {
+ // Adding a Deadline
+ if (line.contains("/re")) {
+ try {
+ addRecurringDeadline(line, tasks);
+ Task.incrementCount();
+ } catch(IllegalDeadlineException | StringIndexOutOfBoundsException e) {
+ Ui.deadlineErrorMessage();
+ } catch (IllegalArgumentException e) {
+ Ui.invalidDayMessage();
+ } catch (DateTimeParseException e) {
+ Ui.invalidDateTimeMessage();
+ }
+ } else {
+ try {
+ addDeadline(line, tasks);
+ Task.incrementCount();
+ } catch (IllegalDeadlineException e) {
+ Ui.deadlineErrorMessage();
+ } catch (expiredDateException e) {
+ Ui.expiredErrorMessage();
+ } catch (DateTimeException e) {
+ Ui.invalidDateTimeMessage();
+ }
+ }
+ } else if (line.contains("/class")) {
+ // Adding a SchoolClass
+ try {
+ addSchoolClass(line, classes);
+ } catch (IllegalSchoolClassException | IndexOutOfBoundsException e) {
+ Ui.eventErrorMessage();
+ } catch (expiredDateException e) {
+ Ui.expiredErrorMessage();
+ } catch (startAfterEndException e) {
+ Ui.startAfterEndErrorMessage();
+ } catch (DateTimeException e) {
+ Ui.invalidDateTimeMessage();
+ }
+ } else if (line.contains("/from") && line.contains("/to")) {
+ // Adding an Event
+ if (line.contains("/re")) {
+ try {
+ addRecurringEvent(line, tasks);
+ Task.incrementCount();
+ } catch (IllegalEventException | StringIndexOutOfBoundsException e) {
+ Ui.eventErrorMessage();
+ } catch (IllegalArgumentException e) {
+ Ui.invalidDayMessage();
+ } catch (DateTimeParseException e) {
+ Ui.invalidDateTimeMessage();
+ }
+ } else {
+ try {
+ addEvent(line, tasks);
+ Task.incrementCount();
+ } catch (IllegalEventException | IndexOutOfBoundsException e) {
+ Ui.eventErrorMessage();
+ } catch (expiredDateException e) {
+ Ui.expiredErrorMessage();
+ } catch (startAfterEndException e) {
+ Ui.startAfterEndErrorMessage();
+ } catch (DateTimeException e) {
+ Ui.invalidDateTimeMessage();
+ }
+ }
+ } else if (line.trim().split(" ")[0].equals("/todo")){
+ // Adding a _Todo_
+ try {
+ addTodo(line, tasks);
+ Task.incrementCount();
+ } catch (IllegalTodoException e) {
+ Ui.todoErrorMessage();
+ }
+ } else {
+ Ui.unknownCommandMessage();
+ }
+ }
+
+ /**
+ * Adds a _Todo_ to the list
+ *
+ * @param line The line of input from the user
+ * @param tasks The array list of tasks
+ */
+ static void addTodo(String line, ArrayList tasks) throws IllegalTodoException {
+ line = line.trim();
+ String description = line.substring(5).trim();
+ if (description.isBlank()) {
+ throw new IllegalTodoException();
+ } else {
+ Todo currTodo = new Todo(description);
+ tasks.add(currTodo);
+ Ui.addedTaskMessage(currTodo);
+ }
+ }
+
+ /**
+ * Sets a priority to the specified task
+ *
+ * @param words The input variable from the user, consisting of an index and a priority (from 1 to 3)
+ * @param tasks The array list of tasks
+ */
+ static void setPriority(ArrayList tasks, String[] words) {
+ if (!words[2].equals("1") && !words[2].equals("2") && !words[2].equals("3")) {
+ Ui.priorityErrorMessage();
+ } else if (!Parser.isNumeric(words[1])) {
+ Ui.unknownCommandMessage();
+ } else {
+ int taskNumber = Integer.parseInt(words[1]);
+ int taskCount = Task.getTaskCount();
+ if (taskNumber > taskCount || taskNumber <= 0) {
+ // Input task number exceeds the number of tasks in the list
+ Ui.exceedTaskNumberMessage(taskNumber);
+ } else {
+ tasks.get(taskNumber - 1).setPriority(words[2]);
+ // Printing out marked as done message
+ Ui.borderLine();
+ System.out.println("\t Understood. The task's new priority is:");
+ System.out.println("\t " + tasks.get(taskNumber - 1).getPriority());
+ Ui.borderLine();
+ }
+ }
+ }
+
+ /**
+ * Adds an event to the list
+ *
+ * @param line The line of input from the user
+ * @param tasks The array list of tasks
+ */
+ static void addEvent(String line, ArrayList tasks) throws IllegalEventException, startAfterEndException,
+ expiredDateException {
+ String description = line.substring(0, line.indexOf("/from")).trim();
+ String startString = line.substring(line.indexOf("/from") + FROM_OFFSET, line.indexOf("/to")).trim();
+ String endString = line.substring(line.indexOf("/to") + 3).trim();
+ DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm");
+ LocalDateTime start = LocalDateTime.parse(startString, dateFormat);
+ LocalDateTime end = LocalDateTime.parse(endString, dateFormat);
+ if (start.isAfter(end)) {
+ throw new startAfterEndException();
+ } else if (start.isBefore(LocalDateTime.now()) || end.isBefore(LocalDateTime.now())) {
+ throw new expiredDateException();
+ } else if (description.isBlank() || startString.isBlank() || endString.isBlank()) {
+ throw new IllegalEventException();
+ } else {
+ Event currEvent = new Event(description, startString, endString);
+ tasks.add(currEvent);
+ Ui.addedTaskMessage(currEvent);
+ }
+ }
+
+ /**
+ * Adds a RecurringEvent to the list
+ * @param line input from user
+ * @param tasks the array list of tasks
+ * @throws IllegalEventException handles incorrect event format
+ */
+ static void addRecurringEvent(String line, ArrayList tasks) throws IllegalEventException{
+ String description = line.substring(4, line.indexOf("/from")).trim();
+ String start = line.substring(line.indexOf("/from") + FROM_OFFSET, line.indexOf("/to")).trim();
+ String end = line.substring(line.indexOf("/to") + TO_OFFSET, line.indexOf("/day")).trim();
+ DayOfWeek day = DayOfWeek.valueOf(line.substring(line.indexOf("/day") + DAY_OFFSET).trim());
+ DateTimeFormatter timeFormat = DateTimeFormatter.ofPattern("HHmm");
+ //check whether start and end are in the correct format
+ LocalTime.parse(start, timeFormat);
+ LocalTime.parse(end, timeFormat);
+ if (description.isBlank() || start.isBlank() || end.isBlank()) {
+ throw new IllegalEventException();
+ } else {
+ RecurringEvent currEvent = new RecurringEvent(description, start, end, day);
+ tasks.add(currEvent);
+ Ui.addedTaskMessage(currEvent);
+ }
+ }
+
+ /**
+ * Adds a schoolClass to the list
+ *
+ * @param line The line of input from the user
+ * @param classes The priority queue of school classes
+ */
+ static void addSchoolClass(String line, PriorityQueue classes) throws IllegalSchoolClassException,
+ startAfterEndException, expiredDateException, IllegalArgumentException, NullPointerException {
+ String description = line.substring(0, line.indexOf("/class")).trim();
+ String className = line.substring(line.indexOf("/class") + 6, line.indexOf("/day")).trim();
+ try {
+ DayOfWeek day = DayOfWeek.valueOf(line.substring(line.indexOf("/day") + 4, line.indexOf("/from")).trim());
+ String startString = line.substring(line.indexOf("/from") + 5, line.indexOf("/to")).trim();
+ String endString = line.substring(line.indexOf("/to") + 3).trim();
+ DateTimeFormatter timeFormat = DateTimeFormatter.ofPattern("HHmm");
+ LocalTime start = LocalTime.parse(startString, timeFormat);
+ LocalTime end = LocalTime.parse(endString, timeFormat);
+ if (start.isAfter(end)) {
+ throw new startAfterEndException();
+ } else if (className.isBlank() || startString.isBlank() || endString.isBlank()) {
+ throw new IllegalSchoolClassException();
+ } else {
+ SchoolClass currSchoolClass = new SchoolClass(className, description, day, startString, endString);
+ classes.add(currSchoolClass);
+ Ui.addedSchoolClassMessage(currSchoolClass, classes);
+ }
+ } catch (IllegalArgumentException e) {
+ Ui.invalidDayMessage();
+ } catch (NullPointerException e) {
+ Ui.emptyDayErrorMessage();
+ }
+ }
+
+ /**
+ * Adds a deadline to the list
+ *
+ * @param line The line of input from the user
+ * @param tasks The array list of tasks
+ */
+ static void addDeadline(String line, ArrayList tasks) throws IllegalDeadlineException, expiredDateException {
+ String description = line.substring(0, line.indexOf("/by")).trim();
+ String deadlineString = line.substring(line.indexOf("/by") + 3).trim();
+ DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm");
+ LocalDateTime deadline = LocalDateTime.parse(deadlineString, dateFormat);
+ //System.out.println(description.isBlank());
+ if (description.isBlank() || deadlineString.isBlank()) {
+ throw new IllegalDeadlineException();
+ } else if (deadline.isBefore(LocalDateTime.now())) {
+ throw new expiredDateException();
+ } else {
+ Deadline currDeadline = new Deadline(description, deadlineString);
+ tasks.add(currDeadline);
+ Ui.addedTaskMessage(currDeadline);
+ }
+ }
+
+
+ /**
+ * adds a recurringDeadline to the list
+ *
+ * @param line the line of input from the user
+ * @param tasks the array list of tasks
+ */
+ static void addRecurringDeadline(String line, ArrayList tasks) throws IllegalDeadlineException,
+ IllegalArgumentException {
+ String description = line.substring(4, line.indexOf("/by")).trim();
+ String deadline = line.substring(line.indexOf("/by") + BY_OFFSET, line.indexOf("/day")).trim();
+ DateTimeFormatter timeFormat = DateTimeFormatter.ofPattern("HHmm");
+ LocalTime.parse(deadline, timeFormat);
+ DayOfWeek day = DayOfWeek.valueOf(line.substring(line.indexOf("/day") + DAY_OFFSET).trim());
+ if (description.isBlank() || deadline.isBlank()) {
+ throw new IllegalDeadlineException();
+ } else {
+ RecurringDeadline currDeadline = new RecurringDeadline(description, deadline, day);
+ tasks.add(currDeadline);
+ Ui.addedTaskMessage(currDeadline);
+ }
+ }
+
+ /**
+ * Marks a task as done
+ *
+ * @param tasks The array list of tasks
+ * @param words The array of words generated from the user input
+ */
+ static void markTask(ArrayList tasks, String[] words) {
+ int taskNumber = Integer.parseInt(words[1]);
+ int taskCount = Task.getTaskCount();
+ if (taskNumber > taskCount || taskNumber <= 0) {
+ // Input task number exceeds the number of tasks in the list
+ Ui.exceedTaskNumberMessage(taskNumber);
+ } else {
+ tasks.get(taskNumber - 1).markAsDone();
+ // Printing out marked as done message
+ Ui.borderLine();
+ System.out.println("\t Understood. I've marked this task as done:");
+ System.out.println("\t " + tasks.get(taskNumber - 1));
+ Ui.borderLine();
+ }
+ }
+
+ /**
+ * Marks a task as not done
+ *
+ * @param tasks The array list of tasks
+ * @param words The array of words generated from the user input
+ */
+ static void unmarkTask(ArrayList tasks, String[] words) {
+ int taskNumber = Integer.parseInt(words[1]);
+ int taskCount = Task.getTaskCount();
+ if (taskNumber > taskCount || taskNumber <= 0) {
+ // Input task number exceeds the number of tasks in the list
+ Ui.exceedTaskNumberMessage(taskNumber);
+ } else {
+ tasks.get(taskNumber - 1).markAsNotDone();
+ // Printing out marked as not done message
+ Ui.borderLine();
+ System.out.println("\t Understood. I've marked this task as not done yet:");
+ System.out.println("\t " + tasks.get(taskNumber - 1));
+ Ui.borderLine();
+ }
+ }
+
+ /**
+ * edits the attributes of a specific task
+ * @param tasks The array list of tasks
+ * @param words The array of words generated from the user input
+ */
+ static void editTask(ArrayList tasks, String[] words) throws expiredDateException,
+ startAfterEndException, EmptyDescriptionException {
+ int taskNumber = Integer.parseInt(words[1]);
+ int taskCount = Task.getTaskCount();
+ DateTimeFormatter timeFormat = DateTimeFormatter.ofPattern("HHmm");
+ DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm");
+ if (taskNumber > taskCount || taskNumber <= 0) {
+ Ui.exceedTaskNumberMessage(taskNumber);
+ return;
+ }
+ Task taskToEdit = tasks.get(taskNumber - 1);
+ if (taskToEdit instanceof Todo) {
+ editTodo(taskToEdit);
+ } else if (taskToEdit instanceof Deadline) {
+ editDeadline(words, timeFormat, dateFormat, taskToEdit);
+ } else if (taskToEdit instanceof Event) {
+ editEvent(timeFormat, dateFormat, taskToEdit);
+ }
+ Ui.printEditedTask(taskToEdit);
+ }
+
+ /**
+ * edits an attribute of an event
+ * @param timeFormat time format for event
+ * @param dateFormat date format for event
+ * @param taskToEdit the event to edit
+ * @throws EmptyDescriptionException if the new description is empty
+ * @throws startAfterEndException if the start-end time is incorrect
+ * @throws expiredDateException if the task is expired
+ */
+ private static void editEvent(DateTimeFormatter timeFormat, DateTimeFormatter dateFormat, Task taskToEdit) throws
+ EmptyDescriptionException, startAfterEndException, expiredDateException {
+ Ui.editEventMessage();
+ String editLine = Ui.askForEditMessage().trim();
+ String[] editWords = editLine.split(" ");
+ if (taskToEdit instanceof RecurringEvent) {
+ if (editWords.length > 1 && editWords[0].equals("/description")) {
+ String newDescription = editLine.substring(DESCRIPTION_OFFSET).trim();
+ if (newDescription.isBlank()) {
+ throw new EmptyDescriptionException();
+ }
+ taskToEdit.setDescription(newDescription);
+ } else if (editWords.length > 1 && editWords[0].equals("/from")){
+ String start = editLine.substring(FROM_OFFSET).trim();
+ LocalTime.parse(start, timeFormat);
+ ((RecurringEvent) taskToEdit).setStart(start);
+ } else if (editWords.length > 1 && editWords[0].equals("/to")) {
+ String end = editLine.substring(TO_OFFSET).trim();
+ LocalTime.parse(end, timeFormat);
+ ((RecurringEvent) taskToEdit).setEnd(end);
+ } else if(editWords.length > 1 && editWords[0].equals("/day")) {
+ DayOfWeek day = DayOfWeek.valueOf(editLine.substring(DAY_OFFSET).trim());
+ ((RecurringEvent) taskToEdit).setDay(day);
+ } else {
+ Ui.unknownCommandMessage();
+ }
+ } else {
+ LocalDateTime start = LocalDateTime.parse(((Event) taskToEdit).getStart(), dateFormat);
+ LocalDateTime end = LocalDateTime.parse(((Event) taskToEdit).getEnd(), dateFormat);
+ String newStartString = null;
+ String newEndString = null;
+ LocalDateTime newStart = null;
+ LocalDateTime newEnd = null;
+ if (editWords.length > 1 && editWords[0].equals("/description")) {
+ String newDescription = editLine.substring(DESCRIPTION_OFFSET).trim();
+ if (newDescription.isBlank()) {
+ throw new EmptyDescriptionException();
+ }
+ taskToEdit.setDescription(newDescription);
+ } else if (editWords.length > 1 && editWords[0].equals("/from")){
+ newStartString = editLine.substring(FROM_OFFSET).trim();
+ newStart = LocalDateTime.parse(newStartString, dateFormat);
+ } else if (editWords.length > 1 && editWords[0].equals("/to")) {
+ newEndString = editLine.substring(TO_OFFSET).trim();
+ newEnd= LocalDateTime.parse(newEndString, dateFormat);
+ } else {
+ Ui.unknownCommandMessage();
+ }
+ if (newStart != null) {
+ if (newStart.isAfter(end)) {
+ throw new startAfterEndException();
+ } else if (newStart.isBefore(LocalDateTime.now()) || end.isBefore(LocalDateTime.now())) {
+ throw new expiredDateException();
+ } else {
+ ((Event) taskToEdit).setStart(newStartString);
+ }
+ } else if (newEnd != null) {
+ if (start.isAfter(newEnd)) {
+ throw new startAfterEndException();
+ } else if (start.isBefore(LocalDateTime.now()) || newEnd.isBefore(LocalDateTime.now())) {
+ throw new expiredDateException();
+ } else {
+ ((Event) taskToEdit).setEnd(newEndString);
+ }
+ }
+ }
+ }
+
+ /**
+ * edits an attribute of a stored deadline
+ *
+ * @param words input split into an array of string
+ * @param timeFormat time format for deadline
+ * @param dateFormat date format for deadline
+ * @param taskToEdit the task to edit
+ * @throws EmptyDescriptionException if the new description is empty
+ * @throws expiredDateException if the deadline has expired
+ */
+ private static void editDeadline(String[] words, DateTimeFormatter timeFormat, DateTimeFormatter dateFormat,
+ Task taskToEdit) throws EmptyDescriptionException, expiredDateException {
+ Ui.editDeadlineMessage();
+ String editLine = Ui.askForEditMessage().trim();
+ String[] editWords = editLine.split(" ");
+ if (taskToEdit instanceof RecurringDeadline) {
+ if (editWords.length > 1 && editWords[0].equals("/description")) {
+ String newDescription = editLine.substring(12).trim();
+ if (newDescription.isBlank()) {
+ throw new EmptyDescriptionException();
+ }
+ taskToEdit.setDescription(newDescription);
+ } else if (editWords.length > 1 && editWords[0].equals("/deadline")){
+ String deadline = editLine.substring(DEADLINE_OFFSET).trim();
+ LocalTime.parse(deadline, timeFormat);
+ ((RecurringDeadline) taskToEdit).setDeadline(deadline);
+ } else if (editWords.length > 1 && editWords[0].equals("/day")) {
+ DayOfWeek day = DayOfWeek.valueOf(editLine.substring(DAY_OFFSET).trim());
+ ((RecurringDeadline) taskToEdit).setDay(day);
+ } else {
+ Ui.unknownCommandMessage();
+ }
+ } else {
+ if (editWords.length > 1 && editWords[0].equals("/description")) {
+ String newDescription = editLine.substring(editLine.indexOf(words[1]));
+ if (newDescription.isBlank()) {
+ throw new EmptyDescriptionException();
+ }
+ taskToEdit.setDescription(newDescription);
+ } else if (editWords.length > 1 && editWords[0].equals("/deadline")) {
+ String deadlineString = editLine.substring(DEADLINE_OFFSET).trim();
+ System.out.println(deadlineString);
+ LocalDateTime deadline = LocalDateTime.parse(deadlineString, dateFormat);
+ if (deadline.isBefore(LocalDateTime.now())){
+ throw new expiredDateException();
+ } else {
+ ((Deadline) taskToEdit).setDeadline(deadlineString);
+ }
+ } else {
+ Ui.unknownCommandMessage();
+ }
+ }
+ }
+
+ /**
+ * edits the todd
+ * @param taskToEdit the todo to edit
+ * @throws EmptyDescriptionException empty description
+ */
+ private static void editTodo(Task taskToEdit) throws EmptyDescriptionException {
+ Ui.editTodoMessage();
+ String editLine = Ui.askForEditMessage().trim();
+ if (editLine.isBlank()) {
+ throw new EmptyDescriptionException();
+ }
+ taskToEdit.setDescription(editLine);
+ }
+
+ /**
+ * tries editTask and handles exceptions
+ *
+ * @param tasks The array list of tasks
+ * @param words The array of words generated from the user input
+ */
+ static void tryEditTask(ArrayList tasks, String[] words) {
+ try {
+ editTask(tasks, words);
+ } catch (DateTimeParseException e) {
+ Ui.invalidDateTimeMessage();
+ } catch (IllegalArgumentException e) {
+ Ui.invalidDayMessage();
+ } catch (expiredDateException e) {
+ Ui.expiredErrorMessage();
+ } catch (startAfterEndException e) {
+ Ui.startAfterEndErrorMessage();
+ } catch (EmptyDescriptionException e) {
+ Ui.emptyDescriptionErrorMessage();
+ }
+ }
+
+ /**
+ * Deletes a task from the list
+ *
+ * @param tasks The array list of tasks
+ * @param words The array of words generated from the user input
+ */
+ static void deleteTask(ArrayList tasks, String[] words) {
+ int taskNumber = Integer.parseInt(words[1]);
+ int taskCount = Task.getTaskCount();
+ if (taskNumber > taskCount || taskNumber <= 0) {
+ // Input task number exceeds the number of tasks in the list
+ Ui.exceedTaskNumberMessage(taskNumber);
+ } else {
+ Task taskToDelete = tasks.get(taskNumber - 1);
+ tasks.remove(taskNumber - 1);
+ Task.decrementCount();
+ Ui.deleteTaskMessage(taskToDelete);
+ }
+ }
+
+ /**
+ * Deletes a SchoolClass from the priority queue
+ *
+ * @param classes The priority queue of SchoolClasses
+ * @param line The line of user input
+ * @throws IllegalArgumentException handle IllegalArgumentException
+ * @throws NullPointerException handle NullPointerException
+ * @throws StringIndexOutOfBoundsException handle StringIndexOutOfBoundsException
+ */
+ static void deleteClass(PriorityQueue classes, String line) throws
+ IllegalArgumentException, NullPointerException, StringIndexOutOfBoundsException{
+ try {
+ // Buffer holds the string "remove class" and is redundant
+ String buffer = line.substring(0, line.indexOf("/class")).trim();
+ String className = line.substring(line.indexOf("/class") + 6, line.indexOf("/description")).trim();
+ String description = line.substring(line.indexOf("/description") + 12, line.indexOf("/day")).trim();
+ DayOfWeek day = DayOfWeek.valueOf(line.substring(line.indexOf("/day") + 4, line.indexOf("/from")).trim());
+ String startString = line.substring(line.indexOf("/from") + 5, line.indexOf("/to")).trim();
+ String endString = line.substring(line.indexOf("/to") + 3).trim();
+ SchoolClass toDelete = new SchoolClass(className, description, day, startString, endString);
+ if (classes.remove(toDelete)) {
+ Ui.deleteClassMessage();
+ } else {
+ Ui.unsuccessfulDeleteClassMessage();
+ }
+ } catch (IllegalArgumentException e) {
+ Ui.invalidDayMessage();
+ } catch (NullPointerException e) {
+ Ui.emptyDayErrorMessage();
+ } catch (StringIndexOutOfBoundsException e) {
+ Ui.invalidRemoveClassMessage();
+ }
+ }
+
+ /**
+ * Tries to delete a SchoolClass from the priority queue, and throws an error message
+ * if unsuccessful. This method should be used instead of directly invoking
+ * the deleteClass() method.
+ *
+ * @param classes The priority queue of SchoolClasses
+ * @param line The line of user input
+ */
+ static void tryDeleteClass(PriorityQueue classes, String line) {
+ if (!line.contains("/class") || !line.contains("/description") || !line.contains("/day") ||
+ !line.contains("/from") || !line.contains("/to")) {
+ Ui.invalidRemoveClassMessage();
+ } else {
+ deleteClass(classes, line);
+ }
+ }
+
+ /**
+ * Checks if the current day and time is past the day and end time of the SchoolClass.
+ * If SchoolClass is over, mark as done, otherwise mark as not done.
+ *
+ * @param day The enum for the day of week registered in the current SchoolClass to check
+ * @param endString The end timing for the current SchoolClass to check
+ * @param currSchoolClass The current SchoolClass
+ */
+ static void checkClassOver(DayOfWeek day, String endString, SchoolClass currSchoolClass) {
+ LocalDate today = LocalDate.now();
+ DayOfWeek dayToday = today.getDayOfWeek();
+ if (dayToday.getValue() > day.getValue()) { // day of week passed
+ currSchoolClass.markAsDone();
+ } else if (dayToday.getValue() < day.getValue()) { // day of week not passed
+ currSchoolClass.markAsNotDone();
+ } else { // same day of week
+ DateTimeFormatter timeFormat = DateTimeFormatter.ofPattern("HHmm");
+ LocalTime classEndTime = LocalTime.parse(endString, timeFormat);
+ LocalTime currTime = LocalTime.now();
+ if (currTime.isAfter(classEndTime)) {
+ currSchoolClass.markAsDone();
+ } else {
+ currSchoolClass.markAsNotDone();
+ }
+ }
+ }
+
+ /**
+ * Clears the task list and SchoolClass priority queue, and reloads from save file.
+ * This function is mainly used to update the done status of SchoolClasses in the schedule.
+ *
+ * @param tasks The ArrayList of tasks
+ * @param classes The priority queue of SchoolClasses
+ */
+ static void refresh(ArrayList tasks, PriorityQueue classes) {
+ tasks.clear();
+ Task.clearCount();
+ classes.clear();
+ Storage.tryLoad(tasks, classes);
+ }
+
+ static void purge(ArrayList tasks, PriorityQueue classes) {
+ Ui.borderLine();
+ System.out.println("\t Displaying all expired tasks below...");
+ System.out.println();
+ if (tasks.size() > 0) {
+ int expiredCount = 0;
+ ArrayList expiredTasks = new ArrayList<>();
+ for (Task task : tasks) {
+ if (task instanceof Deadline && !(task instanceof RecurringDeadline)) {
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HHmm");
+ String deadline = ((Deadline) task).getDeadline();
+ Date d = null;
+ Date n = new Date();
+ try {
+ d = format.parse(deadline);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ assert d != null;
+ long diff = d.getTime() - n.getTime();
+ if (diff < 0) {
+ expiredCount++;
+ System.out.println(task);
+ expiredTasks.add(task);
+ }
+ } else if (task instanceof Event && !(task instanceof RecurringEvent)) {
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HHmm");
+ String end = ((Event) task).getEnd();
+ Date d = null;
+ Date n = new Date();
+ try {
+ d = format.parse(end);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ assert d != null;
+ long diff = d.getTime() - n.getTime();
+ if (diff < 0) {
+ expiredCount++;
+ System.out.println(task);
+ expiredTasks.add(task);
+ }
+ } else if (task instanceof SchoolClass) {
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HHmm");
+ String end = ((SchoolClass) task).getEnd();
+ Date d = null;
+ Date n = new Date();
+ try {
+ d = format.parse(end);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ assert d != null;
+ long diff = d.getTime() - n.getTime();
+ if (diff < 0) {
+ expiredCount++;
+ System.out.println(task);
+ expiredTasks.add(task);
+ }
+ }
+ }
+ if (expiredCount > 0) {
+ Ui.borderLine();
+ System.out.println("\t Quack! A total of " + expiredCount + " tasks have expired!");
+ System.out.println("\t Should I remove these tasks from the pending list human?");
+ Ui.borderLine();
+ if (Ui.doubleCheck()) {
+ for (Task expiredTask : expiredTasks) {
+ tasks.removeIf(task -> task == expiredTask);
+ Task.decrementCount();
+ }
+ Storage.trySave(tasks, classes);
+ Ui.borderLine();
+ System.out.println("\t Expired Tasks have been purged from the list!");
+ System.out.println("\t I love purging things, human...");
+ Ui.borderLine();
+ } else {
+ Ui.borderLine();
+ System.out.println("\t Quack! Expired tasks have not been purged.");
+ Ui.borderLine();
+ }
+ } else {
+ System.out.println("\t Quack! No tasks have expired!");
+ Ui.borderLine();
+ }
+ } else {
+ System.out.println("\t Quack! No tasks currently pending!");
+ Ui.borderLine();
+ }
+ }
+
+ /**
+ * Takes in the task number and adds a note to the list of notes under that task
+ *
+ * @param tasks The arraylist of tasks
+ * @param words The array of strings from user input
+ */
+ static void addNote(ArrayList tasks, String[] words){
+ int index = Integer.parseInt(words[1]);
+ if (index-1 < tasks.size() && index >= 1) {
+ System.out.println("\t What note would you like to add to the following task?");
+ System.out.println(tasks.get(index - 1).toString());
+ Ui.borderLine();
+ Scanner userInput = new Scanner(System.in);
+ String noteToAdd = userInput.nextLine();
+ tasks.get(index - 1).addNotes(noteToAdd);
+ System.out.println("\t The note has been added!");
+ Ui.borderLine();
+ } else {
+ Ui.exceedTaskNumberMessage(index);
+ }
+ }
+
+ /**
+ * Takes in the task number and index of the note to be deleted and then deletes it
+ *
+ * @param tasks The arraylist of tasks
+ * @param words The array of strings from user input
+ */
+ static void deleteNotes(ArrayList tasks, String[] words) {
+ int index = Integer.parseInt(words[1]);
+ int indexOfNoteToBeDeleted = Integer.parseInt(words[2]);
+ if (index-1 < tasks.size() && index >= 1) {
+ if (indexOfNoteToBeDeleted-1 < tasks.get(index-1).numberOfNotes() && indexOfNoteToBeDeleted >= 1) {
+ Ui.borderLine();
+ System.out.println("\t Deleting note: ");
+ ArrayList noteToBeDeleted = tasks.get(index - 1).getAdditionalNotes();
+ System.out.println("\t \t" + noteToBeDeleted.get(indexOfNoteToBeDeleted - 1));
+ tasks.get(index - 1).deleteNote(indexOfNoteToBeDeleted);
+ Ui.borderLine();
+ } else {
+ Ui.exceedNoteNumberMessage(indexOfNoteToBeDeleted);
+ }
+ } else {
+ Ui.exceedTaskNumberMessage(index);
+ }
+ }
+
+ /**
+ * Takes in the task number and index of the note to be edited and then changes it
+ *
+ * @param tasks The arraylist of tasks
+ * @param words The array of strings from user input
+ */
+ static void editNote(ArrayList tasks, String[] words) {
+ int index = Integer.parseInt(words[1]);
+ int indexOfNoteToBeEdited = Integer.parseInt(words[2]);
+ Scanner userInput = new Scanner(System.in);
+ if (index-1 < tasks.size() && index >= 1) {
+ if (indexOfNoteToBeEdited-1 < tasks.get(index-1).numberOfNotes() && indexOfNoteToBeEdited >= 1) {
+ Ui.borderLine();
+ System.out.println("\t What would you like to change the note to? ");
+ System.out.println("\t" + "\t" + tasks.get(index - 1).getNote(indexOfNoteToBeEdited - 1));
+ String editedNote = userInput.nextLine();
+ tasks.get(index - 1).editNote(indexOfNoteToBeEdited - 1, editedNote);
+ System.out.println("\t" + "The specified note has been edited!");
+ Ui.borderLine();
+ } else {
+ Ui.exceedNoteNumberMessage(indexOfNoteToBeEdited);
+ }
+ } else {
+ Ui.exceedTaskNumberMessage(index);
+ }
+ }
+}
diff --git a/src/main/java/seedu/duck/Ui.java b/src/main/java/seedu/duck/Ui.java
new file mode 100644
index 0000000000..2fa76b88eb
--- /dev/null
+++ b/src/main/java/seedu/duck/Ui.java
@@ -0,0 +1,997 @@
+package seedu.duck;
+
+import seedu.duck.task.Deadline;
+import seedu.duck.task.Event;
+import seedu.duck.task.RecurringDeadline;
+import seedu.duck.task.RecurringEvent;
+import seedu.duck.task.SchoolClass;
+import seedu.duck.task.Task;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.PriorityQueue;
+import java.util.Random;
+import java.util.Scanner;
+
+
+/**
+ * Deals with interactions with the user
+ */
+public class Ui {
+ static void printDuck() {
+ System.out.println(" ,-.\n" +
+ " ,--' ~.).\n" +
+ " ,' `.\n" +
+ " ; (((__ __)))\n" +
+ " ; ( (#) ( (#)\n" +
+ " | \\_/___\\_/\n" +
+ " ,\" ,-' `__\".\n" +
+ " ( ( ._ ____`.)--._ _\n" +
+ " `._ `-.`-' \\(`-' _ `-. _,-' `-/`.\n" +
+ " ,') `.`._)) ,' `. `. ,',' ;\n" +
+ " .' . `--' / ). `. ;\n" +
+ " ; `- / ' ) ;\n" +
+ " \\ ') ,'\n" +
+ " \\ ,' ;\n" +
+ " \\ `~~~' ,'\n" +
+ " `. _,'\n" +
+ " `-._________,--'");
+ }
+
+ /**
+ * Prints a random motivational quote
+ */
+ static void printMotivationalQuote() {
+ String[] quotes = {
+ "Believe you can and you're halfway there. -Theodore Roosevelt",
+ "Start where you are. Use what you have. Do what you can. -Arthur Ashe",
+ "You miss 100% of the shots you don't take. -Wayne Gretzky",
+ "Success is not final, failure is not fatal: it is the courage to continue that counts. -Winston Churchill",
+ "You are never too old to set another goal or to dream a new dream. -C.S. Lewis",
+ "Believe in yourself and all that you are. Know that there is something \n\t " +
+ "inside you that is greater than any obstacle. -Christian D. Larson",
+ "Success is not how high you have climbed, but how you make a positive difference to the world. -Roy T. Bennett",
+ "A journey of a thousand miles begins with a single step. -Lao Tzu",
+ "The only way to do great work is to love what you do. -Steve Jobs",
+ "You have brains in your head. You have feet in your shoes. You can steer yourself any direction you choose. -Dr. Seuss",
+ "Believe you can and you're halfway there. -Theodore Roosevelt",
+ "You never know how strong you are until being strong is your only choice. -Bob Marley",
+ "Do not wait for opportunities, create them. -Roy T. Bennett",
+ "Believe in yourself, take on your challenges, dig deep within yourself to conquer fears. \n\t " +
+ "Never let anyone bring you down. You got this. -Chantal Sutherland",
+ "The greatest glory in living lies not in never falling, but in rising every time we fall. -Nelson Mandela",
+ "Believe in your infinite potential. Your only limitations are those you set upon yourself. -Roy T. Bennett",
+ "What you get by achieving your goals is not as important as what you become by achieving your goals. -Zig Ziglar",
+ "Don't watch the clock; do what it does. Keep going. -Sam Levenson",
+ "Believe that you will succeed, and you will. -Dale Carnegie",
+ "Success is not the key to happiness. Happiness is the key to success.\n\t" +
+ " If you love what you are doing, you will be successful. -Albert Schweitzer"
+ };
+ Random rand = new Random();
+ int index = rand.nextInt(quotes.length);
+ System.out.println("\t Have some motivation! Quack!" + "\n");
+ System.out.println("\t " + quotes[index]);
+ }
+
+ /**
+ * Prints out all currently stored tasks in the list
+ *
+ * @param tasks The array list of tasks
+ */
+ static void list(ArrayList tasks) {
+ int taskCount = Task.getTaskCount();
+ borderLine();
+ if(!tasks.isEmpty()) {
+ System.out.println("\t Here are the tasks in your list:");
+ for (int i = 0; i < taskCount; i++) {
+ System.out.println("\t " + (i + 1) + "." + tasks.get(i));
+ if (!tasks.get(i).getAdditionalNotes().isEmpty()) {
+ printList(tasks, i);
+ }
+ }
+ } else {
+ System.out.println("\t There are no tasks in the list currently!");
+ }
+ borderLine();
+ }
+
+ static void listClasses(PriorityQueue classes, ArrayList tasks) {
+ TaskList.refresh(tasks, classes);
+ Iterator iterator = classes.iterator();
+ borderLine();
+ System.out.println("\t Here is your class schedule:\n");
+ while (iterator.hasNext()) {
+ System.out.println("\t" + iterator.next());
+ }
+ borderLine();
+ }
+
+ /**
+ * prints out all classes, deadlines and events happening today
+ *
+ * @param tasks array list of all tasks
+ * @param classes pq of all classes
+ */
+ static void listToday(ArrayList tasks, PriorityQueue classes) {
+ LocalDate today = LocalDate.now();
+ DayOfWeek dayToday = today.getDayOfWeek();
+ borderLine();
+ System.out.println("\t Here is your class schedule for today");
+ for (SchoolClass c : classes) {
+ if (c.getDay() == dayToday) {
+ System.out.println(c);
+ }
+ }
+ System.out.println();
+ DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+ String dateToday = dateFormat.format(today);
+ System.out.println("\t Here are your tasks today");
+ for (Task task : tasks) {
+ if (task instanceof Deadline) {
+ listTodayDeadline(dayToday, dateToday, task);
+ } else if (task instanceof Event) {
+ listTodayEvent(dayToday, dateToday, task);
+ }
+ }
+ borderLine();
+ }
+
+ /**
+ * checks if an event happens today and prints the task if yes
+ *
+ * @param dayToday the DayOfWeek today
+ * @param dateToday the date today
+ * @param task the task (event specifically) to be checked
+ */
+ private static void listTodayEvent(DayOfWeek dayToday, String dateToday, Task task) {
+ if (task instanceof RecurringEvent) {
+ if (((RecurringEvent) task).getDay() == dayToday) {
+ System.out.println(task);
+ }
+ } else {
+ if (((Event) task).getStart().startsWith(dateToday)) {
+ System.out.println(task);
+ }
+ }
+ }
+
+ /**
+ * checks if a deadline happens today and prints the task if yes
+ *
+ * @param dayToday the DayOfWeek today
+ * @param dateToday the date today
+ * @param task the task (deadline specifically) to be checked
+ */
+ private static void listTodayDeadline(DayOfWeek dayToday, String dateToday, Task task) {
+ if (task instanceof RecurringDeadline) {
+ if (((RecurringDeadline) task).getDay() == dayToday) {
+ System.out.println(task);
+ }
+ } else {
+ if (((Deadline) task).getDeadline().startsWith(dateToday)) {
+ System.out.println(task);
+ }
+ }
+ }
+
+ /**
+ * Prints out all currently stored tasks in the list arranged by their priority from high, medium to low
+ *
+ * @param tasks the list of tasks
+ */
+ static void printPriorityList(ArrayList tasks) {
+ borderLine();
+ System.out.println("\t Here are the tasks in your list arranged by priority:");
+ borderLine();
+ printHighPriority(tasks);
+ printMediumPriority(tasks);
+ printLowPriority(tasks);
+ }
+
+ /**
+ * Goes through the task list and prints out the tasks that are high in priority
+ *
+ * @param tasks the list of tasks
+ */
+ static void printHighPriority(ArrayList tasks) {
+ ArrayList indexOfHighPriority = new ArrayList<>();
+ int taskCount = Task.getTaskCount();
+ for (int i = 0; i < taskCount; i++) {
+ if (tasks.get(i).returnPriority() == 3) {
+ indexOfHighPriority.add(i);
+ }
+ }
+ if (!indexOfHighPriority.isEmpty()) {
+ System.out.println("\t QUACK QUACK QUACK!!!");
+ System.out.println("\t You have " + indexOfHighPriority.size() + " tasks that are high in priority!");
+ for (int i = 0; i < indexOfHighPriority.size(); i++) {
+ System.out.println("\t" + (i + 1) + "." + tasks.get(indexOfHighPriority.get(i)));
+ if (!tasks.get(i).getAdditionalNotes().isEmpty()) {
+ ArrayList toBePrinted = tasks.get(i).getAdditionalNotes();
+ for (int j = 0; j < toBePrinted.size(); j++) {
+ System.out.println("\t" + "\t - " + (j + 1) + ". " + toBePrinted.get(j));
+ }
+ }
+ }
+ } else {
+ System.out.println("\t There are no tasks that are high in priority!");
+ }
+ borderLine();
+ }
+
+ /**
+ * Goes through the task list and prints out the tasks that are medium in priority
+ *
+ * @param tasks the list of tasks
+ */
+ static void printMediumPriority(ArrayList tasks) {
+ ArrayList indexOfMediumPriority = new ArrayList<>();
+ int taskCount = Task.getTaskCount();
+ for (int i = 0; i < taskCount; i++) {
+ if (tasks.get(i).returnPriority() == 2) {
+ indexOfMediumPriority.add(i);
+ }
+ }
+ if (!indexOfMediumPriority.isEmpty()) {
+ System.out.println("\t QUACK QUACK!!");
+ System.out.println("\t You have " + indexOfMediumPriority.size() + " tasks that are medium in priority!");
+ for (int i = 0; i < indexOfMediumPriority.size(); i++) {
+ System.out.println("\t" + (i + 1) + "." + tasks.get(indexOfMediumPriority.get(i)));
+ if (!tasks.get(i).getAdditionalNotes().isEmpty()) {
+ ArrayList toBePrinted = tasks.get(i).getAdditionalNotes();
+ for (int j = 0; j < toBePrinted.size(); j++) {
+ System.out.println("\t" + "\t - " + (j + 1) + ". " + toBePrinted.get(j));
+ }
+ }
+ }
+ } else {
+ System.out.println("\t There are no tasks that are medium in priority!");
+ }
+ borderLine();
+ }
+
+ /**
+ * Goes through the task list and prints out the tasks that are low in priority
+ *
+ * @param tasks the list of tasks
+ */
+ static void printLowPriority(ArrayList tasks) {
+ ArrayList indexOfLowPriority = new ArrayList<>();
+ int taskCount = Task.getTaskCount();
+ for (int i = 0; i < taskCount; i++) {
+ if (tasks.get(i).returnPriority() == 1) {
+ indexOfLowPriority.add(i);
+ }
+ }
+ if (!indexOfLowPriority.isEmpty()) {
+ System.out.println("\t Quack!");
+ System.out.println("\t You have " + indexOfLowPriority.size() + " tasks that are low in priority!");
+ for (int i = 0; i < indexOfLowPriority.size(); i++) {
+ System.out.println("\t" + (i + 1) + "." + tasks.get(indexOfLowPriority.get(i)));
+ if (!tasks.get(i).getAdditionalNotes().isEmpty()) {
+ ArrayList toBePrinted = tasks.get(i).getAdditionalNotes();
+ for (int j = 0; j < toBePrinted.size(); j++) {
+ System.out.println("\t" + "\t - " + (j + 1) + ". " + toBePrinted.get(j));
+ }
+ }
+ }
+ } else {
+ System.out.println("\t There are no tasks that are low in priority!");
+ }
+ borderLine();
+ }
+
+ /**
+ * Finds tasks in the list that contain keywords input by the user
+ *
+ * @param tasks The array list of tasks
+ * @param words The array of words generated from the user input
+ */
+ static void find(ArrayList tasks, String[] words) {
+ ArrayList matchingResults = new ArrayList<>();
+ ArrayList matchingResultsIndex = new ArrayList<>();
+ int matchCount = 0;
+ String keyword = Parser.processKeywords(words, 1);
+
+ for (int i = 0; i < tasks.size(); i++) {
+ if (tasks.get(i).getDescription().contains(keyword)) {
+ matchingResults.add(tasks.get(i));
+ matchingResultsIndex.add(i + 1);
+ matchCount++;
+ }
+ }
+ printFindResults(matchingResults, matchCount, matchingResultsIndex);
+ }
+
+
+ /**
+ * Prints the results of the find command
+ *
+ * @param matchingResults The array list of tasks that contain the keywords
+ * @param matchCount The number of tasks in the list that contain the keywords
+ */
+ private static void printFindResults(ArrayList matchingResults, int matchCount,
+ ArrayList matchingResultsIndex) {
+ if (matchingResults.isEmpty()) {
+ noMatchMessage();
+ } else {
+ printMatchingList(matchingResults, matchCount, matchingResultsIndex);
+ }
+ }
+
+ /**
+ * Prints the list of tasks that contain the keywords
+ *
+ * @param matchingResults The array list of tasks that contain the keywords
+ * @param matchCount The number of tasks in the list that contain the keywords
+ * @param matchingResultsIndex The index of the task in the main list
+ */
+ static void printMatchingList(ArrayList matchingResults, int matchCount,
+ ArrayList matchingResultsIndex) {
+ borderLine();
+ System.out.println("\t Here are the matching tasks in your list:");
+ for (int i = 0; i < matchCount; i++) {
+ System.out.println("\t " + (i + 1) + "." + matchingResults.get(i) +
+ " || The index of this item is " + matchingResultsIndex.get(i));
+ }
+ borderLine();
+ }
+
+ /**
+ * Display upcoming deadline
+ *
+ * @param tasks tasks store in the file
+ */
+ static void displayUpcomingDeadline(ArrayList tasks) {
+ System.out.println("\t Here are the upcoming deadlines: ");
+ int count = 0;
+ for (Task t : tasks) {
+ if (t instanceof Deadline && !(t instanceof RecurringDeadline)) {
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HHmm");
+ String deadline = ((Deadline) t).getDeadline();
+ Date d;
+ Date n = new Date();
+ try {
+ d = format.parse(deadline);
+ long diff = d.getTime() - n.getTime();
+ String di = getTimeDiff(diff);
+ String description = t.getDescription().replace("Deadlines", "");
+ System.out.println("\t " + (count + 1) + "." + description + " (" + di + "before the deadline)");
+ count++;
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ borderLine();
+ }
+
+ /**
+ * Display upcoming event
+ *
+ * @param tasks tasks store in the file
+ */
+ static void displayUpcomingEvent(ArrayList tasks) {
+ System.out.println("\t Here are the upcoming events: ");
+ int count = 0;
+ for (Task t : tasks) {
+ if (t instanceof Event && !(t instanceof RecurringEvent)) {
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HHmm");
+ String deadline = ((Event) t).getStart();
+ Date d;
+ Date n = new Date();
+ try {
+ d = format.parse(deadline);
+ long diff = d.getTime() - n.getTime();
+ String di = getTimeDiff(diff);
+ String description = t.getDescription().replace("Events", "");
+ System.out.println("\t " + (count + 1) + "." + description + " (" + di + "before the event start)");
+ count++;
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ borderLine();
+ }
+
+ /**
+ * Prints the list of tasks in x days in the future
+ *
+ * @param tasks the array list of all the tasks
+ * @param days the required the number of days x from now onwards
+ */
+ static void printUpcomingTasks(ArrayList tasks, String days) {
+ borderLine();
+ System.out.println("\t Here are your tasks in " + days + " days:");
+ int count = 0;
+ Date d;
+ Date n = new Date();
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HHmm");
+ int requiredDays = Integer.parseInt(days);
+ for (Task t : tasks) {
+ String timeUntilTask = null;
+ if (t instanceof Deadline && !(t instanceof RecurringDeadline)) {
+ timeUntilTask = ((Deadline) t).getDeadline();
+ } else if (t instanceof Event && !(t instanceof RecurringEvent)) {
+ timeUntilTask = ((Event) t).getStart();
+ }
+ if (timeUntilTask != null) {
+ try {
+ d = format.parse(timeUntilTask);
+ long diff = d.getTime() - n.getTime();
+ int di = getDayDiff(diff);
+ if (di <= requiredDays) {
+ count++;
+ System.out.println("\t " + count + "." + t);
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ borderLine();
+ }
+
+ /**
+ * Prints the list of events in x days in the future
+ *
+ * @param tasks the array list of all the tasks
+ * @param days the required the number of days x from now onwards
+ */
+ static void printUpcomingEvents(ArrayList tasks, String days) {
+ borderLine();
+ System.out.println("\t Here are your events in " + days + " days:");
+ int count = 0;
+ Date d;
+ Date n = new Date();
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HHmm");
+ boolean noEvent = true;
+ for (Task t : tasks) {
+ String timeUntilTask;
+ if (t instanceof Event && !(t instanceof RecurringEvent)) {
+ noEvent = false;
+ timeUntilTask = ((Event) t).getStart();
+ try {
+ d = format.parse(timeUntilTask);
+ long diff = d.getTime() - n.getTime();
+ String di = getTimeDiff(diff);
+ String[] diffSplit = di.split(" ");
+ if (diffSplit.length >= 2 && ((diffSplit[1].contains("day") && Integer.parseInt(diffSplit[0])
+ <= Integer.parseInt(days)) || diffSplit[1].contains("hour")
+ || diffSplit[1].contains("minute"))) {
+ count++;
+ System.out.println("\t " + count + "." + t);
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ if (noEvent) {
+ System.out.println("\t No Upcoming Events!");
+ }
+ borderLine();
+ }
+
+ /**
+ * Prints the list of deadlines in x days in the future
+ *
+ * @param tasks the array list of all the tasks
+ * @param days the required the number of days x from now onwards
+ */
+ static void printUpcomingDeadline(ArrayList tasks, String days) {
+ borderLine();
+ System.out.println("\t Here are your deadlines in " + days + " days:");
+ int count = 0;
+ Date d;
+ Date n = new Date();
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HHmm");
+ boolean noDeadline = true;
+ for (Task t : tasks) {
+ String timeUntilTask;
+ if (t instanceof Deadline && !(t instanceof RecurringDeadline)) {
+ noDeadline = false;
+ timeUntilTask = ((Deadline) t).getDeadline();
+ try {
+ d = format.parse(timeUntilTask);
+ long diff = d.getTime() - n.getTime();
+ String di = getTimeDiff(diff);
+ String[] diffSplit = di.split(" ");
+ if (diffSplit.length >= 2 && ((diffSplit[1].contains("day") && Integer.parseInt(diffSplit[0])
+ <= Integer.parseInt(days)) || diffSplit[1].contains("hour")
+ || diffSplit[1].contains("minute"))) {
+ count++;
+ System.out.println("\t " + count + "." + t);
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ if (noDeadline) {
+ System.out.println("\t No Upcoming Deadline!");
+ }
+ borderLine();
+ }
+
+ /**
+ * gets the day difference
+ * @param timeDifferenceMilliseconds time difference between now and the input time
+ * @return day difference
+ */
+ static int getDayDiff(long timeDifferenceMilliseconds) {
+ return (int) (timeDifferenceMilliseconds / (secondsPerMinute * minutesPerHour * 1000 * hoursPerDay));
+ }
+
+ static final int secondsPerMinute = 60;
+ static final int minutesPerHour = 60;
+ static final int hoursPerDay = 24;
+ static final double daysPerMonth = 30.41666666;
+ static final int monthsPerYear = 12;
+
+ /**
+ * Function help for calculating time difference
+ *
+ * @param timeDifferenceMilliseconds time difference between now and deadline
+ * @return time difference in structured format
+ */
+ static String getTimeDiff(long timeDifferenceMilliseconds) {
+ long diffMinutes = timeDifferenceMilliseconds / (secondsPerMinute * 1000) % minutesPerHour;
+ long diffHours = timeDifferenceMilliseconds / (secondsPerMinute * minutesPerHour * 1000) % hoursPerDay;
+ long diffDays = (long) (timeDifferenceMilliseconds / (secondsPerMinute * minutesPerHour * 1000 * hoursPerDay) % daysPerMonth);
+ long diffMonths = (long) (timeDifferenceMilliseconds / (secondsPerMinute * minutesPerHour * 1000 * hoursPerDay * daysPerMonth)) % monthsPerYear;
+ long diffYears = (long) (timeDifferenceMilliseconds / ( secondsPerMinute * minutesPerHour * 1000 * hoursPerDay * daysPerMonth * monthsPerYear));
+ String result = "";
+ if (diffYears != 0) {
+ result += diffYears;
+ result += " year";
+ if (diffYears != 1) {
+ result += "s";
+ }
+ result += " ";
+ }
+ if (diffMonths != 0) {
+ result += diffMonths;
+ result += " month";
+ if (diffMonths != 1) {
+ result += "s";
+ }
+ result += " ";
+ }
+ if (diffDays != 0) {
+ result += diffDays;
+ result += " day";
+ if (diffDays != 1) {
+ result += "s";
+ }
+ result += " ";
+ }
+ if (diffHours != 0) {
+ result += diffHours;
+ result += " hour";
+ if (diffHours != 1) {
+ result += "s";
+ }
+ result += " ";
+ }
+ if (diffMinutes != 0) {
+ result += diffMinutes;
+ result += " minute";
+ if (diffMinutes != 1) {
+ result += "s";
+ }
+ result += " ";
+ }
+ return result;
+ }
+
+ /**
+ * Display Next Upcoming Class
+ *
+ * @param classes the priority queue of all the classes
+ */
+ static void displayNextUpcomingClass(PriorityQueue classes) {
+ borderLine();
+ ArrayList result = new ArrayList<>(classes);
+ System.out.println("\t Here are your next upcoming class: ");
+ if (result.isEmpty()) {
+ System.out.println("\t No upcoming class!");
+ } else {
+ for (SchoolClass c : result) {
+ if (c.getStatusIcon() != "X") {
+ System.out.println("\t" + c);
+ }
+ }
+ }
+ borderLine();
+ }
+
+ /**
+ * Display Next Upcoming Event
+ *
+ * @param tasks the array list of all the tasks
+ */
+ static void displayNextUpcomingEvent(ArrayList tasks) {
+ borderLine();
+ System.out.println("\t Here are your next upcoming event: ");
+ for (int i = 0; i < tasks.size(); i++) {
+ if (tasks.get(i) instanceof Event && tasks.get(i).getStatusIcon() != "X") {
+ System.out.println("\t " + tasks.get(i));
+ break;
+ } else if (i == tasks.size() - 1) {
+ System.out.println("\t No upcoming event!");
+ }
+ }
+ borderLine();
+ }
+
+ /**
+ * Display Next Upcoming Deadline
+ *
+ * @param tasks the array list of all the tasks
+ */
+ static void displayNextUpcomingDeadline(ArrayList tasks) {
+ borderLine();
+ System.out.println("\t Here are your next upcoming event: ");
+ for (int i = 0; i < tasks.size(); i++) {
+ if (tasks.get(i) instanceof Deadline && tasks.get(i).getStatusIcon() != "X") {
+ System.out.println("\t" + tasks.get(i));
+ break;
+ } else if (i == tasks.size() - 1) {
+ System.out.println("\t No upcoming deadline!");
+ }
+ }
+ borderLine();
+ }
+
+ /**
+ * Display Next Upcoming Task
+ *
+ * @param tasks the array list of all the tasks
+ */
+ static void displayNextUpcomingTask(ArrayList tasks) {
+ borderLine();
+ System.out.println("\t Here are your next upcoming event: ");
+ if (tasks.isEmpty()) {
+ System.out.println("\t no upcoming task");
+ } else {
+ System.out.println("\t" + tasks.get(0));
+ }
+ borderLine();
+ }
+
+ /**
+ * Prints the border for opening or closing messages
+ */
+ static void borderLine() {
+ System.out.println("\t____________________________________________________________");
+ }
+
+ private static void noMatchMessage() {
+ borderLine();
+ System.out.println("\t There are no matching tasks in your list.");
+ borderLine();
+ }
+
+ static void emptyCommandMessage() {
+ borderLine();
+ System.out.println("\t Please enter a non-empty command.");
+ borderLine();
+ }
+
+ static boolean doubleCheck() {
+ System.out.println("\t THIS IS AN IRREVERSIBLE PROCESS. ARE YOU SURE? Y/N");
+ Scanner in = new Scanner(System.in);
+ String line;
+ line = in.nextLine();
+ line = line.toUpperCase();
+ return Objects.equals(line, "Y");
+ }
+
+ static void editTodoMessage() {
+ borderLine();
+ System.out.println("\t Please enter a new Todo description:");
+ }
+
+ static void editDeadlineMessage() {
+ borderLine();
+ System.out.println("\t Please edit one of the following:");
+ System.out.println("\t For non-recurring deadlines: /description or /deadline");
+ System.out.println("\t For recurring deadlines: /description or /deadline or /day");
+ System.out.println("\t Please follow the format: ");
+ System.out.println("\t /description or /deadline or /day ");
+ System.out.println("\t e.g. /deadline 2023-06-30 1200 or /deadline 1200 (for recurring deadlines)");
+ }
+
+ static void editEventMessage() {
+ borderLine();
+ System.out.println("\t Please edit one of the following:");
+ System.out.println("\t For non-recurring events: /description or /from or /to");
+ System.out.println("\t For recurring deadlines: /description or /from or /to or /day");
+ System.out.println("\t Please follow the format: ");
+ System.out.println("\t /description or /from or /day ");
+ System.out.println("\t e.g. /from 2023-06-30 1200 or /from 1200 (for recurring events)");
+ }
+
+ static void printEditedTask(Task task) {
+ borderLine();
+ System.out.println("\t Quack!");
+ System.out.println("\t I have changed your task to:");
+ System.out.println("\t " + task);
+ borderLine();
+ }
+
+ static String askForEditMessage() {
+ Scanner in = new Scanner(System.in);
+ String line = in.nextLine();
+ return line;
+ }
+
+ static void help() {
+ borderLine();
+ System.out.println("\t Quack! Here are the commands you can give me:");
+ System.out.println("\t - list: I'll list out all the tasks you have recorded.");
+ System.out.println("\t - list : I'll list out all the tasks in that number of days.");
+ System.out.println("\t - list_classes: I'll list out the classes you have on your schedule.");
+ System.out.println("\t - list_today: I'll list out all the classes, deadlines and events you have today.");
+ System.out.println("\t - priority_list: " +
+ "I'll list out all the tasks you have recorded arranged by their priority.");
+ System.out.println("\t - upcoming_class: I'll list out the next upcoming class.");
+ System.out.println("\t - priority <1/2/3>: I'll set the priority of a given task as");
+ System.out.println("\t 1:Low, 2:Medium and 3:High.");
+ System.out.println("\t Default: Low priority.");
+ System.out.println("\t - low_priority: I'll list out all the tasks you have that are low in priority.");
+ System.out.println("\t - medium_priority: I'll list out all the tasks you have that are medium in priority.");
+ System.out.println("\t - high_priority: I'll list out all the tasks you have that are high in priority.");
+ System.out.println("\t - clear: The list will be cleared. This is an IRREVERSIBLE process.");
+ System.out.println("\t - mark : I'll mark that task as done.");
+ System.out.println("\t - unmark : I'll mark that task as undone.");
+ System.out.println("\t - delete : I'll delete that task from your list.");
+ System.out.println("\t - remove /class /description " +
+ "/day /from /to ");
+ System.out.println("\t (/description can be followed by whitespace if the class has no description.");
+ System.out.println("\t : I'll remove this class from your class schedule.");
+ System.out.println("\t - add_notes : I'll add an additional note to that task!");
+ System.out.println("\t - delete_notes : I'll delete the note to that task!");
+ System.out.println("\t - edit_notes : I'll edit the note for that task!");
+ System.out.println("\t - view_notes : I'll print the additional notes for that task!");
+ System.out.println("\t - purge: I'll delete all expired tasks from your list after a confirmation.");
+ System.out.println("\t - find : I'll find the tasks in your list that contain the keyword.");
+ System.out.println("\t - The index of the item will also be displayed.");
+ System.out.println("\t - motivation: I'll print a random motivational quack for you!");
+ System.out.println("\t - bye: I will shut down my program.\n");
+ System.out.println("\t Here are the following ways to input tasks/classes:");
+ System.out.println("\t Deadlines: /by ");
+ System.out.println("\t (eg. Eat bread /by 2023-03-15 2015)");
+ System.out.println("\t Recurring deadlines: /re /by /day ");
+ System.out.println("\t (eg. /re Eat bread /by 2015 /day MONDAY)");
+ System.out.println("\t Events : /from /to ");
+ System.out.println("\t (eg. Meeting /from 2023-03-15 2015 /to 2023-03-15 2215)");
+ System.out.println("\t Recurring events: /re /from /to /day ");
+ System.out.println("\t (eg. /re Meeting /from 2015 /to 2215 /day MONDAY)");
+ System.out.println("\t Todo : /todo ");
+ System.out.println("\t (eg. /todo Water the plants)");
+ System.out.println("\t Classes : /class /day " +
+ "/from /to ");
+ System.out.println("\t (eg. Bring laptop /class CS2113 /day TUESDAY /from 1100 /to 1200) \n");
+ System.out.println("\t How else may I assist you today, human?");
+ borderLine();
+ }
+
+ static void addedTaskMessage(Task currentTask) {
+ borderLine();
+ System.out.println("\t Alright, I have added this task: \n\t" + currentTask);
+ System.out.println("\t You now have " + (Task.getTaskCount() + 1) + " tasks in your list.");
+ borderLine();
+ }
+
+ static void addedSchoolClassMessage(SchoolClass currentClass, PriorityQueue classes) {
+ borderLine();
+ System.out.println("\t Alright, I have added this class: \n\t" + currentClass);
+ System.out.println("\t You now have " + (classes.size()) + " classes in your schedule.");
+ borderLine();
+ }
+
+ static void deleteTaskMessage(Task taskToDelete) {
+ borderLine();
+ System.out.println("\t Understood. I have removed this task:");
+ System.out.println("\t" + taskToDelete);
+ System.out.println("\t You now have " + Task.getTaskCount() + " tasks in your list.");
+ borderLine();
+ }
+
+ static void deleteClassMessage() {
+ borderLine();
+ System.out.println("\t Class has been deleted successfully.");
+ borderLine();
+ }
+
+ static void unsuccessfulDeleteClassMessage() {
+ borderLine();
+ System.out.println("\t Unsuccessful. No class has been deleted.");
+ borderLine();
+ }
+
+ static void refreshedMessage() {
+ borderLine();
+ System.out.println("\t Your task list and class schedule have been refreshed!");
+ borderLine();
+ }
+
+ static void exceedTaskNumberMessage(int taskNumber) {
+ borderLine();
+ System.out.println("\t Task " + taskNumber + " does not exist.");
+ borderLine();
+ }
+
+ static void exceedNoteNumberMessage(int noteNumber) {
+ borderLine();
+ System.out.println("\t Note " + noteNumber + " does not exist for this task");
+ borderLine();
+ }
+
+ static void todoErrorMessage() {
+ borderLine();
+ System.out.println("\t Error. Please enter a valid description.");
+ borderLine();
+ }
+
+ static void unknownCommandMessage() {
+ borderLine();
+ System.out.println("\t Error. Please check that the command has been entered correctly.");
+ borderLine();
+ }
+
+ static void expiredErrorMessage() {
+ borderLine();
+ System.out.println("\t Quack! I know humans wish to undo their past mistakes, " +
+ "but the start date has already passed!");
+ System.out.println("\t Please try again!");
+ borderLine();
+ }
+
+ static void emptyDescriptionErrorMessage() {
+ borderLine();
+ System.out.println("\t Error. Description cannot be empty");
+ borderLine();
+ }
+
+ static void startAfterEndErrorMessage() {
+ borderLine();
+ System.out.println("\t Quack! Somehow this human has time travelled, " +
+ "and the start date seems to be after the end date! ");
+ System.out.println("\t Please try again!");
+ borderLine();
+ }
+
+ static void eventErrorMessage() {
+ borderLine();
+ System.out.println("\t Error. Please enter a valid description, start time and end time");
+ borderLine();
+ }
+
+ static void deadlineErrorMessage() {
+ borderLine();
+ System.out.println("\t Error. Please enter a valid description and deadline.");
+ borderLine();
+ }
+
+ static void schoolClassErrorMessage() {
+ borderLine();
+ System.out.println("\t Error. Please enter a valid class name, description, start time and end time");
+ borderLine();
+ }
+
+ static void invalidDayMessage() {
+ borderLine();
+ System.out.println("\t Error. Please enter a valid day of week in all capital letters (Eg. MONDAY).");
+ borderLine();
+ }
+
+ static void emptyDayErrorMessage() {
+ borderLine();
+ System.out.println("\t Error. Please enter a day of week.");
+ borderLine();
+ }
+
+ static void priorityErrorMessage() {
+ Ui.borderLine();
+ System.out.println("\t Please enter a priority from 1 to 3!");
+ Ui.borderLine();
+ }
+
+ static void invalidRemoveClassMessage() {
+ borderLine();
+ System.out.println("\t Error. Please follow the correct format to remove classes.");
+ borderLine();
+ }
+
+ static void invalidDateTimeMessage() {
+ borderLine();
+ System.out.println("\t Please check the inputted format human!\n" +
+ "\t Try typing 'help' if you are not sure what the correct format is!\n");
+ System.out.println("\t Please try again!");
+ borderLine();
+ }
+
+ static void loadingErrorMessage() {
+ borderLine();
+ System.out.println("\t Error loading save file.");
+ borderLine();
+ }
+
+ /**
+ * Prints the startup message, includes instructions on available commands
+ */
+ static void greetingMessage() {
+ printDuck();
+ borderLine();
+ printMotivationalQuote();
+ borderLine();
+ System.out.println("\t Quack! Nice to meet you human. As you can see, I'm a Duck.");
+ System.out.println("\t As a Duck, I can only understand simple commands. Quack. " +
+ "Human speech is so confusing!");
+ System.out.println("\t That being said, I am a smart Duck. " +
+ "If you wish to know what I understand, just enter 'help'.");
+ System.out.println("\t How may I assist you today, human?");
+ }
+
+ /**
+ * Prints out the notes of the task whose index was taken in
+ *
+ * @param tasks The arraylist of tasks
+ * @param words The index of the task
+ */
+ static void printNotes(ArrayList tasks, String[] words) {
+ int index = Integer.parseInt(words[1]);
+ if (index > tasks.size() || index <= 0) {
+ Ui.exceedTaskNumberMessage(index);
+ } else {
+ ArrayList toBePrinted = tasks.get(index - 1).getAdditionalNotes();
+ borderLine();
+ if (!toBePrinted.isEmpty()) {
+ System.out.println("\t Here are the notes for that task quack!");
+ System.out.println(tasks.get(index - 1).toString());
+ for (int i = 0; i < toBePrinted.size(); i++) {
+ System.out.println("\t \t" + (i + 1) + ". " + toBePrinted.get(i));
+ }
+ } else {
+ System.out.println("\t There are no notes for this task!");
+ }
+ borderLine();
+ }
+ }
+
+ /**
+ * Prints the lists of notes under the specified tasks
+ *
+ * @param tasks The arraylist of tasks
+ * @param index The index of the task whose notes are to be printed
+ */
+ static void printList(ArrayList tasks, int index) {
+ ArrayList toBePrinted = tasks.get(index).getAdditionalNotes();
+ for (int j = 0; j < toBePrinted.size(); j++) {
+ System.out.println("\t" + "\t - " + (j + 1) + ". " + toBePrinted.get(j));
+ }
+ }
+
+ /**
+ * Prints the exiting message when closing the program
+ */
+ static void exitMessage() {
+ printDuck();
+ borderLine();
+ System.out.println("\t Bye. Hope to see you again soon!");
+ borderLine();
+ }
+
+
+}
diff --git a/src/main/java/seedu/duck/exception/EmptyDescriptionException.java b/src/main/java/seedu/duck/exception/EmptyDescriptionException.java
new file mode 100644
index 0000000000..fd61332512
--- /dev/null
+++ b/src/main/java/seedu/duck/exception/EmptyDescriptionException.java
@@ -0,0 +1,4 @@
+package seedu.duck.exception;
+
+public class EmptyDescriptionException extends Exception{
+}
diff --git a/src/main/java/seedu/duck/exception/IllegalDeadlineException.java b/src/main/java/seedu/duck/exception/IllegalDeadlineException.java
new file mode 100644
index 0000000000..394193a618
--- /dev/null
+++ b/src/main/java/seedu/duck/exception/IllegalDeadlineException.java
@@ -0,0 +1,5 @@
+package seedu.duck.exception;
+
+public class IllegalDeadlineException extends Exception {
+
+}
diff --git a/src/main/java/seedu/duck/exception/IllegalEventException.java b/src/main/java/seedu/duck/exception/IllegalEventException.java
new file mode 100644
index 0000000000..e3fa7261fa
--- /dev/null
+++ b/src/main/java/seedu/duck/exception/IllegalEventException.java
@@ -0,0 +1,5 @@
+package seedu.duck.exception;
+
+public class IllegalEventException extends Exception {
+
+}
diff --git a/src/main/java/seedu/duck/exception/IllegalSchoolClassException.java b/src/main/java/seedu/duck/exception/IllegalSchoolClassException.java
new file mode 100644
index 0000000000..b5268f20ac
--- /dev/null
+++ b/src/main/java/seedu/duck/exception/IllegalSchoolClassException.java
@@ -0,0 +1,4 @@
+package seedu.duck.exception;
+
+public class IllegalSchoolClassException extends Exception{
+}
diff --git a/src/main/java/seedu/duck/exception/IllegalTodoException.java b/src/main/java/seedu/duck/exception/IllegalTodoException.java
new file mode 100644
index 0000000000..8ac39560e7
--- /dev/null
+++ b/src/main/java/seedu/duck/exception/IllegalTodoException.java
@@ -0,0 +1,5 @@
+package seedu.duck.exception;
+
+public class IllegalTodoException extends Exception {
+
+}
diff --git a/src/main/java/seedu/duck/exception/expiredDateException.java b/src/main/java/seedu/duck/exception/expiredDateException.java
new file mode 100644
index 0000000000..f34db55da8
--- /dev/null
+++ b/src/main/java/seedu/duck/exception/expiredDateException.java
@@ -0,0 +1,5 @@
+package seedu.duck.exception;
+
+public class expiredDateException extends Exception {
+
+}
diff --git a/src/main/java/seedu/duck/exception/startAfterEndException.java b/src/main/java/seedu/duck/exception/startAfterEndException.java
new file mode 100644
index 0000000000..a81a5f10d7
--- /dev/null
+++ b/src/main/java/seedu/duck/exception/startAfterEndException.java
@@ -0,0 +1,5 @@
+package seedu.duck.exception;
+
+public class startAfterEndException extends Exception {
+
+}
diff --git a/src/main/java/seedu/duck/task/Deadline.java b/src/main/java/seedu/duck/task/Deadline.java
new file mode 100644
index 0000000000..08afc3027b
--- /dev/null
+++ b/src/main/java/seedu/duck/task/Deadline.java
@@ -0,0 +1,28 @@
+package seedu.duck.task;
+
+public class Deadline extends Task {
+ private String by;
+
+ public Deadline(String description, String deadline) {
+ super(description);
+ by = deadline;
+ }
+
+ public void setDeadline(String deadline) {
+ by = deadline;
+ }
+
+ public String getDeadline() {
+ return by;
+ }
+
+ @Override
+ public String toSaveString() {
+ return super.toSaveString() + " /by " + getDeadline() + " " + getPriorityIndex() + " " + getSavedNotes() + System.lineSeparator();
+ }
+
+ @Override
+ public String toString() {
+ return "\t [D]" + super.toString() + " (by: " + by + ")" + " (" + getPriority() + ")";
+ }
+}
diff --git a/src/main/java/seedu/duck/task/Event.java b/src/main/java/seedu/duck/task/Event.java
new file mode 100644
index 0000000000..1ece8fd64c
--- /dev/null
+++ b/src/main/java/seedu/duck/task/Event.java
@@ -0,0 +1,40 @@
+package seedu.duck.task;
+
+public class Event extends Task {
+ private String start; // Start date/time
+ private String end; // End date/time
+
+ public Event(String description, String start, String end) {
+ super(description);
+ this.start = start;
+ this.end = end;
+ }
+
+ public String getStart() {
+ return start;
+ }
+
+ public void setStart(String start) {
+ this.start = start;
+ }
+
+ public String getEnd() {
+ return end;
+ }
+
+ public void setEnd(String end) {
+ this.end = end;
+ }
+
+ @Override
+ public String toSaveString() {
+ return super.toSaveString() + " /from " + getStart() + " /to " + getEnd() +
+ " " + getPriorityIndex() + " " + getSavedNotes() + System.lineSeparator();
+ }
+
+ @Override
+ public String toString() {
+ return "\t [E]" + super.toString() + " (from: " + start
+ + " to: " + end + ")" + " (" + getPriority() + ")";
+ }
+}
diff --git a/src/main/java/seedu/duck/task/RecurringDeadline.java b/src/main/java/seedu/duck/task/RecurringDeadline.java
new file mode 100644
index 0000000000..c19a1a3d71
--- /dev/null
+++ b/src/main/java/seedu/duck/task/RecurringDeadline.java
@@ -0,0 +1,31 @@
+package seedu.duck.task;
+
+import java.time.DayOfWeek;
+public class RecurringDeadline extends Deadline{
+ private DayOfWeek day;
+
+ public RecurringDeadline(String description, String by, DayOfWeek day) {
+ super(description, by);
+ this.day = day;
+ }
+
+ public DayOfWeek getDay() {
+ return this.day;
+ }
+
+ public void setDay(DayOfWeek day) {
+ this.day = day;
+ }
+
+ @Override
+ public String toSaveString() {
+ return getDoneConditionString() + " " + getDescription() + " /by " + getDeadline() + " " +
+ getPriorityIndex() + " /day " + day + System.lineSeparator();
+ }
+
+ @Override
+ public String toString() {
+ return "\t [D]" + "[" + getStatusIcon() + "] " + getDescription() + " (by: " + super.getDeadline() + ")" +
+ " (every " + day + ") (" + getPriority() + ")";
+ }
+}
diff --git a/src/main/java/seedu/duck/task/RecurringEvent.java b/src/main/java/seedu/duck/task/RecurringEvent.java
new file mode 100644
index 0000000000..ea6900b735
--- /dev/null
+++ b/src/main/java/seedu/duck/task/RecurringEvent.java
@@ -0,0 +1,32 @@
+package seedu.duck.task;
+
+import java.time.DayOfWeek;
+
+public class RecurringEvent extends Event {
+ private DayOfWeek day;
+
+ public RecurringEvent(String description, String start, String end, DayOfWeek day) {
+ super(description, start, end);
+ this.day = day;
+ }
+
+ public DayOfWeek getDay() {
+ return this.day;
+ }
+
+ public void setDay(DayOfWeek day) {
+ this.day = day;
+ }
+
+ @Override
+ public String toSaveString() {
+ return getDoneConditionString() + " " + getDescription() + " /from " + getStart() + " /to " + getEnd() +
+ "
" + getPriorityIndex() + " /day " + day + System.lineSeparator();
+ }
+
+ @Override
+ public String toString() {
+ return "\t [E]" + "[" + getStatusIcon() + "] " + getDescription() + " (from: " + super.getStart()
+ + " to: " + super.getEnd() + ")" + " (every " + day + ") (" + getPriority() + ")";
+ }
+}
diff --git a/src/main/java/seedu/duck/task/SchoolClass.java b/src/main/java/seedu/duck/task/SchoolClass.java
new file mode 100644
index 0000000000..c78d241d1a
--- /dev/null
+++ b/src/main/java/seedu/duck/task/SchoolClass.java
@@ -0,0 +1,84 @@
+package seedu.duck.task;
+
+import java.time.DayOfWeek;
+
+public class SchoolClass extends Task implements Comparable {
+ private String className; // Name of class
+ private DayOfWeek day; // Day of the week
+ private String start; // Start date/time
+ private String end; // End date/time
+
+ public SchoolClass(String className, String description, DayOfWeek day, String start, String end) {
+ super(description);
+ this.className = className;
+ this.day = day;
+ this.start = start;
+ this.end = end;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public void setClassName(String className) {
+ this.className = className;
+ }
+
+ public DayOfWeek getDay() {
+ return this.day;
+ }
+
+ public String getStart() {
+ return start;
+ }
+
+ public void setStart(String start) {
+ this.start = start;
+ }
+
+ public String getEnd() {
+ return end;
+ }
+
+ public void setEnd(String end) {
+ this.end = end;
+ }
+
+ @Override
+ public int compareTo(SchoolClass lesson) {
+ if (lesson.day.compareTo(this.day) == 0) {
+ return this.start.compareTo(lesson.start);
+ } else {
+ return this.day.compareTo(lesson.day);
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || obj.getClass() != this.getClass()) {
+ return false;
+ }
+ SchoolClass lesson = (SchoolClass) obj;
+ return className.equals(lesson.getClassName()) && this.getDescription().equals(lesson.getDescription())
+ && day.equals(lesson.getDay()) && start.equals(lesson.getStart()) && end.equals(lesson.getEnd());
+ }
+
+ @Override
+ public String toSaveString() {
+ return super.toSaveString() + " /class " + getClassName() + " /day " + getDay() + " /from "
+ + getStart() + " /to "+ getEnd() + System.lineSeparator();
+ }
+
+ @Override
+ public String toString() {
+ if (getDescription().isBlank()) {
+ return "\t [" + day + "]" + "[" + getStatusIcon() + "] " + className + " (from: "
+ + start + " to: " + end + ")";
+ }
+ return "\t [" + day + "]" + "[" + getStatusIcon() + "] " + className + ": "
+ + getDescription() + " (from: " + start + " to: " + end + ")";
+ }
+}
diff --git a/src/main/java/seedu/duck/task/Task.java b/src/main/java/seedu/duck/task/Task.java
new file mode 100644
index 0000000000..76f344e262
--- /dev/null
+++ b/src/main/java/seedu/duck/task/Task.java
@@ -0,0 +1,137 @@
+package seedu.duck.task;
+import java.util.ArrayList;
+
+public class Task {
+ private static int taskCount;
+ private String description;
+ private int priority;
+ private boolean isDone;
+ private final ArrayList additionalNotes = new ArrayList();
+
+ public Task(String description) {
+ this.description = description;
+ this.isDone = false;
+ this.priority = 1; //automatically set to low priority
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+ public void setPriority(String priority) {
+ this.priority = Integer.parseInt(priority);
+ }
+
+ public String getDescription() {
+ return this.description;
+ }
+
+ public static void clearCount() {
+ taskCount = 0;
+ }
+
+ public void markAsDone() {
+ this.isDone = true;
+ }
+
+ public void markAsNotDone() {
+ this.isDone = false;
+ }
+
+ public String getStatusIcon() {
+ if(isDone) {
+ // Mark done task with X
+ return "X";
+ }
+ return " ";
+ }
+ public String hasNotes(){
+ if (additionalNotes.isEmpty()){
+ return "0";
+ } else {
+ return "1";
+ }
+ }
+ public String getSavedNotes(){
+ String save = "";
+ save += hasNotes();
+ for (int i = 0; i < additionalNotes.size(); i++){
+ save += additionalNotes.get(i);
+ if (!(i==additionalNotes.size()-1)) {
+ save += "@";
+ }
+ }
+ return save;
+ }
+ public void addNotes(String noteToAdd){
+ this.additionalNotes.add(noteToAdd);
+ }
+
+ public ArrayList getAdditionalNotes(){
+ return this.additionalNotes;
+ }
+ public String getNote(int index){
+ return this.additionalNotes.get(index);
+ }
+
+ public void deleteNote(int indexToBeDeleted){
+ this.additionalNotes.remove(indexToBeDeleted-1);
+ }
+
+ public void editNote(int indexToBeEdited, String editedNote){
+ this.additionalNotes.set(indexToBeEdited,editedNote);
+ }
+
+ public int numberOfNotes(){
+ return this.additionalNotes.size();
+ }
+
+ public String getPriority() {
+ if (priority == 1) {
+ // Mark done task with X
+ return "Low priority.";
+ } else if(priority == 2) {
+ // Mark done task with X
+ return "Medium priority.";
+ } else if(priority == 3) {
+ // Mark done task with X
+ return "High priority.";
+ }
+ return "No priority established.";
+ }
+
+ public int returnPriority(){
+ return this.priority;
+ }
+
+ public int getPriorityIndex() {
+ return this.priority;
+ }
+
+ public static void incrementCount() {
+ taskCount++;
+ }
+
+ public static void decrementCount() {
+ taskCount--;
+ }
+
+ public static int getTaskCount() {
+ return taskCount;
+ }
+
+ public String getDoneConditionString() {
+ if (isDone) {
+ return "1";
+ }
+ return "0";
+ }
+
+ public String toSaveString() {
+ return getDoneConditionString() + " " + getDescription();
+ }
+
+ @Override
+ public String toString() {
+ return "[" + getStatusIcon() + "] " + getDescription();
+ }
+}
diff --git a/src/main/java/seedu/duck/task/Todo.java b/src/main/java/seedu/duck/task/Todo.java
new file mode 100644
index 0000000000..cb94286ee2
--- /dev/null
+++ b/src/main/java/seedu/duck/task/Todo.java
@@ -0,0 +1,18 @@
+package seedu.duck.task;
+
+public class Todo extends Task {
+
+ public Todo(String description) {
+ super(description);
+ }
+
+ @Override
+ public String toSaveString() {
+ return super.toSaveString() + " " + getPriorityIndex() + "