diff --git a/README.md b/README.md index 8715d4d91..c397df57e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Duke project template +# Duke project template :) -This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it. +This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it. :) ## Setting up in Intellij diff --git a/caraData.txt b/caraData.txt new file mode 100644 index 000000000..e69de29bb diff --git a/docs/README.md b/docs/README.md index 8077118eb..ad2e767c4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,126 @@ -# User Guide +# User Guide of Cara +Cara: a fun and friendly task management bot that helps you to organise your task efficiently and easily :) -## Features +### Task Management +- **Add Tasks**: Easily add different task types to your to-do list, such as Todo, Deadline, and Event. +- **Mark Tasks as Done**: Mark tasks as completed when you've finished them. +- **Delete Tasks**: Remove tasks that you no longer need. +- **List Tasks**: View a list of all your tasks. +- **Find Tasks**: Search for specific tasks using keywords. -### Feature-ABC +## Features -Description of the feature. +### 1. Add Todo Task - `todo` -### Feature-XYZ +Add a todo task to the tasklist -Description of the feature. +Format: `todo DESCRIPTION` -## Usage +Example of usage: + +``` +todo buy book +todo return money +``` -### `Keyword` - Describe action +### 2. Add Deadline Task - `deadline` -Describe the action and its outcome. +Add a deadline task to the tasklist, with a date to complete by + +Format: `deadline DESCRIPTION /by DEADLINE` Example of usage: -`keyword (optional arguments)` +``` +Deadline do homework /by 8 nov 2023 +``` + +### 3. Add Event Task - `event` -Expected outcome: +Add an event task to the tasklist, with a start and end time -Description of the outcome. +Format: `event DESCRIPTION /from STARTTIME /to ENDTIME` + +Example of usage: ``` -expected output +event concert /from 6pm /to 9pm ``` + +### 4. Delete Task - `delete` + +Delete a task from the tasklist base on index + +Format: `delete INDEX` + +- The index refers to the index number shown in the tasklist +- the index **must be a positive integer** 1,2,3... + +Example of usage: + +``` +delete 5 +``` + +### 5. List Task - `list` + +Shows a list of all tasks in the list + +Format: `list` + +Example of usage: + +``` +list +``` + +### 6. Find Task - `find` + +Find tasks that contains any of the keywords + +Format: `find KEYWORD` + +- The search is case-insensitive, e.g `Book` will match `book` + +Example of usage: + +``` +find book +``` + +### 7. Mark Task - `mark` + +Mark a task as done based on their index + +Format: `mark INDEX` + +Example of usage: + +``` +mark 1 +``` + +### 8. Unmark Task - `unmark` + +Mark a task as not done based on their index + +Format: `unmark INDEX` + +Example of usage: + +``` +unmark 1 +``` + +### 9. Ending the program - `bye` + +Exits the program + +Format: `bye` + +Example of usage: + +``` +bye +``` + diff --git a/src/main/java/Cara/Cara.java b/src/main/java/Cara/Cara.java new file mode 100644 index 000000000..fff796777 --- /dev/null +++ b/src/main/java/Cara/Cara.java @@ -0,0 +1,67 @@ +package Cara; + +import Commands.Command; +import Tasks.TaskList; + +import java.io.IOException; + +/** + * Duke is a task management program that allows users to manage their tasks. + * It provides functionality for adding, deleting, and listing tasks. + */ +public class Cara { + private Ui ui; + private TaskList tasks; + private Storage storage; + + /** + * Constructs a Duke instance with the specified file path. + * + * @param filePath The path to the file used for task storage. + * @throws CaraException If there is an issue initializing Duke. + */ + public Cara(String filePath) throws CaraException { + ui = new Ui(); + storage = new Storage(filePath); + try { + tasks = new TaskList(storage.loadTasks()); + } catch (CaraException | IOException e) { + ui.showLoadingError(); + tasks = new TaskList(); + } + } + + /** + * Runs the Duke program, handling user input and executing commands. + */ + public void run() { + ui.printWelcomeMessage(); + boolean isExit = false; + + while (!isExit) { + try { + String fullCommand = ui.readCommand(); + ui.showLine(); + Command c = Parser.parse(fullCommand); + c.execute(tasks.getTasks(), ui, storage); + isExit = c.isExit(); + Storage.saveTasks(tasks.getTasks()); + } catch (IOException | CaraException e) { + ui.showError(e.getMessage()); + } finally { + ui.showLine(); + } + } + } + + /** + * The main entry point for running the Duke program. + * + * @param args The command-line arguments (not used in this program). + * @throws IOException If an I/O error occurs. + * @throws CaraException If there is an issue with Duke initialization. + */ + public static void main(String[] args) throws IOException, CaraException { + new Cara("data/tasks.txt").run(); + } +} diff --git a/src/main/java/Cara/CaraException.java b/src/main/java/Cara/CaraException.java new file mode 100644 index 000000000..63cd3c0d6 --- /dev/null +++ b/src/main/java/Cara/CaraException.java @@ -0,0 +1,16 @@ +package Cara; + +/** + * DukeException is a custom exception class used to represent exceptions specific to the Duke program. + */ +public class CaraException extends Exception { + + /** + * Constructs a DukeException with the specified error message. + * + * @param message The error message associated with the exception. + */ + public CaraException(String message) { + super(message); + } +} diff --git a/src/main/java/Cara/Parser.java b/src/main/java/Cara/Parser.java new file mode 100644 index 000000000..62debbd8d --- /dev/null +++ b/src/main/java/Cara/Parser.java @@ -0,0 +1,43 @@ +package Cara; + +import Commands.*; + +/** + * The Parser class is responsible for parsing user input and generating corresponding commands. + */ +public class Parser { + + /** + * Parses the user input and returns the corresponding command. + * + * @param input The user input to be parsed. + * @return A Command object based on the parsed input. + * @throws CaraException If there is an issue with parsing the input. + */ + public static Command parse(String input) throws CaraException { + // Split the input into words + String[] words = input.split(" "); + String command = words[0].toLowerCase(); // Extract the first word as the command + + switch (command) { + case "bye": + return new ExitCommand(); // Create an ExitCommand + case "list": + return new ListCommand(); // Create a ListCommand + case "mark": + return new MarkCommand(input); // Create a MarkCommand with the input as a parameter + case "unmark": + return new UnmarkCommand(input); // Create an UnmarkCommand with the input as a parameter + case "delete": + return new DeleteCommand(input); // Create a DeleteCommand with the input as a parameter + case "find": + return new FindCommand(input); // Create a FindCommand with the input as a parameter + case "todo": + case "event": + case "deadline": + return new AddCommand(input); //Create a AddCommand with the input as a parameter + default: + throw new CaraException(" ☹ OOPS!!! I'm sorry, but I don't know what that means :-("); + } + } +} diff --git a/src/main/java/Cara/Storage.java b/src/main/java/Cara/Storage.java new file mode 100644 index 000000000..d20f99d4f --- /dev/null +++ b/src/main/java/Cara/Storage.java @@ -0,0 +1,44 @@ +package Cara; + +import Tasks.Task; +import Tasks.TasksHandler; + +import java.io.*; +import java.util.ArrayList; + +/** + * The Storage class is responsible for loading and saving tasks from/to a file. + */ +public class Storage { + + /** + * Constructs a Storage instance with the specified file path (ignored). + * + * @param ignoredFilePath The path to the file (ignored). + */ + public Storage(String ignoredFilePath) { + } + + /** + * Loads tasks from a file and returns them as an ArrayList. + * + * @return An ArrayList of tasks loaded from the file. + * @throws IOException If an I/O error occurs during file reading. + * @throws CaraException If there is an issue with Duke while reading the file. + */ + public ArrayList loadTasks() throws IOException, CaraException { + ArrayList tasks = new ArrayList<>(); + TasksHandler.readFromFile(tasks); // Pass an ArrayList to the readFromFile() method + return tasks; + } + + /** + * Saves tasks to a file. + * + * @param tasks The ArrayList of tasks to be saved to the file. + * @throws IOException If an I/O error occurs during file writing. + */ + public static void saveTasks(ArrayList tasks) throws IOException { + TasksHandler.writeToFile(tasks); // Pass the provided ArrayList to the writeToFile method + } +} diff --git a/src/main/java/Cara/Ui.java b/src/main/java/Cara/Ui.java new file mode 100644 index 000000000..736c76feb --- /dev/null +++ b/src/main/java/Cara/Ui.java @@ -0,0 +1,77 @@ +package Cara; + +import java.util.Scanner; + +/** + * The Ui class is responsible for handling user interaction. + * It provides methods to read user input and display messages. + */ +public class Ui { + private final Scanner scanner; + + /** + * Constructs an Ui object with a Scanner for reading user input. + */ + public Ui() { + + this.scanner = new Scanner(System.in); + } + + /** + * Reads a command entered by the user. + * + * @return The command entered by the user as a string. + */ + public String readCommand() { + return scanner.nextLine(); + } + + /** + * Prints a welcome message when the program starts. + */ + public void printWelcomeMessage() { + System.out.println("____________________________________________________________"); + System.out.println("Hello! I'm"); + System.out.println(" ________ ________ ________ ________ \n" + + "|\\ ____\\|\\ __ \\|\\ __ \\|\\ __ \\ \n" + + "\\ \\ \\___|\\ \\ \\|\\ \\ \\ \\|\\ \\ \\ \\|\\ \\ \n" + + " \\ \\ \\ \\ \\ __ \\ \\ _ _\\ \\ __ \\ \n" + + " \\ \\ \\____\\ \\ \\ \\ \\ \\ \\\\ \\\\ \\ \\ \\ \\ \n" + + " \\ \\_______\\ \\__\\ \\__\\ \\__\\\\ _\\\\ \\__\\ \\__\\\n" + + " \\|_______|\\|__|\\|__|\\|__|\\|__|\\|__|\\|__|\n" + + " "); + System.out.println("What can I do for you?"); + } + + /** + * Prints a goodbye message when the program exits. + */ + public void printByeMessage() { + System.out.println("Bye! Hope to see you again soon!"); + } + + /** + * Throws a DukeException with an error message for loading errors. + * + * @throws CaraException If there is an error loading tasks from a file. + */ + public void showLoadingError() throws CaraException { + throw new CaraException("Error reading from file. Unable to load tasks."); + } + + /** + * Prints a horizontal line separator. + */ + public void showLine() { + System.out.println("____________________________________________________________"); + } + + /** + * Displays an error message to the user. + * + * @param errorMessage The error message to be displayed. + */ + public void showError(String errorMessage) { + System.out.println(errorMessage); + } +} diff --git a/src/main/java/Commands/AddCommand.java b/src/main/java/Commands/AddCommand.java new file mode 100644 index 000000000..6d61dfec8 --- /dev/null +++ b/src/main/java/Commands/AddCommand.java @@ -0,0 +1,46 @@ +package Commands; + +import Cara.*; +import Tasks.Task; +import Tasks.TaskList; + +import java.util.ArrayList; + +/** + * Represents a command to add a task to the task list. + */ +public class AddCommand implements Command { + private final String input; + + /** + * Constructs an AddCommand with the given input. + * + * @param input The input string representing the task to be added. + */ + public AddCommand(String input) { + this.input = input; + } + + /** + * Executes the AddCommand by adding the task to the task list. + * + * @param tasks The list of tasks. + * @param ui The user interface. + * @param storage The storage manager. + * @throws CaraException If an error occurs during task addition. + */ + @Override + public void execute(ArrayList tasks, Ui ui, Storage storage) throws CaraException { + TaskList.addTaskToList(input, tasks); + } + + /** + * Indicates whether this command triggers program exit. + * + * @return False because this command does not indicate program exit. + */ + @Override + public boolean isExit() { + return false; + } +} diff --git a/src/main/java/Commands/Command.java b/src/main/java/Commands/Command.java new file mode 100644 index 000000000..8e62ba568 --- /dev/null +++ b/src/main/java/Commands/Command.java @@ -0,0 +1,32 @@ +package Commands; + +import Cara.CaraException; +import Cara.Storage; +import Tasks.Task; +import Cara.Ui; + +import java.util.ArrayList; + +/** + * The Command interface represents an action that can be executed by Duke. + * Implementing classes should define the behavior of the execute method. + */ +public interface Command { + + /** + * Executes the command with the given parameters. + * + * @param tasks The list of tasks. + * @param ui The user interface. + * @param storage The storage manager. + * @throws CaraException If an error occurs during command execution. + */ + void execute(ArrayList tasks, Ui ui, Storage storage) throws CaraException; + + /** + * Checks if this command indicates program exit. + * + * @return True if the command indicates program exit, false otherwise. + */ + boolean isExit(); +} diff --git a/src/main/java/Commands/DeleteCommand.java b/src/main/java/Commands/DeleteCommand.java new file mode 100644 index 000000000..870d0b77f --- /dev/null +++ b/src/main/java/Commands/DeleteCommand.java @@ -0,0 +1,46 @@ +package Commands; + +import Cara.*; +import Tasks.Task; +import Tasks.TaskList; + +import java.util.ArrayList; + +/** + * Represents a command to delete a task from the task list. + */ +public class DeleteCommand implements Command { + private final String input; + + /** + * Constructs a DeleteCommand with the given input. + * + * @param input The input string representing the task to be deleted. + */ + public DeleteCommand(String input) { + this.input = input; + } + + /** + * Executes the DeleteCommand by deleting the task from the task list. + * + * @param tasks The list of tasks. + * @param ui The user interface. + * @param storage The storage manager. + * @throws CaraException If an error occurs during task deletion. + */ + @Override + public void execute(ArrayList tasks, Ui ui, Storage storage) throws CaraException { + TaskList.deleteTask(input, tasks); + } + + /** + * Indicates whether this command triggers program exit. + * + * @return False because this command does not indicate program exit. + */ + @Override + public boolean isExit() { + return false; + } +} diff --git a/src/main/java/Commands/ExitCommand.java b/src/main/java/Commands/ExitCommand.java new file mode 100644 index 000000000..150ae9a65 --- /dev/null +++ b/src/main/java/Commands/ExitCommand.java @@ -0,0 +1,36 @@ +package Commands; + +import Cara.Storage; +import Tasks.Task; +import Cara.Ui; + +import java.util.ArrayList; + +/** + * Represents a command to exit the Duke program. + * The "bye" command is used to terminate the program. + */ +public class ExitCommand implements Command { + + /** + * Executes the ExitCommand by displaying a farewell message. + * + * @param tasks The list of tasks (not used in this command). + * @param ui The user interface. + * @param storage The storage manager (not used in this command). + */ + @Override + public void execute(ArrayList tasks, Ui ui, Storage storage) { + ui.printByeMessage(); + } + + /** + * Checks if this command indicates program exit. + * + * @return True because this command indicates program exit. + */ + @Override + public boolean isExit() { + return true; + } +} diff --git a/src/main/java/Commands/FindCommand.java b/src/main/java/Commands/FindCommand.java new file mode 100644 index 000000000..335193d6d --- /dev/null +++ b/src/main/java/Commands/FindCommand.java @@ -0,0 +1,46 @@ +package Commands; + +import Cara.*; +import Tasks.Task; +import Tasks.TaskList; + +import java.util.ArrayList; + +/** + * Represents a command to find tasks in the task list that match a specific keyword. + */ +public class FindCommand implements Command { + private final String input; + + /** + * Constructs a FindCommand with the given keyword to search for. + * + * @param input The keyword to search for in the task list. + */ + public FindCommand(String input) { + this.input = input; + } + + /** + * Executes the FindCommand by searching for tasks that match the keyword. + * + * @param tasks The list of tasks. + * @param ui The user interface. + * @param storage The storage manager (not used in this command). + * @throws CaraException If an error occurs during the task search. + */ + @Override + public void execute(ArrayList tasks, Ui ui, Storage storage) throws CaraException { + TaskList.findTask(input, tasks); + } + + /** + * Checks if this command indicates program exit. + * + * @return False because this command does not indicate program exit. + */ + @Override + public boolean isExit() { + return false; + } +} diff --git a/src/main/java/Commands/ListCommand.java b/src/main/java/Commands/ListCommand.java new file mode 100644 index 000000000..b69deabce --- /dev/null +++ b/src/main/java/Commands/ListCommand.java @@ -0,0 +1,36 @@ +package Commands; + +import Cara.Storage; +import Tasks.Task; +import Tasks.TaskList; +import Cara.Ui; + +import java.util.ArrayList; + +/** + * Represents a command to list all tasks in the task list. + */ +public class ListCommand implements Command { + + /** + * Executes the ListCommand by displaying the list of tasks. + * + * @param tasks The list of tasks to be displayed. + * @param ui The user interface. + * @param storage The storage manager (not used in this command). + */ + @Override + public void execute(ArrayList tasks, Ui ui, Storage storage) { + TaskList.printList(tasks); // Display the list of tasks using TaskList.printList + } + + /** + * Checks if this command indicates program exit. + * + * @return False because this command does not indicate program exit. + */ + @Override + public boolean isExit() { + return false; + } +} diff --git a/src/main/java/Commands/MarkCommand.java b/src/main/java/Commands/MarkCommand.java new file mode 100644 index 000000000..0d2e13508 --- /dev/null +++ b/src/main/java/Commands/MarkCommand.java @@ -0,0 +1,46 @@ +package Commands; + +import Cara.*; +import Tasks.Task; +import Tasks.TaskList; + +import java.util.ArrayList; + +/** + * Represents a command to mark a task as completed in the task list. + */ +public class MarkCommand implements Command { + private final String input; + + /** + * Constructs a MarkCommand with the given input. + * + * @param input The input string representing the task to be marked as completed. + */ + public MarkCommand(String input) { + this.input = input; + } + + /** + * Executes the MarkCommand by marking the specified task as completed. + * + * @param tasks The list of tasks. + * @param ui The user interface. + * @param storage The storage manager (not used in this command). + * @throws CaraException If an error occurs during task marking. + */ + @Override + public void execute(ArrayList tasks, Ui ui, Storage storage) throws CaraException { + TaskList.markTask(input, tasks); + } + + /** + * Checks if this command indicates program exit. + * + * @return False because this command does not indicate program exit. + */ + @Override + public boolean isExit() { + return false; + } +} diff --git a/src/main/java/Commands/UnmarkCommand.java b/src/main/java/Commands/UnmarkCommand.java new file mode 100644 index 000000000..5500025a0 --- /dev/null +++ b/src/main/java/Commands/UnmarkCommand.java @@ -0,0 +1,47 @@ +package Commands; + +import Cara.*; +import Tasks.Task; +import Tasks.TaskList; + +import java.util.ArrayList; + +/** + * The UnmarkCommand class represents a command to unmark a task as done. + * It implements the Command interface. + */ +public class UnmarkCommand implements Command { + private final String input; + + /** + * Constructs an UnmarkCommand with the specified input. + * + * @param input The input string that specifies the task to be unmarked. + */ + public UnmarkCommand(String input) { + this.input = input; + } + + /** + * Executes the UnmarkCommand to unmark a task as done. + * + * @param tasks The list of tasks to be operated on. + * @param ui The user interface for displaying messages. + * @param storage The storage for saving tasks to a file. + * @throws CaraException If there is an error during the unmarking process. + */ + @Override + public void execute(ArrayList tasks, Ui ui, Storage storage) throws CaraException { + TaskList.unmarkTask(input, tasks); + } + + /** + * Indicates whether this command represents a program exit. + * + * @return False, as this command does not indicate program exit. + */ + @Override + public boolean isExit() { + return false; + } +} diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java deleted file mode 100644 index 5d313334c..000000000 --- a/src/main/java/Duke.java +++ /dev/null @@ -1,10 +0,0 @@ -public class Duke { - public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - } -} diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 000000000..4c200a150 --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: Cara.Cara + diff --git a/src/main/java/Tasks/DeadlineTask.java b/src/main/java/Tasks/DeadlineTask.java new file mode 100644 index 000000000..f61f073c1 --- /dev/null +++ b/src/main/java/Tasks/DeadlineTask.java @@ -0,0 +1,59 @@ +package Tasks; + +/** + * Represents a task with a deadline, which is a subclass of Task. + */ +public class DeadlineTask extends Task { + private final String by; + + /** + * Constructs a DeadlineTask with the given description. + * + * @param description The description of the task, including the deadline (if provided). + */ + public DeadlineTask(String description) { + super(description); + this.by = this.extractDeadline(description); + } + + private String deadlineDescription(String description){ + int byIndex = description.indexOf("/by"); + if(byIndex != -1){ + return description.substring(0, byIndex).trim(); + } + return description.trim(); // If "/by" is not found, return the whole description + } + + /** + * Extracts the deadline from the task description. + * + * @param description The description of the task. + * @return The extracted deadline or "No Deadline" if not found. + */ + private String extractDeadline(String description) { + int index = description.indexOf("/by"); + return index != -1 ? description.substring(index + 3).trim() : "No Deadline"; + } + + /** + * Gets the deadline associated with this task. + * + * @return The deadline string. + */ + public String getBy() { + return by; + } + + /** + * Returns a string representation of the DeadlineTask. + * + * @return A string representation in the format: "[D][TaskDescription] (by: [Deadline])". + */ + + public String getDeadlineDescription(){ + return deadlineDescription(super.getDescription()); + } + public String toString() { + return "[D]" + "[" + getStatusIcon() + "] " + this.getDeadlineDescription() + " (by: " + this.by + ")"; + } +} diff --git a/src/main/java/Tasks/EventTask.java b/src/main/java/Tasks/EventTask.java new file mode 100644 index 000000000..d2c46fe24 --- /dev/null +++ b/src/main/java/Tasks/EventTask.java @@ -0,0 +1,105 @@ +package Tasks; + +/** + * Represents a task that is an event, which is a subclass of Task. + */ +public class EventTask extends Task { + private final String from; + private final String to; + + /** + * Constructs an EventTask with the given description. + * + * @param description The description of the event task, including start and end dates (if provided). + */ + public EventTask(String description) { + super(description); + this.from = this.extractFromDate(description); + this.to = this.extractToDate(description); + } + + /** + * Extracts the part of the description before "/from" if "/from" is found, + * otherwise, it extracts the part of the description before "/to" if "/to" is found, + * or returns the full description if neither "/from" nor "/to" is found. + * + * @param description The description of the event task. + * @return The extracted part of the description based on the conditions. + */ + private String eventDescription(String description) { + int fromIndex = description.indexOf("/from"); + int toIndex = description.indexOf("/to"); + + if (fromIndex != -1) { + return description.substring(0, fromIndex).trim(); + } else if (toIndex != -1) { + return description.substring(0, toIndex).trim(); + } else { + return description.trim(); + } + } + + /** + * Extracts the start date from the task description. + * + * @param description The description of the event task. + * @return The extracted start date or "No Start Date" if not found. + */ + private String extractFromDate(String description) { + int fromIndex = description.indexOf("/from"); + if (fromIndex != -1) { + int toIndex = description.indexOf("/to"); + if (toIndex != -1 && toIndex > fromIndex) { + return description.substring(fromIndex + 5, toIndex).trim(); + } else { + // If there is "/from" but no "/to," return the portion after "/from." + return description.substring(fromIndex + 5).trim(); + } + } + return "No Start Date"; + } + + + /** + * Extracts the end date from the task description. + * + * @param description The description of the event task. + * @return The extracted end date or "No End Date" if not found. + */ + private String extractToDate(String description) { + int toIndex = description.indexOf("/to"); + return toIndex != -1 ? description.substring(toIndex + 3).trim() : "No End Date"; + } + + /** + * Gets the start date of the event. + * + * @return The start date string. + */ + public String getFrom() { + return from; + } + + /** + * Gets the end date of the event. + * + * @return The end date string. + */ + public String getTo() { + return to; + } + + /** + * Returns a string representation of the EventTask. + * + * @return A string representation in the format: "[E][TaskDescription] (from: [Start Date] to: [End Date])". + */ + public String getEventDescription() { + return eventDescription(super.getDescription()); + } + + public String toString() { + return "[E]" + "[" + getStatusIcon() + "] " + this.getEventDescription() + " (from: " + this.from + " to: " + this.to + ")"; + } + +} diff --git a/src/main/java/Tasks/Task.java b/src/main/java/Tasks/Task.java new file mode 100644 index 000000000..bf4e1742b --- /dev/null +++ b/src/main/java/Tasks/Task.java @@ -0,0 +1,70 @@ +package Tasks; + +/** + * The Task class represents a task with a description and completion status. + */ +public class Task { + private final String description; + private boolean isDone; + + /** + * Constructs a Task with the specified description. + * + * @param description The description of the task. + */ + public Task(String description) { + this.description = description; + this.isDone = false; // Set initial completion to false + } + + /** + * Marks the task as done. + */ + public void markAsDone() { + isDone = true; + } + + /** + * Marks the task as not done. + */ + public void markAsNotDone() { + isDone = false; + } + + /** + * Gets the description of the task. + * + * @return The description of the task. + */ + public String getDescription() { + return description; + } + + /** + * Checks if the task is done. + * + * @return True if the task is done, false otherwise. + */ + public boolean isDone() { + return isDone; + } + + /** + * Gets the status icon for the task. + * + * @return "X" if the task is done, " " (a space) if the task is not done. + */ + public String getStatusIcon() { + return (isDone ? "X" : " "); + } + + /** + * Returns a string representation of the task. + * + * @return A string in the format: "[status icon] description". + */ + @Override + public String toString() { + return "[" + getStatusIcon() + "] " + description; + } +} diff --git a/src/main/java/Tasks/TaskList.java b/src/main/java/Tasks/TaskList.java new file mode 100644 index 000000000..47b43431b --- /dev/null +++ b/src/main/java/Tasks/TaskList.java @@ -0,0 +1,176 @@ +package Tasks; + +import Cara.CaraException; + +import java.util.ArrayList; + +/** + * The TaskList class extends ArrayList and represents a list of tasks. + */ +public class TaskList extends ArrayList { + + private final ArrayList tasks; + + /** + * Constructs an empty TaskList. + */ + public TaskList() { + tasks = new ArrayList<>(); + } + + /** + * Constructs a TaskList with the specified list of tasks. + * + * @param tasks The list of tasks to initialize the TaskList. + */ + public TaskList(ArrayList tasks) { + this.tasks = tasks; + } + + /** + * Adds a task to the task list based on the given input. + * + * @param line The input string representing the task to be added. + * @param tasks The list of tasks to which the new task is added. + * @throws CaraException If there is an issue with adding the task. + */ + public static void addTaskToList(String line, ArrayList tasks) throws CaraException { + String[] parts = line.split(" ", 2); + String command = parts[0]; + String taskDescription = parts.length > 1 ? parts[1] : ""; + switch (command) { + case "todo": + if (taskDescription.isEmpty()) { + throw new CaraException("☹ OOPS!!! The description of a todo cannot be empty."); + } + tasks.add(new TodoTask(taskDescription)); + break; + case "deadline": + if (taskDescription.isEmpty()) { + throw new CaraException("☹ OOPS!!! The description of a deadline cannot be empty."); + } + tasks.add(new DeadlineTask(taskDescription)); + break; + case "event": + if (taskDescription.isEmpty()) { + throw new CaraException("☹ OOPS!!! The description of an event cannot be empty."); + } + tasks.add(new EventTask(taskDescription)); + break; + default: + throw new CaraException(" ☹ OOPS!!! I'm sorry, but I don't know what that means :-("); + } + System.out.println("Got it. I've added this task: "); + System.out.println(tasks.get(tasks.size() - 1)); + System.out.println("Now you have " + tasks.size() + " tasks in the list."); + } + + /** + * Deletes a task from the task list based on the given input. + * + * @param line The input string representing the task to be deleted. + * @param tasks The list of tasks from which the task is deleted. + * @throws CaraException If there is an issue with deleting the task. + */ + public static void deleteTask(String line, ArrayList tasks) throws CaraException { + if (line.length() < 8) { + throw new CaraException("Task not found. Please provide a valid task number."); + } + int taskIndex = Integer.parseInt(line.substring(7)) - 1; + if (taskIndex >= 0 && taskIndex < tasks.size()) { + Task removedTask = tasks.remove(taskIndex); + System.out.println("Noted. I've removed this task:\n" + removedTask); + System.out.println("Now you have " + tasks.size() + " tasks in the list."); + } else { + throw new CaraException("Task not found. Please provide a valid task number."); + } + } + + /** + * Unmark a task as done based on the given input. + * + * @param line The input string representing the task to be unmarked. + * @param tasks The list of tasks in which the task is unmarked. + * @throws CaraException If there is an issue with unmarking the task. + */ + public static void unmarkTask(String line, ArrayList tasks) throws CaraException { + if (line.length() < 8) { + throw new CaraException("Task not found. Please provide a valid task number."); + } + int taskIndex = Integer.parseInt(line.substring(7)) - 1; + if (taskIndex >= 0 && taskIndex < tasks.size()) { + Task task = tasks.get(taskIndex); + task.markAsNotDone(); + System.out.println("OK, I've marked this task as not done yet:\n" + task); + } + else { + throw new CaraException("Task not found. Please provide a valid task number."); + } + } + + /** + * Marks a task as done based on the given input. + * + * @param line The input string representing the task to be marked. + * @param tasks The list of tasks in which the task is marked. + * @throws CaraException If there is an issue with marking the task. + */ + public static void markTask(String line, ArrayList tasks) throws CaraException { + if (line.length() < 6) { + throw new CaraException("Task not found. Please provide a valid task number."); + } + int taskIndex = Integer.parseInt(line.substring(5)) - 1; //in the array is 0-based + if (taskIndex >= 0 && taskIndex < tasks.size()) { + Task task = tasks.get(taskIndex); + task.markAsDone(); + System.out.println("Nice! I've marked this task as done:\n" + task); + } + else { + throw new CaraException("Task not found. Please provide a valid task number."); + } + } + + /** + * Prints the list of tasks. + * + * @param tasks The list of tasks to be printed. + */ + public static void printList(ArrayList tasks) { + System.out.println("Here are the tasks in your list:"); + for (int i = 0; i < tasks.size(); i++) { + System.out.println(i + 1 + ". " + tasks.get(i)); + } + } + + /** + * Finds tasks in the list based on the given keyword and prints them. + * + * @param line The input string representing the keyword to search for. + * @param tasks The list of tasks to search within. + * @throws CaraException If there is an issue with finding tasks. + */ + public static void findTask(String line, ArrayList tasks) throws CaraException { + if (line.length() < 6) { + throw new CaraException("Keyword not found. Please provide a valid keyword."); + } + System.out.println("Here are the matching tasks in your list:"); + String keyword = line.substring(5).trim().toLowerCase(); + for (int i = 0; i < tasks.size(); i++) { + Task task = tasks.get(i); //the task object that I want + String taskDescription = task.getDescription().toLowerCase(); + if (taskDescription.contains(keyword)) { + System.out.println(i + 1 + ". " + task); + } + } + } + + /** + * Gets the list of tasks contained within the TaskList. + * + * @return The list of tasks. + */ + public ArrayList getTasks() { + return tasks; + } +} + diff --git a/src/main/java/Tasks/TasksHandler.java b/src/main/java/Tasks/TasksHandler.java new file mode 100644 index 000000000..14c6ea341 --- /dev/null +++ b/src/main/java/Tasks/TasksHandler.java @@ -0,0 +1,92 @@ +package Tasks; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Scanner; + +/** + * The TasksHandler class is responsible for reading and writing tasks to a file. + */ +public class TasksHandler { + + private static final String FILE_PATH = "caraData.txt"; + + /** + * Writes tasks to a file. + * + * @param tasks The list of tasks to be written to the file. + * @throws IOException If an I/O error occurs during file writing. + */ + public static void writeToFile(ArrayList tasks) throws IOException { + FileWriter fileWriter = new FileWriter(FILE_PATH); + for (Task task : tasks) { + if (task instanceof TodoTask) { + fileWriter.write("T | " + task.isDone() + " | " + + task.getDescription() + System.lineSeparator()); + } else if (task instanceof DeadlineTask) { + DeadlineTask deadlineTask = (DeadlineTask) task; // Cast to DeadlineTask + fileWriter.write("D | " + task.isDone() + " | " + + task.getDescription() + " | " + deadlineTask.getBy() + System.lineSeparator()); + } else if (task instanceof EventTask) { + EventTask eventTask = (EventTask) task; // Cast to EventTask + fileWriter.write("E | " + task.isDone() + " | " + task.getDescription() + " | " + + eventTask.getFrom() + " | " + eventTask.getTo() + System.lineSeparator()); + } + } + fileWriter.close(); + } + + /** + * Reads tasks from a file and populates the tasks list. + * + * @param tasks The list of tasks to be populated with tasks from the file. + * @throws IOException If an I/O error occurs during file reading. + */ + public static void readFromFile(ArrayList tasks) throws IOException { + File file = new File(FILE_PATH); + boolean fileCreated = false; + + if (!file.exists()) { + fileCreated = file.createNewFile(); + } + + if (fileCreated || file.exists()) { + Scanner scanner = new Scanner(file); // Initialize the scanner + while (scanner.hasNext()) { + String line = scanner.nextLine(); + String[] lineArray = line.split("\\|"); + + Task task = null; + switch (lineArray[0].trim()) { + case "T": + task = new TodoTask(lineArray[2].trim()); + break; + case "D": + task = new DeadlineTask(lineArray[2].trim()); + break; + case "E": + task = new EventTask(lineArray[2].trim()); + break; + } + + if (task != null) { + // Parse the "done" status as a boolean + boolean isDone = lineArray[1].trim().equals("true"); + if (isDone) { + task.markAsDone(); + } + tasks.add(task); + } else { + // Handle the case where there was an issue creating the task + System.err.println("Error: Unable to create a task from input line: " + line); + } + } + scanner.close(); // Close the scanner + } else { + // Handle the case where the file couldn't be created or opened. + System.err.println("Error: Unable to create or access the file."); + } + } +} diff --git a/src/main/java/Tasks/TodoTask.java b/src/main/java/Tasks/TodoTask.java new file mode 100644 index 000000000..f0d5f1975 --- /dev/null +++ b/src/main/java/Tasks/TodoTask.java @@ -0,0 +1,29 @@ +package Tasks; + +import Tasks.Task; + +/** + * The TodoTask class represents a task of type "Todo." + * It extends the Task class and inherits its properties and methods. + */ +public class TodoTask extends Task { + /** + * Constructs a TodoTask with the specified description. + * + * @param description The description of the task. + */ + public TodoTask(String description) { + super(description); + } + + /** + * Returns a string representation of the TodoTask. + * The format is "[T] [status icon] description." + * + * @return A string representing the TodoTask. + */ + @Override + public String toString() { + return "[T]" + super.toString(); + } +}