diff --git a/data/duke.txt b/data/duke.txt new file mode 100644 index 000000000..84066e73c --- /dev/null +++ b/data/duke.txt @@ -0,0 +1,2 @@ +1|T|0|read book +2|D|1|return book|2022-06-06|1700 diff --git a/docs/README.md b/docs/README.md index 8077118eb..e3d56258b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,93 @@ # User Guide +Duke is a chat-bot that manages your tasks. It is accessed via a Command Line Interface (CLI). -## Features +##Quick start +1. Ensure that you have **Java 11** installed on your system. +2. Download the latest [ip.jar](https://github.com/cheshire-doge/ip/releases/tag/A-Release) +3. Open a **Command Line** and change your directory to the folder containing **ip.jar** +4. Enter `java -jar ip.jar` to start Duke +5. Refer to **Usage** below or enter `commands` into the Command Line to view commands. -### Feature-ABC +## Features -Description of the feature. +### Storing of Tasks `ToDo`, `Deadline`, `Event` -### Feature-XYZ +**ToDos** are tasks that do not have a date they have to be accomplished by. -Description of the feature. +**Deadlines** are tasks that have a deadline they have to be accomplished by. + +**Events** are tasks that run for a period of time, with a starting time and ending time. + +### Mark/Unmark Tasks + +Mark or Unmark tasks to remind you if you have completed them. + +### Find Tasks + +Search for tasks using specific keywords. + +### Other Features! + +**Delete**, **Check Date**, **List** ## Usage -### `Keyword` - Describe action +### `todo` - Creates a ToDo + +Example: + +`todo DESCRIPTION` - Adds a ToDo with DESCRIPTION onto the task list + +``` +todo Groceries +____________________________________________________________ +Got it. I've added this task: + [T][ ] Groceries +Now you have 1 tasks in the list. +``` -Describe the action and its outcome. +### `deadline` - Creates a Deadline -Example of usage: +`deadline DESCRIPTION /by DD/MM/YYYY time` - Adds a deadline with DESCRIPTION and deadline -`keyword (optional arguments)` +``` +deadline iP /by 03/03/2022 2359 +____________________________________________________________ +Got it. I've added this task: + [D][ ] iP (by: Mar 3 2022 2359) +Now you have 6 tasks in the list. +``` -Expected outcome: +### `event` - Creates an Event -Description of the outcome. +`event DESCRIPTION /at DD/MM/YYYY time /to DD/MM/YYYY time` - Adds an event with DESCRIPTION, start time and end time. ``` -expected output +event Project Meeting /at 05/03/2022 2000 /to 05/03/2022 2200 +____________________________________________________________ +Got it. I've added this task: + [E][ ] Project Meeting (at: Mar 5 2022 2000 to Mar 5 2022 2200) +Now you have 3 tasks in the list. ``` + +### `list` - Lists out all tasks + +`list` - All tasks will be listed down + +### `mark`/`unmark` `NUMBER` - marks/unmarks task NUMBER in the list + +`mark 3` - Task 3 in the list would be marked + +### `find KEYWORD` - searches the list based on KEYWORD + +`find project` - Lists down every Task in the list containing `project` + +### `check date DD/MM/YYYY` - checks the list if any task is due or happens on that day +`check date 04/03/2021` - Checks if any task happens or is due on 04/03/2021 + +### `delete NUMBER` - deletes task NUMBER in the list +`delete 1` - Deletes the first task on the list + +### `bye` - closes the bot + +### `commands` - lists down all commands \ No newline at end of file diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java deleted file mode 100644 index 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..8f308fd8e --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: main.java.duke.Duke + diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java new file mode 100644 index 000000000..3935ad4e9 --- /dev/null +++ b/src/main/java/duke/Duke.java @@ -0,0 +1,61 @@ +package main.java.duke; + +import java.util.Scanner; +import java.io.IOException; +import java.util.ArrayList; +import main.java.duke.ui.Ui; +import main.java.duke.parser.Parser; +import main.java.duke.command.Command; +import main.java.duke.task.Task; +import main.java.duke.exception.DukeException; +import main.java.duke.storage.Storage; + +/** + * Main class for Duke that runs the bot. The bot takes in user inputs, and has various commands + * that would perform various tasks + */ + +public class Duke { + + private static Scanner sc = new Scanner(System.in); + public static ArrayList tasks = new ArrayList(); + public static int taskCounter = 0; + private final Parser parser = new Parser(); + + /** + * Main method used to run the bot. It calls the load() method from the Storage class to + * load data saved from previous uses, will ask for user inputs, will call the writeToFile() + * method from Storage to update the latest information. + */ + private void run() { + try { + Storage.load(); + } catch (IOException e) { + System.out.println("ERROR IN LOADING FILE"); + } catch (DukeException e) { + System.out.println(e.getMessage()); + return; + } + Ui.printIntro(); + String input = ""; + while (!input.equals("bye")) { + try { + input = sc.nextLine(); + Command command = parser.parse(input); + command.execute(); + } catch (DukeException e) { + Ui.printError(e); + } + } + + } + + /** + * Main method for Duke. + * + * @param args NIL. + */ + public static void main(String[] args) { + new Duke().run(); + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/ByeCommand.java b/src/main/java/duke/command/ByeCommand.java new file mode 100644 index 000000000..01c962305 --- /dev/null +++ b/src/main/java/duke/command/ByeCommand.java @@ -0,0 +1,25 @@ +package main.java.duke.command; + +import java.io.IOException; +import main.java.duke.ui.Ui; +import main.java.duke.storage.Storage; + +/** + * Class for ByeCommand. It is created when the user wants to close Duke. + */ + +public class ByeCommand extends Command { + + /** + * Method to carry out the command. It initiates the writing of the task list into + * the txt file, and prints a goodbye message before closing Duke. + */ + public void execute() { + try { + Storage.writeToFile(); + } catch (IOException e) { + System.out.println("ERROR IN WRITING FILE"); + } + Ui.printBye(); + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/CheckDateCommand.java b/src/main/java/duke/command/CheckDateCommand.java new file mode 100644 index 000000000..92c30babf --- /dev/null +++ b/src/main/java/duke/command/CheckDateCommand.java @@ -0,0 +1,40 @@ +package main.java.duke.command; + +import main.java.duke.exception.DukeException; +import main.java.duke.ui.Ui; +import java.time.LocalDate; + +/** + * Class for the CheckDateCommand. It is created when the user wants to check if a date + * has any task. + */ + +public class CheckDateCommand extends Command { + + private final String date; + + /** + * Constructor for CheckDateCommand. + * + * @param date String date that is being checked in the format DD/MM/YYYY + */ + public CheckDateCommand(String date) { + this.date = date; + } + + /** + * Method to carry out the command. Calls a Ui method to show tasks on the date. + * + * @throws DukeException If user input is invalid. + */ + public void execute() throws DukeException { + if (isValidDate(convertDate(this.date))) { + LocalDate localDate = LocalDate.parse(convertDate(this.date)); + Ui.printCheckDate(localDate); + + } else { + throw new DukeException("Oh no! You have typed an invalid date!\n" + + "The format for date is DD/MM/YYYY !, e.g. 15/02/2022"); + } + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/Command.java b/src/main/java/duke/command/Command.java new file mode 100644 index 000000000..1cef15f9e --- /dev/null +++ b/src/main/java/duke/command/Command.java @@ -0,0 +1,120 @@ +package main.java.duke.command; + +import main.java.duke.Duke; +import main.java.duke.exception.DukeException; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +/** + * Abstract class for all Commands. Contains basic methods for different commands. + */ + +public abstract class Command { + + /** + * Method to check if a String is a number. + * + * @param string String that is being checked. + * @return Boolean value whether the String is a number. + */ + protected boolean isNum(String string) { + try { + Integer.parseInt(string); + } catch (NumberFormatException e) { + return false; + } + return true; + } + + /** + * Method to convert a date from DD/MM/YYYY to YYYY-MM-DD. + * + * @param date String date in DD/MM/YYYY time format. + * @return String date in YYYY-MM-DD format. + * @throws DukeException If input date format is invalid. + */ + protected String convertDate(String date) throws DukeException { + String[] dateTimeArray = date.split(" "); + String[] dateArray = dateTimeArray[0].split("/"); + if (dateArray.length != 3) { + throw new DukeException("Oh no! Your date format is invalid!\n" + + "The format for date is DD/MM/YYYY !, e.g. 15/02/2022"); + } else if (!isNum(dateArray[0]) || !isNum(dateArray[1]) || !isNum(dateArray[2])) { + throw new DukeException("Oh no! Your date format is invalid!\n" + + "The format for date is DD/MM/YYYY !, e.g. 15/02/2022"); + } + String dayString = String.format("%02d", Integer.parseInt(dateArray[0])); + String monthString = String.format("%02d", Integer.parseInt(dateArray[1])); + String yearString; + String localDateString; + if (dateArray[2].length() == 2) { + yearString = "20" + dateArray[2]; + } else if (dateArray[2].length() == 4) { + yearString = dateArray[2]; + } else { + throw new DukeException("Oh no! You have typed an invalid date!\n" + + "The format for date is DD/MM/YYYY !, e.g. 15/02/2022"); + } + + localDateString = yearString + "-" + monthString + "-" + dayString; + if (isValidDate(localDateString)) { + return localDateString; + } else { + throw new DukeException("Oh no! You have typed an invalid date!\n" + + "The format for date is DD/MM/YYYY !, e.g. 15/02/2022"); + } + } + + /** + * Checks if date in YYYY-MM-DD is a valid date. + * + * @param date String date in YYYY-MM-DD format. + * @return Boolean value whether date is a valid date. + */ + protected boolean isValidDate(String date) { + try { + LocalDate.parse(date); + } catch (DateTimeParseException e) { + return false; + } + return true; + } + + /** + * Method that checks if time input is valid. + * + * @param date String date in DD/MM/YYYY time format. + * @return String time in 24-hour format. + * @throws DukeException If time is invalid. + */ + protected String convertTime(String date) throws DukeException { + String[] dateTimeArray = date.split(" "); + String time; + if (dateTimeArray.length < 2) { + throw new DukeException("Oh no! You did not key in a time"); + } else { + time = dateTimeArray[1]; + if (isNum(time)) { + if (Integer.parseInt(time) < 2400 && Integer.parseInt(time) >= 0 && + Integer.parseInt(time) % 100 < 60) { + return time; + } else { + throw new DukeException("Oh no! The time you entered is invalid!\n" + + "The format for time is in 24-hour format! e.g. 1800"); + } + } else { + throw new DukeException("Oh no! The time you entered is invalid!\n" + + "The format for time is in 24-hour format! e.g. 1800"); + } + } + } + + /** + * Abstract method that all commands have. + * + * @throws DukeException If command cannot be executed due to invalid inputs. + */ + public abstract void execute() throws DukeException; + +} \ No newline at end of file diff --git a/src/main/java/duke/command/DeadlineCommand.java b/src/main/java/duke/command/DeadlineCommand.java new file mode 100644 index 000000000..6427ea795 --- /dev/null +++ b/src/main/java/duke/command/DeadlineCommand.java @@ -0,0 +1,45 @@ +package main.java.duke.command; + +import main.java.duke.task.Deadline; +import main.java.duke.Duke; +import main.java.duke.ui.Ui; +import main.java.duke.exception.DukeException; + +/** + * Class for DeadlineCommand. It is called when the user wants to create a Deadline. + */ + +public class DeadlineCommand extends Command { + + private String input; + + /** + * Constructor for DeadlineCommand. + * + * @param input User input. + */ + public DeadlineCommand(String input) { + this.input = input; + } + + /** + * Method to carry out the command. It checks if user input is valid, creates a new Deadline + * and adds it onto the task list. It then calls the Ui to print if the task has been added. + * + * @throws DukeException If user input is invalid. + */ + public void execute() throws DukeException { + String[] splitString = input.split(" /by ", 2); + if (splitString.length < 2) { + throw new DukeException("Oh no! You need to include a date after '/by'!"); + } else if (splitString[0].equals("")) { + throw new DukeException("Oh no! You need a description for this event!"); + } else { + Deadline task = new Deadline(splitString[0], convertDate(splitString[1]), + convertTime(splitString[1])); + Duke.tasks.add(task); + Duke.taskCounter++; + Ui.printTask(task); + } + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java new file mode 100644 index 000000000..cf9d27ef0 --- /dev/null +++ b/src/main/java/duke/command/DeleteCommand.java @@ -0,0 +1,34 @@ +package main.java.duke.command; + +import main.java.duke.task.Task; +import main.java.duke.Duke; +import main.java.duke.ui.Ui; + +/** + * Class for DeleteCommand. It is created when the user wants to delete a task from the task list. + */ + +public class DeleteCommand extends Command { + + private final int deleteInt; + + /** + * Constructor for DeleteCommand. + * + * @param deleteInt The task of number deleteInt that the user wants to remove. + */ + public DeleteCommand(int deleteInt) { + this.deleteInt = deleteInt; + } + + /** + * Method to carry out the command. It gets the task to be removed from the task list, and + * calls the Ui command to show the task that has been deleted. + */ + public void execute() { + Task task = Duke.tasks.get(deleteInt - 1); + Duke.tasks.remove(deleteInt - 1); + Duke.taskCounter--; + Ui.printDelete(task); + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/EventCommand.java b/src/main/java/duke/command/EventCommand.java new file mode 100644 index 000000000..64fcdaffc --- /dev/null +++ b/src/main/java/duke/command/EventCommand.java @@ -0,0 +1,96 @@ +package main.java.duke.command; + +import main.java.duke.task.Event; +import main.java.duke.Duke; +import main.java.duke.ui.Ui; +import main.java.duke.exception.DukeException; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +/** + * Class for EventCommand. It is created when the user wants to create a new Event. + */ + +public class EventCommand extends Command { + + private String input; + + /** + * Constructor for EventCommand. + * + * @param input User input. + */ + public EventCommand(String input) { + this.input = input; + } + + /** + * Method to check if user input dates are valid. + * + * @param startDate The start date in YYYY-MM-DD. + * @param startTime The start time in 24-hour format. + * @param endDate The end date in YYYY-MM-DD. + * @param endTime The end time in 24-hour format. + * @return Boolean value whether the input dates are valid. + */ + private boolean isValidDates(String startDate, String startTime, + String endDate, String endTime) { + LocalDate startLocalDate = LocalDate.parse(startDate); + LocalDate endLocalDate = LocalDate.parse(endDate); + if (startLocalDate.isBefore(endLocalDate)) { + return true; + + } else if (startLocalDate.equals(endLocalDate) && + Integer.parseInt(endTime) > Integer.parseInt(startTime)) { + return true; + + } else { + return false; + + } + } + + /** + * Method to carry out the command. It checks if user input is valid at various points. If + * valid, it creates an Event and adds it onto the task list. + * + * @throws DukeException If user input is invalid. + */ + public void execute() throws DukeException { + String[] splitString = input.split(" /at ", 2); + if (splitString.length < 2) { + throw new DukeException("Oh no! You need to include a date after '/at'!"); + } else if (splitString[0].equals("")) { + throw new DukeException("Oh no! You need a description for this event!"); + } else { + String date = splitString[1]; + if (date.contains(" /to ")) { + String[] timings = date.split(" /to "); + if (timings.length < 2) { + throw new DukeException("Oh no! You need to include a date after '/to'!"); + } else if (timings[0].equals("")) { + throw new DukeException("Oh no! You need to include a date before '/to'!"); + } else { + String startDate = convertDate(timings[0]); + String startTime = convertTime(timings[0]); + String endDate = convertDate(timings[1]); + String endTime = convertTime(timings[1]); + if (isValidDates(startDate, startTime, endDate, endTime)) { + Event task = new Event(splitString[0], startDate, + startTime, endDate, endTime); + Duke.tasks.add(task); + Duke.taskCounter++; + Ui.printTask(task); + } else { + throw new DukeException("Oh no! Your ending date is after " + + "your starting date!"); + } + } + } else { + throw new DukeException("Oh no! You need to include a '/to' between" + + " your start and end time!"); + } + + } + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/FindCommand.java b/src/main/java/duke/command/FindCommand.java new file mode 100644 index 000000000..72a4f56d4 --- /dev/null +++ b/src/main/java/duke/command/FindCommand.java @@ -0,0 +1,38 @@ +package main.java.duke.command; + +import main.java.duke.ui.Ui; +import main.java.duke.Duke; +import main.java.duke.exception.DukeException; + +/** + * Class for FindCommand. It is created when the user requests to search for a specific keyword in + * the tasks in the list. + */ +public class FindCommand extends Command { + + private final String input; + + /** + * Constructor for FindCommand. + * + * @param input User input. + */ + public FindCommand(String input) { + this.input = input; + } + + /** + * Method to carry out the command. It calls Ui to search for tasks with description + * matching the keyword. + * + * @throws DukeException If user input is invalid. + */ + public void execute() throws DukeException { + String[] splitString = input.split(" ", 2); + if (splitString.length < 2) { + throw new DukeException("Oh no! You need include a keyword to search for"); + } else { + Ui.printFind(splitString[1]); + } + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/InvalidCommand.java b/src/main/java/duke/command/InvalidCommand.java new file mode 100644 index 000000000..ec334b033 --- /dev/null +++ b/src/main/java/duke/command/InvalidCommand.java @@ -0,0 +1,18 @@ +package main.java.duke.command; + +import main.java.duke.ui.Ui; + +/** + * Class for InvalidCommand. It is called when the user inputs an invalid command. + */ + +public class InvalidCommand extends Command { + + /** + * Method to carry out the command. It calls Ui to print out a message to let the user know + * the command is invalid. + */ + public void execute() { + Ui.printInvalid(); + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java new file mode 100644 index 000000000..2deeb40b9 --- /dev/null +++ b/src/main/java/duke/command/ListCommand.java @@ -0,0 +1,17 @@ +package main.java.duke.command; + +import main.java.duke.ui.Ui; + +/** + * Class for ListCommand. It is created when the user requests for the task list. + */ + +public class ListCommand extends Command { + + /** + * Method to carry out the command. It calls Ui to print out the tasks in the list. + */ + public void execute() { + Ui.printList(); + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/MarkCommand.java b/src/main/java/duke/command/MarkCommand.java new file mode 100644 index 000000000..bd04b740c --- /dev/null +++ b/src/main/java/duke/command/MarkCommand.java @@ -0,0 +1,33 @@ +package main.java.duke.command; + +import main.java.duke.task.Task; +import main.java.duke.Duke; +import main.java.duke.ui.Ui; + +/** + * Class for MarkCommand. It is created when the user requests to mark a task. + */ + +public class MarkCommand extends Command { + + private final int markInt; + + /** + * Constructor for MarkCommand. + * + * @param markInt The task of number markInt in the task list that the user wants to mark. + */ + public MarkCommand(int markInt) { + this.markInt = markInt; + } + + /** + * Method to carry out the command. It marks the task and calls Ui let the user know the + * task has been marked. + */ + public void execute() { + Task task = Duke.tasks.get(markInt - 1); + task.setDone(true); + Ui.printMark(markInt, task); + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/ToDoCommand.java b/src/main/java/duke/command/ToDoCommand.java new file mode 100644 index 000000000..af2c90fc3 --- /dev/null +++ b/src/main/java/duke/command/ToDoCommand.java @@ -0,0 +1,34 @@ +package main.java.duke.command; + +import main.java.duke.task.ToDo; +import main.java.duke.Duke; +import main.java.duke.ui.Ui; + +/** + * Class for ToDoCommand. It is created when the user requests to create a new ToDo. + */ + +public class ToDoCommand extends Command { + + private String input; + + /** + * Constructor for ToDoCommand. + * + * @param input User input. + */ + public ToDoCommand(String input) { + this.input = input; + } + + /** + * Method to carry out command. It creates a ToDo which is added onto the list, and calls + * Ui to print that the ToDo has been added onto the task list. + */ + public void execute() { + ToDo task = new ToDo(this.input); + Duke.tasks.add(task); + Duke.taskCounter++; + Ui.printTask(task); + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/UnmarkCommand.java b/src/main/java/duke/command/UnmarkCommand.java new file mode 100644 index 000000000..f9af1c7b5 --- /dev/null +++ b/src/main/java/duke/command/UnmarkCommand.java @@ -0,0 +1,33 @@ +package main.java.duke.command; + +import main.java.duke.task.Task; +import main.java.duke.Duke; +import main.java.duke.ui.Ui; + +/** + * Class for UnmarkCommand. It is created when the user requests to unmark a task. + */ + +public class UnmarkCommand extends Command { + + private final int markInt; + + /** + * Constructor for UnmarkCommand. + * + * @param markInt The task of number markInt in the task list that the user wants to unmark. + */ + public UnmarkCommand(int markInt) { + this.markInt = markInt; + } + + /** + * Method to carry out the command. It unmarks the task and calls Ui let the user know the + * task has been unmarked. + */ + public void execute() { + Task task = Duke.tasks.get(markInt - 1); + task.setDone(false); + Ui.printUnmark(markInt, task); + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/commandsCommand.java b/src/main/java/duke/command/commandsCommand.java new file mode 100644 index 000000000..3654eec06 --- /dev/null +++ b/src/main/java/duke/command/commandsCommand.java @@ -0,0 +1,17 @@ +package main.java.duke.command; + +import main.java.duke.ui.Ui; + +/** + * Class for CommandsCommand. It is created when a user request for the command list. + */ + +public class CommandsCommand extends Command { + + /** + * Method to carry out the command. Calls Ui to print out all valid commands into a list. + */ + public void execute() { + Ui.printCommand(); + } +} \ No newline at end of file diff --git a/src/main/java/duke/exception/DukeException.java b/src/main/java/duke/exception/DukeException.java new file mode 100644 index 000000000..258b1e652 --- /dev/null +++ b/src/main/java/duke/exception/DukeException.java @@ -0,0 +1,29 @@ +package main.java.duke.exception; + +/** + * Class for the DukeException. It is the exception that handles almost all errors raised by + * invalid inputs from the user. + */ + +public class DukeException extends Exception { + + private final String error; + + /** + * Constructor for DukeException. + * + * @param error String error message + */ + public DukeException(String error) { + this.error = error; + } + + /** + * Method to get the error message. + * + * @return The error message. + */ + public String getMessage() { + return this.error; + } +} \ No newline at end of file diff --git a/src/main/java/duke/parser/Parser.java b/src/main/java/duke/parser/Parser.java new file mode 100644 index 000000000..8aceac290 --- /dev/null +++ b/src/main/java/duke/parser/Parser.java @@ -0,0 +1,287 @@ +package main.java.duke.parser; + +import main.java.duke.Duke; +import main.java.duke.ui.Ui; +import main.java.duke.exception.DukeException; +import main.java.duke.command.Command; +import main.java.duke.command.ListCommand; +import main.java.duke.command.UnmarkCommand; +import main.java.duke.command.MarkCommand; +import main.java.duke.command.DeleteCommand; +import main.java.duke.command.ToDoCommand; +import main.java.duke.command.DeadlineCommand; +import main.java.duke.command.EventCommand; +import main.java.duke.command.InvalidCommand; +import main.java.duke.command.CommandsCommand; +import main.java.duke.command.CheckDateCommand; +import main.java.duke.command.ByeCommand; +import main.java.duke.command.FindCommand; + +/** + * Class for the Parser object. It is the class used to parse user inputs and calls Commands + * from the input. + */ +public class Parser { + + private final String LIST = "list"; + private final String UNMARK = "unmark"; + private final String MARK = "mark"; + private final String TODO = "todo"; + private final String DEADLINE = "deadline"; + private final String EVENT = "event"; + private final String COMMANDS = "commands"; + private final String DELETE = "delete"; + private final String CHECK_DATE = "check date"; + private final String BYE = "bye"; + private final String FIND = "find"; + + /** + * Main method that takes in the initial user input and decides how to deal with it. + * + * @param input The user input. + * @return Calls another method to handle the input. + * @throws DukeException If the user input is invalid. + */ + public Command parse(String input) throws DukeException { + String lowerCaseInput = input.toLowerCase(); + if (lowerCaseInput.startsWith(LIST)) { + return parseList(); + + } else if (lowerCaseInput.startsWith(UNMARK)) { + return parseUnmark(input); + + } else if (lowerCaseInput.startsWith(MARK)) { + return parseMark(input); + + } else if (lowerCaseInput.startsWith(TODO)) { + return parseToDo(input); + + } else if (lowerCaseInput.startsWith(DEADLINE)) { + if (input.contains("/by")) { + return parseDeadline(input); + } else { + throw new DukeException("Oh no! You need to include a '/by' in the command!"); + } + + } else if (lowerCaseInput.startsWith(EVENT)) { + if (input.contains("/at")) { + return parseEvent(input); + } else { + throw new DukeException("Oh no! You need to include a '/at' in the command!"); + } + + } else if (lowerCaseInput.startsWith(COMMANDS)) { + return parseCommands(); + + } else if (lowerCaseInput.startsWith(DELETE)) { + return parseDelete(input); + + } else if (lowerCaseInput.startsWith(CHECK_DATE)) { + return parseCheckDate(input); + + } else if (lowerCaseInput.startsWith(BYE)) { + return new ByeCommand(); + + } else if (lowerCaseInput.startsWith(FIND)) { + return new FindCommand(input); + + } else { + return new InvalidCommand(); + + } + } + + /** + * Method to check if a String is a number + * + * @param string String that is being checked. + * @return Boolean value whether it is a number. + */ + private boolean isNum(String string) { + try { + Integer.parseInt(string); + } catch (NumberFormatException e) { + return false; + } + return true; + } + + /** + * Method to parse user input asking for the task list. + * @return ListCommand which will be executed. + */ + private Command parseList() { + return new ListCommand(); + } + + /** + * Method to parse user input asking to unmark a specific task. + * + * @param input User input. + * @return UnmarkCommand to be executed. + * @throws DukeException If input is invalid. + */ + private Command parseUnmark(String input) throws DukeException { + String[] splitString = input.split(" ", 2); + if (splitString.length < 2) { + throw new DukeException("Oh no! You need to choose a task to unmark!"); + + } else if (isNum(splitString[1])) { + int markInt = Integer.parseInt(splitString[1]); + if ((markInt > Duke.taskCounter) || (markInt < 1)) { + throw new DukeException("Oh no! The number you have chosen is not valid!"); + + } else if (!Duke.tasks.get(markInt - 1).isDone()) { + throw new DukeException("Oh no! The task you have selected is not been marked!"); + + } + else { + return new UnmarkCommand(markInt); + + } + } else { + throw new DukeException("Oh no! You need to choose a number!"); + + } + } + + /** + * Method to parse user input asking to mark a specific task. + * + * @param input User input. + * @return MarkCommand to be executed. + * @throws DukeException If input is invalid. + */ + private Command parseMark(String input) throws DukeException { + String[] splitString = input.split(" ", 2); + if (splitString.length < 2) { + throw new DukeException("Oh no! You need to choose a task to unmark!"); + + } else if (isNum(splitString[1])) { + int markInt = Integer.parseInt(splitString[1]); + if ((markInt > Duke.taskCounter) || (markInt < 1)) { + throw new DukeException("Oh no! The number you have chosen is not valid!"); + + } else if (Duke.tasks.get(markInt - 1).isDone()) { + throw new DukeException("Oh no! The task you have selected is already been marked"); + + } + else { + return new MarkCommand(markInt); + + } + } else { + throw new DukeException("Oh no! You need to choose a number!"); + + } + } + + /** + * Method to parse user input asking to delete a specific task. + * + * @param input User input. + * @return DeleteCommand to be executed. + * @throws DukeException If input is invalid. + */ + private Command parseDelete(String input) throws DukeException { + String[] splitString = input.split(" ", 2); + if (splitString.length < 2) { + throw new DukeException("Oh no! You need to choose a task to unmark!"); + + } else if (isNum(splitString[1])) { + int deleteInt = Integer.parseInt(splitString[1]); + if ((deleteInt > Duke.taskCounter) || (deleteInt < 1)) { + throw new DukeException("Oh no! The number you have chosen is not valid!"); + + } else { + return new DeleteCommand(deleteInt); + + } + } else { + throw new DukeException("Oh no! You need to choose a number!"); + + } + } + + /** + * Method to parse user input requesting to create a new ToDo. + * + * @param input User input. + * @return ToDoCommand to be executed. + * @throws DukeException If input is invalid. + */ + private Command parseToDo(String input) throws DukeException { + String[] splitString = input.split(" ", 2); + if (splitString.length < 2) { + throw new DukeException("Oh no! You need to enter the description of the task!"); + + } else { + return new ToDoCommand(splitString[1]); + + } + } + + /** + * Method to parse user input requesting to create a new Deadline. + * + * @param input User input. + * @return DeadlineCommand to be executed. + * @throws DukeException If input is invalid. + */ + private Command parseDeadline(String input) throws DukeException { + String[] splitString = input.split(" ", 2); + if (splitString.length < 2) { + throw new DukeException("Oh no! You need to enter the description of the task!"); + + } else { + return new DeadlineCommand(splitString[1]); + + } + } + + /** + * Method to parse user input requesting to create a new Event. + * + * @param input User input. + * @return EventCommand to be executed. + * @throws DukeException If input is invalid. + */ + private Command parseEvent(String input) throws DukeException { + String[] splitString = input.split(" ", 2); + if (splitString.length < 2) { + throw new DukeException("Oh no! You need to enter the description of the task!"); + + } else { + return new EventCommand(splitString[1]); + + } + } + + /** + * Method to parse user input requesting to check if a specific date has any task. + * + * @param input User input. + * @return CheckDateCommand to be executed. + * @throws DukeException If input is invalid. + */ + private Command parseCheckDate(String input) throws DukeException { + String[] splitString = input.split(" ", 3); + if (splitString.length < 3) { + throw new DukeException("Oh no! You need to enter the date that you want to check!"); + + } else { + return new CheckDateCommand(splitString[2]); + + } + } + + /** + * Method to parse user input requesting to see the command list. + * + * @return commandsCommand to be executed. + */ + private Command parseCommands() { + return new CommandsCommand(); + } + +} \ No newline at end of file diff --git a/src/main/java/duke/storage/Storage.java b/src/main/java/duke/storage/Storage.java new file mode 100644 index 000000000..83a8feebc --- /dev/null +++ b/src/main/java/duke/storage/Storage.java @@ -0,0 +1,119 @@ +package main.java.duke.storage; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Scanner; +import main.java.duke.task.Task; +import main.java.duke.task.ToDo; +import main.java.duke.task.Deadline; +import main.java.duke.task.Event; +import main.java.duke.Duke; +import main.java.duke.exception.DukeException; + +/** + * Class for the Storage object. It contains methods to read from a data file, and to write onto + * it after Duke has ended. + * + * @throws IOException If an input or output exception occured. + */ + +public class Storage { + + private static String DATA_DIRECTORY = System.getProperty("user.dir") + "/data"; + private static String DATA_FILE = DATA_DIRECTORY + "/duke.txt"; + private static Path dataDirectoryPath = Paths.get(DATA_DIRECTORY); + + /** + * Method used to initiate read from data/duke.txt, and to retrieve when Duke is started. + * + * @throws IOException If an input or output exception occured. + * @throws DukeException If data file is corrupted or contains unexpected information. + */ + public static void load() throws IOException, DukeException { + boolean directoryExists = new File(DATA_DIRECTORY).exists(); + boolean fileExists = new File(DATA_FILE).exists(); + File dataFile = new File(DATA_FILE); + if (!directoryExists) { + Files.createDirectory(dataDirectoryPath); + } + if (!fileExists) { + dataFile.createNewFile(); + } + Scanner s = new Scanner(dataFile); + while (s.hasNext()) { + readData(s.nextLine()); + } + Duke.taskCounter = Duke.tasks.size(); + } + + /** + * Method that reads lines in duke.txt and adds them to the task list. + * + * @param data Input line from duke.txt. + * @throws DukeException If task type is of an unexpected value. + */ + private static void readData(String data) throws DukeException { + String[] dataArr = data.split("\\|"); + Task newTask; + if (dataArr[1].equals("T")) { + newTask = new ToDo(dataArr[3]); + if (Integer.parseInt(dataArr[2]) == 1) { + newTask.setDone(true); + } + } else if (dataArr[1].equals("D")) { + newTask = new Deadline(dataArr[3], dataArr[4], dataArr[5]); + if (Integer.parseInt(dataArr[2]) == 1) { + newTask.setDone(true); + } + } else if (dataArr[1].equals("E")) { + newTask = new Event(dataArr[3], dataArr[4], dataArr[5], dataArr[6], dataArr[7]); + if (Integer.parseInt(dataArr[2]) == 1) { + newTask.setDone(true); + } + } else { + throw new DukeException("ERROR IN DATA FILE"); + } + Duke.tasks.add(newTask); + } + + /** + * Method that is used to initiate the writing to data/duke.txt before closing Duke. + * + * @throws IOException If an input or output exception occured. + */ + public static void writeToFile() throws IOException { + FileWriter fw = new FileWriter(DATA_FILE, false); + int taskNum = 0; + for (Task task : Duke.tasks) { + taskNum++; + fw.write(convertTask(taskNum, task)); + } + fw.close(); + } + + /** + * Method that converts a task into a String that can be readable for future use. + * + * @param taskNum The number of the task on the list. + * @param task The task that is being converted. + * @return A string which is written onto data/duke.txt. + */ + private static String convertTask(int taskNum, Task task) { + String line = String.valueOf(taskNum) + "|" + task.getType() + "|"; + if (task.isDone()) { + line += "1|"; + } else { + line += "0|"; + } + line += task.getDescription(); + if (task.toString().contains("(")) { + line += "|" + task.getDateTime(); + } + line += System.lineSeparator(); + return line; + } +} \ No newline at end of file diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java new file mode 100644 index 000000000..16fbf6461 --- /dev/null +++ b/src/main/java/duke/task/Deadline.java @@ -0,0 +1,78 @@ +package main.java.duke.task; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +/** + * Class for the Deadline object. Deadlines are Tasks that do not have a specific due date. + */ + +public class Deadline extends Task { + + private final String date; + private final String time; + private final LocalDate localDate; + + /** + * Constructor for Deadline object. + * + * @param description String describing the task. + * @param date String date in YYYY-MM-DD that the task is due by . + * @param time String time in 24-hour format that the task is due by. + */ + public Deadline(String description, String date, String time) { + super(description); + this.date = date; + this.time = time; + this.localDate = LocalDate.parse(date); + } + + /** + * Method used to show that the Task is a Deadline. + * + * @return A String "D". + */ + public String getType() { + return "D"; + } + + /** + * Method used to retrieve the date the deadline is due. + * + * @return LocalDate of the due date. + */ + public LocalDate getStartDate() { + return this.localDate; + } + + /** + * Duplicate method used to retrieve the date the deadline is due. + * + * @return LocalDate of the due date. + */ + public LocalDate getEndDate() { + return this.localDate; + } + + /** + * Formats the timing of the event into date|time for saving. + * + * @return String in the format for writing to file. + */ + public String getDateTime() { + return this.date + "|" + this.time; + } + + /** + * Converts the parameters of the Deadline into a readable line with it's description + * and due date and time. + * + * @return String that contains the information of the Deadline. + */ + @Override + public String toString() { + String dateTime = this.localDate. + format(DateTimeFormatter.ofPattern("MMM d yyyy")).toString() + " " + this.time; + return String.format("[D]%s (by: %s)", super.toString(), dateTime); + } +} \ No newline at end of file diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java new file mode 100644 index 000000000..e19c8eb40 --- /dev/null +++ b/src/main/java/duke/task/Event.java @@ -0,0 +1,93 @@ +package main.java.duke.task; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +/** + * Class for the Event object. An event is a task that has a start date and an end date. + */ + +public class Event extends Task { + + private final String startDate; + private final String startTime; + private final String endDate; + private final String endTime; + private final LocalDate localStartDate; + private final LocalDate localEndDate; + + /** + * Constructor for the Event class. + * + * @param description String describing the event. + * @param startDate String of the date it starts on in YYYY-MM-DD. + * @param startTime String of the time it starts in 24-hour format. + * @param endDate String of the date it ends on in YYYY-MM-DD. + * @param endTime String of the time it ends in 24-hour format. + */ + public Event(String description, String startDate, String startTime, + String endDate, String endTime) { + super(description); + this.startDate = startDate; + this.startTime = startTime; + this.endDate = endDate; + this.endTime = endTime; + this.localStartDate = LocalDate.parse(startDate); + this.localEndDate = LocalDate.parse(endDate); + } + + /** + * Method used to show that the Task is an Event. + * + * @return A String "E" + */ + public String getType() { + return "E"; + } + + /** + * Method used to retrieve the start date of the event. + * + * @return LocalDate of the start date. + */ + public LocalDate getStartDate() { + return this.localStartDate; + } + + /** + * Method used to retrieve the end date of the event. + * + * @return LocalDate of the end date. + */ + public LocalDate getEndDate() { + return this.localEndDate; + } + + /** + * Formats the timing of the event into start date|start time|end date|end time for saving. + * + * @return String in the format for writing to file. + */ + public String getDateTime() { + return String.format("%s|%s|%s|%s", this.startDate, this.startTime, + this.endDate, this.endTime); + } + + /** + * Converts the parameters of the Event into a readable line with it's description, + * start and end dates and times. + * + * @return String that contains the information of the Event. + */ + @Override + public String toString() { + String startDateTime = this.localStartDate. + format(DateTimeFormatter.ofPattern("MMM d yyyy")).toString() + " " + + this.startTime; + String endDateTime = this.localEndDate. + format(DateTimeFormatter.ofPattern("MMM d yyyy")).toString() + " " + + this.endTime; + return String.format("[E]%s (at: %s to %s)", super.toString(), + startDateTime, endDateTime); + } +} \ No newline at end of file diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java new file mode 100644 index 000000000..cde309aa6 --- /dev/null +++ b/src/main/java/duke/task/Task.java @@ -0,0 +1,104 @@ +package main.java.duke.task; + +import java.time.LocalDate; + +/** + * Abstract class for ToDos, Deadlines, and Events. It contains basic methods for the + * 3 sub-classes. + */ +public abstract class Task { + + public String description; + public Boolean isDone = false; + public String mark = " "; + + /** + * Constructor for the Task object. + * + * @param description String of the description of the task. + */ + public Task(String description) { + this.description = description; + } + + /** + * Marks the task as done or not done. + * + * @param isDone Boolean value that marks the task as done or not. + */ + public void setDone(Boolean isDone) { + this.isDone = isDone; + } + + /** + * Method to return the description of the task. + * + * @return String desciption of the task. + */ + public String getDescription() { + return this.description; + } + + /** + * Method to find out if the task is done. + * + * @return Boolean value whether the task is done. + */ + public boolean isDone() { + return this.isDone; + } + + /** + * Method to show whether a task is done with an "X", or " " if not done. + * + * @return A String "X" or " " depending on whether the task is done. + */ + public String getMark() { + if (this.isDone()) { + this.mark = "X"; + } else { + this.mark = " "; + } + return this.mark; + } + + /** + * Abstract method to find out the type of task. + * + * @return String "T" for ToDos, String "D" for Deadlines, String "E" for Events. + */ + public abstract String getType(); + + /** + * Abstract method to get the starting date of a task. + * + * @return A LocalDate of the starting date of a task. + */ + public abstract LocalDate getStartDate(); + + /** + * Abstract method to get the ending date of a task. + * + * @return A LocalDate of the ending date of a task. + */ + public abstract LocalDate getEndDate(); + + /** + * Abstract method to get the date and time of a task in the format for writing onto + * the save file. + * + * @return A String containing the dates and times of the task. + */ + public abstract String getDateTime(); + + /** + * The method to represent the Task object as a String + * + * @return A partially complete String that shows whether the task is marked as done, and + * it's description. + */ + @Override + public String toString() { + return String.format("[%s] %s", this.getMark(), this.description); + } +} \ No newline at end of file diff --git a/src/main/java/duke/task/ToDo.java b/src/main/java/duke/task/ToDo.java new file mode 100644 index 000000000..18e494a05 --- /dev/null +++ b/src/main/java/duke/task/ToDo.java @@ -0,0 +1,60 @@ +package main.java.duke.task; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +/** + * Class for the ToDo object. ToDos are Tasks that do not have any specific due date. + */ + +public class ToDo extends Task { + + /** + * Constructor for the ToDo object. + * + * @param description A String describing the task. + */ + public ToDo(String description) { + super(description); + } + + /** + * Method used to show that the Task is an ToDo. + * + * @return A String "T". + */ + public String getType() { + return "T"; + } + + /** + * Un-used method from Task + */ + public LocalDate getStartDate() { + return null; + } + + /** + * Un-used method from Task + */ + public LocalDate getEndDate() { + return null; + } + + /** + * Un-used method from Task + */ + public String getDateTime() { + return null; + } + + /** + * The method to represent the ToDo object as a String + * + * @return String that contains the information of the ToDo + */ + @Override + public String toString() { + return String.format("[T]%s", super.toString()); + } +} \ No newline at end of file diff --git a/src/main/java/duke/ui/Ui.java b/src/main/java/duke/ui/Ui.java new file mode 100644 index 000000000..77c449bc7 --- /dev/null +++ b/src/main/java/duke/ui/Ui.java @@ -0,0 +1,223 @@ +package main.java.duke.ui; + +/** + * The Ui class handles all print statements. It contains all methods for printing + * the result of various commands. + */ + +import java.util.ArrayList; +import main.java.duke.task.Task; +import main.java.duke.Duke; +import main.java.duke.exception.DukeException; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +public class Ui { + + private final static String HORIZONTAL_LINE = "____________________________________" + + "________________________"; + + /** + * This method is the main method used format outputs such that they appear within 2 + * horizontal lines. + * + * @param args A vararg that takes in Strings that are to be printed on a new horizontal line + * between the 2 horizontal lines. + */ + public static void printFormat(String... args) { + System.out.println(HORIZONTAL_LINE); + for (String arg : args) { + System.out.println(arg); + } + System.out.println(HORIZONTAL_LINE); + } + + /** + * Prints out the DUKE ASCII art, and welcomes the user. + */ + public static void printIntro() { + String logo = " ____ _ \n" + + "| _ \\ _ _| | _____ \n" + + "| | | | | | | |/ / _ \\\n" + + "| |_| | |_| | < __/\n" + + "|____/ \\__,_|_|\\_\\___|\n"; + System.out.println("Hello from\n" + logo); + printFormat("Hello! I'm Duke", + "What can I do for you?", + "type 'commands' for the list of commands"); + } + + /** + * Prints out all tasks description (and date) and numbers them. + */ + public static void printList() { + System.out.println(HORIZONTAL_LINE); + System.out.println("Here are the tasks in your list:"); + for (int i = 0; i < Duke.tasks.size(); i++) { + System.out.println(String.valueOf(i + 1) + "." + Duke.tasks.get(i).toString()); + } + System.out.println(HORIZONTAL_LINE); + } + + /** + * Searches for task description based on a keyword, and prints out the list of those tasks. + * + * @param keyword A String that is used to search in the description of the tasks. + */ + public static void printFind(String keyword) { + Boolean foundTask = false; + System.out.println(HORIZONTAL_LINE); + System.out.println("Here are the matching tasks in your list:"); + for (int i = 0; i < Duke.tasks.size(); i++) { + Task task = Duke.tasks.get(i); + if (task.getDescription().toLowerCase().contains(keyword.toLowerCase())) { + foundTask = true; + System.out.println(String.valueOf(i + 1) + "." + task.toString()); + } + } + if (!foundTask) { + System.out.println("There are no matching task in your list"); + } + System.out.println(HORIZONTAL_LINE); + } + + /** + * Prints a sentence that lets the user know that the task has been unmarked. + * + * @param markInt Integer number of the task in the list. + * @param task The task that has been unmarked. + */ + public static void printUnmark(int markInt, Task task) { + printFormat("OK, I've marked this task as not done yet:", + task.toString()); + } + + /** + * Prints a sentence that lets the user know that the task has been marked. + * + * @param markInt Integer number of the task in the list. + * @param task The task that has been marked. + */ + public static void printMark(int markInt, Task task) { + printFormat("Nice! I've marked this task as done:", + task.toString()); + } + + /** + * Prints a sentence that lets the user know the task has been deleted, and lets the + * user know how many tasks are left in the task list. + * + * @param task Task that has been removed from the list. + */ + public static void printDelete(Task task) { + printFormat("Noted. I've removed this task:", task.toString(), + "Now you have " + String.valueOf(Duke.taskCounter) + " tasks in the list."); + } + + /** + * Method used to let the user know that the task has been added onto the list. It also shows + * the total number of tasks in the list. + * + * @param task Task that had been added into the list. + */ + public static void printTask(Task task) { + printFormat("Got it. I've added this task:", + " " + task.toString(), + "Now you have " + String.valueOf(Duke.taskCounter) + " tasks in the list."); + } + + /** + * Prints out possible commands the user can use. + */ + public static void printCommand() { + printFormat("List of valid commands:", + "'list' - lists out all tasks and its details", + "'mark NUMBER' - marks item NUMBER on the list as done", + " e.g. 'mark 3' marks item 3 on the list", + "'unmark NUMBER' - unmarks item NUMBER on the list as done", + " e.g. 'unmark 3' unmarks item 3 on the list", + "'delete NUMBER' - deletes item NUMBER on the list", + " e.g. 'delete 3' deletes item 3 on the list", + "'find KEYWORD' - lists items in the list that contain KEYWORD", + " e.g. 'find book' lists items in the list that contain 'book'", + "'todo DESC' - ToDos are tasks without specific deadlines", + " e.g. 'todo buy shampoo' adds the task 'buy shampoo' to the list", + "'deadline DESC /by DD/MM/YYYY TIME' - Deadlines are tasks that need to" + + "be done before a specific date and time in 24-hour format", + " e.g. 'deadline math homework /by 2/3/2022 1400' adds a " + + "task with deadline Mar 2 2022 1400 to the list", + "'event DESC /at DD/MM/YYYY TIME /to DD/MM/YYYY TIME' - Events are tasks that" + + "start at a specific date and time and ends at a specific date and time", + " e.g. 'event project meeting /at 3/3/2022 0900' /to 4/3/2022 1800 " + + "adds a task with a time range", + "'check date DD/MM/YYYY' - checks if there are tasks due or occuring" + + " on that date", + " e.g. 'check date 04/03/2022' - checks if anything is on 04/03/2022", + "'bye' - saves changes and closes Duke"); + } + + /** + * Prints out tasks that are due or happening on a specific date. + * + * @param localDate The date which the user wants to know if there is anything happening. + */ + public static void printCheckDate(LocalDate localDate) { + System.out.println(HORIZONTAL_LINE); + System.out.println("Here are the tasks on " + + localDate.format(DateTimeFormatter.ofPattern("MMM d yyyy")).toString() + ":"); + for (int i = 0; i < Duke.tasks.size(); i++) { + Task task = Duke.tasks.get(i); + if (isOnDate(task, localDate)) { + System.out.println(String.valueOf(i + 1) + "." + task.toString()); + } + } + System.out.println(HORIZONTAL_LINE); + } + + /** + * Method used to check if a task is due or happening on a specific date. + * + * @param task The task that is being checked. + * @param localDate The date that the task is being checked on. + * @return A boolean value whether the task is happening on the date. + */ + private static boolean isOnDate(Task task, LocalDate localDate) { + if (task.getType().equals("D")) { + if (localDate.equals(task.getStartDate())) { + return true; + } + } else if (task.getType().equals("E")) { + if (localDate.equals(task.getStartDate()) || localDate.equals(task.getEndDate()) || + (localDate.isAfter(task.getStartDate()) && localDate.isBefore(task.getEndDate()))) { + return true; + } + } + return false; + } + + /** + * Prints out a goodbye before shutting the bot down. + */ + public static void printBye() { + printFormat("Bye. Hope to see you again soon!"); + } + + /** + * Prints out a message to let the user know his command was invalid, and suggests the user + * to use the 'command' command if the user is unsure of commands availiable. + */ + public static void printInvalid() { + printFormat("OOPS!!! I'm sorry, but I don't know what that means :-(", + "Please type in 'commands' if you are not sure of the commands"); + } + + /** + * Method used to print messages from Exceptions. Usually indicates what the user did wrong. + * + * @param e A DukeException that was thrown during processing of user input. + */ + public static void printError(DukeException e) { + System.out.println(e.getMessage()); + } + +} \ No newline at end of file diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 657e74f6e..07420f524 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -4,4 +4,114 @@ Hello from | | | | | | | |/ / _ \ | |_| | |_| | < __/ |____/ \__,_|_|\_\___| +____________________________________________________________ +Got it. I've added this task: + [T][ ] read book +Now you have 1 tasks in the list. +____________________________________________________________ +____________________________________________________________ +Got it. I've added this task: + [D][ ] return book (by: Jun 6 2022 1700) +Now you have 2 tasks in the list. +____________________________________________________________ +____________________________________________________________ +Got it. I've added this task: + [E][ ] project meeting (at: Mar 12 2021 0600 to Mar 13 2022 0700) +Now you have 3 tasks in the list. +____________________________________________________________ +____________________________________________________________ +Here are the tasks in your list: +1.[T][ ] read book +2.[D][ ] return book (by: Jun 6 2022 1700) +3.[E][ ] project meeting (at: Mar 12 2021 0600 to Mar 13 2022 0700) +____________________________________________________________ +____________________________________________________________ +Nice! I've marked this task as done: +[T][X] read book +____________________________________________________________ +____________________________________________________________ +Nice! I've marked this task as done: +[D][X] return book (by: Jun 6 2022 1700) +____________________________________________________________ +____________________________________________________________ +OK, I've marked this task as not done yet: +[T][ ] read book +____________________________________________________________ +Oh no! The time you entered is invalid! +The format for time is in 24-hour format! e.g. 1800 +Oh no! You have typed an invalid date! +The format for date is DD/MM/YYYY !, e.g. 15/02/2022 +____________________________________________________________ +Here are the tasks in your list: +1.[T][ ] read book +2.[D][X] return book (by: Jun 6 2022 1700) +3.[E][ ] project meeting (at: Mar 12 2021 0600 to Mar 13 2022 0700) +____________________________________________________________ +Oh no! You need to enter the description of the task! +____________________________________________________________ +OOPS!!! I'm sorry, but I don't know what that means :-( +Please type in 'commands' if you are not sure of the commands +____________________________________________________________ +Oh no! The task you have selected is already been marked +____________________________________________________________ +Here are the matching tasks in your list: +1.[T][ ] read book +2.[D][X] return book (by: Jun 6 2022 1700) +____________________________________________________________ +____________________________________________________________ +Noted. I've removed this task: +[E][ ] project meeting (at: Mar 12 2021 0600 to Mar 13 2022 0700) +Now you have 2 tasks in the list. +____________________________________________________________ +Oh no! The number you have chosen is not valid! +____________________________________________________________ +Here are the tasks on Jun 6 2022: +2.[D][X] return book (by: Jun 6 2022 1700) +____________________________________________________________ +____________________________________________________________ +Here are the tasks on Jun 7 2022: +____________________________________________________________ +Oh no! You need to choose a number! +____________________________________________________________ +OOPS!!! I'm sorry, but I don't know what that means :-( +Please type in 'commands' if you are not sure of the commands +____________________________________________________________ +Oh no! You need to choose a number! +____________________________________________________________ +OOPS!!! I'm sorry, but I don't know what that means :-( +Please type in 'commands' if you are not sure of the commands +____________________________________________________________ +____________________________________________________________ +Here are the tasks in your list: +1.[T][ ] read book +2.[D][X] return book (by: Jun 6 2022 1700) +____________________________________________________________ +____________________________________________________________ +List of valid commands: +'list' - lists out all tasks and its details +'mark NUMBER' - marks item NUMBER on the list as done + e.g. 'mark 3' marks item 3 on the list +'unmark NUMBER' - unmarks item NUMBER on the list as done + e.g. 'unmark 3' unmarks item 3 on the list +'delete NUMBER' - deletes item NUMBER on the list + e.g. 'delete 3' deletes item 3 on the list +'find KEYWORD' - lists items in the list that contain KEYWORD + e.g. 'find book' lists items in the list that contain 'book' +'todo DESC' - ToDos are tasks without specific deadlines + e.g. 'todo buy shampoo' adds the task 'buy shampoo' to the list +'deadline DESC /by DD/MM/YYYY TIME' - Deadlines are tasks that need tobe done before a specific date and time in 24-hour format + e.g. 'deadline math homework /by 2/3/2022 1400' adds a task with deadline Mar 2 2022 1400 to the list +'event DESC /at DD/MM/YYYY TIME /to DD/MM/YYYY TIME' - Events are tasks thatstart at a specific date and time and ends at a specific date and time + e.g. 'event project meeting /at 3/3/2022 0900' /to 4/3/2022 1800 adds a task with a time range +'check date DD/MM/YYYY' - checks if there are tasks due or occuring on that date + e.g. 'check date 04/03/2022' - checks if anything is on 04/03/2022 +'bye' - saves changes and closes Duke +____________________________________________________________ +Oh no! You need to include a date after '/by'! +Oh no! The time you entered is invalid! +The format for time is in 24-hour format! e.g. 1800 +____________________________________________________________ +Bye. Hope to see you again soon! +____________________________________________________________ +Process finished with exit code 0 \ No newline at end of file diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index e69de29bb..5c851f61a 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -0,0 +1,28 @@ +todo read book +deadline return book /by 06/06/2022 1700 +Event project meeting /at 12/03/2021 0600 /to 13/03/2022 0700 +list +mark 1 +mark 2 +unmark 1 +deadline return book /by 03/04/2023 2401 +event project meeting /at 04/13/0000 1234 /to 01/12/3214 +list +todo +test invalid command +mark 2 +find book +delete 3 +delete 6 +check date 06/06/2022 +check date 07/06/2022 +mark test +test +delete test +desfasda +list2131 +commands +deadline /by 04/06/22 1543 +event testttt /at 06/08/23 1567 /to 06/04/24 1322 +bye + diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat index 087374464..832026065 100644 --- a/text-ui-test/runtest.bat +++ b/text-ui-test/runtest.bat @@ -5,17 +5,20 @@ if not exist ..\bin mkdir ..\bin REM delete output from previous run if exist ACTUAL.TXT del ACTUAL.TXT - +Pause REM compile the code into the bin folder javac -cp ..\src\main\java -Xlint:none -d ..\bin ..\src\main\java\*.java IF ERRORLEVEL 1 ( echo ********** BUILD FAILURE ********** + Pause exit /b 1 ) REM no error here, errorlevel == 0 - +Pause REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT java -classpath ..\bin Duke < input.txt > ACTUAL.TXT REM compare the output to the expected output FC ACTUAL.TXT EXPECTED.TXT + +Pause