diff --git a/Main.java b/Main.java new file mode 100644 index 000000000..70464179b --- /dev/null +++ b/Main.java @@ -0,0 +1,2 @@ +public class Main { +} diff --git a/data/dukey.txt b/data/dukey.txt new file mode 100644 index 000000000..e351be872 --- /dev/null +++ b/data/dukey.txt @@ -0,0 +1,3 @@ +4.[T][ ] hey +4.[T][ ] yn +3.[T][ ] hi diff --git a/docs/README.md b/docs/README.md index 8077118eb..9f1db02d1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,139 @@ +# Dukey Chatbot # User Guide -## Features -### Feature-ABC -Description of the feature. +## Usage of Features -### Feature-XYZ +### `bye` - Exit Program -Description of the feature. +This command is used to exit the program. -## Usage +Format: -### `Keyword` - Describe action +`bye` -Describe the action and its outcome. +Expected outcome: Bye. Hope to see you again soon! -Example of usage: -`keyword (optional arguments)` +### `list` - List Tasks + +This command is used to list all tasks. + +Format: + +`list` + Expected outcome: +1.[T][ ] homework +2.[T][ ] go to the beach +3.[E][ ] cycle (from: 5am to: 8am) + + +### `mark` - Mark Task as Done + +This command is used to mark a task as done. + +Format: + +`mark (task number)` + + +Expected outcome: Nice! I've marked this task as done: +`[T][X]` hi + + +### `unmark` - Unmark Task + +This command is used to unmark a task (mark it as not done). + +Format: + +`unmark (task number)` + +Expected outcome: Nice! I've marked this task as done: +[T][ ] hi + + + +### `deadline` - Add Deadline Task + +This command is used to add a deadline task. + +Format: + +`deadline (description) /by (due date)` + +Example of input : +`Submit assignment /by 9am` + +Expected outcome: [D][ ] Submit assignment (by: 9am) + + +### `event` - Add Event Task + +This command is used to add an event task. + +Format: + +`event (description) /from (start time) /to (end time)` + +Example of input : +`Rohit attends cs2113 lecture /from 4pm /to 6pm` + +Expected outcome: [E][ ] Rohit attends cs2113 lecture (from: 4pm to: 6pm) + + +### `todo` - Add Todo Task + +This command is used to add a todo task. + +Format: + +`todo (description)` + +Example of input : +`todo buy groceries` + +Expected outcome: [T][ ] buy groceries + + +### `delete` - Delete Task + +This command is used to delete a task. + +Format: + +`delete (task number)` + +Expected outcome: +"Noted. I have removed this task: +[D][ ] bro (by:tmr) +Now you have 3 tasks in the list." + +### `find` - Find a task/tasks + +This command is used to search for tasks that contain a particular +keyword in the description. + +Format: + +`find (task number)` + +Example of input: +`find hohoho` + +Expected Outcome: + +"Here are the matching tasks in your list: + +[T][ ] hohoho +[T][ ] hohoho +[E][ ] hohoho (from: 9am to: 5pm)" + -Description of the outcome. +### Additional Notes For Users -``` -expected output -``` +- Do not input whitespaces before your command +- e.g. ( `todo homework` is invalid), (`todo homework` is valid) \ No newline at end of file diff --git a/docs/dukey.txt b/docs/dukey.txt new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/docs/dukey.txt @@ -0,0 +1 @@ + diff --git a/docs/psuedo.txt b/docs/psuedo.txt new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 5d313334c..8b1378917 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,10 +1 @@ -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/Dukey.java b/src/main/java/Dukey.java new file mode 100644 index 000000000..7ca585ac9 --- /dev/null +++ b/src/main/java/Dukey.java @@ -0,0 +1,139 @@ +import Exceptions.DukeyErrorMessages; +import Tasks.*; + +import java.util.ArrayList; +import java.util.Scanner; +import java.io.IOException; +public class Dukey { + protected Storage storage; + protected TaskList tasks; + protected Ui ui; + protected String filePath = "data/dukey.txt"; + + public Dukey(String filePath) { + ui = new Ui(); + storage = new Storage(filePath); + try { + ArrayList array1 = new ArrayList<>(); + storage.fileToTaskArray(filePath, array1); + tasks = new TaskList(array1); // Assigning the TaskList to the class-level variable + } catch (Exception e) { + Ui.showLoadingError(); + this.tasks = new TaskList(new ArrayList<>()); + } + } + + public void run() throws IOException { + ui.showWelcomeMessage(); + Scanner in = new Scanner(System.in); + String line; + storage.checkDirectoryExists("data"); + storage.checkFileExists(filePath); + while (true) { + line = in.nextLine(); + String[] input = Parser.parseUserInput(line); + String command = input[0]; + switch (command) { + case "bye": + Ui.showExitMessage(); + return; + case "list": + TaskList.printTaskList(tasks.tasks); + break; + case "mark": + try { + TaskList.markTask(line, tasks.tasks); + storage.markTaskInFile(Integer.parseInt(input[1].trim()) - 1, filePath); + } catch (IndexOutOfBoundsException e) { + DukeyErrorMessages.markInvalidError(); + } catch (NumberFormatException e) { + DukeyErrorMessages.markInvalidTypeError(); + } + break; + case "unmark": + try { + TaskList.unmarkTask(line, tasks.tasks); + storage.unmarkTaskInFile(Integer.parseInt(input[1].trim()) - 1, filePath); + } catch (IndexOutOfBoundsException e) { + DukeyErrorMessages.unmarkInvalidError(); + } catch (NumberFormatException e) { + DukeyErrorMessages.unmarkInvalidTypeError(); + } + break; + case "deadline": + try { + String[] deadline = Parser.parseCommandInput(command, input[1]); + if (deadline[0].trim().isEmpty() || deadline[1].trim().isEmpty()) { + DukeyErrorMessages.deadlineEmptyInputError(); + break; + } + TaskList.addDeadline(deadline[0], deadline[1], tasks.tasks); + } catch (ArrayIndexOutOfBoundsException e) { + DukeyErrorMessages.deadlineFormatError(); + } + storage.taskArrayToFile(filePath, tasks.tasks); + break; + case "event": + try { + String[] events = Parser.parseCommandInput(command, input[1]); + if (events[2].isEmpty() || events[1].isEmpty() || events[0].isEmpty()) { + DukeyErrorMessages.eventEmptyInputError(); + break; + } + TaskList.addEvent(events[0], events[1], events[2], tasks.tasks); + storage.taskArrayToFile(filePath, tasks.tasks); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(Exceptions.DukeyException.EmptyInputError()); + DukeyErrorMessages.eventFormatError(); + } catch (StringIndexOutOfBoundsException e) { + DukeyErrorMessages.eventFormatError(); + } + break; + case "todo": + try { + String[] todo = Parser.parseCommandInput(command, input[1]); + if (input[1].trim().isEmpty()) { + DukeyErrorMessages.todoEmptyInputError(); + break; + } + TaskList.addTodo(todo[0], tasks.tasks); + storage.taskArrayToFile(filePath, tasks.tasks); + } catch (ArrayIndexOutOfBoundsException e) { + DukeyErrorMessages.todoFormatError(); + } + break; + case "delete": + try { + TaskList.deleteTask(line, tasks.tasks); + storage.deleteLineFromFile(Integer.parseInt(input[1].trim()) - 1, filePath); + } + catch (ArrayIndexOutOfBoundsException e) { + DukeyErrorMessages.deleteEmptyInputError(); + } catch (NumberFormatException e) { + DukeyErrorMessages.deleteInvalidTypeError(); + } + break; + case "find": + TaskList.findKeyword(line, tasks.tasks); + break; + default: + if (line.trim().isEmpty()) { + DukeyErrorMessages.unrecognizedCommandError(); + } else { + DukeyErrorMessages.unrecognizedCommandError(); + } + } + } + } + public static void main(String[] args) { + try { + new Dukey("data/dukey.txt").run(); + } catch (IOException e) { + System.out.println("An error occurred: " + e.getMessage()); + } + } + +} + + + diff --git a/src/main/java/Exceptions/DukeyErrorMessages.java b/src/main/java/Exceptions/DukeyErrorMessages.java new file mode 100644 index 000000000..a0df9d8a2 --- /dev/null +++ b/src/main/java/Exceptions/DukeyErrorMessages.java @@ -0,0 +1,172 @@ +package Exceptions; + + +public class DukeyErrorMessages { + + /** + * Displays an error message when the description for a todo task is empty. + */ + public static void todoEmptyInputError() { + printLine(); + System.out.println("Oops! I'm sorry, but description cannot be empty.\nPlease input your command for todo " + + "in this " + + "format:\ntodo (\"insert description here\")"); + printLine(); + } + + /** + * Displays an error message when the format of a todo command is incorrect. + */ + public static void todoFormatError() { + printLine(); + System.out.println("Oops! I'm sorry, I didn't understand your command.\nPlease input your command for todo " + + "in this " + + "format:\ntodo (\"insert description here\")"); + printLine(); + } + + /** + * Displays an error message when any field for an event task is empty. + */ + public static void eventEmptyInputError() { + printLine(); + System.out.println("Oops! I'm sorry, but none of the fields can be empty.\nPlease input your " + + "command for event in this " + + "format:\nevent (\"insert description here\") /from (\"insert description" + + " here\") /to (\"insert description here\")"); + printLine(); + } + + + /** + * Displays an error message when the format of an event command is incorrect. + */ + public static void eventFormatError() { + printLine(); + System.out.println("Oops! I'm sorry, I didn't understand your command.\nPlease input your " + + "command for event in this " + + "format:\nevent (\"insert description here\") /from (\"insert description" + + " here\") /to (\"insert description here\")"); + printLine(); + } + + /** + * Displays an error message when any field for a deadline task is empty. + */ + public static void deadlineEmptyInputError() { + printLine(); + System.out.println("Oops! I'm sorry, but none of the fields can be empty.\nPlease input your " + + "command for deadline in this " + + "format:\ndeadline (\"insert description here\") /by (\"insert description" + + " here\")"); + printLine(); + } + + /** + * Displays an error message when the format of a deadline command is incorrect. + */ + public static void deadlineFormatError() { + printLine(); + System.out.println("Oops! I'm sorry, I didn't understand your command.\nPlease input your " + + "command for deadline in this " + + "format:\ndeadline (\"insert description here\") /by (\"insert description" + + " here\")"); + printLine(); + } + + /** + * Displays an error message for an unrecognized command. + */ + public static void unrecognizedCommandError() { + printLine(); + System.out.println("Oops! I'm sorry, I didn't understand your command.\nPlease input " + + "one of the available commands in its specific format\n" + + "Commands: todo, event, deadline, delete, find, mark, unmark"); + printLine(); + } + + public static void printLine() { + System.out.println("_____________________________________________________"); + } + + + /** + * Displays an error message when the mark command has an invalid input. + */ + public static void markInvalidError() { + printLine(); + System.out.println("Oops! I'm sorry, your input for the mark command is invalid.\nPlease input " + + "your command for mark in this specific format\n" + + "mark (\"index\")"); + printLine(); + } + + /** + * Displays an error message when the input for mark is not an integer. + */ + public static void markInvalidTypeError() { + printLine(); + System.out.println("Oops! I'm sorry, your input for the mark command is not an integer.\nPlease input " + + "your command for mark in this specific format\n" + + "mark (\"index\")"); + printLine(); + } + + + /** + * Displays an error message when the unmark command has an invalid input. + */ + public static void unmarkInvalidError() { + printLine(); + System.out.println("Oops! I'm sorry, your input for the unmark command is invalid.\nPlease input " + + "your command for unmark in this specific format\n" + + "find (\"index\")"); + printLine(); + } + + /** + * Displays an error message when the input for unmark is not an integer. + */ + public static void unmarkInvalidTypeError() { + printLine(); + System.out.println("Oops! I'm sorry, your input for the unmark command is not an integer.\nPlease input " + + "your command for unmark in this specific formatt\n" + + "mark (\"index\")"); + printLine(); + } + + /** + * Displays an error message when the description for a find command is empty. + */ + public static void findEmptyInputError() { + printLine(); + System.out.println("Oops! I'm sorry, but description cannot be empty.\nPlease input " + + "command for find in this specific format\n" + + "find (\"description\")"); + printLine(); + } + + /** + * Displays an error message when the index for a delete command is empty. + */ + public static void deleteEmptyInputError() { + printLine(); + System.out.println("Oops! I'm sorry, but index cannot be empty.\nPlease input " + + "command for delete in this specific format\n" + + "delete (\"index\")"); + printLine(); + } + + /** + * Displays an error message when the input for delete is not an integer. + */ + public static void deleteInvalidTypeError() { + printLine(); + System.out.println("Oops! I'm sorry, your input for the deleted command is invalid.\nPlease input " + + "command for delete in this specific format\n" + + "delete (\"index\")"); + printLine(); + } + + +} diff --git a/src/main/java/Exceptions/DukeyException.java b/src/main/java/Exceptions/DukeyException.java new file mode 100644 index 000000000..8f45baa94 --- /dev/null +++ b/src/main/java/Exceptions/DukeyException.java @@ -0,0 +1,11 @@ +package Exceptions; + +public class DukeyException extends Exception { + public DukeyException(String message){ + super(message); + } + public static String EmptyInputError(){ + return "☹ OOPS!!! I'm sorry, but you have to input something :-|"; + } + +} diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 000000000..b6ea9ac99 --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: Dukey + diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java new file mode 100644 index 000000000..f7053e956 --- /dev/null +++ b/src/main/java/Parser.java @@ -0,0 +1,59 @@ +/** + * The Parser class provides methods for parsing user input and command-specific input. + */ +public class Parser { + /** + * Parses the user input into an array of words. + * + * @param line The user input to be parsed. + * @return An array containing the words in the input. + */ + public static String[] parseUserInput(String line) { + return line.split(" ", 2); + } + + /** + * Parses command-specific input based on the given command type. + * + * @param command The type of command (e.g., "deadline", "event", etc.). + * @param input The input specific to the command. + * @return An array containing parsed information based on the command. + */ + public static String[] parseCommandInput(String command, String input) { + String[] words = null; // Initialize the array + switch (command) { + case "deadline": + words = input.split("/by"); + words[0] = words[0].trim(); + words[1] = words[1].trim(); + break; + case "event": + int startIndexOfFrom = input.indexOf("/from"); + int startIndexOfTo = input.indexOf("/to"); + String from = input.substring(startIndexOfFrom + 5, startIndexOfTo); + String to = input.substring(startIndexOfTo + 4); + String description = input.substring(0, startIndexOfFrom); + words = new String[]{from.trim(), to.trim(), description.trim()}; + break; + case "todo": + words = new String[]{input.trim()}; + break; + case "delete": + break; + case "bye": + break; + case "list": + break; + case "mark": + break; + case "unmark": + break; + default: + // Handle the default case, if needed + break; + } + return words; // Return the array + } + +} + diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java new file mode 100644 index 000000000..9673df145 --- /dev/null +++ b/src/main/java/Storage.java @@ -0,0 +1,269 @@ +import Tasks.Deadline; +import Tasks.Event; +import Tasks.Task; +import Tasks.Todo; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.PrintWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * The Storage class handles reading from and writing to a file. + */ +public class Storage { + + protected String filePath; + + /** + * Constructs a Storage object with the specified file path. + * + * @param filePath The file path of the storage file. + */ + public Storage(String filePath) { + this.filePath = filePath; + } + + /** + * Checks if the file exists, and creates it if it doesn't. + * + * @param filePath The file path to check and create. + */ + protected void checkFileExists(String filePath) { + File file = new File(filePath); + // Check if the file or directory exists, and create it if it doesn't + String dirName = "docs"; + Path dirPath = Paths.get(dirName); + if (!Files.exists(dirPath)) { + try { + Files.createDirectory(dirPath); + } catch (IOException e) { + throw new RuntimeException("Error creating directory: " + dirName, e); + } + } + try { + file.createNewFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Checks if the specified directory exists, and creates it if it doesn't. + * + * @param directoryPath The path of the directory to be checked and created if necessary. + */ + protected void checkDirectoryExists(String directoryPath) { + File directory = new File(directoryPath); + // Check if the directory exists, and create it if it doesn't + if (!directory.exists()) { + if (directory.mkdirs()) { + System.out.println("Directory created"); + } else { + System.out.println("Failed to create directory"); + } + } + } + + + + /** + * Appends the details of the last task in the list to the storage file. + * + * @param filePath The file path to write to. + * @param tasks The list of tasks. + * @throws IOException If an I/O error occurs. + */ + protected void taskArrayToFile(String filePath, ArrayList tasks) throws IOException { + checkFileExists(filePath); + FileWriter fw = new FileWriter(filePath, true); + int index = tasks.size() - 1; + Task lastTask = tasks.get(tasks.size() - 1); + fw.write((index + 1) + "." + lastTask); + fw.write("\n"); + fw.close(); + } + /** + * Reads tasks from the storage file and adds them to the tasks list. + * + * @param filePath The file path to read from. + * @param tasks The list of tasks to populate. + * @throws IOException If an I/O error occurs. + */ + protected void fileToTaskArray(String filePath, ArrayList tasks) throws IOException { + File f = new File(filePath); // create a File for the given file path + Scanner list = new Scanner(f); // create a Scanner using the File as the source + while (list.hasNext()) { + String line = list.nextLine(); + char type = line.charAt(3); + boolean mark = false; + if (line.charAt(6) == 'X') { + mark = true; + } + switch (type) { + case 'T': + addTodoFromFile(line, tasks, mark); + break; + case 'D': + addDeadlineFromFile(line, tasks, mark); + break; + case 'E': + addEventFromFile(line, tasks, mark); + break; + default: + break; + } + } + } + /** + * Adds a Todo task to the tasks list based on the input line. + * + * @param line The input line. + * @param tasks The list of tasks. + * @throws IOException If an I/O error occurs. + */ + private static void addTodoFromFile(String line, ArrayList tasks, boolean mark) throws IOException { + Task element = new Todo(line.substring(8).trim()); + if (line.charAt(6) == 'X') { + element.setDone(); + } + tasks.add(element); + if (mark) { + tasks.get(tasks.size() - 1).setDone(); + } + } + /** + * Adds a Deadline task to the tasks list based on the input line. + * + * @param line The input line. + * @param tasks The list of tasks. + * @throws IOException If an I/O error occurs. + */ + private static void addDeadlineFromFile(String line, ArrayList tasks, boolean mark) throws IOException { + int endOfDescriptionIndex = line.indexOf("(by"); + String description = line.substring(8, endOfDescriptionIndex).trim(); + int startOfDueIndex = line.indexOf(':'); + int endOfDueIndex = line.indexOf(')'); + String due = line.substring(startOfDueIndex + 1, endOfDueIndex).trim(); + Task element = new Deadline(description, due); + tasks.add(element); + if (mark) { + tasks.get(tasks.size() - 1).setDone(); + } + } + /** + * Adds an Event task to the tasks list based on the input line. + * + * @param line The input line. + * @param tasks The list of tasks. + * @throws IOException If an I/O error occurs. + */ + private static void addEventFromFile(String line, ArrayList tasks, boolean mark) throws IOException { + int endOfDescriptionIndex = line.indexOf("(from:"); + String description = line.substring(8, endOfDescriptionIndex).trim(); + int startOfFromIndex = endOfDescriptionIndex + 7; + int endOfFromIndex = line.indexOf("to:"); + String from = line.substring(startOfFromIndex, endOfFromIndex).trim(); + String to = line.substring(endOfFromIndex + 4, line.indexOf(')')).trim(); + Task element = new Event(from, to, description); + tasks.add(element); + if (mark) { + tasks.get(tasks.size() - 1).setDone(); + } + } + + /** + * Deletes a specific line from a file. + * + * @param index The line number to be deleted. + * @param filePath The path of the file to perform the deletion. + * @throws IOException If an I/O error occurs while deleting the line. + */ + protected void deleteLineFromFile(int index, String filePath) throws IOException { + File inputFile = new File(filePath); + File tempFile = new File("tempFile.txt"); + Scanner list = new Scanner(inputFile); + PrintWriter writer = new PrintWriter(new FileWriter(tempFile)); + // Read all lines into a list + List lines = new ArrayList<>(); + while (list.hasNextLine()) { + lines.add(list.nextLine()); + } + // Remove the line at the specified index + if (index >= 0 && index < lines.size()) { + lines.remove(index); + } + // Write the modified list back to the file + for (String line : lines) { + writer.println(line); + } + list.close(); + writer.close(); + if (!inputFile.delete()) { + throw new IOException("Could not delete original file"); + } + if (!tempFile.renameTo(inputFile)) { + throw new IOException("Could not rename temp file"); + } + } + /** + * Marks a task as done in the file by updating its status. + * + * @param index The index of the task to be marked as done. + * @param filePath The path of the file containing the task list. + * @throws IOException If an I/O error occurs while marking the task. + */ + public void markTaskInFile(int index, String filePath) throws IOException { + File inputFile = new File(filePath); + File tempFile = new File("temp.txt"); + Scanner list = new Scanner(inputFile); + PrintWriter writer = new PrintWriter(new FileWriter(tempFile)); + int count = -1; + while (list.hasNextLine()) { + String line = list.nextLine(); + count++; + if (count == index && line.length() >= 6) { + StringBuilder modifiedLine = new StringBuilder(line); + modifiedLine.setCharAt(6, 'X'); + line = modifiedLine.toString(); + } + writer.write(line + System.lineSeparator()); + } + writer.close(); + list.close(); + inputFile.delete(); + tempFile.renameTo(inputFile); + } + + public void unmarkTaskInFile(int index, String filePath) throws IOException { + File inputFile = new File(filePath); + File tempFile = new File("temp.txt"); + Scanner list = new Scanner(inputFile); + PrintWriter writer = new PrintWriter(new FileWriter(tempFile)); + int count = -1; + while (list.hasNextLine()) { + String line = list.nextLine(); + count++; + if (count == index && line.length() >= 6) { + StringBuilder modifiedLine = new StringBuilder(line); + modifiedLine.setCharAt(6, ' '); + line = modifiedLine.toString(); + } + writer.write(line + System.lineSeparator()); + } + writer.close(); + list.close(); + inputFile.delete(); + tempFile.renameTo(inputFile); + } + + +} + diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java new file mode 100644 index 000000000..6bc25fe4e --- /dev/null +++ b/src/main/java/TaskList.java @@ -0,0 +1,156 @@ +import Exceptions.DukeyErrorMessages; +import Tasks.Deadline; +import Tasks.Event; +import Tasks.Task; +import Tasks.Todo; + +import java.util.ArrayList; + +/** + * The TaskList class manages a list of tasks (add/delete/mark) + */ +public class TaskList { + protected ArrayList tasks; + /** + * Constructs a TaskList with the given list of tasks. + * + * @param tasks The list of tasks to be managed. + */ + public TaskList(ArrayList tasks) { + this.tasks = tasks; + } + + /** + * Adds a Todo task to the task list. + * + * @param words The description of the Todo task. + * @param tasks The list of tasks. + */ + public static void addTodo(String words, ArrayList tasks) { + tasks.add(new Todo(words)); + tasks.get(tasks.size() - 1).printNewTask(); + } + + /** + * Deletes a task from the task list based on its index. + * + * @param line The user input containing the index of the task. + * @param tasks The list of tasks. + */ + public static void deleteTask(String line, ArrayList tasks) { + try { + String[] words = line.split(" "); + int index = Integer.parseInt(words[1].trim()) - 1; + Task element = tasks.get(index); + tasks.remove(index); + element.printDeleteTask(); + } catch (ArrayIndexOutOfBoundsException e) { + DukeyErrorMessages.deleteEmptyInputError(); + } catch (IndexOutOfBoundsException e) { + DukeyErrorMessages.deleteInvalidTypeError(); + } + } + + /** + * Adds an Event task to the task list. + * + * @param from The starting time of the event. + * @param to The ending time of the event. + * @param description The description of the Event task. + * @param tasks The list of tasks. + */ + public static void addEvent(String from, String to, String description, ArrayList tasks) { + tasks.add(new Event(from, to, description)); + tasks.get(tasks.size() - 1).printNewTask(); + + } + + /** + * Adds a Deadline task to the task list. + * + * @param description The description of the Deadline task. + * @param by The deadline of the task. + * @param tasks The list of tasks. + */ + public static void addDeadline(String description, String by, ArrayList tasks) { + tasks.add(new Deadline(description, by)); + tasks.get(tasks.size() - 1).printNewTask(); + } + + /** + * Unmarks a task in the task list. + * + * @param line The user input containing the index of the task. + * @param tasks The list of tasks. + */ + public static void unmarkTask(String line, ArrayList tasks) { + String[] words = line.split(" "); + int taskNum = Integer.parseInt(words[1]) - 1; + tasks.get(taskNum).unmarkTask(); + } + + /** + * Marks a task in the task list as done. + * + * @param line The user input containing the index of the task. + * @param tasks The list of tasks. + */ + public static void markTask(String line, ArrayList tasks) { + try { + String[] words = line.split(" "); + int taskNum = Integer.parseInt(words[1]) - 1; + tasks.get(taskNum).setDone(); + Ui.printLine(); + System.out.println("Nice! I've marked this task as done:\n\t " + tasks.get(taskNum)); + Ui.printLine(); + } catch (NumberFormatException e) { + DukeyErrorMessages.markInvalidError(); + } + } + + /** + * Prints the list of tasks. + * + * @param tasks The list of tasks to be printed. + */ + public static void printTaskList(ArrayList tasks) { + Ui.printLine(); + System.out.println("Here are the tasks in your list:"); + int index = 1; + for (Task task : tasks) { + System.out.println((index++) + "." + task); + } + Ui.printLine(); + } + + /** + * Searches for tasks containing a specified keyword and prints the results. + * + * @param line The user input containing the keyword search command. + * @param tasks The list of tasks to be searched. + */ + protected static void findKeyword(String line, ArrayList tasks) { + ArrayList searchResults = new ArrayList<>(); + String keyword = line.substring(4).trim(); + if (keyword.isEmpty()) { + DukeyErrorMessages.findEmptyInputError(); + return; + } + int count = 0; + for (Task task : tasks) { + if (task.getDescription().contains(keyword)) { + searchResults.add(task); + count++; + } + } + if (count == 0) { + System.out.println("There are no matching tasks in your list"); + } else { + Ui.outputHeader(); + } + for (Task task : searchResults) { + System.out.println(task); + } + Ui.printLine(); + } +} diff --git a/src/main/java/Tasks/Deadline.java b/src/main/java/Tasks/Deadline.java new file mode 100644 index 000000000..ca36002ea --- /dev/null +++ b/src/main/java/Tasks/Deadline.java @@ -0,0 +1,35 @@ +package Tasks; + +import Tasks.Task; + +/** + * The Deadline class represents a task with a specific due date. + * It extends the Task class and inherits its properties and behavior. + */ +public class Deadline extends Task { + private String due; + + /** + * Constructs a Deadline object with the provided description and due date. + * + * @param description The description of the deadline. + * @param due The due date of the deadline. + */ + public Deadline(String description, String due) { + super(description); + this.due = due; + this.type = 'D'; + } + // appends "[D]" to the beginning of the string. + // Then, it calls super.toString(), ie. it calls the toString() method of the superclass + // then adds the due date + /** + * Returns a formatted string representation of the Deadline object. + * + * @return A string representing the Deadline. + */ + @Override + public String toString() { + return "[" + this.type + "]" + super.toString() + " (by: "+ this.due + ")"; + } +} diff --git a/src/main/java/Tasks/Event.java b/src/main/java/Tasks/Event.java new file mode 100644 index 000000000..360dae103 --- /dev/null +++ b/src/main/java/Tasks/Event.java @@ -0,0 +1,37 @@ +package Tasks; + +import Tasks.Task; + +/** + * The Event class represents a task with a specific start and end time. + * It extends the Task class and inherits its properties and behavior. + */ +public class Event extends Task { + private String from; + private String by; + + /** + * Constructs an Event object with the provided start and end times, and a description. + * + * @param from The starting time of the event. + * @param by The ending time of the event. + * @param description The description of the event. + */ + public Event(String from, String by, String description) { + // call by the superclass (task) constructor + super(description); + this.from = from; + this.by = by; + this.type = 'E'; + } + + /** + * Returns a formatted string representation of the Event object. + * + * @return A string representing the Event. + */ + @Override + public String toString() { + return "[E]" + super.toString() + " (from: " + this.from + " to: " + this.by + ")"; + } +} \ No newline at end of file diff --git a/src/main/java/Tasks/Task.java b/src/main/java/Tasks/Task.java new file mode 100644 index 000000000..dd5b38432 --- /dev/null +++ b/src/main/java/Tasks/Task.java @@ -0,0 +1,123 @@ +package Tasks; + +/** + * The Task class represents a basic task with a description and completion status. + * It serves as the superclass for various types of tasks (Todo, Deadline, Event). + */ +public class Task { + protected String description; + protected boolean isDone; + protected char type; + protected static int numTasks = 0; + + public Task(String description) { + this.description = description; + this.isDone = false; + this.type = 'T'; + numTasks++; + } + + /** + * Returns the completion status icon for the task. + * + * @return The completion status icon ("X" for completed, " " for incomplete). + */ + public String getStatusIcon() { + return (isDone ? "X" : " "); + } + + /** + * Returns the total number of tasks created. + * + * @return The total number of tasks. + */ + public static int getNumTasks() { + return numTasks; + } + + /** + * Returns the description of the task. + * + * @return The description of the task. + */ + public String getDescription() { + return this.description; + } + + /** + * Checks if the task is marked as done. + * + * @return True if the task is marked as done, false otherwise. + */ + public boolean isDone() { + return this.isDone; + } + + /** + * Marks the task as done and prints a completion message. + */ + public void setDone() { + this.isDone = true; + } + + /** + * Sets the type of the task (T for Todo, D for Deadline, E for Event). + * + * @param letter The type of task. + */ + public void setType(char letter) { + this.type = letter; + } + + /** + * Constructs a Task object with the provided description. + * + * @param description The description of the task. + */ + + + /** + * Unmarks a completed task and prints a message. + */ + public void unmarkTask() { + this.isDone = false; + System.out.println("Nice! I've unmarked this task:\n\t " + this); + + } + + /** + * Returns a formatted string representation of the Task object. + * + * @return A string representing the Task. + */ + @Override + public String toString() { + return "[" + this.getStatusIcon() + "] " + this.getDescription(); + } + + /** + * Prints a number of tasks. + */ + public void printNewTask() { + System.out.print("Got it. I've added this task:\n" + this + "\nNow you have " + getNumTasks()); + if (getNumTasks() > 1) { + System.out.println(" tasks in the list."); + } else { + System.out.println(" task in the list."); + } + } + /** + * Prints the task that is going to be deleted. + */ + public void printDeleteTask() { + System.out.println("_____________________________________________________"); + numTasks--; + System.out.print("Noted. I have removed this task:\n " + this + "\nNow you have " + (getNumTasks())); + if (numTasks > 1) { + System.out.println(" tasks in the list."); + } else { + System.out.println(" task in the list."); + } + System.out.println("_____________________________________________________"); + } +} diff --git a/src/main/java/Tasks/Todo.java b/src/main/java/Tasks/Todo.java new file mode 100644 index 000000000..eec26511d --- /dev/null +++ b/src/main/java/Tasks/Todo.java @@ -0,0 +1,29 @@ +package Tasks; + +import Tasks.Task; + +/** + * The Todo class represents a task without a specific due date or time. + * It is a subclass of the Task class. + */ +public class Todo extends Task { + /** + * Constructs a Todo object with the provided description. + * + * @param description The description of the todo task. + */ + public Todo(String description) { + super(description); + } + + /** + * Returns a formatted string representation of the Todo object. + * + * @return A string representing the Todo task. + */ + @Override + public String toString() { + return "[T]" + super.toString(); + } + +} diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java new file mode 100644 index 000000000..0585584c3 --- /dev/null +++ b/src/main/java/Ui.java @@ -0,0 +1,46 @@ +import Tasks.*; +import java.util.ArrayList; + +/** + * The Ui class manages user interface interactions and messages. + */ +public class Ui { + /** + * Displays a welcome message to the user. + */ + public void showWelcomeMessage() { + System.out.println("Hey! I'm Dukey, your virtual assistant!\nWhat can I do for you?"); + } + + /** + * Displays an exit message to the user. + */ + public static void showExitMessage() { + System.out.println("Bye. Hope to see you again soon!\n"); + } + + /** + * Outputs a header for the task list. + */ + public static void outputHeader() { + printLine(); + System.out.println("Here are the matching tasks in your list:\n"); + } + + /** + * Prints a visual line separator. + */ + public static void printLine() { + System.out.println("_____________________________________________________"); + } + + /** + * Shows an error message when loading tasks from a file. + */ + public static void showLoadingError() { + System.out.println("Error loading tasks from text file to Dukey"); + } + + +} +