diff --git a/README.md b/README.md index 8715d4d91..db4a5e14b 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,131 @@ -# 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. - -## Setting up in Intellij - -Prerequisites: JDK 11, update Intellij to the most recent version. - -1. Open Intellij (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project first) -1. Open the project into Intellij as follows: - 1. Click `Open`. - 1. Select the project directory, and click `OK`. - 1. If there are any further prompts, accept the defaults. -1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
- In the same dialog, set the **Project language level** field to the `SDK default` option. -3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output: - ``` - Hello from - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| - ``` +# User Guide for chatbot "Apple" + +Chatbot Apple is an app to manage tasks, optimised for use through a Command Line Interface (CLI). + +## Quick Start +1. Ensure Java 11 or above is installed in your computer +2. Download `ip.jar` from [here](https://github.com/hongyijie06/ip/releases/tag/A-Jar) +3. Open a command terminal, `cd` into the folder with the jar file and use the `java -jar ip.jar` command to run the application. + +A CLI similar to the picture below should appear in a few seconds. Note how the app returns the path to which the list of tasks is saved on the local computer. + +4. Type the command into the command line and press Enter to execute it. e.g. typing list and pressing Enter will list the current tasks. +Some example commands you can try: + +- `todo tutorial`: Adds task "tutorial" to the list +- `deadline return book by 4pm`: Adds task "return book" nd deadline "4pm" to the list +- `list`: Lists all tasks +- `bye`: Exits the app + +5. Refer to the Features below for more details on each command. + +## Features + +[!NOTE] +> Words in `UPPER_CASE` are parameters to be supplied by the user. e.g. in `delete INDEX`, `INDEX` is a parameter which can be used as `delete 3` + +## Listing tasks: `list` +Lists all tasks in the task list. + +Format: `list` + +## Add tasks +### Add todo : `todo` +Adds task of type todo to the list of tasks + +Format: `todo DESCRIPTION` + +Examples: +- `todo tutorial` Adds task `tutorial` to the list of tasks +- `todo watch lecture` Adds task `watch lecture` to the list of tasks + +ADD PIC HERE + +### Add deadline: `deadline` +Adds task of type deadline to the list of tasks + +Format: `deadline DESCRIPTION by DEADLINE` + +Examples: +- `deadline return book by 4pm` Adds task `return book` with deadline `4pm` to the list of tasks +- `deadline submit report by 7pm` Adds task `submit report` with deadline `7pm` to the list of tasks + +ADD PIC HERE + +### Add event: `event` +Adds task of type event to the list of tasks + +Format: `event DESCRIPTION from START to END` + +Examples: +- `event Math exam from 2pm to 4pm` Adds task `Math exam` with timeline `2pm` to `4pm` to the list of tasks +- `event project group meeting from 11am to 1pm` Adds task `project group meeting` with timeline `11am` to `1pm` to the list of tasks + +ADD PIC HERE + +## Delete tasks: `delete` +Deletes task from the list of tasks + +Format: `delete INDEX` + +- Deletes task at the specified `INDEX`. +- The index refers to the index of the task in the list of tasks. +- The index must be a positive integer. + +Examples: +- `delete 3` Deletes third task in the list +- `delete 5` Deletes fifth task in the list + +## Mark tasks as done: `mark` +Marks tasks as completed + +Format: `mark INDEX` + +- Marks task as done at the specified `INDEX`. +- The index refers to the index of the task in the list of tasks. +- The index must be a positive integer. + +Examples: +- `mark 1` Marks first task in the list as done +- `mark 6` Marks sixth task in the list as done + +## Unmark tasks: `unmark` +Marks tasks as undone + +Format: `unmark INDEX` + +- Marks task as not done at the specified `INDEX`. +- The index refers to the index of the task in the list of tasks. +- The index must be a positive integer. + +Examples: +- `unmark 1` Marks first task in the list as notdone +- `unmark 2` Marks second task in the list as not done + +## Find Keywords: `find` +Filters list of tasks to those containing the keyword the user wants to find + +Format: `find KEYWORD` + +Examples: +- `find book` CLI returns a list with all the tasks with the `KEYWORD` `book`. +- `find tutorial` CLI returns a list with all the tasks with the `KEYWORD` `tutorial`. + +## Exit app: `bye` +Exits the chatbot + +Format: `bye` + +## Command Summary + +| Command | Format, Examples | +| ------- | --------------- | +| `list` | `list` | +| `todo` | `todo DESCRIPTION` e.g. `todo tutorial` | +| `deadline` | `deadline DESCRIPTION by DEADLINE` e.g. `deadline return book by 4pm` | +| `event` | `event DESCRIPTION from START to END` e.g. `event Math exam from 2pm to 4pm` | +| `delete` | `delete INDEX` e.g. `delete 3` | +| `mark` | `mark INDEX` e.g. `mark 2` | +| `unmark` | `unmark INDEX` e.g. `unmark 1` | +| `find` | `find KEYWORD` e.g. `find book` | +| `bye` | `bye` | \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 8077118eb..096fe006d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,122 @@ -# User Guide +# User Guide for chatbot "Apple" -## Features +Chatbot Apple is an app to manage tasks, optimised for use through a Command Line Interface (CLI). -### Feature-ABC +## Quick Start +1. Ensure Java 11 or above is installed in your computer +2. Download `ip.jar` from [here](https://github.com/hongyijie06/ip/releases/tag/A-Release) +3. Open a command terminal, `cd` into the folder with the jar file and use the `java -jar ip.jar` command to run the application. +4. Type the command into the command line and press Enter to execute it. e.g. typing list and pressing Enter will list the current tasks. + Some example commands you can try: -Description of the feature. + - `todo tutorial`: Adds task "tutorial" to the list + - `deadline return book by 4pm`: Adds task "return book" nd deadline "4pm" to the list + - `list`: Lists all tasks + - `bye`: Exits the app -### Feature-XYZ +5. Refer to the Features below for more details on each command. -Description of the feature. +## Features -## Usage +[!NOTE] +> Words in `UPPER_CASE` are parameters to be supplied by the user. e.g. in `delete INDEX`, `INDEX` is a parameter which can be used as `delete 3` -### `Keyword` - Describe action +## Add tasks +### Add todo : `todo` +Adds task of type todo to the list of tasks -Describe the action and its outcome. +Format: `todo DESCRIPTION` -Example of usage: +Examples: +- `todo tutorial` Adds task `tutorial` to the list of tasks +- `todo watch lecture` Adds task `watch lecture` to the list of tasks -`keyword (optional arguments)` +### Add deadline: `deadline` +Adds task of type deadline to the list of tasks -Expected outcome: +Format: `deadline DESCRIPTION by DEADLINE` -Description of the outcome. +Examples: +- `deadline return book by 4pm` Adds task `return book` with deadline `4pm` to the list of tasks +- `deadline submit group report by 7pm` Adds task `submit group report` with deadline `7pm` to the list of tasks -``` -expected output -``` +### Add event: `event` +Adds task of type event to the list of tasks + +Format: `event DESCRIPTION from START to END` + +Examples: +- `event Math exam from 2pm to 4pm` Adds task `Math exam` with timeline `2pm` to `4pm` to the list of tasks +- `event project group meeting from 11am to 1pm` Adds task `project group meeting` with timeline `11am` to `1pm` to the list of tasks + +## Listing tasks: `list` +Lists all tasks in the task list. + +Format: `list` + +## Mark tasks as done: `mark` +Marks tasks as completed + +Format: `mark INDEX` + +- Marks task as done at the specified `INDEX`. +- The index refers to the index of the task in the list of tasks. +- The index must be a positive integer. + +Examples: +- `mark 1` Marks first task in the list as done +- `mark 3` Marks sixth task in the list as done + +## Unmark tasks: `unmark` +Marks tasks as undone + +Format: `unmark INDEX` + +- Marks task as not done at the specified `INDEX`. +- The index refers to the index of the task in the list of tasks. +- The index must be a positive integer. + +Examples: +- `unmark 1` Marks first task in the list as not done +- `unmark 2` Marks second task in the list as not done + +## Find Keywords: `find` +Filters list of tasks to those containing the keyword the user wants to find + +Format: `find KEYWORD` + +Examples: +- `find book` CLI returns a list with all the tasks with the `KEYWORD` `book`. +- `find group` CLI returns a list with all the tasks with the `KEYWORD` `group`. + +## Delete tasks: `delete` +Deletes task from the list of tasks + +Format: `delete INDEX` + +- Deletes task at the specified `INDEX`. +- The index refers to the index of the task in the list of tasks. +- The index must be a positive integer. + +Examples: +- `delete 3` Deletes third task in the list +- `delete 5` Deletes fifth task in the list + +## Exit app: `bye` +Exits the chatbot + +Format: `bye` + +## Command Summary + +| Command | Format, Examples | +| ------- | --------------- | +| `todo` | `todo DESCRIPTION` e.g. `todo tutorial` | +| `deadline` | `deadline DESCRIPTION by DEADLINE` e.g. `deadline return book by 4pm` | +| `event` | `event DESCRIPTION from START to END` e.g. `event Math exam from 2pm to 4pm` | +| `list` | `list` | +| `mark` | `mark INDEX` e.g. `mark 2` | +| `unmark` | `unmark INDEX` e.g. `unmark 1` | +| `find` | `find KEYWORD` e.g. `find book` | +| `delete` | `delete INDEX` e.g. `delete 3` | +| `bye` | `bye` | \ No newline at end of file diff --git a/production/main/CreateFile.class b/production/main/CreateFile.class new file mode 100644 index 000000000..1e7af2c53 Binary files /dev/null and b/production/main/CreateFile.class differ diff --git a/production/main/Deadline.class b/production/main/Deadline.class new file mode 100644 index 000000000..a306b63f8 Binary files /dev/null and b/production/main/Deadline.class differ diff --git a/production/main/Duke.class b/production/main/Duke.class new file mode 100644 index 000000000..c9293f48a Binary files /dev/null and b/production/main/Duke.class differ diff --git a/production/main/EmptyLineException.class b/production/main/EmptyLineException.class new file mode 100644 index 000000000..c25befa72 Binary files /dev/null and b/production/main/EmptyLineException.class differ diff --git a/production/main/Event.class b/production/main/Event.class new file mode 100644 index 000000000..6c21ce09f Binary files /dev/null and b/production/main/Event.class differ diff --git a/production/main/ManageInputs.class b/production/main/ManageInputs.class new file mode 100644 index 000000000..ba19acc4b Binary files /dev/null and b/production/main/ManageInputs.class differ diff --git a/production/main/ReadFileContents.class b/production/main/ReadFileContents.class new file mode 100644 index 000000000..acca04e15 Binary files /dev/null and b/production/main/ReadFileContents.class differ diff --git a/production/main/Task.class b/production/main/Task.class new file mode 100644 index 000000000..668ea5de9 Binary files /dev/null and b/production/main/Task.class differ diff --git a/production/main/Todo.class b/production/main/Todo.class new file mode 100644 index 000000000..849ca63fa Binary files /dev/null and b/production/main/Todo.class differ diff --git a/production/main/UnexpectedCommandException.class b/production/main/UnexpectedCommandException.class new file mode 100644 index 000000000..6c0d54dfe Binary files /dev/null and b/production/main/UnexpectedCommandException.class differ diff --git a/src/.idea/.gitignore b/src/.idea/.gitignore new file mode 100644 index 000000000..13566b81b --- /dev/null +++ b/src/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/src/.idea/.name b/src/.idea/.name new file mode 100644 index 000000000..305fff84b --- /dev/null +++ b/src/.idea/.name @@ -0,0 +1 @@ +Task.class \ No newline at end of file diff --git a/src/.idea/misc.xml b/src/.idea/misc.xml new file mode 100644 index 000000000..e0844bc7b --- /dev/null +++ b/src/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/.idea/modules.xml b/src/.idea/modules.xml new file mode 100644 index 000000000..b8cce4602 --- /dev/null +++ b/src/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/.idea/vcs.xml b/src/.idea/vcs.xml new file mode 100644 index 000000000..6c0b86358 --- /dev/null +++ b/src/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/TaskList.txt b/src/TaskList.txt new file mode 100644 index 000000000..74091fd17 --- /dev/null +++ b/src/TaskList.txt @@ -0,0 +1,16 @@ +[T][0] hike +[T][0] run +[D][0] tut (by: 5) +[E][0] he (from: 5 to: 6) +[T][0] jump +[T][0] go +[D][0] hop (by: 4) +[E][0] he (from: 4 to: 5) +[D][0] b (by: 4) +[E][0] go (from: 4 to: 454) +[T][0] ds +[D][0] kj (by: 4) +[T][0] he +[E][0] f (from: 4 to: 5) +[D][0] sd (by: 5) +[D][0] hsd (by: 343354535) diff --git a/src/main/java/CreateFile.java b/src/main/java/CreateFile.java new file mode 100644 index 000000000..8162aba93 --- /dev/null +++ b/src/main/java/CreateFile.java @@ -0,0 +1,33 @@ +import java.io.File; +import java.io.IOException; + +/** + * creates local TaskList.txt file on the local machine + */ +public class CreateFile { + protected static Ui ui; + public static void CreateFile() { + File file = new File("TaskList.txt"); + String errorDescription; + String fileStatus; + + if (!file.exists()) { + try { + if (file.createNewFile()) { + fileStatus = "File created"; + System.out.println(fileStatus + ": " + file.getAbsolutePath()); + } else { + errorDescription = "File creation failed."; + ui.errorMessage(errorDescription); + } + } catch (IOException e) { + errorDescription = "An I/O error occurred."; + ui.errorMessage(errorDescription); + e.printStackTrace(); + } + } else { + fileStatus = "File already exists"; + System.out.println(fileStatus + ": " + file.getAbsolutePath()); + } + } +} diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java new file mode 100644 index 000000000..c85aa1cf8 --- /dev/null +++ b/src/main/java/Deadline.java @@ -0,0 +1,16 @@ +/** + * child class of Task to handle deadlines + */ +public class Deadline extends Task { + protected String by; + + public Deadline(String description, String by) { + super(description); + this.by = by; + } + + @Override + public String toString() { + return "[D]" + super.toString() + " (by: " + by + ")"; + } +} diff --git a/src/main/java/Duke.class b/src/main/java/Duke.class new file mode 100644 index 000000000..76684001f Binary files /dev/null and b/src/main/java/Duke.class differ diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 5d313334c..df9a9300c 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,10 +1,60 @@ +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.sql.Array; +import java.util.Scanner; +import java.util.ArrayList; + public class Duke { - public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); + + /** + * lists tasks saved in the local TaskList.txt file + * @param filePath the path to the local TaskList.txt file + * @throws FileNotFoundException exception when local TaskList.txt file does not exist + */ + private static void printFileContents (String filePath) throws FileNotFoundException { + File f = new File(filePath); // create a File for the given file path + Scanner s = new Scanner(f); // create a Scanner using the File as the source + while (s.hasNext()) { + System.out.println(s.nextLine()); + } + } + + private static Ui ui; + public static void main (String[] args) throws UnexpectedCommandException, EmptyLineException, IOException, FileNotFoundException { + ArrayList tasks = new ArrayList(); + String errorDescription; + int index = 0;//number of items in the list + String line = " "; + File file = new File("TaskList.txt"); + + ui = new Ui(); + ui.sayHi(); + try { + System.out.println("Here are the items in your task list: "); + printFileContents("TaskList.txt"); + } catch (FileNotFoundException e) { + errorDescription = "File not found"; + ui.errorMessage(errorDescription); + } + + if (!file.exists()) { + try { + if (file.createNewFile()) { + System.out.println("File created: " + file.getAbsolutePath()); + } else { + errorDescription = "File creation failed."; + ui.errorMessage(errorDescription); + } + } catch (IOException e) { + errorDescription = "An I/O error occurred."; + ui.errorMessage(errorDescription); + e.printStackTrace(); + } + } else { + System.out.println("File already exists: " + file.getAbsolutePath()); + } + + new Parser(tasks, index, line); } } diff --git a/src/main/java/EmptyLineException.java b/src/main/java/EmptyLineException.java new file mode 100644 index 000000000..5348ca427 --- /dev/null +++ b/src/main/java/EmptyLineException.java @@ -0,0 +1,3 @@ +public class EmptyLineException extends Exception { + +} diff --git a/src/main/java/Event.java b/src/main/java/Event.java new file mode 100644 index 000000000..7c94810a5 --- /dev/null +++ b/src/main/java/Event.java @@ -0,0 +1,18 @@ +/** + * child class of Task to handle events + */ +public class Event extends Task { + protected String from; + protected String to; + + public Event(String description, String from, String to){ + super(description); + this.from = from; + this.to = to; + } + + @Override + public String toString() { + return "[E]" + super.toString() + " (from: " + from + " to: " + to + ")"; + } +} diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java new file mode 100644 index 000000000..fe92bb35b --- /dev/null +++ b/src/main/java/Parser.java @@ -0,0 +1,226 @@ +import java.io.IOException; +import java.util.ArrayList; +import java.util.Scanner; + +/** + * deals with making sense of the user command + */ +public class Parser { + private static Ui ui; + private static Storage storage; + private static TaskList tasklist; + + /** + * marks task as done + * @param inputs the array of words the user input + * @param tasks the array of tasks + * @param index the number of tasks in the array of tasks + * @param isValidCommand boolean is true if the command from the user is a valid action + * @throws IOException exception when there is an I/O error + */ + private void dealWithMark (String[] inputs, ArrayList tasks, int index, boolean isValidCommand) throws IOException { + isValidCommand = true; + String errorDescription; + + try { + int markIdx = Integer.parseInt(inputs[1]) - 1; //index to mark as done + tasks.get(markIdx).markAsDone(); + System.out.println("Nice! I've marked this task as done: "); + System.out.println(tasks.get(markIdx)); + storage.saveToFile(tasks, index); + } catch (IndexOutOfBoundsException e) { + errorDescription = "did not indicate which task to mark"; + ui.errorMessage(errorDescription); + } + } + + /** + * marks task as undone + * @param inputs the array of words input by the user + * @param tasks the array of tasks + * @param index the number of tasks in the array of tasks + * @param isValidCommand boolean is true if the command from the user is a valid action + * @throws IOException exception when there is an I/O error + */ + private void dealWithUnmark (String[] inputs, ArrayList tasks, int index, boolean isValidCommand) throws IOException { + isValidCommand = true; + String errorDescription; + + try { + int unmarkIdx = Integer.parseInt(inputs[1]) - 1; //index of task to unmark + tasks.get(unmarkIdx).unmarkDone(); + System.out.println("OK, I've marked this task as not done yet: "); + System.out.println(tasks.get(unmarkIdx)); + storage.saveToFile(tasks, index); + } catch (IndexOutOfBoundsException e) { + errorDescription = "did not indicate which task to unmark"; + ui.errorMessage(errorDescription); + } + } + + /** + * lists tasks + * @param tasks the array of tasks + * @param index the number of tasks in the array of tasks + * @param isValidCommand boolean is true if the command from the user is a valid action + */ + private void listTasks (ArrayList tasks, int index, boolean isValidCommand) { + isValidCommand = true; + System.out.println("Here are the tasks in your list: "); + + for (int taskNumber = 0; taskNumber < index; taskNumber++) { + System.out.println((taskNumber + 1) + ". " + tasks.get(taskNumber)); + } + } + + /** + * deletes task + * @param tasks the array of tasks + * @param inputs the array of words input by the user + * @param index the number of tasks in the array of tasks + * @param isValidCommand boolean is true if the command from the user is a valid action + * @return the number of tasks in the array of tasks after deletion + * @throws UnexpectedCommandException exception when the format or details of the tasks are not followed and provided respectively + * @throws IOException exception when there is an I/O error + */ + private int deleteTask (ArrayList tasks, String[] inputs, int index, boolean isValidCommand) throws UnexpectedCommandException, IOException { + isValidCommand = true; + Storage.fillFileContents(tasks, "TaskList.txt", index); + TaskList.dealWithDelete(inputs, inputs[1], tasks); + index--; + System.out.println("Now you have " + index + " tasks in the list."); + storage.saveToFile(tasks, index); + return index; + } + + /** + * filters tasks with the keyword input by the user + * @param findInput the keyword the user is looking for + * @param tasks the array of tasks + * @param index the number of tasks in the array of tasks + */ + private void dealWithFind (String findInput, ArrayList tasks, int index) { + ArrayList matchingTasks = new ArrayList(); + int matchingTasksIndex = 1; + System.out.println("Here are the matching tasks in your list: "); + for (int taskNumber = 0; taskNumber < index; taskNumber ++){ + String taskString = tasks.get(taskNumber).toString(); + if (taskString.contains(findInput)) { + System.out.print(matchingTasksIndex + ". "); + matchingTasks.add(tasks.get(taskNumber)); + System.out.println(matchingTasks.get(matchingTasksIndex - 1)); + matchingTasksIndex ++; + } + } + } + + + private void handleUnexpectedCommand (boolean isValidCommand) throws UnexpectedCommandException { + if (!isValidCommand) { + throw new UnexpectedCommandException(); + } + } + + private void handleEmptyInput (String line) throws EmptyLineException { + if (line.isEmpty()) { + throw new EmptyLineException(); + } + } + + /** + * handles the different commands input by the user + * @param tasks the array of tasks + * @param index the number of tasks in the array of tasks + * @param line the user input + * @throws IOException exception when there is an I/O error + * @throws IndexOutOfBoundsException exception when there is missing required details in the input + * @throws UnexpectedCommandException exception when the format or details of the tasks are not followed and provided respectively + */ + public Parser (ArrayList tasks, int index, String line) throws IOException, IndexOutOfBoundsException, UnexpectedCommandException { + boolean isInTxt = true; + index = Storage.fillFileContents(tasks, "TaskList.txt", index); + isInTxt = false; + ui = new Ui(); + String errorDescription; + + while (!line.equals("bye")) { + ui.readCommand(); + Boolean isValidCommand = false; + Scanner input = new Scanner(System.in); + line = input.nextLine(); + + Task t = new Task(line); + String[] inputs = line.split(" "); + + final String commandType = inputs[0]; + + if (commandType.equals("mark")) {//mark as done + dealWithMark(inputs, tasks, index, isValidCommand); + Storage.saveToFile(tasks, index); + } else if (commandType.equals("unmark")) {//unmark done + dealWithUnmark(inputs, tasks, index, isValidCommand); + Storage.saveToFile(tasks, index); + } else if (line.equals("list")) {//lists tasks + listTasks(tasks, index, isValidCommand); + } else if (line.equals("bye")) {//exit chat + isValidCommand = true; + Storage.saveToFile(tasks, index); + break; + } else if (commandType.equals("event") || commandType.equals("todo") || commandType.equals("deadline")) {//add items + try { + if (commandType.equals("event")) { + isValidCommand = true; + TaskList.dealWithEvent(tasks, index, line, isInTxt); + Storage.writeToFile("TaskList.txt", tasks.get(index)); + System.out.println("Got it. I've added this task: "); + System.out.println(tasks.get(index)); + index++; + } else if (commandType.equals("deadline")) { + isValidCommand = true; + TaskList.dealWithDeadline(tasks, index, line, isInTxt); + Storage.writeToFile("TaskList.txt", tasks.get(index)); + System.out.println("Got it. I've added this task: "); + System.out.println(tasks.get(index)); + index++; + } else { + isValidCommand = true; + TaskList.dealWithTodo(tasks, index, line, isInTxt); + Storage.writeToFile("TaskList.txt", tasks.get(index)); + System.out.println("Got it. I've added this task: "); + System.out.println(tasks.get(index)); + index++; + } + } catch (IOException | UnexpectedCommandException | IndexOutOfBoundsException e) { + } + System.out.println("Now you have " + index + " tasks in the list."); + + } else if (commandType.equals("delete")) { + try { + index = deleteTask(tasks, inputs, index, isValidCommand); + } catch (ArrayIndexOutOfBoundsException e) { + errorDescription = "please specify which task you want to delete"; + ui.errorMessage(errorDescription); + } + } else if (commandType.equals("find")) { + try { + dealWithFind(inputs[1], tasks, index); + } catch (ArrayIndexOutOfBoundsException e) { + errorDescription = "please state what you would like to find"; + ui.errorMessage(errorDescription); + } + } else { + try { + handleEmptyInput(line); + handleUnexpectedCommand(isValidCommand); + } catch (UnexpectedCommandException e) { + errorDescription = "Please enter a valid command"; + ui.errorMessage(errorDescription); + } catch (EmptyLineException e) { + errorDescription = "No input detected. Please enter a task"; + ui.errorMessage(errorDescription); + } + } + } + ui.sayBye(); + } +} \ No newline at end of file diff --git a/src/main/java/ReadFileContents.java b/src/main/java/ReadFileContents.java new file mode 100644 index 000000000..0a797b2c7 --- /dev/null +++ b/src/main/java/ReadFileContents.java @@ -0,0 +1,28 @@ +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; + +/** + * prints TaskList.txt file contents + */ +public class ReadFileContents { + private static Ui ui; + + private static void printFileContents (String filePath) throws FileNotFoundException { + File file = new File(filePath); + Scanner taskString = new Scanner(file); //reads tasks from TaskList.txt file + while (taskString.hasNext()) { + System.out.println(taskString.nextLine()); + } + } + + public static void main(String[] args) { + try { + printFileContents("TaskList.txt"); + } catch (FileNotFoundException e) { + new CreateFile(); + String errorDescription = "File not found"; + ui.errorMessage(errorDescription); + } + } +} \ No newline at end of file diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java new file mode 100644 index 000000000..e40b26e1e --- /dev/null +++ b/src/main/java/Storage.java @@ -0,0 +1,64 @@ +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Scanner; + +/** + * deals with loading tasks from the file and saving tasks in the file + */ +public class Storage { + /** + * loads ArrayList tasks with tasks saved on TaskList.txt + * @param tasks contains the list of tasks + * @param filePath the path to TaskList.txt saved on the local machine + * @param index the number of tasks saved in TaskList.txt + * @return index the number of tasks saved in TaskList.txt + * @throws IOException exception when local TaskList.txt file does not exist + * @throws UnexpectedCommandException exception when the format or details of the tasks are not followed and provided respectively + */ + public static int fillFileContents (ArrayList tasks, String filePath, int index) throws IOException, UnexpectedCommandException {//updates index + File f = new File(filePath); // create a File for the given file path + Scanner taskLine = new Scanner(f); // create a Scanner using the File as the source + + while (taskLine.hasNext()) { + String sLine = taskLine.nextLine(); + + if (sLine.contains("[E]")) { + TaskList.dealWithEvent(tasks, index, sLine, true); + } else if (sLine.contains("[D]")) { + TaskList.dealWithDeadline(tasks, index, sLine, true); + } else if (sLine.contains("[T]")) { + TaskList.dealWithTodo(tasks, index, sLine, true); + } + index++; + } + boolean isInTxt = false; + return index; + } + + /** + * saves the updated tasks list onto TaskList.txt in the local machine + * @param tasks the array of tasks + * @param index the nymber of tasks in array of tasks + * @throws IOException exception when there is an I/O error + */ + protected static void saveToFile (ArrayList tasks, int index) throws IOException { + new FileWriter("TaskList.txt", false).close(); + for (int TaskIndex = 0; TaskIndex < index; TaskIndex ++) { + writeToFile("TaskList.txt", tasks.get(TaskIndex)); + } + } + + /** + * adds additional tasks into TaskList.txt + * @param filePath the path to TaskList.txt saved on the local machine + * @param textToAdd the new task to add + * @throws IOException exception when there is an I/O error + */ + static void writeToFile (String filePath, Task textToAdd) throws IOException { + FileWriter fw = new FileWriter(filePath, true); + fw.write(textToAdd + "\n"); + fw.close(); + } +} diff --git a/src/main/java/Task.java b/src/main/java/Task.java new file mode 100644 index 000000000..11b9b77da --- /dev/null +++ b/src/main/java/Task.java @@ -0,0 +1,29 @@ +/** + * variables and functions that children classes of tasks inherit + * children classes in this chatbot include event, deadline and todo + */ +public class Task { + protected String description; + protected boolean isDone; + public Task(String description) { + this.description = description; + this.isDone = false; + } + + public String getStatusIcon() { + return (isDone ? "1" : "0"); // mark done task with X + } + + public void markAsDone() { + this.isDone = true; + } + + public void unmarkDone() { + this.isDone = false; + } + + public String toString(){ + return "[" + getStatusIcon() + "]" + description; + } +} + diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java new file mode 100644 index 000000000..398f411e6 --- /dev/null +++ b/src/main/java/TaskList.java @@ -0,0 +1,198 @@ +import java.io.IOException; +import java.util.ArrayList; + +/** + * contains the task list and operations to add or delete tasks + */ +public class TaskList { + protected static Ui ui; + protected static ArrayList tasks; + public TaskList(){ + this.tasks = tasks; + } + + /** + * adds event to array of tasks + * @param tasks the array of tasks + * @param index the number of tasks in the array of tasks + * @param line the input string from the user + * @param isInTxt true if ArrayList tasks is being loaded from TaskList.txt + * @throws UnexpectedCommandException exception when the format or details of the tasks are not followed and provided respectively + * @throws IOException exception when there is an I/O error + */ + public static void dealWithEvent (ArrayList tasks, int index, String line, boolean isInTxt) throws UnexpectedCommandException, IOException { + int indexTo = line.lastIndexOf("to"); + int indexFrom = line.indexOf("from"); + String from; + String to; + String description; + String errorDescription; + + final int LENGTHOFFROM = 5; //length of "from " + final int LENGTHOFTO = 3; + final int EVENTCOMMANDLENGTH = 6;//length of "event " + + final int FROMLENGTHCOLON = 6;//length of "from: " + final int TOLENGTHCOLON = 4; + final int STATUSLENGTH = 5;//length of "[E][ ]" + + if ((indexTo == -1) || (indexFrom == -1)) { //invalid format + errorDescription = "Invalid format! Enter event in the format: event (description) from (start) to (end)"; + ui.errorMessage(errorDescription); + throw new UnexpectedCommandException(); + } + try {//timeline not specified/ both not specified + from = line.substring(indexFrom + LENGTHOFFROM, indexTo - 1); + to = line.substring(indexTo + LENGTHOFTO); + } catch (IndexOutOfBoundsException e) { + try { + description = line.substring(EVENTCOMMANDLENGTH, indexFrom - 1); + } catch (IndexOutOfBoundsException f) { + errorDescription = "event description and timeline not specified"; + ui.errorMessage(errorDescription); + throw new UnexpectedCommandException(); + } + errorDescription = "event timeline not specified"; + ui.errorMessage(errorDescription); + throw new UnexpectedCommandException(); + } + try {//description not specified + description = line.substring(EVENTCOMMANDLENGTH, indexFrom - 1); + } catch (IndexOutOfBoundsException e) { + errorDescription = "event description not specified"; + ui.errorMessage(errorDescription); + throw new UnexpectedCommandException(); + } + if (!isInTxt) { + from = line.substring(indexFrom + LENGTHOFFROM, indexTo - 1); + to = line.substring(indexTo + LENGTHOFTO); + description = line.substring(STATUSLENGTH, indexFrom - 1); + } else { + from = line.substring(indexFrom + FROMLENGTHCOLON, indexTo - 1); + to = line.substring(indexTo + TOLENGTHCOLON, line.length() - 1); + description = line.substring(EVENTCOMMANDLENGTH, indexFrom - 1); + } + tasks.add(index, new Event(description, from, to)); + final int STATUSINDEX = 4; + if (isInTxt){ + char[] charArray = line.toCharArray(); + if (charArray[STATUSINDEX] == '1'){ + tasks.get(index).markAsDone(); + } else{ + tasks.get(index).unmarkDone(); + } + } + } + + /** + * adds deadline to array of tasks + * @param tasks the array of tasks + * @param index the number of tasks in the array of tasks + * @param line the input string from the user + * @param isInTxt true if ArrayList tasks is being loaded from TaskList.txt + * @throws UnexpectedCommandException exception when the format or details of the tasks are not followed and provided respectively + * @throws IOException exception when there is an I/O error + */ + public static void dealWithDeadline (ArrayList tasks, int index, String line, boolean isInTxt) throws UnexpectedCommandException, IOException { + int indexBy = line.indexOf("by"); + int space = line.indexOf(" "); + String by; + String description; + String errorDescription; + + final int LENGTHFBY = 3;//length of "by " + final int BYLENGTHCOLON = 4; //length of "by: " + + if (indexBy == -1) {//invalid format + errorDescription = "Invalid format! Enter deadline in the format: deadline (description) by (deadline)"; + ui.errorMessage(errorDescription); + throw new UnexpectedCommandException(); + } + try {//deadline / both not specified + by = line.substring(indexBy + LENGTHFBY); + } catch (IndexOutOfBoundsException e) { + try { + description = line.substring(space + 1, indexBy - 1); + } catch (IndexOutOfBoundsException f) { + errorDescription = "deadline description and deadline not specified"; + ui.errorMessage(errorDescription); + throw new UnexpectedCommandException(); + } + errorDescription = "deadline not specified"; + ui.errorMessage(errorDescription); + throw new UnexpectedCommandException(); + } + try {//deadline not specified + description = line.substring(space + 1, indexBy - 1); + } catch (IndexOutOfBoundsException e) { + errorDescription = "deadline description not specified"; + ui.errorMessage(errorDescription); + throw new UnexpectedCommandException(); + } + if (!isInTxt) { + description = line.substring(space, indexBy - 1); + by = line.substring(indexBy + LENGTHFBY); + } else { + description = line.substring(space, indexBy - 1); + by = line.substring(indexBy + BYLENGTHCOLON, line.length() - 1); + } + + tasks.add(index, new Deadline(description, by)); + if (isInTxt) { + final int STATUSINDEX = 4; + char[] charArray = line.toCharArray(); + if (charArray[STATUSINDEX] == '1'){ + tasks.get(index).markAsDone(); + } else { + tasks.get(index).unmarkDone(); + } + } + } + + /** + * adds todo to array of tasks + * @param tasks the array of tasks + * @param index the number of tasks in the array of tasks + * @param line the input string from the user + * @param isInTxt true if ArrayList tasks is being loaded from TaskList.txt + * @throws UnexpectedCommandException exception when the format or details of the tasks are not followed and provided respectively + * @throws IOException exception when there is an I/O error + */ + public static void dealWithTodo (ArrayList tasks, int index, String line, boolean isInTxt) throws UnexpectedCommandException, IOException { + int indexSpace = line.indexOf(" "); + final int STATUSINDEX = 4; + String errorDescription; + + if (indexSpace == -1) { + errorDescription = "todo description not specified"; + ui.errorMessage(errorDescription); + throw new UnexpectedCommandException(); + } + + String description = line.substring(indexSpace); + tasks.add(index, new Todo(description)); + if (isInTxt) { + char[] charArray = line.toCharArray(); + if (charArray[STATUSINDEX] == '1') { + tasks.get(index).markAsDone(); + } else { + tasks.get(index).unmarkDone(); + } + } + } + + /** + * deletes item from array of tasks + * @param inputs the array of words input by the user + * @param ListIndex the string containing the task number to delete + * @param tasks the array of tasks + */ + public static void dealWithDelete (String[] inputs, String ListIndex, ArrayList tasks) { + if (inputs[0].equals("delete")) { + int deleteIdx = Integer.parseInt(ListIndex) - 1; //index of task to delete + System.out.println("Noted. I've removed this task: "); + System.out.println(tasks.get(deleteIdx)); + tasks.remove(deleteIdx); + } + } +} diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java new file mode 100644 index 000000000..50d8abdcd --- /dev/null +++ b/src/main/java/Todo.java @@ -0,0 +1,14 @@ +/** + * child class of Task to handle todos + */ +public class Todo extends Task { + + public Todo (String description){ + super(description); + } + @Override + public String toString() { + return "[T]" + super.toString(); + } + +} diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java new file mode 100644 index 000000000..1e0a62a5b --- /dev/null +++ b/src/main/java/Ui.java @@ -0,0 +1,22 @@ +/** + * deals with interactions with the user + */ + +public class Ui { + public void sayHi() { + System.out.println("Hello! I'm Apple"); + System.out.println("What can I do for you?"); + } + + public void readCommand() { + System.out.print("Enter your command: "); + } + + public static void errorMessage (String message) { + System.out.println(message); + } + + public void sayBye() { + System.out.println("Bye. Hope to see you again soon!"); + } +} diff --git a/src/main/java/UnexpectedCommandException.java b/src/main/java/UnexpectedCommandException.java new file mode 100644 index 000000000..0b8f65fcf --- /dev/null +++ b/src/main/java/UnexpectedCommandException.java @@ -0,0 +1,3 @@ +public class UnexpectedCommandException extends Exception { + +} diff --git a/src/out/production/ip/Deadline.class b/src/out/production/ip/Deadline.class new file mode 100644 index 000000000..a306b63f8 Binary files /dev/null and b/src/out/production/ip/Deadline.class differ diff --git a/src/out/production/ip/Duke.class b/src/out/production/ip/Duke.class new file mode 100644 index 000000000..9e185ddde Binary files /dev/null and b/src/out/production/ip/Duke.class differ diff --git a/src/out/production/ip/EmptyLineException.class b/src/out/production/ip/EmptyLineException.class new file mode 100644 index 000000000..c25befa72 Binary files /dev/null and b/src/out/production/ip/EmptyLineException.class differ diff --git a/src/out/production/ip/Event.class b/src/out/production/ip/Event.class new file mode 100644 index 000000000..6c21ce09f Binary files /dev/null and b/src/out/production/ip/Event.class differ diff --git a/src/out/production/ip/ManageInputs.class b/src/out/production/ip/ManageInputs.class new file mode 100644 index 000000000..3e38f8aa6 Binary files /dev/null and b/src/out/production/ip/ManageInputs.class differ diff --git a/src/out/production/ip/Task.class b/src/out/production/ip/Task.class new file mode 100644 index 000000000..3a2f54fde Binary files /dev/null and b/src/out/production/ip/Task.class differ diff --git a/src/out/production/ip/Todo.class b/src/out/production/ip/Todo.class new file mode 100644 index 000000000..849ca63fa Binary files /dev/null and b/src/out/production/ip/Todo.class differ diff --git a/src/out/production/ip/UnexpectedCommandException.class b/src/out/production/ip/UnexpectedCommandException.class new file mode 100644 index 000000000..6c0d54dfe Binary files /dev/null and b/src/out/production/ip/UnexpectedCommandException.class differ