diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index fd8c44d086..e2062c4201 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -33,18 +33,18 @@ jobs:
- name: Build and check with Gradle
run: ./gradlew check
- - name: Perform IO redirection test (*NIX)
- if: runner.os == 'Linux'
- working-directory: ${{ github.workspace }}/text-ui-test
- run: ./runtest.sh
-
- - name: Perform IO redirection test (MacOS)
- if: always() && runner.os == 'macOS'
- working-directory: ${{ github.workspace }}/text-ui-test
- run: ./runtest.sh
-
- - name: Perform IO redirection test (Windows)
- if: always() && runner.os == 'Windows'
- working-directory: ${{ github.workspace }}/text-ui-test
- shell: cmd
- run: runtest.bat
\ No newline at end of file
+# - name: Perform IO redirection test (*NIX)
+# if: runner.os == 'Linux'
+# working-directory: ${{ github.workspace }}/text-ui-test
+# run: ./runtest.sh
+#
+# - name: Perform IO redirection test (MacOS)
+# if: always() && runner.os == 'macOS'
+# working-directory: ${{ github.workspace }}/text-ui-test
+# run: ./runtest.sh
+#
+# - name: Perform IO redirection test (Windows)
+# if: always() && runner.os == 'Windows'
+# working-directory: ${{ github.workspace }}/text-ui-test
+# shell: cmd
+# run: runtest.bat
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index f69985ef1f..892becd300 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,11 @@ src/main/resources/docs/
.DS_Store
*.iml
bin/
+data/
+
/text-ui-test/ACTUAL.txt
text-ui-test/EXPECTED-UNIX.TXT
+
+src/main/java/META-INF/MANIFEST.MF
+
diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..7ab5d3776f
--- /dev/null
+++ b/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: NuSchedule
+
diff --git a/README.md b/README.md
index 698b938529..8544e5db99 100644
--- a/README.md
+++ b/README.md
@@ -1,64 +1 @@
-# 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 (use the exact version), update Intellij to the most recent version.
-
-1. **Configure Intellij for JDK 11**, as described [here](https://se-education.org/guides/tutorials/intellijJdk.html).
-1. **Import the project _as a Gradle project_**, as described [here](https://se-education.org/guides/tutorials/intellijImportGradleProject.html).
-1. **Verify the set up**: After the importing is complete, locate the `src/main/java/seedu/duke/Duke.java` file, right-click it, and choose `Run Duke.main()`. If the setup is correct, you should see something like the below:
- ```
- > Task :compileJava
- > Task :processResources NO-SOURCE
- > Task :classes
-
- > Task :Duke.main()
- Hello from
- ____ _
- | _ \ _ _| | _____
- | | | | | | | |/ / _ \
- | |_| | |_| | < __/
- |____/ \__,_|_|\_\___|
-
- What is your name?
- ```
- Type some word and press enter to let the execution proceed to the end.
-
-## Build automation using Gradle
-
-* This project uses Gradle for build automation and dependency management. It includes a basic build script as well (i.e. the `build.gradle` file).
-* If you are new to Gradle, refer to the [Gradle Tutorial at se-education.org/guides](https://se-education.org/guides/tutorials/gradle.html).
-
-## Testing
-
-### I/O redirection tests
-
-* To run _I/O redirection_ tests (aka _Text UI tests_), navigate to the `text-ui-test` and run the `runtest(.bat/.sh)` script.
-
-### JUnit tests
-
-* A skeleton JUnit test (`src/test/java/seedu/duke/DukeTest.java`) is provided with this project template.
-* If you are new to JUnit, refer to the [JUnit Tutorial at se-education.org/guides](https://se-education.org/guides/tutorials/junit.html).
-
-## Checkstyle
-
-* A sample CheckStyle rule configuration is provided in this project.
-* If you are new to Checkstyle, refer to the [Checkstyle Tutorial at se-education.org/guides](https://se-education.org/guides/tutorials/checkstyle.html).
-
-## CI using GitHub Actions
-
-The project uses [GitHub actions](https://github.com/features/actions) for CI. When you push a commit to this repo or PR against it, GitHub actions will run automatically to build and verify the code as updated by the commit/PR.
-
-## Documentation
-
-`/docs` folder contains a skeleton version of the project documentation.
-
-Steps for publishing documentation to the public:
-1. If you are using this project template for an individual project, go your fork on GitHub.
- If you are using this project template for a team project, go to the team fork on GitHub.
-1. Click on the `settings` tab.
-1. Scroll down to the `GitHub Pages` section.
-1. Set the `source` as `master branch /docs folder`.
-1. Optionally, use the `choose a theme` button to choose a theme for your documentation.
+Please see [README.md](https://github.com/AY2021S1-CS2113T-F14-4/tp/tree/master/docs) in docs
diff --git a/build.gradle b/build.gradle
index b0c5528fb5..1162749d95 100644
--- a/build.gradle
+++ b/build.gradle
@@ -29,11 +29,11 @@ test {
}
application {
- mainClassName = "seedu.duke.Duke"
+ mainClassName = "NuSchedule"
}
shadowJar {
- archiveBaseName = "duke"
+ archiveBaseName = "TPv1.0"
archiveClassifier = null
}
@@ -41,6 +41,8 @@ checkstyle {
toolVersion = '8.23'
}
-run{
+run {
standardInput = System.in
+ enableAssertions = true
}
+
diff --git a/data/bus_stops.txt b/data/bus_stops.txt
new file mode 100644
index 0000000000..119cf974d3
--- /dev/null
+++ b/data/bus_stops.txt
@@ -0,0 +1,19 @@
+EA:B2,C,BTC2
+Raffles Hall:B2,C
+Information Technology:A2,B1,B2,D1
+Opp YIH:A2,B1,B2,D1
+NUS Museum:A2,BTC1,BTC2,C,D1,D2
+YIH:A1,B1,BTC1,D1
+CLB:A1,B1,BTC1,D1
+LT13:A1,B,D1,BTC1
+AS5:A1,B,D1,BTC1
+Ventus:A2,A2E,B,D1
+BIZ2:A1,A1E,D1,BTC1
+Opp NUSSU:A2,D1
+Opp HSSML:A2,D1
+Opp UHC:A1,C,D2
+COM2:A1,A2,B,D1
+UTown:D1,D2,B1,B1,C,BTC
+PGP:A1
+LT27:A1,A1E,C,D2
+S17:A2,A2E,C,D2
\ No newline at end of file
diff --git a/data/locations.txt b/data/locations.txt
new file mode 100644
index 0000000000..55e30f21fc
--- /dev/null
+++ b/data/locations.txt
@@ -0,0 +1,102 @@
+BLK/EA/EA
+BLK/EA/Information Technology
+BLK/E1A/EA
+BLK/EW1/EA,Information Technology
+BLK/EW1A/EA
+BLK/E2/EA
+BLK/E3/EA,Raffles Hall
+BLK/E3A/EA
+BLK/E4/Information Technology
+BLK/E4A/Opp YIH,YIH
+BLK/E5/Information Technology
+BLK/E5A/Raffles Hall
+BLK/E6/Opp YIH,YIH
+BLK/IT/Information Technology,CLB
+BLK/AS1/CLB,LT13
+BLK/AS2/Ventus,LT13
+BLK/AS3/Ventus,LT13
+BLK/AS4/LT13,AS5
+BLK/AS5/AS5
+BLK/AS6/CLB,COM2
+BLK/AS7/Ventus,LT13
+BLK/AS8/CLB
+BLK/SDE1/IT
+BLK/SDE2/IT
+BLK/SDE3/EA
+BLK/SDE4/IT
+BLK/CELC/IT
+BLK/S1/LT27
+BLK/S2/LT27
+BLK/S3/LT27
+BLK/S4/LT27
+BLK/S5/LT27
+BLK/S6/LT27
+BLK/S7/LT27
+BLK/S8/LT27
+BLK/S9/LT27
+BLK/S10/LT27
+BLK/S11/LT27
+BLK/S12/LT27
+BLK/S13/LT27
+BLK/S14/LT27
+BLK/S15/LT27
+BLK/S16/LT27
+BLK/S17/S17,LT27
+BLK/MD1/LT27
+BLK/MD2/LT27
+BLK/MD3/LT27
+BLK/MD4/LT27
+BLK/MD5/LT27
+BLK/MD6/LT27
+BLK/MD7/LT27
+BLK/MD8/LT27
+BLK/MD9/LT27
+BLK/MD10/LT27
+BLK/MD11/LT27
+BLK/COM1/COM2
+BLK/COM2/COM2
+BLK/BIZ1/BIZ2,COM2
+BLK/BIZ2/BIZ2
+BLK/Shaw Foundation Alumni House/Opp NUSSU
+H/Raffles Hall/Raffles Hall,NUS Museum
+H/Kent Ridge Hall/Opp HSSML
+H/King Edward VII Hall/PGP
+H/Sheares Hall/Opp HSSML
+H/Eusoff Hall/Ventus
+H/Temasek Hall/Opp NUSSU
+H/Cinnamon College/UTown
+H/College of Alice and Peter Tan/UTown
+H/Residental College 4/UTown
+H/RVRC/Opp UHC
+H/Tembusu College/UTown
+H/Prince George's Park/PGP
+H/UTown Residence/UTown
+L/LT1/E2
+L/LT2/E2
+L/LT6/E4
+L/LT7/EA
+L/LT7A/EA
+L/LT8/AS5
+L/LT9/AS1
+L/LT10/AS1
+L/LT11/AS2
+L/LT12/AS3
+L/LT13/AS3
+L/LT14/AS6
+L/LT15/AS6
+L/LT16/COM2
+L/LT17/COM2
+L/LT18/COM2
+L/LT19/COM2
+L/LT20/S3
+L/LT21/S5
+L/LT24/MD4
+L/LT25/MD7
+L/LT26/MD9
+L/LT27/LT27
+L/LT28/LT27
+L/LT29/LT27
+L/LT31/S16
+L/LT32/S1
+L/LT33/S17
+L/LT34/S17
\ No newline at end of file
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 0f072953ea..c8aa2196fd 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -2,8 +2,9 @@
Display | Name | Github Profile | Portfolio
--------|:----:|:--------------:|:---------:
- | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
+ | Wu Nan | [Github](https://github.com/max-wunan/) | [Portfolio](team/max-wunan.md)
+ | Xu Che | [Github](https://github.com/xuche123) | [Portfolio](team/xuche123.md)
+ | Yang Jiaqi | [Github](https://github.com/jiaaaqi) | [Portfolio](team/jiaaaqi.md)
+ | Wan Shi Jie Brendan | [Github](https://github.com/madbeez) | [Portfolio](team/madbeez.md)
+ | Zhuang Mengjin | [Github](https://github.com/Lee-Juntong) | [Portfolio](team/Lee-Juntong.md)
+
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 0ec3db103d..8f86bbe194 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -1,34 +1,466 @@
# Developer Guide
-## Design & implementation
+
+
-{Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.}
+Yang Jiaqi
+Zhuang Mengjin
-## Product scope
-### Target user profile
+Xu Che
-{Describe the target user profile}
+Wu Nan
-### Value proposition
+Wan Shi Jie Brendan
-{Describe the value proposition: what problem does it solve?}
+
-## User Stories
+## Table of Contents
+* [Introduction](#introduction)
+* [Getting Started](#getting-started)
+ * [Prerequisites](#prerequisites)
+ * [Setting Up](#setting-up)
+* [Design](#design)
+ * [Architecture](#architecture)
+ * [UI](#ui)
+ * [Storage](#storage)
+ * [Logic](#logic)
+ * [Model](#model)
+ * [Event](#event)
+ * [Location](#location)
+* [Implementation](#implementation)
+ * [Add events](#add-events)
+ * [Clear events](#clear-events)
+ * [Edit events](#edit-events)
+ * [Locate](#locate)
+ * [Reminders](#reminder)
+ * [Sort events](#sort-events)
+ * [View events](#view-events)
+ * [Help](#help)
+ * [Repeat](#repeat)
+ * [Delete](#delete)
+ * [Find](#find)
+ * [Find based on date](#find-based-on-date)
+ * [Print locations of a certain group](#print-locations-of-a-certain-group)
+ * [Study time](#study-time)
+ * [Done](#done)
+ * [User Info](#user-info)
+ * [Exit](#exit)
+* [Documentation](#documentation)
+* [Testing](#testing)
+* [Appendix A. Product scope](#appendix-a-product-scope)
+* [Appendix B. User stories](#appendix-b-user-stories)
+* [Appendix C. Non-functional requirements](#appendix-c-non-functional-requirements)
+* [Appendix D. Instructions for manual testing](#appendix-d-instructions-for-manual-testing)
-|Version| As a ... | I want to ... | So that I can ...|
-|--------|----------|---------------|------------------|
-|v1.0|new user|see usage instructions|refer to them when I forget how to use the application|
-|v2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list|
+## Introduction
+
+NUSchedule is a Command-Line based application that manages all of your commitments. Built with a clean and intuitive
+interface, NUSchedule will help you manage your commitments without any hassle. If you are a proficient in typing,
+NUSchedule will prove itself to be the most efficient way to manage your commitments.
+
+This developer guide provides information on the architecture and design of the application, NUSchedule. This guide
+provides information that will not only help you get started as a NUSchedule contributor, but that you will find useful
+to refer to even if you are already a contributor.
+
+## Getting Started
+
+This section provides information to help you get NUSchedule up and running on your own computers.
+
+### Prerequisites
+1. JDK 11
+2. Intellij IDEA
+
+### Setting Up
+
+1. Fork [this repo](https://github.com/AY2021S1-CS2113T-F14-4/tp), and clone the fork onto your computer.
+2. Open IntelliJ (if you are not in the welcome screen, click File > Close Project
+to close the existing project dialog
+first).
+3. Set up the correct JDK version for Gradle
+ 1. Click Configure > Project Defaults > Project Structure
+ 2. Click New… and set it to the directory of the JDK.
+4. Click Import Project (or Open or Import in newer version of Intellij).
+5. Locate the build.gradle file (not the root folder as you would do in a normal importing) and select it. Click OK.
+ If asked, choose to Open as Project (not Open as File).
+6. Click OK to accept the default settings but do ensure that the selected version of Gradle JVM matches the JDK
+ being used for the project.
+
+## Design
+
+This section describes the different components of the application and how each component interact with
+each other to run the program.
+
+### Architecture
+
+
+The Architecture Diagram above provides a high-level view of the design of NUSchedule. The app can be broken down into
+5 different components:
+1. Main: Initializes the other components and connects them with each other.
+2. UI: Manages the User Interface that the user interacts with.
+3. Logic: Interprets user commands.
+4. Storage: Reads data from and writes data to the hard disk.
+5. Model: Stores the data the app uses in memory.
+
+### UI
+
+
+*Figure 3.2.1 Class diagram for UI component*
+
+ __API__:`UI.java`
+The UI consists of various parts, e.g. `printGreetingMessage`, `printEventList`, `showError`, `printNumEvent`, etc.
+
+The `UI` component reads user input using readCommand() and then executes user commands according to the Logic component.
+
+### Storage
+__API__:`Storage.java`
+The `Storage` component can save the list of event data in .txt format and read it back.
+### Logic
+__API__:`Parser.java`
+
+
+
+*Figure 3.4.1 Class diagram for Logic component*
+
+The `Logic` component parses the user input and executes commands based on the given input.
+ 1. Parser reads the user input and returns a command to be executed by `NuSchedule`.
+ 2. The command execution affects the EventList (e.g. clearing the list).
+ 3. The result passes back to the UI, which then displays relevant feedback to the user (e.g. successful execution).
+
+### Model
+The `Model` component stores an ArrayList, events, that represents the current list of events and available locations.
+
+#### Event
+__API__:`EventList.java`
+
+### Location
+
+*Figure 3.6.1 Class diagram for location component*
+
+__API:__ `LocationList.java`
+
+The `LocationList` is made up of an ArrayList of Locations, which is a type of variable that stores different information
+for different types of location (eg. `Building`, `Hostel`, etc.). However, do note that any place that is
+not within the list of saved locations will be saved as type `OutOfNUS`, and would not be saved into the `location.txt`
+file. The location will still be part of the location list before the app closes, and it will also be
+saved as part of the Event information.
+
+
There is a separate api for bus stops (`BusStopList.java`), which stores all available bus stops
+and their information. Although the variable is declared in the main NUSchedule class, it is only referenced
+and not edited in any part of the program.
+
+
The `Location` component
+* stores information about various types of locations
+* prints the list of locations that is saved in the data file
+* checks if a location is being saved in the list and returns the location when asked
+
+## Implementation
+
+This section describes the implementation of some noteworthy features.
+
+### Add events
+
+This feature allows users to add events and relevant information about them (description, time and location) to the list
+. There are three possible types of events that can be added: classes, assignments, and personal events.
+
+Given below is an example usage scenario:
+
+Step 1. The user launches the application to add a class to his schedule. The user executes
+`class CS1010 Lecture /t 2020-05-05 10:00 /e 2020-05-05 12:00 /l LT27` to add a new class to the list.
+
+Step 2. The Parser class parses the input as a new class with description ‘CS1010 Lecture’,
+starting time ‘2020-05-05 at 10:00’, ending time ’2020-05-05 at 12:00’, and location ‘LT27’.
+
+Step 3. `addCommand()` is then called with the above parameters, and calls `addEvent()` from EventList to adds it to the list of events. It also checks
+whether there are any events that overlap in timing with the newly added event. The newly added event is then printed for the user through `UI`.
+
+The sequence diagram below shows the process of adding a new event.
+
+*Figure 4.1 Sequence Diagram for add function*
+
+### Clear events
+
+This feature allows users to completely delete the existing event information that is previously typed in by users.
+Users may choose to delete all events, events happened one month ago, or events happened before a certain date.
+
+Given below is an example usage scenario:
+
+Step 1. The user launches the application and wants to clear some events that happened a long time ago as there is no
+need to refer to these events anymore. The user types `clearBefore 2020-06-01` to clear all events before 1st June, 2020.
+
+Step 2. The Parser class parses the input and identifies the full command to be a ClearBeforeCommand class, and so
+`clearBeforeCommand()` will be called to create a `clearBeforeCommand` object with parameter `2020-06-01`.
+
+Step 3. After that, the `execute()` function of `clearBeforeCommand` will be called and as a result `EventList#clearBefore(clearDate)` will
+also be called, where `2020-06-01` will be passed as the parameter `clearDate`.
+
+Step 4. The user wants to clear all the extra information of events but does not want to do it manually, hence the user
+types in `autoClear on` to turn on the autoClear function, which will clear all events happened one month ago automatically.
+This function can be switched off by typing `autoClear off`.
+
+Note that the command `clear` does not require any parameter input.
+
+The sequence diagram below shows the process of clearing events before a certain date.
+
+*Figure 4.2.1 Sequence Diagram for clearBefore function*
+
+The sequence diagram below shows the process of clearing all events.
+
+*Figure 4.2.2 Sequence Diagram for clear function*
+
+### Edit events
+
+This feature allows users to edit the information of events that was previously added.
+
+Given below is an example usage scenario:
+
+Step 1. The user launches the application and inputs `assignment homework \t 2020-02-02 20:00 \l home` command to add an event.
+
+Step 2. The user realises that there was a mistake in the event added and decides to edit the task information by
+entering `edit 1`, which will be parsed by `Parser` and calls an `EditCommand` object.
+
+Step 3. The user follows the instructions on screen and enters the desired changes.
+
+Step 4. `EditCommand#execute()` will call `EventList#editEvents` to edit the event.
+
+
+*Figure 4.3 Sequence Diagram for EditCommand()*
+
+### Locate
+
+This feature allows users to add locations as part of the event information. If the place is located within the school,
+additional information about the location will be provided such as nearest bus stops or buildings. If the place is a
+bus stop, the buses available will be provided instead. The user will add location name as the last piece of information
+when adding an event. The LocationList has a method that searches for the place with the exact same name, if such a
+place is not found, it will create a location and allocate it to be OutOfNUS.
+
+This feature also allows users to search for a location based on a given location name, or the location where an event
+is held. It will print out additional information about the location to the user.
+
+The `locate` command executes with the following steps:
+
+Step 1. When the user type in `locate [input]`, the Parser class will extract the input from the command and call a
+`LocateCommand` object.
+* `input` will always be a String when passed into the command object.
+
+Step 2. `LocateCommand` will then try to convert the input into an integer, if possible.
+
+Step 3. If conversion is possible, the method will obtain the event at the given index and return its location
+information.
+* Tries to catch `IndexOutOfBoundException` to check if the given index is within the range of the
+event list.
+
+Step 4. If conversion is not possible, then it will check if the given string is a valid location.
+* Returns the location if valid
+* Prints an error message if invalid
+
+The sequence diagram below shows exactly which methods, from which classes, are called to obtain the required location.
+
+*Figure 4.4 Sequence diagram for locate function*
-## Non-Functional Requirements
+### Reminder
+
+This feature allows users to get a reminder of the events that will occur today.
-{Give non-functional requirements}
+Given below is an example usage scenario:
-## Glossary
+Step 1. The user wants to see all the events that are happening today. He inputs the command `reminder`.
+
+Step 2. The command filters the list of all events based on the current date.
+
+Step 3. It then calls `UI` to print the filtered list.
+
+The sequence diagram belows shows the process of executing the reminder command.
+
+*Figure 4.5 Sequence Diagram for reminder function*
+
+### Sort events
+
+This feature allows users to sort the available task by a sorting criteria. Currently, the sorting criteria available
+are sorting by time, description and location.
+
+Given below is an example usage scenario:
+
+Step 1. The user wants to view the events in a chronological order.
+
+Step 2. The user enters `sort time`, which will call the `sortCommand()` function which will sort all events.
+
+*Figure 4.6 Sequence diagram for SortCommand()*
+
+### View events
+
+This feature allows users to view a numbered list of all the events/tasks they have added so far,
+in the order which they were added.
+
+Given below is an example usage scenario:
+
+Step 1. The user wants to see a list of all the events he has added so far, and executes the command `list`.
+
+Step 2. The command calls the `printEventList` function from `UI`, which then prints the list of events.
+
+The sequence diagram below shows what happens when the list command is executed.
+
+*Figure 4.7 Sequence Diagram for list function*
+
+### Help
+
+This feature allows users to view a summary of all the features available for the current version of NUSchedule.
+When the user inputs `help`, all available commands and a simple description for each of them will be printed.
+
+The sequence diagram below shows what happens when user enters `help`:
+
+
+*Figure 4.8 Sequence Diagram for help function*
+
+### Repeat
+This feature allows users to repeat all classes in the current week or a selected event for several weeks.
+
+### Delete
+This feature allows the user to delete unwanted events. `DeleteCommand#Execute` deletes the specified event in the
+following steps:
+
+Step 1. The user enters `delete NUMBER` where `NUMBER` refers to the index of the command to be deleted. The user input is parsed by the Parser class which creates a new `DeleteCommand` object.
+
+Step 2. `Eventlist#remove()` is called which will delete the event with the specified index.
+
+### Find
+This feature allows the user to filter his/her events by a particular keyword. This command will search through all the events and find events that have descriptions
+containing the search criteria. The process takes place in the following steps:
+
+Step 1. The user enters `find CRITERIA` which will be parsed by the `Parser` class. The `Parser` class will create a new `FindCommand`
+object.
+
+Step 2. `EventList#filterWith()` will be called which will create a ArrayList containing events that match the specified criteria.
+
+Step 3. `UI#printFilteredEventList` is called to print out the events.
+
+### Find based on date
+
+This feature allows users to find events on the date inputted by the user.
+
+Given below is an example usage scenario:
+
+Step 1. The user wishes to find events happening on a certain date, so he inputs `date 2020-10-10`.
+
+Step 2. This executes FindDateCommand, which calls `filterDateWith(2020-10-10)` to create a new filtered list.
+
+Step 3. This filtered list is then printed by calling `printFilteredDateEventList` from UI.
+
+### Print locations of a certain group
+
+This feature allows users to know locations in a certain faculty, including blocks and lecture theatres when users input
+abbreviations of various faculties (e.g. FOS).
+
+The sequence diagram belows shows what happens when user input any faculty abbreviation:
+
+*Figure 4.13 Sequence Diagram for print area locations function*
+
+### Study time
+This feature allows the user to know the amount of time spent on study for certain date. The command is `studyTime DATE`.
+
+### Done
+This feature allows users to mark an event as done, provided the event's time has passed. With the exception of event
+type `Assignment`, all the other event types cannot be marked as done before event occurs.
+
+`DoneCommand` marks an event as done with the following steps:
+
+Step 1. The user will input `done` followed by an integer that represents the index of the event they want to mark as
+done.
+
+Step 2. The program will first check if the index is valid. If invalid, application will print an error message.
+
+Step 3. Then it will check for the type and time of event. If the time of event is later, and the event is not an
+`Assignment`, then it will print a warning message. Else, it will mark the event as done.
+
+### User Info
+
+This feature allows users to input information about themselves into the app, specifically their name, and
+whether they are a student or a professor.
+
+Given below is an example usage scenario:
+
+Step 1: The user wishes to store his personal information, so he inputs `student Harry`.
+
+Step 2: This calls the UserInfoCommand, which stores his name, Harry, and type, student in UserInfo.
+
+1. The user enters `delete NUMBER` where `NUMBER` refers to the index of the command to be deleted. The user input is parsed by the Parser class which creates a new `DeleteCommand` object.
+
+2. `Eventlist#remove()` is called which will delete the event with the specified index.
+
+### Exit
+
+This feature allows users to terminate this app. By inputting `bye`, the isExit flag of the app will be changed to true, and the app will exit with
+an exit message.
+
+## Documentation
+All documentation can be found in the `docs/` folder.
+* [Jekyll](https://jekyllrb.com/) is used to manage documentation.
+* [Markdown](https://guides.github.com/features/mastering-markdown/) style is used for the documentation.
+* [PlantUML](https://plantuml.com/) is used to create the diagrams.
+
+## Testing
+
+JUnit is used to write tests for the project. Learn more about JUnit [here](https://se-education.org/guides/tutorials/gradle.html).
+If you are using IntelliJ, you can run all test by right-clicking on the `test/java` folder and selecting `Run 'Tests'` or press `CRTL` + `SHIFT` + `F10`
+on your keyboard. Alternatively, you can open a console and run the command `gradelw clean test` (Mac/linus: `.gradlew clean test`).
+
+## Appendix A: Product scope
+
+### User profile
+
+__Target user profile:__
+* NUS student or staff
+* able to type quickly
+* has quite a number of events to keep track of
+* prefers to use desktop apps
+* prefers using Command Line Interface (CLI) apps
+* prefers typing instead of mouse interactions
+
+### Value proposition
+
+NUSchedule aims to assist the target audience with:
+* managing all their events in one application (personal or work)
+* easily finding out about the location of their events
+
+## Appendix B: User stories
+
+|Version| As a ... | I want to ... | So that I can ...|
+|--------|----------|---------------|------------------|
+|1.0|busy individual|keep track of both personal and school activities|avoid clashing events
+|1.0|freshman|know module details and lesson venues|be on time for my activities
+|1.0|forgetful person|be reminded of the deadlines for my assignments|submit on time
+|1.0|tutor|know the estimated time for my students to travel to their next class|pace my lesson suitably
+|1.0|hardworking student|track how much time I have spent studying|allocate my time efficiently
+|2.0|exchange student|know the optimal path to reach my next destination|avoid getting lost
+|2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list|
+|2.0|professor|Know whether my students have another lesson after mine and the expected time of travelling|Pace my lesson appropriately
+|2.0|student using zoom for lessons|record the virtual locations|store the links and passwords of the meetings
+|2.1|student having periodic lessons|repeat the classes on a weekly basis|spend less time in adding same classes but just different weeks
-* *glossary item* - Definition
+
+## Appendix C: Non-Functional Requirements
+
+1. This application will work on any computers running either Windows, macOS or Unix that has Java 11 or a higher version installed.
-## Instructions for manual testing
+2. A user that is proficient in typing will find this application to be faster and more convenient to use than applications that requires mouse clicks.
-{Give instructions on how to do a manual product testing e.g., how to load sample data to be used for testing}
+
+## Appendix D: Instructions for manual testing
+
+1. Initial launch
+ * Download the jar file [here](https://github.com/AY2021S1-CS2113T-F14-4/tp/releases) and place it in an empty folder.
+ * Open the command prompt and enter the command `java -jar NuSchedule.jar`.
+ * Expected: The application shows the NuSchedule logo.
+
+2. Adding events
+ * Test case: `assignment homework /t 2020-02-02 20:00 /l home`
+ * Expected: Confirmation message to indicate that the assignment has been added successfully.
+ * Test case: `class cs2113 /t 2020-02-02 20:00 /e 2020-02-02 21:00 /o zoom.com /p 123`
+ * Expected: Confirmation message to indicate that the class has been added successfully.
+ * Test case: `personalEvent shopping /t 2020-02-02 21:00 /e 2020-02-02 22:00 /l supermarket`
+ * Expected: Confirmation message to indicate that the personal event has been added successfully.
+
+3. Editing events
+ * Test case: `edit NUMBER` where `NUMBER` is the index of the event to be editted.
+ * Expected: Confirmation message asking for the desired changes.
+
diff --git a/docs/README.md b/docs/README.md
index bbcc99c1e7..4be01687e9 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,8 +1,12 @@
-# Duke
+# NUSchedule
-{Give product intro here}
+A scheduler help you, who live in NUS, to manage your classes, assignments, personal events easily and efficiently.
+
+
Useful links:
* [User Guide](UserGuide.md)
* [Developer Guide](DeveloperGuide.md)
* [About Us](AboutUs.md)
+
+
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index abd9fbe891..ddaf3d55ca 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,42 +1,389 @@
# User Guide
+
+
+Yang Jiaqi
+
+Zhuang Mengjin
+
+Xu Che
+
+Wu Nan
+
+Wan Shi Jie Brendan
+
+
+
## Introduction
-{Give a product intro}
+NUSchedule is a straightforward yet sophisticated application that helps you manage your events. It allows you
+ to keep track of not only your school events or activities (eg. lectures, tutorials, assignments), but
+also your personal activities. It utilises a command line interface (CLI), which accepts user input in the form of text.
+This gives the application both simplicity and speed, setting it apart from other apps such as NUSMods and Luminus.
+
+* [Quick Start](#quick-start)
+* [Features](#features)
+ * [View available commands](#view-available-commands---wu-nan)
+ * [Add an event](#add-an-event---brendan)
+ * [Edit an event](#edit-an-event---xu-che)
+ * [Sort events](#sort-events---xu-che)
+ * [Find a location](#find-a-location---yang-jiaqi)
+ * [List all locations](#list-all-locations---yang-jiaqi)
+ * [List all events](#list-all-events---brendan)
+ * [Clear events](#clear-events---wu-nan)
+ * [Mark event as done](#mark-event-as-done---wu-nan)
+ * [Reminder of deadlines](#reminder-of-deadlines---brendan)
+ * [Repeat of events](#repeat-of-events---zhuang-mengjin)
+ * [Delete an event](#delete-an-event---zhuang-mengjin)
+ * [Find a keyword](#find-a-keyword---zhuang-mengjin)
+ * [Find a date](#find-a-date---zhuang-mengjin)
+ * [Find locations exist in a certain group](#find-locations-exist-in-a-certain-group---zhuang-mengjin)
+ * [Keep track on the study time](#keep-track-on-the-study-time---zhuang-mengjin)
+ * [Make the app know you](#make-the-app-know-you---zhuang-mengjin)
+ * [Exit the app](#exit-the-app---zhuang-mengjin)
+* [FAQs](#faq)
+* [Command Summary](#command-summary---brendan)
+
## Quick Start
-{Give steps to get started quickly}
+1. Ensure that you have Java 11 or above installed in your Computer.
+2. Download the latest `nuschedule.jar` from here.
+3. Copy the file into a new folder, which will serve as the home folder for NuSchedule.
+4. Copy the latest `location.txt` and `bus_stops.txt` files into a directory named `data` in the home folder.
+5. Open the command prompt and navigate to the home folder.
+6. Run `nuschedule.jar` using the following command: `java -jar nuschedule.jar`
+
-1. Ensure that you have Java 11 or above installed.
-1. Down the latest version of `Duke` from [here](http://link.to/duke).
## Features
-{Give detailed description of each feature}
+### Tips:
+In the following description, `DATE` refers to the date in the format yyyy-MM-dd. e.g. `2020-10-31`
+`TIME` refers to the time in the format HH:mm. e.g. `10:00`
+
+`/t` refers to the starting time for PersonalEvent and Class, and deadline for Assignment
+`/e` refers to the ending time for PersonalEvent and Class
+
+### View available commands - Wu Nan
+
+Shows list of commands and provides a link to the user guide for more details.
+
+Format: `help`
+
+
+### Add an event - Brendan
+
+Adds events/tasks to the schedule. Can support various types of tasks:
+
+* PersonalEvent
+ Format:
+ `personalEvent EVENTNAME /t DATE TIME /e DATE TIME /l LOCATION` for offline events.
+ OR
+ `personalEvent EVENTNAME /t DATE TIME /e DATE TIME /o MEETING_LINK /p MEETING_PASSWORD` for online events.
+
+ Note that `/e DATE TIME` is optional. You may input a personal event without an ending time.
+ In `/e DATE TIME`, `DATE` is optional. If you enter `/e TIME`, the default date will be the same
+ as the date that the event starts.
+ For online events, `/p MEETING_PASSWORD` is optional, since not all online events require a password.
+
+* Assignment
+ Format:
+ `assignment EVENTNAME /t DATE TIME /l LOCATION`
+ OR
+ `assignment EVENTNAME /t DATE TIME /o SUBMISSION_LINK`
+
+* Class
+ Format:
+ `class CLASSNAME /t DATE TIME /e DATE TIME /l LOCATION`
+ OR
+ `class CLASSNAME /t DATE TIME /e DATE TIME /o MEETING_LINK /p MEETING_PASSWORD`
+
+ Similar to personal events, in `/e DATE TIME`, `DATE` is optional. For online events,`/p MEETING_PASSWORD` is optional.
+ However, `/e DATE TIME` or `/e TIME` is required, since all classes should have an ending time.
+
+* SelfStudy
+ Format:
+ `selfStudy EVENTNAME /t DATE TIME /e DATE TIME /l LOCATION` for offline events.
+ OR
+ `selfStudy EVENTNAME /t DATE TIME /e DATE TIME /o MEETING_LINK /p MEETING_PASSWORD` for online events.
+
+ Note that `/e DATE TIME` is optional. You may input a personal event without an ending time.
+ In `/e DATE TIME`, `DATE` is optional. If you enter `/e TIME`, the default date will be the same
+ as the date that the event starts.
+ For online events, `/p MEETING_PASSWORD` is optional, since not all online events require a password.
+
+Examples of usage:
+
+`class CS2113 Lecture /t 2020-09-23 10:00 /e 12:00 /l LT27`
+`personalEvent Mom’s Birthday /t 2020-10-26 19:00 /l home`
+`assignment CS1010 Assignment /t 2020-01-04 23:59 /o Luminus`
+`selfStudy Prepare for exam /t 2020-11-26 15:00 /l home`
+
+Adding a class:
+
+
+Adding a personal event:
+
+
+Adding an assignment:
+
+
+Adding a self study event:
+
+
+Adding an event with a timing clash:
+
+
+
+### Edit an event - Xu Che
+The `edit` command allows you to edit the event type, description, start/end date and location for an existing
+event. You can start using this command by entering `edit INDEX`, where INDEX is the number of the task you want to
+edit.
+
+Format: `edit INDEX`
+
+Example:
+
+Let's say you have one event stored in NuSchedule currently:
+
+
+
+Suppose you entered the timing incorrectly and would like to edit it to the correct timing. Enter the following command
+to edit the event:
+
+
+
+Next, you will be prompted to enter the new values for the 5 fields which are type, description, location start and end
+date respectively. Enter your desired changes and press the `ENTER` key to go through the fields. You can leave a field
+blank and simply press enter if you do not want to make any changes.
+
+
+
+Expected Outcome:
+
+
+
+
+
+### Sort events - Xu Che
+With this command, you can sort all events by either their end time, location or their description. When sorting by time, events
+will be sorted in a chronological order. Events with an earlier end date will be sorted on top of events with later end
+dates. This way, you can prioritize the events that are due soon.
+
+When sorting by description, the events will be sorted in alphabetical order according to their descriptions. Events
+with descriptions starting with 'a' will be sorted on top of events with descriptions starting with 'z' for example.
+
+When sorting by location, the events will be sorted in alphabetical order according to their location. Events with
+offline locations will be sorted on top of locations with online locations.
+
+Format: `sort SORT_CRITERIA`
+
+Example: `sort description`
+
+Before sorting:
+
+
+After sorting:
+
+
+Sort by time:
+
+
+Sort by location:
+
+
+### Find a location - Yang Jiaqi
+With this command, you can find out about locations around NUS. Depending on the type of location, different additional
+information will be shown together with the location (e.g. nearest building, nearest bus stops).
+
+Format: `locate LOCATIONNAME` or `locate EVENTINDEX`
-### Adding a todo: `todo`
-Adds a new item to the list of todo items.
+Example: `locate lt1`
-Format: `todo n/TODO_NAME d/DEADLINE`
+Find lecture theatres using location name:
+
-* The `DEADLINE` can be in a natural language format.
-* The `TODO_NAME` cannot contain punctuation.
+Find buildings using location name:
+
-Example of usage:
+Find locations using event index:
+
-`todo n/Write the rest of the User Guide d/next week`
+### List all locations - Yang Jiaqi
+Displays a list of all locations within NUS
-`todo n/Refactor the User Guide to remove passive voice d/13/04/2020`
+Format: `locations`
+
+Expected output: (list given here is incomplete)
+
+
+### List all events - Brendan
+Shows you a list of all events.
+
+Format: `list`
+
+Example Output:
+
+
+### Clear events - Wu Nan
+
+Delete events existing in the list, you can choose to delete all, auto delete or delete events before a certain date:
+
+* Clear all events
+ Format: `clear`
+
+* Switch the autoClear function on so that events happened one month ago will be automatically cleared.
+ Format: `autoClear on`
+ Note that this function will clear all events which happened one month ago no matter they are done or not.
+
+* Switch the autoClear function off
+ Format: `autoClear off`
+
+* Clear events happened before a certain date
+ Format: `clearBefore CLEAR_DATE`
+
+ Example: `clearBefore 2020-03-10`
+
+Example Output:
+
+
+### Mark event as done - Wu Nan
+Mark an event that has been completed with `DONE`.
+Note that the events which are not assignments, cannot be done before its ending time.
+
+Format: `done INDEX`
+
+Example: `done 2`
+
+Example Output:
+
+
+### Reminder of deadlines - Brendan
+Shows a list of all events for today's date.
+
+Format: `reminder`
+
+Example Output:
+
+
+
+### Repeat of events - Zhuang Mengjin
+Repeat the selected event for several weeks, or repeat all classes this week for several weeks.
+
+Format: `repeat INDEX NUMBER_OF_WEEKS` OR `repeat all NUMBER_OF_WEEKS`
+
+Example: `repeat 3 1`, `repeat all 2`
+
+Example Output:
+
+
+
+### Delete an event - Zhuang Mengjin
+Delete the selected event from the list.
+
+Format: `delete INDEX`
+
+Example: `delete 1`
+
+Example Output:
+
+
+### Find a keyword - Zhuang Mengjin
+Find the events with given keyword. Note that it's case-sensitive.
+
+Format: `find KEYWORD`
+
+Example: `find CS`
+
+Example Output:
+
+
+### Find a date - Zhuang Mengjin
+Find the events happen on the given date.
+
+Format: `date yyyy-MM-dd`
+
+Example `date 2020-11-10`
+
+Example Output:
+
+
+### Find locations exist in a certain group - Zhuang Mengjin
+Find the locations in NUS that belongs to certain faculty or the hostels.
+
+Format: `FOS` OR `FOE` OR `SOC` OR `BIZ` OR `HOSTEL` OR `SDE` OR `FASS`
+
+Example Output:
+
+
+### Keep track on the study time - Zhuang Mengjin
+Find the amount of time you spent on study on a certain date.
+
+Format: `studyTime DATE`
+
+Example Output:
+
+
+### Make the app know you - Zhuang Mengjin
+Tell the app your name, and whether you are a professor or a student. Whether you indicate yourself as a professor,
+ or a student, will make a difference in another function, which will come in a later version.
+
+Format: `student NAME` OR `professor NAME`
+
+Example Output:
+
+
+
+### Exit the app - Zhuang Mengjin
+Exit.
+
+Format: `bye`
+
+Example Output:
+
+
## FAQ
**Q**: How do I transfer my data to another computer?
-**A**: {your answer here}
+**A**: Install the app in the other computer and overwrite the empty data file it creates with the file that contains
+the data of your previous AddressBook home folder.
+
+**Q**: What if I cannot run the application, or the application suddenly stops running unexpectedly?
+
+**A**: If you cannot run the application at the beginning, please refer back to the Quick Start section and check
+whether the jar file is in the correct folder. If you cannot find what is wrong, please take a screenshot of your computer
+and report it as an issue to [this link](https://github.com/AY2021S1-CS2113T-F14-4/tp/issues).
+
+**Q**: What should I do if I cannot get the input format for adding events correctly?
+
+**A**: For all wrong input format, there will be an error message to tell you what exactly you have input wrongly. If
+the error message is not helpful, please refer back to relevant sections in Features. We recommend you to follow the
+instructions provided closely as the current version of NUSchedule has a relatively high requirement in terms of input
+accuracy. If you really cannot find what is wrong, please report it as an issue to [this link](https://github.com/AY2021S1-CS2113T-F14-4/tp/issues).
+
+## Command Summary - Brendan
-## Command Summary
+|Action|Command|Example|
+|------|-------|-------|
+|add|`EVENTTYPE EVENTNAME /t DATE TIME` `/e DATE TIME`(optional personal event and self study, compulsory for class, must not have for assignment) `/l LOCATION` OR `/o LINK` `/p PASSWORD`(optional)|`personalEvent Mom’s Birthday /t 2020-10-26 19:00 /l home`|
+|clear|`clear` OR `autoClear STATUS` OR `clearBefore CLEAR_DATE` |`clearBefore 2020-10-22`|
+|delete|`delete INDEX`|`delete 1`|
+|done|`done INDEX` |`done 1` |
+|edit|`edit`, then fill in each fields when prompted and press `ENTER` to move on to the next field|`edit 1` `ENTER` `class` `ENTER` `cs2113t` `ENTER` `\l school` `ENTER` `2020-10-26 19:00` `ENTER` `2020-10-26 20:00`|
+|help|`help`|
+|list|`list`|
+|locate|`locate LOCATION_NAME` OR `locate EVENT_INDEX`|`locate LT1`|
+|sort|`sort SORT_CRITERIA` |`sort description`|
+|reminder|`reminder`|`reminder`|
+|repeat|`repeat INDEX NUMBER_OF_WEEKS` OR `repeat all NUMBER_OF_WEEKS`|`repeat all 1`|
+|find (keyword)|`find KEYWORD`|`find book`|
+|find (date)|`date`|`date 2020-11-08`|
+|calculate study time|`studyTime DATE`|`studyTime 2020-11-08`|
+|find locations belongs to a certain group|`FACULTY` or `HOSTEL`|`FOE`,`FOS`|
+|UserInfo|`student NAME` OR `professor NAME`|`student LeeJuntong`|
+|exit|`bye`|`bye`|
-{Give a 'cheat sheet' of commands here}
-* Add todo `todo n/TODO_NAME d/DEADLINE`
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000000..f4b41887d6
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1,2 @@
+theme: jekyll-theme-cayman
+markdown: GFM
diff --git a/docs/architecture.png b/docs/architecture.png
new file mode 100644
index 0000000000..d24ae29b69
Binary files /dev/null and b/docs/architecture.png differ
diff --git a/docs/diagrams/AddCommand.png b/docs/diagrams/AddCommand.png
new file mode 100644
index 0000000000..c56c875842
Binary files /dev/null and b/docs/diagrams/AddCommand.png differ
diff --git a/docs/diagrams/AddCommand.puml b/docs/diagrams/AddCommand.puml
new file mode 100644
index 0000000000..1087af4739
--- /dev/null
+++ b/docs/diagrams/AddCommand.puml
@@ -0,0 +1,16 @@
+@startuml
+actor User
+
+
+User -> ":NuSchedule" ++ : add
+":NuSchedule" -> ":Parser" ++ : parse()
+":Parser" --> ":NuSchedule" -- : parsed command
+":NuSchedule" -> ":AddCommand" ++ : execute()
+":AddCommand" -> ":EventList" ++ : addEvent()
+":EventList" --> ":AddCommand" -- : event
+":AddCommand" -> ":UI" ++ : printMessage()
+":UI" --> ":AddCommand" -- : message
+":AddCommand" --> ":NuSchedule" -- : return
+
+deactivate ":NuSchedule"
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ArchitechtureSequence.puml b/docs/diagrams/ArchitechtureSequence.puml
new file mode 100644
index 0000000000..83f327cfa0
--- /dev/null
+++ b/docs/diagrams/ArchitechtureSequence.puml
@@ -0,0 +1,34 @@
+@startuml
+
+@startuml
+Actor User
+
+User -> ui : "edit 1"
+activate ui
+ui -> logic : readCommand("edit 1")
+activate logic
+
+logic -> model :execute(1)
+activate model
+
+model -> logic
+deactivate model
+
+logic -> storage :
+activate storage
+
+storage -> storage : Save to file
+activate storage
+storage --> storage
+deactivate storage
+
+storage --> logic
+deactivate storage
+
+logic --> ui
+deactivate logic
+
+ui--> user
+deactivate ui
+@enduml
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/ArchitectureSequence.png b/docs/diagrams/ArchitectureSequence.png
new file mode 100644
index 0000000000..b95a34f831
Binary files /dev/null and b/docs/diagrams/ArchitectureSequence.png differ
diff --git a/docs/diagrams/AutoClearCommand.png b/docs/diagrams/AutoClearCommand.png
new file mode 100644
index 0000000000..829908a8d9
Binary files /dev/null and b/docs/diagrams/AutoClearCommand.png differ
diff --git a/docs/diagrams/ClearBeforeCommand.png b/docs/diagrams/ClearBeforeCommand.png
new file mode 100644
index 0000000000..829419ff35
Binary files /dev/null and b/docs/diagrams/ClearBeforeCommand.png differ
diff --git a/docs/diagrams/ClearCommand.png b/docs/diagrams/ClearCommand.png
new file mode 100644
index 0000000000..4eb278be59
Binary files /dev/null and b/docs/diagrams/ClearCommand.png differ
diff --git a/docs/diagrams/EditCommand.png b/docs/diagrams/EditCommand.png
new file mode 100644
index 0000000000..5f0487cf1d
Binary files /dev/null and b/docs/diagrams/EditCommand.png differ
diff --git a/docs/diagrams/EditCommand.puml b/docs/diagrams/EditCommand.puml
new file mode 100644
index 0000000000..15f8cd1234
--- /dev/null
+++ b/docs/diagrams/EditCommand.puml
@@ -0,0 +1,43 @@
+@startuml
+actor User
+
+box Logic
+participant "NuSchedule" as NuSchedule
+participant "Parser" as Parser
+participant "EditCommand" as EditCommand
+end box
+
+box Model
+participant ":EventList" as EventList
+end box
+
+User -> NuSchedule: (edit index)
+activate NuSchedule
+
+NuSchedule -> Parser: (edit index)
+activate Parser
+
+create EditCommand
+Parser -> EditCommand:newEditInformation()
+activate EditCommand
+
+EditCommand --> Parser: String[] editInformation
+deactivate EditCommand
+
+Parser --> NuSchedule: parsed command
+deactivate Parser
+
+NuSchedule -> EditCommand: execute()
+activate EditCommand
+
+EditCommand -> EventList: editEvent()
+activate EventList
+
+EventList --> EditCommand: event
+deactivate EventList
+
+EditCommand --> NuSchedule
+deactivate EditCommand
+
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/HelpCommand.png b/docs/diagrams/HelpCommand.png
new file mode 100644
index 0000000000..35349d4374
Binary files /dev/null and b/docs/diagrams/HelpCommand.png differ
diff --git a/docs/diagrams/Lee_Juntong'sCat.jpg b/docs/diagrams/Lee_Juntong'sCat.jpg
new file mode 100644
index 0000000000..a72aac5095
Binary files /dev/null and b/docs/diagrams/Lee_Juntong'sCat.jpg differ
diff --git a/docs/diagrams/ListCommand.png b/docs/diagrams/ListCommand.png
new file mode 100644
index 0000000000..fd480d1187
Binary files /dev/null and b/docs/diagrams/ListCommand.png differ
diff --git a/docs/diagrams/ListCommand.puml b/docs/diagrams/ListCommand.puml
new file mode 100644
index 0000000000..b7831e4621
--- /dev/null
+++ b/docs/diagrams/ListCommand.puml
@@ -0,0 +1,14 @@
+@startuml
+actor user
+
+user --> NuSchedule : list
+NuSchedule --> Parser ++ : parse()
+Parser --> NuSchedule -- : PrintFullListCommand
+NuSchedule --> PrintFullListCommand ++ : execute()
+PrintFullListCommand --> UI ++ : PrintEventList()
+UI --> EventList ++: getEventList()
+EventList --> UI -- : eventList
+UI --> PrintFullListCommand --
+PrintFullListCommand --> NuSchedule --
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/LocateSequence.png b/docs/diagrams/LocateSequence.png
new file mode 100644
index 0000000000..f8c3d6aea1
Binary files /dev/null and b/docs/diagrams/LocateSequence.png differ
diff --git a/docs/diagrams/LocateSequence.puml b/docs/diagrams/LocateSequence.puml
new file mode 100644
index 0000000000..e6fb7d911b
--- /dev/null
+++ b/docs/diagrams/LocateSequence.puml
@@ -0,0 +1,36 @@
+@startuml
+Actor User
+
+box Logic
+User -> Parser: locate [input]
+activate Parser
+Parser -> LocateCommand: LocateCommand(input)
+activate LocateCommand
+LocateCommand -> LocateCommand: execute()
+activate LocateCommand
+end box
+
+box Model
+alt input is an integer
+ LocateCommand -> EventList: getLocation(input)
+ activate EventList
+ return location
+else input is a String
+ alt valid location
+ LocateCommand -> LocationList: findLocation(input)
+ activate LocationList
+ return location
+ else invalid location
+ LocateCommand -> LocationList: checkValidLocation(input)
+ activate LocationList
+ return false
+note left: prints error message
+ end
+end
+
+deactivate LocateCommand
+destroy LocateCommand
+
+deactivate Parser
+return
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/LocationClass.png b/docs/diagrams/LocationClass.png
new file mode 100644
index 0000000000..9160513346
Binary files /dev/null and b/docs/diagrams/LocationClass.png differ
diff --git a/docs/diagrams/LocationClass.puml b/docs/diagrams/LocationClass.puml
new file mode 100644
index 0000000000..01987ff480
--- /dev/null
+++ b/docs/diagrams/LocationClass.puml
@@ -0,0 +1,56 @@
+@startuml
+package locationlist {
+ Class LocationList {
+ +checkLocation(String)
+ +findLocation(String)
+ +getLocationList()
+ }
+ Class BusStopList {
+ +checkExistence(String)
+ +getBusStopList()
+ }
+}
+
+package location {
+ enum LocationType {
+ BUILDING,
+ BUSSTOP,
+ HOSTEL,
+ LT,
+ OUT_OF_NUS
+ }
+ LocationList --> "0..1"Location:locationList
+ Class Location {
+ #name:String
+ #type:LocationType
+ +getName()
+ -printType()
+ +fileString()
+ +toString()
+ }
+ BusStopList --> "0..1"BusStop:busStopList
+ Class BusStop {
+ -name:String
+ -buses:String[]
+ +getName()
+ +fileString()
+ +toString()
+ }
+ Location <|-- Building
+ Class Building {
+ -nearestBusStops:String[]
+ -printNearestBusStops()
+ }
+ Location <|-- Hostel
+ Class Hostel {
+ -nearestBusStops:String[]
+ -printNearestBusStops()
+ }
+ Location <|-- LectureTheatre
+ Class LectureTheatre {
+ -nearestBuilding:String
+ }
+ Location <|-- OutOfNUS
+}
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/LogicClass.png b/docs/diagrams/LogicClass.png
new file mode 100644
index 0000000000..da92d8fac9
Binary files /dev/null and b/docs/diagrams/LogicClass.png differ
diff --git a/docs/diagrams/LogicClass.puml b/docs/diagrams/LogicClass.puml
new file mode 100644
index 0000000000..03ac19d0bc
--- /dev/null
+++ b/docs/diagrams/LogicClass.puml
@@ -0,0 +1,24 @@
+@startuml
+
+package parser{
+ Class parser{
+ +parse()
+ +parseLocation()
+
+}
+
+package command{
+ Abstract Class command
+ Class XYZCommand
+ note bottom: e.g AddCommand, DeleteCommand, etc.
+}
+
+package eventlist{}
+
+parser ..> XYZCommand : creates >
+parser --> eventlist
+XYZCommand ..> eventlist
+
+XYZCommand -u|> command
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/Logo.png b/docs/diagrams/Logo.png
new file mode 100644
index 0000000000..1305caa673
Binary files /dev/null and b/docs/diagrams/Logo.png differ
diff --git a/docs/diagrams/ReminderCommand.png b/docs/diagrams/ReminderCommand.png
new file mode 100644
index 0000000000..f9179e33b3
Binary files /dev/null and b/docs/diagrams/ReminderCommand.png differ
diff --git a/docs/diagrams/ReminderCommand.puml b/docs/diagrams/ReminderCommand.puml
new file mode 100644
index 0000000000..6bcd05dc09
--- /dev/null
+++ b/docs/diagrams/ReminderCommand.puml
@@ -0,0 +1,16 @@
+@startuml
+actor User
+activate ":NuSchedule"
+
+User -> ":NuSchedule" : reminder
+":NuSchedule" -> ":Parser" ++ : parse()
+":Parser" --> ":NuSchedule" -- : ReminderCommand
+":NuSchedule" -> ":ReminderCommand" ++ : execute()
+":ReminderCommand" -> ":EventList" ++ : filterDateWith()
+":EventList" --> ":ReminderCommand" -- : FilteredList
+":ReminderCommand" -> ":UI" ++ : printFilteredList()
+":UI" --> ":ReminderCommand" --
+":ReminderCommand" --> ":NuSchedule" --
+
+deactivate ":NuSchedule"
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/SortCommand.png b/docs/diagrams/SortCommand.png
new file mode 100644
index 0000000000..ccf6adcd4a
Binary files /dev/null and b/docs/diagrams/SortCommand.png differ
diff --git a/docs/diagrams/SortCommand.puml b/docs/diagrams/SortCommand.puml
new file mode 100644
index 0000000000..47827e651b
--- /dev/null
+++ b/docs/diagrams/SortCommand.puml
@@ -0,0 +1,36 @@
+@startuml
+actor User
+
+box Logic
+participant ":NuSchedule" as NuSchedule
+participant ":Parser" as Parser
+participant ":SortCommand" as SortCommand
+end box
+
+box Model
+participant ":EventList" as EventList
+end box
+
+User -> NuSchedule : sort
+activate NuSchedule
+
+NuSchedule -> Parser : parse(sort)
+activate Parser
+
+Parser --> NuSchedule : command to execute
+deactivate Parser
+
+NuSchedule -> SortCommand : execute(sort)
+activate SortCommand
+
+SortCommand -> EventList : sortEvent()
+activate EventList
+
+EventList --> SortCommand : event
+deactivate EventList
+
+SortCommand --> NuSchedule
+deactivate SortCommand
+
+deactivate NuSchedule
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/Ui.png b/docs/diagrams/Ui.png
new file mode 100644
index 0000000000..2564cddff7
Binary files /dev/null and b/docs/diagrams/Ui.png differ
diff --git a/docs/diagrams/Ui.puml b/docs/diagrams/Ui.puml
new file mode 100644
index 0000000000..00b8193183
--- /dev/null
+++ b/docs/diagrams/Ui.puml
@@ -0,0 +1,14 @@
+@startuml
+
+package ui{
+class UI {
++printGreetingMessage()
++printLine()
++printEventList()
++printLocationList()
++printHelp()
++showError()
++printExitMessage()
+}
+
+@enduml
\ No newline at end of file
diff --git a/docs/diagrams/add1.png b/docs/diagrams/add1.png
new file mode 100644
index 0000000000..6841fa52fd
Binary files /dev/null and b/docs/diagrams/add1.png differ
diff --git a/docs/diagrams/add2.png b/docs/diagrams/add2.png
new file mode 100644
index 0000000000..16446df9d9
Binary files /dev/null and b/docs/diagrams/add2.png differ
diff --git a/docs/diagrams/add3.png b/docs/diagrams/add3.png
new file mode 100644
index 0000000000..4a968966e4
Binary files /dev/null and b/docs/diagrams/add3.png differ
diff --git a/docs/diagrams/add4.png b/docs/diagrams/add4.png
new file mode 100644
index 0000000000..146ac551fe
Binary files /dev/null and b/docs/diagrams/add4.png differ
diff --git a/docs/diagrams/add5.png b/docs/diagrams/add5.png
new file mode 100644
index 0000000000..8abac5d41d
Binary files /dev/null and b/docs/diagrams/add5.png differ
diff --git a/docs/diagrams/architecture.png b/docs/diagrams/architecture.png
new file mode 100644
index 0000000000..d24ae29b69
Binary files /dev/null and b/docs/diagrams/architecture.png differ
diff --git a/docs/diagrams/clear.png b/docs/diagrams/clear.png
new file mode 100644
index 0000000000..68beb7db84
Binary files /dev/null and b/docs/diagrams/clear.png differ
diff --git a/docs/diagrams/delete.png b/docs/diagrams/delete.png
new file mode 100644
index 0000000000..8f10396d01
Binary files /dev/null and b/docs/diagrams/delete.png differ
diff --git a/docs/diagrams/done.png b/docs/diagrams/done.png
new file mode 100644
index 0000000000..723e0a9048
Binary files /dev/null and b/docs/diagrams/done.png differ
diff --git a/docs/diagrams/edit1.png b/docs/diagrams/edit1.png
new file mode 100644
index 0000000000..17ff5c6ec0
Binary files /dev/null and b/docs/diagrams/edit1.png differ
diff --git a/docs/diagrams/edit2.png b/docs/diagrams/edit2.png
new file mode 100644
index 0000000000..e7e47c8fd4
Binary files /dev/null and b/docs/diagrams/edit2.png differ
diff --git a/docs/diagrams/edit3.png b/docs/diagrams/edit3.png
new file mode 100644
index 0000000000..9ae61dd709
Binary files /dev/null and b/docs/diagrams/edit3.png differ
diff --git a/docs/diagrams/edit4.png b/docs/diagrams/edit4.png
new file mode 100644
index 0000000000..36c3340b0c
Binary files /dev/null and b/docs/diagrams/edit4.png differ
diff --git a/docs/diagrams/edit5.png b/docs/diagrams/edit5.png
new file mode 100644
index 0000000000..d3c14d6153
Binary files /dev/null and b/docs/diagrams/edit5.png differ
diff --git a/docs/diagrams/exit.png b/docs/diagrams/exit.png
new file mode 100644
index 0000000000..3f0571a2d4
Binary files /dev/null and b/docs/diagrams/exit.png differ
diff --git a/docs/diagrams/find.png b/docs/diagrams/find.png
new file mode 100644
index 0000000000..e7b60f0805
Binary files /dev/null and b/docs/diagrams/find.png differ
diff --git a/docs/diagrams/findDate.png b/docs/diagrams/findDate.png
new file mode 100644
index 0000000000..32c7a601e3
Binary files /dev/null and b/docs/diagrams/findDate.png differ
diff --git a/docs/diagrams/list.png b/docs/diagrams/list.png
new file mode 100644
index 0000000000..2fdfc89ae7
Binary files /dev/null and b/docs/diagrams/list.png differ
diff --git a/docs/diagrams/locate1.png b/docs/diagrams/locate1.png
new file mode 100644
index 0000000000..2d1c5c355f
Binary files /dev/null and b/docs/diagrams/locate1.png differ
diff --git a/docs/diagrams/locate2.png b/docs/diagrams/locate2.png
new file mode 100644
index 0000000000..1515cef4eb
Binary files /dev/null and b/docs/diagrams/locate2.png differ
diff --git a/docs/diagrams/locate3.png b/docs/diagrams/locate3.png
new file mode 100644
index 0000000000..e24d26e236
Binary files /dev/null and b/docs/diagrams/locate3.png differ
diff --git a/docs/diagrams/locations.png b/docs/diagrams/locations.png
new file mode 100644
index 0000000000..bbdfd85f2a
Binary files /dev/null and b/docs/diagrams/locations.png differ
diff --git a/docs/diagrams/locationsInNUS.png b/docs/diagrams/locationsInNUS.png
new file mode 100644
index 0000000000..d5b0f4b015
Binary files /dev/null and b/docs/diagrams/locationsInNUS.png differ
diff --git a/docs/diagrams/printAreaLocationsCommand.png b/docs/diagrams/printAreaLocationsCommand.png
new file mode 100644
index 0000000000..5ab69228d7
Binary files /dev/null and b/docs/diagrams/printAreaLocationsCommand.png differ
diff --git a/docs/diagrams/reminder.png b/docs/diagrams/reminder.png
new file mode 100644
index 0000000000..fac56b7409
Binary files /dev/null and b/docs/diagrams/reminder.png differ
diff --git a/docs/diagrams/repeat1.png b/docs/diagrams/repeat1.png
new file mode 100644
index 0000000000..9ca0505abe
Binary files /dev/null and b/docs/diagrams/repeat1.png differ
diff --git a/docs/diagrams/repeat2.png b/docs/diagrams/repeat2.png
new file mode 100644
index 0000000000..528413e12b
Binary files /dev/null and b/docs/diagrams/repeat2.png differ
diff --git a/docs/diagrams/sort1.png b/docs/diagrams/sort1.png
new file mode 100644
index 0000000000..4b20be4aa1
Binary files /dev/null and b/docs/diagrams/sort1.png differ
diff --git a/docs/diagrams/sort2.png b/docs/diagrams/sort2.png
new file mode 100644
index 0000000000..da49a62a5a
Binary files /dev/null and b/docs/diagrams/sort2.png differ
diff --git a/docs/diagrams/sort3.png b/docs/diagrams/sort3.png
new file mode 100644
index 0000000000..7a90bdc475
Binary files /dev/null and b/docs/diagrams/sort3.png differ
diff --git a/docs/diagrams/sort4.png b/docs/diagrams/sort4.png
new file mode 100644
index 0000000000..2dbc0a9e7e
Binary files /dev/null and b/docs/diagrams/sort4.png differ
diff --git a/docs/diagrams/studyTime.png b/docs/diagrams/studyTime.png
new file mode 100644
index 0000000000..54e2f4f86e
Binary files /dev/null and b/docs/diagrams/studyTime.png differ
diff --git a/docs/diagrams/userInfo1.png b/docs/diagrams/userInfo1.png
new file mode 100644
index 0000000000..9f62057b8b
Binary files /dev/null and b/docs/diagrams/userInfo1.png differ
diff --git a/docs/diagrams/userInfo2.png b/docs/diagrams/userInfo2.png
new file mode 100644
index 0000000000..c49e8af8af
Binary files /dev/null and b/docs/diagrams/userInfo2.png differ
diff --git a/docs/team/jiaaaqi.md b/docs/team/jiaaaqi.md
new file mode 100644
index 0000000000..6e9360547b
--- /dev/null
+++ b/docs/team/jiaaaqi.md
@@ -0,0 +1,42 @@
+# Yang Jiaqi - Project Portfolio Page
+
+## Project: NUSchedule
+
+NuSchedule is a desktop task management application used for keeping track of user's events. The user interacts with it
+using a Command Line Interface (CLI). It is written in Java and has around 5 kLoC.
+
+Given below are my contributions to the project:
+* __Main Frame:__ Added the Location classes to an event
+ * What it does: a location element will allow the user to save the location of their events. The location element
+ will also include additional information about the location.
+ * Justification: This feature will users to note down the location which the event is occurring at.
+ If the place is located within NUS, the additional information would include the nearest buildings and bus stops,
+ which allows our target audience to be able to easily find the exact place.
+
+* __Main Frame:__ Added Location List classes
+ * What it does: record all the pre-saved location data of places within NUS. It also includes a separate bus stops
+ list, which saves bus stop data. Users are able to view the entire list by keying in the command `locations` or
+ `busstops`.
+
+* __Storage:__ Added location data of locations within NUS
+
+* __New Feature:__ Added a `locate` command to find a location using location name or event index
+ * Justification: This feature will allow user to receive location information. It allows users to find more
+ information using a location name, or an event index based on the event list.
+
+* __Code Contributed:__ [RepoSense Link](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=jiaaaqi)
+
+* __Project Management:__
+ * Managed releases `v1.0` - `v2.0` on GitHub
+
+* __Documentation:__
+ * User guide:
+ * Added documentation for `locate` command ([#84](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/84), [#176](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/176))
+ * Developer guide:
+ * Added design details for Location, under Model ([#69](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/69/files), [#75](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/75))
+ * Added implementation details for `locate` feature ([#69](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/69/files), [#75](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/75))
+ * Added target user profile and value proposition ([#67](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/67/files))
+
+* __Community:__
+ * PRs reviewed (with non-trivial comments): [Fitr](https://github.com/nus-cs2113-AY2021S1/tp/pull/16)
+ * Reported bugs in other teams: example [1](https://github.com/AY2021S1-CS2113T-W12-4/tp/issues/323), [2](https://github.com/AY2021S1-CS2113T-W12-4/tp/issues/319), [3](https://github.com/AY2021S1-CS2113T-W12-4/tp/issues/322)
diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md
deleted file mode 100644
index ab75b391b8..0000000000
--- a/docs/team/johndoe.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# John Doe - Project Portfolio Page
-
-## Overview
-
-
-### Summary of Contributions
diff --git a/docs/team/lee-juntong.md b/docs/team/lee-juntong.md
new file mode 100644
index 0000000000..ba03d54dba
--- /dev/null
+++ b/docs/team/lee-juntong.md
@@ -0,0 +1,61 @@
+# Project: NUSchedule
+
+NuSchedule is a desktop task management application used for keeping track of user's events. The user interacts with it using a CLI. It is written in Java and has around 5 kLoC.
+
+Given below are my contributions to the project.
+
+* **Main Frame**
+ * Events and its subclasses: the basic elements in this product. All commands depend on them.
+ * EventList class: provides the functions to operate on the list of events.
+ * Storage: the way to store the data as well as load them from the hard disk.
+ * UI,Parser, Command, and the main running class: makes the product object oriented.
+
+* **New Feature**: Added the ability to add events, and manage different cases accordingly.
+
+* **New Feature**: Added the ability to record amount of time spent on study on certain date.
+ * What it does: allows the user to check what is the amount of time spent on study on the day.
+ * Justification: this feature provides the way to know the amount of effort the user spent on study, which is useful for NUS students.
+ * Highlights: the implementation uses several filters of the stream of the list of events, and only the appropriate ones are
+ recorded. It also considers the case when certain event is across more than one day, the study time will be calculated correctly
+ for different dates.
+
+* **New Feature**: Added the ability to mark an event as done, as well as reject it if the current time is before the ending time.
+
+* **New Feature**: Added the ability to delete an event.
+
+* **New Feature**: Added the ability to set the name of the user, as well as indicate the occupation. (i.e. student or professor)
+
+* **New Feature**: Added the ability to find the events with given keyword in the description.
+
+* **New Feature**: Added the ability to find the events happening on the given date.
+
+* **New Feature**: Added the ability to Repeat of required events for several weeks.
+ * Highlights: Added copy constructor for Event and its subclasses, because Java does not pass reference as a copy, so
+ we need to create a copy to avoid the edit being effective to the original object.
+ * Credits: The code to compare whether 2 localDateTimes are within the same week.
+ Provided by Sunil Katti [here](https://stackoverflow.com/a/56246095)
+
+* **New Feature**: Added the ability to exit the application.
+
+* **New Feature**: Added the ability to print the list of locations at the selected area in NUS.
+
+* **Code contributed**: [RepoSense link](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=Lee-Juntong&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other&tabOpen=true&tabType=authorship&tabAuthor=Lee-Juntong&tabRepo=AY2021S1-CS2113T-F14-4%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other)
+
+* **Project management**:
+ * Managed releases `v1.0` - `v2.1` (3 releases) on GitHub
+
+* **Enhancements to existing features**:
+ * Fix bugs happening to the features. (Pull requests [\#37](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/37), [\#145](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/145))
+ * Make Auto Clear as an option that user can turn on or off. (Pull request [\#182](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/182))
+
+* **Documentation**:
+ * User Guide:
+ * Add documentation for the features delete, find, studyTime, add events, exit, repeat, find base on date, make the app know you, and find locations exist in a certain group [\#199](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/199)
+ * Did cosmetic tweaks to existing documentation of features `done`, `autoClear` : [\#199](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/199)
+ * Developer Guide:
+ * Make the hyperlinks work properly [\#92](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/92)
+
+* **Community**:
+ * PRs reviewed (with non-trivial review comments):[\#162](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/162), [\#172](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/172), [\#147](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/147), [\#144](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/144)
+ * Contributed to forum discussions (examples: [1](https://github.com/nus-cs2113-AY2021S1/forum/issues/48#issuecomment-709282848))
+ * Reported bugs and suggestions for other teams in the class (examples: [1](https://github.com/Lee-Juntong/ped/issues/9), [2](https://github.com/Lee-Juntong/ped/issues/13), [3](https://github.com/Lee-Juntong/ped/issues/14))
diff --git a/docs/team/madbeez.md b/docs/team/madbeez.md
new file mode 100644
index 0000000000..ecc0a309c8
--- /dev/null
+++ b/docs/team/madbeez.md
@@ -0,0 +1,39 @@
+# Wan Shi Jie Brendan's Project Portfolio Page
+
+# Project: NUSchedule
+
+NuSchedule is a task scheduling app targeted at NUS students and staff. It is written in Java and has about 5 kLoC.
+The user interacts with the app via a command line interface.
+
+## Summary of Contributions
+Given below are my contributions to the project.
+* **New Feature**: Implemented the ability to add new events
+ * What it does: This function allows users to add new events to their schedule, like classes and assignments.
+ It then provides feedback on whether the event was added successfully.
+ * Justification: This function is core to the app as it allows
+ * Highlights: The parameters of this command must be updated when new features are added to the app.
+
+* **New Feature**: Added the ability to get a reminder of events/tasks for the current date
+ * What it does: Allows users to know what events they have for the day, and the deadlines they need to submit assignments by.
+ * Justification: Helps forgetful users to remember what tasks are due.
+
+* **Enhancements to existing features**:
+ * Updated Parser to work with new features
+ * Fixed bugs related to Parser and AddCommand
+* **Code Contributed**: [Link](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=madbeez&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+* **Project management**:
+ * Managed releases `v1.0` - `v2.1` (3 releases) on GitHub
+
+* **Documentation**:
+ * User Guide
+ * Added documentation for add, reminder and list features
+ * Added section for command summary
+ * Developer Guide
+ * Added documentation for UI and Logic components
+ * Added documentation for add, reminder, list, find based on date, and user info features
+ * Added sections on target user profile and user stories
+
+* **Community**
+ * PRs reviewed(with non-trivial review comments): [1](https://github.com/nus-cs2113-AY2021S1/tp/pull/14), [2](https://github.com/nus-cs2113-AY2021S1/ip/pull/215)
+ * Reported bugs for other teams in the class (examples: [1](https://github.com/madbeez/ped/issues/4), [2](https://github.com/madbeez/ped/issues/5), [3](https://github.com/madbeez/ped/issues/8) )
+
diff --git a/docs/team/max-wunan.md b/docs/team/max-wunan.md
new file mode 100644
index 0000000000..c29accaae8
--- /dev/null
+++ b/docs/team/max-wunan.md
@@ -0,0 +1,49 @@
+# Wu Nan - Project Portfolio Page
+
+## Project: NUSchedule:
+
+NUSchedule is a desktop task management application used for keeping track of user's events. The user interacts with it
+using a Command Line Interface (CLI). It is written in Java and has around 5 kLoC.
+
+Given below are my contributions to this project:
+
+* __New Feature:__ Added the ability to view all available commands
+ * What it does: This function allows users to view the current version of this application by typing in `help`, and gives them a brief
+ description of all features. This function also provides users with a link to the detailed user guide.
+ * Justification: This feature improves the user-friendliness of this application greatly as users may choose to
+ refer to help message whenever they feel lost or are unfamiliar yet with the usage of NUSchedule. Also, with further
+ development of NuSchedule, there will be more and more features/commands available, this function will become more
+ and more useful for users to refer to.
+ * Highlights: The code for this function needs to be updated everytime there is a new feature, or a new version release.
+
+* __New Feature:__ Added the ability to clear events based on users' needs
+ * What it does: This function allows users to clear all events by typing in `clear`, or clear events that happened
+ before a certain date by typing in `clearBefore CLEAR_DATE`, or enable autoClear function of this application by
+ typing in `autoClear`, which clears all events that happened one month ago automatically.
+ * Justification: This feature improves the product efficiency and user-friendliness as it allows the space and memory
+ for data storage to be reduced, hence the speed of running this application can be increased. This function also
+ allows users to view all their events more efficiently as those unwanted events are cleared, users will be able to
+ have a more clean and straight-forward view of all ongoing events.
+ * Highlights: This function allows 3 different commands, and the status of `autoClear` function can be kept after
+ the application stops running.
+
+* __Code Contributed:__ [RepoSense Link](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=max-wunan&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+
+* __Project Management:__
+ * Managed releases `v1.0` - `v2.1` (3 releases) on GitHub
+
+* __Documentation:__
+ * User Guide:
+ * Added the project logo picture [#79](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/79), [#179](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/179)
+ * Added documentation for help and clear function [#169](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/169), [#175](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/175)
+ * Added several solutions in Q&A section [#189](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/189)
+ * Developer Guide:
+ * Added the project logo picture [#79](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/79), [#179](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/179)
+ * Added implementation details and sequence diagrams for help and clear function [#83](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/83)
+
+* __Community:__
+ * Reviewed Developer Guide of the team and fixed format error [#86](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/86/files)
+ * PRs reviewed (with non-trivial review comments): [#174](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/174#pullrequestreview-526179937)
+ * Reported for bugs and suggestions for other teams in the class (examples: [1](https://github.com/AY2021S1-CS2113T-W12-2/tp/issues/221), [2](https://github.com/AY2021S1-CS2113T-W12-2/tp/issues/223), [3](https://github.com/AY2021S1-CS2113T-W12-2/tp/issues/224))
+
+
\ No newline at end of file
diff --git a/docs/team/xuche123.md b/docs/team/xuche123.md
new file mode 100644
index 0000000000..70746b8fc8
--- /dev/null
+++ b/docs/team/xuche123.md
@@ -0,0 +1,33 @@
+# Project: NUSchedule
+
+NUSchedule is a task management application written in Java. It is operated on the command line interface.
+
+Given below are my contributions to the project.
+
+* **New Feature**: Added the ability to edit previous events.
+ * What it does: Allows the user to edit previous commands. The user can choose to edit individual fields of an event such as just choosing to edit the location of an event.
+ * Justification: This feature improves the product significantly because it provides the user a quick and simple method to correct any mistakes made in the addition of an event. Instead of deleting the event and creating a new one, the user can just edit that particular event with the correct field information.
+ * Highlights: This command has to be constantly updated whenever a new event class is added to allow for the editing of an event into that event class. Testing and implementation of this command was difficult as the command has to cover for all of the event classes.
+
+* **New Feature**: Added a sort command that allows the user to sort events.
+ * What it does: Allows the user to sort previous commands. The user can organise their events to by sorting them in a specified order.
+ * Justification: This feature improves the product significantly as it allows the user to order the events, allowing the user to prioritise certain events over others. For example, the user can choose to sort by time, which will cause eventing that are due soon to be sorted on top of events that are due later in the future.
+ * Highlights: This command was implemented by making use of comparators. Sorting by location was challenging to implement as there were two location types, online and offline locations and the command had to account for situations where either of them where null.
+
+* **Code contributed**: [RepoSense link](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=xuche123&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+
+* **Project management**:
+ * Managed releases `v1.0` - `v2.1` (3 releases) on GitHub
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features `edit` and `sort` [\#167](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/167)
+ * Added sections on Introduction, quick start and command summary [\#78](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/78)
+ * Developer Guide:
+ * Added implementation details and sequence diagrams of the `edit` and `sort` feature. [\#171](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/171)
+ * Added sections on Introduction, Architecture, Documentation and Appendix [\#74](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/74), [\#171](https://github.com/AY2021S1-CS2113T-F14-4/tp/pull/171)
+
+* **Community**:
+ * Reviewed developer guide for team [Study It](https://github.com/nus-cs2113-AY2021S1/tp/pulls?q=is%3Aopen+is%3Apr+CS2113T-T12-1+).
+ * Reported bugs and suggestions for other teams in the class (examples: [1](https://github.com/AY2021S1-CS2113T-W12-3/tp/issues/177), [2](https://github.com/AY2021S1-CS2113T-W12-3/tp/issues/175), [3](https://github.com/AY2021S1-CS2113T-W12-3/tp/issues/174))
+
diff --git a/src/main/java/NuSchedule.java b/src/main/java/NuSchedule.java
new file mode 100644
index 0000000000..d8dbbd8908
--- /dev/null
+++ b/src/main/java/NuSchedule.java
@@ -0,0 +1,85 @@
+import command.AutoClearCommand;
+import command.Command;
+import eventlist.EventList;
+import exception.CreatingFileException;
+import exception.NuScheduleException;
+import exception.WritingFileException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import parser.Parser;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+/**
+ * Main entry-point for the NUSchedule application.
+ */
+public class NuSchedule {
+
+ private Storage storage;
+ private EventList events;
+ private static BusStopList busStops;
+ private static LocationList locations;
+ private final UI ui;
+ private UserInfo userInfo = new UserInfo("", "",false);
+
+ public NuSchedule(String... filePaths) {
+ ui = new UI();
+
+ busStops = new BusStopList();
+ locations = new LocationList();
+
+ try {
+ storage = new Storage(filePaths);
+ } catch (CreatingFileException e) {
+ ui.showError(e.getMessage());
+ }
+ try {
+ events = new EventList(storage.loadEvents(locations));
+ userInfo = storage.loadUserInfo();
+ } catch (NuScheduleException e) {
+ ui.showLoadingError();
+ events = new EventList();
+ }
+
+ storage.loadBusStopData(busStops.getBusStopList());
+ storage.loadLocationData(locations.getLocationList());
+ // ui.printBusStopList(busStops.getBusStopList());
+ // ui.printLocationList(locations.getLocationList());
+
+ }
+
+ /**
+ * Runs the program until termination.
+ */
+ public void run() {
+ ui.printGreetingMessage(userInfo);
+ try {
+ AutoClearCommand.autoClear(events, storage, userInfo);
+ } catch (WritingFileException e) {
+ ui.showError(e.getMessage());
+ }
+ boolean isExit = false;
+ while (!isExit) {
+ try {
+ String fullCommand = ui.readCommand();
+ ui.printLine(); // show the divider line ("_______")
+ int size = events.getSize();
+ //Command auto_clear = new AutoClearCommand();
+ //auto_clear.execute(events, locations, busStops, ui, storage);
+ Command c = Parser.parse(fullCommand, locations, size);
+ c.execute(events, locations, busStops, ui, storage,userInfo);
+ isExit = c.isExit();
+ } catch (NuScheduleException e) {
+ ui.showError(e.getMessage());
+ } finally {
+ ui.printLine();
+ }
+ }
+ }
+
+
+ public static void main(String[] args) {
+ new NuSchedule("data/events.txt", "data/UserInfo.txt").run();
+ }
+}
diff --git a/src/main/java/command/AddCommand.java b/src/main/java/command/AddCommand.java
new file mode 100644
index 0000000000..ca6ae37800
--- /dev/null
+++ b/src/main/java/command/AddCommand.java
@@ -0,0 +1,50 @@
+package command;
+
+import event.Event;
+import eventlist.EventList;
+import exception.ExistingEventInListException;
+import exception.WritingFileException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+
+/**
+ * Represents the command call when the user adds a new event.
+ */
+public class AddCommand extends Command {
+ private final Event event;
+
+ /**
+ * Sets the task to be added to the list.
+ *
+ * @param event The event to be added.
+ */
+ public AddCommand(Event event) {
+ this.event = event;
+ }
+
+ /**
+ * Adds the appropriate type of event/task to the list.
+ *
+ * @param events the list of events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ * @throws WritingFileException the file is not correctly written.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo)
+ throws WritingFileException, ExistingEventInListException {
+ ui.printConflictEvents(events.checkConflictTiming(event));
+ events.addEvent(event);
+ ui.printAddEventMessage(event);
+ ui.printNumEvent(events.getSize());
+ storage.writeFile(events.getEventList());
+ }
+}
diff --git a/src/main/java/command/AutoClearCommand.java b/src/main/java/command/AutoClearCommand.java
new file mode 100644
index 0000000000..db082a08b9
--- /dev/null
+++ b/src/main/java/command/AutoClearCommand.java
@@ -0,0 +1,71 @@
+package command;
+
+import event.Event;
+import eventlist.EventList;
+import exception.EmptyEventListException;
+import exception.WritingFileException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+
+/**
+ * Represents the command call when the user wants to turn on/off the auto-clear function.
+ * Everytime the user input the function, events of one month ago will be cleared.
+ */
+public class AutoClearCommand extends Command {
+
+ protected boolean isAutoClear;
+
+ public AutoClearCommand(boolean isAutoClear) {
+ this.isAutoClear = isAutoClear;
+ }
+
+ /**
+ * Set the AutoClear flag as ON or OFF.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo) throws WritingFileException {
+ userInfo.setAutoClear(isAutoClear);
+ storage.writeUserInfo(userInfo);
+ if (isAutoClear) {
+ ui.printAutoClearOn();
+ } else {
+ ui.printAutoClearOff();
+ }
+ }
+
+ /**
+ * Clear all events one month ago.
+ *
+ * @param events the list of Events.
+ * @param storage store the data.
+ * @param userInfo User's information.
+ * @throws WritingFileException the file is not correctly written.
+ */
+ public static void autoClear(EventList events, Storage storage, UserInfo userInfo) throws WritingFileException {
+ if (userInfo.isAutoClear() && events != null) {
+ if (events.getSize() != 0) {
+ try {
+ events.clearBefore(LocalDate.now().minusMonths(1));
+ } catch (EmptyEventListException e) {
+ return;//this exception is unreachable because of the if condition
+ }
+ storage.writeFile(events.getEventList());
+ }
+ }
+
+ }
+}
diff --git a/src/main/java/command/ClearBeforeCommand.java b/src/main/java/command/ClearBeforeCommand.java
new file mode 100644
index 0000000000..2f176fa37e
--- /dev/null
+++ b/src/main/java/command/ClearBeforeCommand.java
@@ -0,0 +1,50 @@
+package command;
+
+import event.Event;
+import eventlist.EventList;
+import exception.NoDateBeforeException;
+import exception.EmptyEventListException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+
+/*
+ * Represents the command when the user wants to clear all events before a certain date
+ * */
+public class ClearBeforeCommand extends Command {
+ protected LocalDate clearDate;
+
+ public ClearBeforeCommand(LocalDate date) {
+ clearDate = date;
+ }
+
+ /**
+ * Execute the command based on the specific command type.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ * @throws EmptyEventListException the exceptions when the user try to clear an empty list.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo)
+ throws NoDateBeforeException, EmptyEventListException {
+ ArrayList filteredEventList = events.filterDateBefore(clearDate);
+ if (filteredEventList.size() == 0) {
+ throw new NoDateBeforeException();
+ } else {
+ events.clearBefore(clearDate);
+ ui.printClearBefore(clearDate);
+ }
+
+ }
+}
diff --git a/src/main/java/command/ClearCommand.java b/src/main/java/command/ClearCommand.java
new file mode 100644
index 0000000000..09b32f6250
--- /dev/null
+++ b/src/main/java/command/ClearCommand.java
@@ -0,0 +1,38 @@
+package command;
+
+import eventlist.EventList;
+import exception.EmptyEventListException;
+import exception.WritingFileException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+/**
+ * Represents the command call when the user clears all events.
+ */
+public class ClearCommand extends Command {
+ /**
+ * Execute the command based on the specific command type.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ * @throws EmptyEventListException the exceptions when the user try to clear an empty list.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo)
+ throws EmptyEventListException, WritingFileException {
+ if (events.getSize() == 0) {
+ throw new EmptyEventListException();
+ }
+ events.clearEvents();
+ storage.writeFile(events.getEventList());
+ ui.printClearEventsSuccessful();
+ }
+}
diff --git a/src/main/java/command/Command.java b/src/main/java/command/Command.java
new file mode 100644
index 0000000000..3872695e78
--- /dev/null
+++ b/src/main/java/command/Command.java
@@ -0,0 +1,36 @@
+package command;
+
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import eventlist.EventList;
+import ui.UI;
+import exception.NuScheduleException;
+import usercommunication.UserInfo;
+
+/**
+ * Represents the command to be executed.
+ */
+public abstract class Command {
+ protected boolean isExit = false;
+
+ /**
+ * Execute the command based on the specific command type.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ * @throws NuScheduleException the exceptions can happen in this program,
+ * to be handled based on the specific exception.
+ */
+ public abstract void execute(EventList events, LocationList locations, BusStopList busStops, UI ui,
+ Storage storage, UserInfo userInfo)
+ throws NuScheduleException;
+
+ public boolean isExit() {
+ return isExit;
+ }
+}
diff --git a/src/main/java/command/DeleteCommand.java b/src/main/java/command/DeleteCommand.java
new file mode 100644
index 0000000000..17dd0028ec
--- /dev/null
+++ b/src/main/java/command/DeleteCommand.java
@@ -0,0 +1,47 @@
+package command;
+
+
+import eventlist.EventList;
+import exception.UndefinedEventException;
+import exception.WritingFileException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+/**
+ * Represents the command call when the user deletes some event.
+ */
+public class DeleteCommand extends Command {
+ private final int eventIndex;
+
+ public DeleteCommand(int eventIndex) {
+ this.eventIndex = eventIndex;
+ }
+
+ /**
+ * Delete the event, and update the file.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ * @throws UndefinedEventException the user trying to operate (delete/edit/done) some events that does not exist.
+ * @throws WritingFileException the file is not correctly written.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo)
+ throws UndefinedEventException, WritingFileException {
+ if (eventIndex <= -1 || eventIndex >= events.getSize()) {
+ throw new UndefinedEventException(eventIndex + 1);
+ }
+ ui.printDeleteMessage(events.get(eventIndex));
+ events.remove(eventIndex);
+ ui.printNumEvent(events.getSize());
+ storage.writeFile(events.getEventList());
+ }
+}
diff --git a/src/main/java/command/DoneCommand.java b/src/main/java/command/DoneCommand.java
new file mode 100644
index 0000000000..b47c66619c
--- /dev/null
+++ b/src/main/java/command/DoneCommand.java
@@ -0,0 +1,47 @@
+package command;
+
+import eventlist.EventList;
+import exception.DoneBeforeEndException;
+import exception.UndefinedEventException;
+import exception.WritingFileException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+/**
+ * Represents the command call when the user mark a task as done.
+ */
+public class DoneCommand extends Command {
+ private final int eventIndex;
+
+ public DoneCommand(int eventIndex) {
+ this.eventIndex = eventIndex;
+ }
+
+ /**
+ * Mark the task as done, and update the file.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ * @throws UndefinedEventException the case when the the user trying to operate (delete/edit/done) some events
+ * that does not exist.
+ * @throws WritingFileException the file is not correctly written.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo)
+ throws UndefinedEventException, WritingFileException, DoneBeforeEndException {
+ if (eventIndex <= -1 || eventIndex >= events.getSize()) {
+ throw new UndefinedEventException(eventIndex + 1);
+ }
+ events.doneEvent(eventIndex);
+ ui.printDoneMessage(events.get(eventIndex));
+ storage.writeFile(events.getEventList());
+ }
+}
diff --git a/src/main/java/command/EditCommand.java b/src/main/java/command/EditCommand.java
new file mode 100644
index 0000000000..944f92ebaf
--- /dev/null
+++ b/src/main/java/command/EditCommand.java
@@ -0,0 +1,69 @@
+package command;
+
+import event.Event;
+import eventlist.EventList;
+import exception.EditNoEndTimeException;
+import exception.EndBeforeStartEventException;
+import exception.UndefinedEventException;
+import exception.WritingFileException;
+import location.Location;
+import location.OnlineLocation;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+import java.time.LocalDateTime;
+
+/**
+ * Represents the command call when the user adds a new event.
+ */
+public class EditCommand extends Command {
+ private final int index;
+ private final String[] editInformation;
+ private final LocalDateTime[] startEnd;
+
+ private final Location location;
+ private final OnlineLocation onlineLocation;
+
+ public EditCommand(int index, String[] editInformation, LocalDateTime[] startEnd, Location location,
+ OnlineLocation onlineLocation) {
+ this.index = index;
+ this.editInformation = editInformation;
+ this.startEnd = startEnd;
+ this.location = location;
+ this.onlineLocation = onlineLocation;
+ }
+
+ /**
+ * Edits the corresponding event/task in the list.
+ *
+ * @param events the list of events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ * @throws UndefinedEventException the user trying to operate (delete/edit/done) some events that does not
+ * exist.
+ * @throws WritingFileException Represents the exception when the file is not correctly written.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo)
+ throws UndefinedEventException, WritingFileException, EndBeforeStartEventException, EditNoEndTimeException {
+ if (index >= events.getSize() || index == -1) {
+ throw new UndefinedEventException(index + 1);
+ }
+ Event newEvent = events.editEvent(index, editInformation, startEnd, location, onlineLocation);
+ ui.printConflictEvents(events.checkConflictTiming(newEvent));
+ ui.printEditEventMessage(newEvent);
+ storage.writeFile(events.getEventList());
+ }
+
+ public static String[] newEditInformation() {
+ UI ui = new UI();
+ return ui.readEditCommand();
+ }
+}
diff --git a/src/main/java/command/ExitCommand.java b/src/main/java/command/ExitCommand.java
new file mode 100644
index 0000000000..0b1859c062
--- /dev/null
+++ b/src/main/java/command/ExitCommand.java
@@ -0,0 +1,31 @@
+package command;
+
+import eventlist.EventList;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+/**
+ * Represents the command call when the user exits this program.
+ */
+public class ExitCommand extends Command {
+ /**
+ * Mark the status of the program, isExit, as true.
+ * Also prints the exit message.
+ *
+ * @param events the list of tasks.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo) {
+ isExit = true;
+ ui.printExitMessage();
+ }
+}
diff --git a/src/main/java/command/FindCommand.java b/src/main/java/command/FindCommand.java
new file mode 100644
index 0000000000..49da8dc592
--- /dev/null
+++ b/src/main/java/command/FindCommand.java
@@ -0,0 +1,47 @@
+package command;
+
+
+import event.Event;
+import eventlist.EventList;
+import exception.NoMatchingEventException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+import java.util.ArrayList;
+
+/**
+ * Represents the command call when the user want to find the tasks having a certain keyword.
+ */
+public class FindCommand extends Command {
+ private final String filterString;
+
+ public FindCommand(String filterString) {
+ this.filterString = filterString;
+ }
+
+ /**
+ * Find the tasks having the keyword provided by the user, and print that filtered list.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ * @throws NoMatchingEventException the user trying to find a Task with a certain keyword, but such task does not
+ * exist in the list.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo)
+ throws NoMatchingEventException {
+ ArrayList filteredEventList = events.filterWith(filterString);
+ if (filteredEventList.size() == 0) {
+ throw new NoMatchingEventException();
+ }
+ ui.printFilteredEventList(filteredEventList);
+ }
+}
diff --git a/src/main/java/command/FindDateCommand.java b/src/main/java/command/FindDateCommand.java
new file mode 100644
index 0000000000..b93fb020df
--- /dev/null
+++ b/src/main/java/command/FindDateCommand.java
@@ -0,0 +1,48 @@
+package command;
+
+
+import event.Event;
+import eventlist.EventList;
+import exception.NoEventDateException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+
+/**
+ * Represents the command call when the user want to find the tasks in certain date.
+ */
+public class FindDateCommand extends Command {
+ private final LocalDate date;
+
+ public FindDateCommand(LocalDate date) {
+ this.date = date;
+ }
+
+ /**
+ * Execute the command based on the specific command type.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ * @throws NoEventDateException the user trying to find a Event with a certain date, but such Event does not
+ * exist in the list.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo)
+ throws NoEventDateException {
+ ArrayList filteredEventList = events.filterDateWith(date);
+ if (filteredEventList.size() == 0) {
+ throw new NoEventDateException();
+ }
+ ui.printFilteredDateEventList(filteredEventList);
+ }
+}
diff --git a/src/main/java/command/HelpCommand.java b/src/main/java/command/HelpCommand.java
new file mode 100644
index 0000000000..e2a21bf788
--- /dev/null
+++ b/src/main/java/command/HelpCommand.java
@@ -0,0 +1,29 @@
+package command;
+
+import eventlist.EventList;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+/**
+ * Represents the command call when the user asking for helps.
+ */
+public class HelpCommand extends Command {
+ /**
+ * Execute the command based on the specific command type.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo) {
+ ui.printHelp();
+ }
+}
diff --git a/src/main/java/command/LocateCommand.java b/src/main/java/command/LocateCommand.java
new file mode 100644
index 0000000000..8100179527
--- /dev/null
+++ b/src/main/java/command/LocateCommand.java
@@ -0,0 +1,46 @@
+package command;
+
+import eventlist.EventList;
+import location.Location;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+/**
+ * Represents the command call when the user wants to locate an event.
+ */
+public class LocateCommand extends Command {
+ private final String input;
+
+ public LocateCommand(String input) {
+ this.input = input;
+ }
+
+ /**
+ * Provides location information when user gives a number within size of EventList or name of a location.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo) {
+ int eventNum;
+ if (locations.checkIfInteger(input)) {
+ eventNum = Integer.parseInt(input) - 1;
+ Location location = events.get(eventNum).getLocation();
+ System.out.println(events.get(eventNum).getDescription() + " is located at:");
+ System.out.println(location);
+ } else if (locations.checkValidLocation(input)) {
+ Location location = locations.findLocation(input);
+ System.out.println("Location Information: ");
+ System.out.println(location);
+ }
+ }
+}
diff --git a/src/main/java/command/PrintAreaLocationsCommand.java b/src/main/java/command/PrintAreaLocationsCommand.java
new file mode 100644
index 0000000000..b52a9c768b
--- /dev/null
+++ b/src/main/java/command/PrintAreaLocationsCommand.java
@@ -0,0 +1,57 @@
+package command;
+
+import eventlist.EventList;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+/**
+ * Represents the command for printing locations available at some areas in NUS.
+ */
+public class PrintAreaLocationsCommand extends Command {
+ String area;
+
+ public PrintAreaLocationsCommand(String area) {
+ this.area = area;
+ }
+
+ /**
+ * Purely print the available locations at the area selected by the user.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo) {
+ switch (area.toUpperCase()) {
+ case "FOS":
+ ui.printFosLocations();
+ break;
+ case "FOE":
+ ui.printFoeLocations();
+ break;
+ case "FASS":
+ ui.printFassLocations();
+ break;
+ case "SDE":
+ ui.printSdeLocations();
+ break;
+ case "SOC":
+ case "BIZ":
+ ui.printSocAndBizLocations();
+ break;
+ case "HOSTEL":
+ ui.printHostelLocations();
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/src/main/java/command/PrintFullListCommand.java b/src/main/java/command/PrintFullListCommand.java
new file mode 100644
index 0000000000..8d6df186c2
--- /dev/null
+++ b/src/main/java/command/PrintFullListCommand.java
@@ -0,0 +1,33 @@
+package command;
+
+import exception.EmptyEventListException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import eventlist.EventList;
+import ui.UI;
+import usercommunication.UserInfo;
+
+/**
+ * Represent the command for printing everything in the list.
+ */
+public class PrintFullListCommand extends Command {
+
+ /**
+ * Prints the list of Events.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ * @throws EmptyEventListException the exception when the user want to print an empty list.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo)
+ throws EmptyEventListException {
+ ui.printEventList(events.getEventList());
+ }
+}
diff --git a/src/main/java/command/PrintLocationCommand.java b/src/main/java/command/PrintLocationCommand.java
new file mode 100644
index 0000000000..982f95e25f
--- /dev/null
+++ b/src/main/java/command/PrintLocationCommand.java
@@ -0,0 +1,29 @@
+package command;
+
+import eventlist.EventList;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+/**
+ * Represent the command for print the locations.
+ */
+public class PrintLocationCommand extends Command {
+ /**
+ * Prints list of locations.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo) {
+ ui.printLocationList(locations.getLocationList());
+ }
+}
diff --git a/src/main/java/command/ReminderCommand.java b/src/main/java/command/ReminderCommand.java
new file mode 100644
index 0000000000..ba47d112a4
--- /dev/null
+++ b/src/main/java/command/ReminderCommand.java
@@ -0,0 +1,45 @@
+package command;
+
+import event.Event;
+import eventlist.EventList;
+import exception.NoEventDateRemindException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+
+/**
+ * Represents the command call when the user wants a list of events within the day.
+ */
+public class ReminderCommand extends Command {
+ private final LocalDate filterDate;
+
+ public ReminderCommand() {
+ filterDate = LocalDate.now();
+ }
+
+ /**
+ * Command to print list of events within the day when called.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo)
+ throws NoEventDateRemindException {
+ ArrayList filteredEventList = events.filterDateNotDoneWith(filterDate);
+ if (filteredEventList.size() == 0) {
+ throw new NoEventDateRemindException();
+ }
+ ui.printRemindEventList(filteredEventList);
+ }
+}
diff --git a/src/main/java/command/RepeatCommand.java b/src/main/java/command/RepeatCommand.java
new file mode 100644
index 0000000000..957cb36ab4
--- /dev/null
+++ b/src/main/java/command/RepeatCommand.java
@@ -0,0 +1,61 @@
+package command;
+
+import eventlist.EventList;
+import exception.NuScheduleException;
+import exception.UndefinedEventException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+/**
+ * Represents the command to repeat certain classes for several weeks.
+ */
+public class RepeatCommand extends Command {
+ private int index;
+ private final int numWeeks;//repeat the event for numWeeks weeks
+ private boolean isAllClasses = false;
+
+ public RepeatCommand(int index, int numWeeks) {
+ this.index = index;
+ this.numWeeks = numWeeks;
+ }
+
+ public RepeatCommand(boolean isAllClasses, int numWeeks) {
+ this.isAllClasses = true;
+ this.numWeeks = numWeeks;
+ }
+
+ /**
+ * Execute the command based on the input. If the input is "repeat INDEX NUMBER_OF_WEEKS", repeat the event for
+ * NUMBER_OF_WEEKS.
+ * If the input is "repeat all NUMBER_OF_WEEKS", repeat all the classes happening in the current week for
+ * NUMBER_OF_WEEKS.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ * @throws NuScheduleException the exceptions can happen in this program,
+ * to be handled based on the specific exception.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo)
+ throws NuScheduleException {
+ if (isAllClasses) {
+ events.repeatAllClasses(numWeeks);
+ ui.printRepeatAll(numWeeks);
+ } else if (index < 0 || index >= events.getSize()) {
+ throw new UndefinedEventException(index + 1);
+ } else {
+ events.repeatEvent(index, numWeeks);
+ ui.printRepeatEvent(numWeeks);
+ }
+
+ storage.writeFile(events.getEventList());
+ }
+}
diff --git a/src/main/java/command/SortCommand.java b/src/main/java/command/SortCommand.java
new file mode 100644
index 0000000000..3d4213d83c
--- /dev/null
+++ b/src/main/java/command/SortCommand.java
@@ -0,0 +1,41 @@
+package command;
+
+import eventlist.EventList;
+import exception.NuScheduleException;
+import exception.WritingFileException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+/**
+ * Represents the command call when the user wants to sort the list.
+ */
+public class SortCommand extends Command {
+ private final String type;
+
+ public SortCommand(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Sort the list with given condition.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ * @throws WritingFileException the file is not correctly written.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo)
+ throws WritingFileException {
+ events.sortEvent(type);
+ ui.printSortEventMessage();
+ storage.writeFile(events.getEventList());
+ }
+}
diff --git a/src/main/java/command/StudyTimeCommand.java b/src/main/java/command/StudyTimeCommand.java
new file mode 100644
index 0000000000..1b68482d4d
--- /dev/null
+++ b/src/main/java/command/StudyTimeCommand.java
@@ -0,0 +1,47 @@
+package command;
+
+import event.Event;
+import eventlist.EventList;
+import exception.NoEventDoneException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+
+/**
+ * Represents the Command for finding the study time spent on a certain day.
+ */
+public class StudyTimeCommand extends Command {
+ protected LocalDate date;
+
+ public StudyTimeCommand(LocalDate date) {
+ this.date = date;
+ }
+
+ /**
+ * Execute the command based on the specific command type.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ * @throws NoEventDoneException the users try to find the study time but he had not done any thing related to
+ * academics on that day.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo)
+ throws NoEventDoneException {
+ ArrayList filteredEventList = events.filterDateDoneAcademicEventWith(date);
+ if (filteredEventList.size() == 0) {
+ throw new NoEventDoneException();
+ }
+ ui.printStudyTime(filteredEventList, date);
+ }
+}
diff --git a/src/main/java/command/UserInfoCommand.java b/src/main/java/command/UserInfoCommand.java
new file mode 100644
index 0000000000..568f963ca7
--- /dev/null
+++ b/src/main/java/command/UserInfoCommand.java
@@ -0,0 +1,45 @@
+package command;
+
+import eventlist.EventList;
+import exception.NuScheduleException;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+/**
+ * Represents the command call when the user wants to change the type of himself or herself.
+ */
+public class UserInfoCommand extends Command {
+ private String name;
+ private String userType;
+
+ public UserInfoCommand(String name, String userType) {
+ this.name = name;
+ this.userType = userType;
+ }
+
+
+ /**
+ * Execute the command based on the specific command type.
+ *
+ * @param events the list of Events.
+ * @param locations the list of Locations.
+ * @param busStops the list of BusStops.
+ * @param ui do outputs.
+ * @param storage store the data.
+ * @param userInfo personal information and settings about the user.
+ * @throws NuScheduleException the exceptions can happen in this program,
+ * to be handled based on the specific exception.
+ */
+ @Override
+ public void execute(EventList events, LocationList locations, BusStopList busStops, UI ui, Storage storage,
+ UserInfo userInfo)
+ throws NuScheduleException {
+ userInfo.setName(name);
+ userInfo.setType(userType);
+ storage.writeUserInfo(userInfo);
+ ui.helloWithName(userInfo.getName());
+ }
+}
diff --git a/src/main/java/event/Assignment.java b/src/main/java/event/Assignment.java
new file mode 100644
index 0000000000..f26f3fdca9
--- /dev/null
+++ b/src/main/java/event/Assignment.java
@@ -0,0 +1,114 @@
+package event;
+
+
+import location.Location;
+import location.OnlineLocation;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Comparator;
+
+/**
+ * Represents the Assignment Events.
+ */
+public class Assignment extends Event {
+
+ protected LocalDateTime by;
+
+ /**
+ * Convert the information about this assignment to a string that is to be stored in a file.
+ *
+ * @return the result string to be stored.
+ */
+ public String fileString() {
+ return "A//" + (isDone ? 1 : 0) + "//" + description + "//" + by + "//" + (location != null
+ ? location.fileString() : link.fileString());
+ }
+
+ public Assignment(String description, Location location, LocalDateTime by) {
+ super(description, location);
+ this.by = by;
+ }
+
+ public Assignment(String description, OnlineLocation location, LocalDateTime by) {
+ super(description, location);
+ this.by = by;
+ }
+
+ /**
+ * Provides the date of the Assignment.
+ *
+ * @return the LocalDate get from LocalDateTime.
+ */
+ public LocalDate getDate() {
+ return LocalDate.from(by);
+ }
+
+ /**
+ * A dummy method which provides the same function as getDate().
+ *
+ * @return the LocalDate get from LocalDateTime.
+ */
+ public LocalDate getEndDate() {
+ return getDate();
+ }
+
+ /**
+ * Provides the date time of the class.
+ *
+ * @return the LocalDateTime get from LocalDateTime.
+ */
+ public LocalDateTime getEndDateTime() {
+ return LocalDateTime.from(by);
+ }
+
+ public LocalDateTime getStartDateTime() {
+ return getEndDateTime();
+ }
+
+ /**
+ * Prepare the string to be printed in the list.
+ *
+ * @return the string required in a certain format.
+ */
+ public String toString() {
+ return "[A]" + super.toString() + " (by: " + by.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH':'mm")) + ")"
+ + "\n" + (location != null ? location : link);
+ }
+
+ /**
+ * Provides the binary operator for checking whether 2 assignments are the same.
+ */
+ @Override
+ public boolean equals(Object object) {
+ boolean isEqual = false;
+
+ if (object instanceof Assignment) {
+ isEqual = (this.description.equalsIgnoreCase(((Assignment) object).description))
+ && (this.link != null ? (this.link.equals(((Assignment) object).link))
+ : (this.location.equals(((Assignment) object).location)))
+ && (this.by.isEqual(((Assignment) object).by));
+ }
+
+ return isEqual;
+ }
+
+ public void setDateTime(LocalDateTime newDateTime) {
+ this.by = newDateTime;
+ }
+
+ /**
+ * A copy constructor.
+ *
+ * @param anotherAssignment the assignment to be copied.
+ */
+ public Assignment(Assignment anotherAssignment) {
+ super(anotherAssignment);
+ this.by = anotherAssignment.by;
+ }
+
+ public Assignment clone() {
+ return new Assignment(this);
+ }
+}
diff --git a/src/main/java/event/Class.java b/src/main/java/event/Class.java
new file mode 100644
index 0000000000..dfbbc8c266
--- /dev/null
+++ b/src/main/java/event/Class.java
@@ -0,0 +1,132 @@
+package event;
+
+
+import exception.EndBeforeStartEventException;
+import location.Location;
+import location.OnlineLocation;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * Represents the Class events.
+ */
+public class Class extends Event {
+ protected LocalDateTime at;
+ protected LocalDateTime end;
+
+ public void setDateTime(LocalDateTime at) {
+ this.at = at;
+ }
+
+ public void setEndDateTime(LocalDateTime end) {
+ this.end = end;
+ }
+
+
+ public Class(String description, Location location, LocalDateTime at, LocalDateTime end)
+ throws EndBeforeStartEventException {
+ super(description, location);
+ this.at = at;
+ this.end = end;
+ if (!end.isAfter(at)) {
+ throw new EndBeforeStartEventException();
+ }
+ }
+
+ public Class(String description, OnlineLocation meeting, LocalDateTime at, LocalDateTime end)
+ throws EndBeforeStartEventException {
+ super(description, meeting);
+ this.at = at;
+ this.end = end;
+ if (!end.isAfter(at)) {
+ throw new EndBeforeStartEventException();
+ }
+ }
+
+ /**
+ * Convert the information about this class to a string that is to be stored in a file.
+ *
+ * @return the result string to be stored.
+ */
+ public String fileString() {
+ return "C//" + (isDone ? 1 : 0) + "//" + description + "//" + at + "//" + end + "//" + (location != null
+ ? location.fileString() : link.fileString());
+ }
+
+ /**
+ * Provides the date of the class.
+ *
+ * @return the LocalDate get from LocalDateTime.
+ */
+ public LocalDate getDate() {
+ return LocalDate.from(at);
+ }
+
+ public LocalDate getEndDate() {
+ return LocalDate.from(end);
+ }
+
+ /**
+ * Provides the date time of the class.
+ *
+ * @return the LocalDateTime get from LocalDateTime.
+ */
+ public LocalDateTime getStartDateTime() {
+ return LocalDateTime.from(at);
+ }
+
+ /**
+ * Provides the end date time of the class.
+ *
+ * @return the LocalDateTime get from LocalDateTime.
+ */
+ public LocalDateTime getEndDateTime() {
+ return LocalDateTime.from(end);
+ }
+
+ /**
+ * Prepare the string to be printed in the list.
+ *
+ * @return the string required in a certain format.
+ */
+ public String toString() {
+ return "[C]" + super.toString() + " (at: " + at.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH':'mm"))
+ + ")\n"
+ + "(end at: " + end.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH':'mm")) + ")"
+ + "\n" + (location != null ? location : link);
+ }
+
+ /**
+ * Provides the binary operator for checking whether 2 classes are the same.
+ */
+ @Override
+ public boolean equals(Object object) {
+ boolean isEqual = false;
+
+ if (object instanceof Class) {
+ isEqual = (this.description.equalsIgnoreCase(((Class) object).description))
+ && (this.link != null ? (this.link.equals(((Class) object).link))
+ : (this.location.equals(((Class) object).location)))
+ && (this.at.isEqual(((Class) object).at));
+ }
+
+ return isEqual;
+ }
+
+ /**
+ * A copy constructor.
+ *
+ * @param anotherClass the class to be copied.
+ */
+ public Class(Class anotherClass) {
+ super(anotherClass);
+ this.at = anotherClass.at;
+ this.end = anotherClass.end;
+ }
+
+ public Class clone() {
+ return new Class(this);
+ }
+}
diff --git a/src/main/java/event/Event.java b/src/main/java/event/Event.java
new file mode 100644
index 0000000000..d5e7313c14
--- /dev/null
+++ b/src/main/java/event/Event.java
@@ -0,0 +1,164 @@
+package event;
+
+import location.Location;
+import location.OnlineLocation;
+
+import java.time.LocalDateTime;
+import java.util.Comparator;
+
+import java.time.LocalDate;
+
+/**
+ * Represents the event objects.
+ * Contains a String description , which is the description of the event,
+ * and a boolean isDone, which is the status of the Event.
+ * Provides methods to mark an event as done(either during user input or reading from file),
+ * get the value of isDone,
+ * convert the event object to a string to be printed out or write to a file.
+ */
+public abstract class Event {
+ protected String description;
+ protected boolean isDone;
+ protected Location location = null;
+ protected OnlineLocation link = null;
+
+ public Event(Event anotherEvent) {
+ this.description = anotherEvent.description;
+ this.isDone = anotherEvent.isDone;
+ this.location = anotherEvent.location;
+ this.link = anotherEvent.link;
+ }
+
+ public Event clone() {
+ return null;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public void setLink(OnlineLocation link) {
+ this.link = link;
+ }
+
+ public void setLocation(Location location) {
+ this.location = location;
+ }
+
+ public Event(String description, Location location) {
+ this.description = description;
+ this.isDone = false;
+ this.location = location;
+ }
+
+ public Event(String description, OnlineLocation location) {
+ this.description = description;
+ this.isDone = false;
+ this.link = location;
+ }
+
+ /**
+ * Mark a Event's status as done.
+ */
+ public void markAsDone() {
+ this.isDone = true;
+ }
+
+ public boolean isDone() {
+ return isDone;
+ }
+
+ public abstract String fileString();
+
+ /**
+ * Provides the status of the Event as a icon.
+ *
+ * @return returns a tick if the Event is done, and returns a cross if the Event is not done.
+ */
+ public String getStatus() {
+ return (isDone ? "Done" : "Not Done");
+ //return tick or X symbols
+ }
+
+ /**
+ * Prepare the string to be printed in the list.
+ *
+ * @return the common part for Event, Assignment, Class.
+ */
+ public String toString() {
+ return "[" + getStatus() + "]" + description;
+ }
+
+ /**
+ * Provides the date of the Event.
+ *
+ * @return the LocalDate get from LocalDateTime.
+ */
+ public LocalDate getDate() {
+ return null;
+ }
+
+ public LocalDateTime getStartDateTime() {
+ return null;
+ }
+
+ public LocalDateTime getEndDateTime() {
+ return null;
+ }
+
+ public LocalDate getEndDate() {
+ return null;
+ }
+
+ public void setDateTime(LocalDateTime newDateTime) {
+ }
+
+ public void setEndDateTime(LocalDateTime newDateTime) {
+ }
+
+ /**
+ * Provides the String variable of the description of this Event.
+ *
+ * @return the description of this Event.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ public Location getLocation() {
+ return location;
+ }
+
+ public OnlineLocation getLink() {
+ return link;
+ }
+
+ public static Comparator descriptionComparator = (o1, o2) ->
+ o1.getDescription().compareToIgnoreCase(o2.getDescription());
+
+
+ public static Comparator locationComparator = (e1, e2) -> {
+
+ if (e2.getLocation() == null && e1.getLocation() == null) {
+ if (e1.getLink() == null) {
+ return 1;
+ }
+ if (e2.getLink() == null) {
+ return -1;
+ }
+ return e1.getLink().getLink().compareToIgnoreCase(e2.getLink().getLink());
+ }
+
+ if (e1.getLocation() == null) {
+ return 1;
+ }
+ if (e2.getLocation() == null) {
+ return -1;
+ }
+ return e1.getLocation().getName().compareToIgnoreCase(e2.getLocation().getName());
+ };
+
+}
+
+
+
diff --git a/src/main/java/event/PersonalEvent.java b/src/main/java/event/PersonalEvent.java
new file mode 100644
index 0000000000..cd4e09700b
--- /dev/null
+++ b/src/main/java/event/PersonalEvent.java
@@ -0,0 +1,155 @@
+package event;
+
+
+import exception.EndBeforeStartEventException;
+import location.Location;
+import location.OnlineLocation;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Comparator;
+
+
+/**
+ * Represents the PersonalEvent Events.
+ * PersonalEvent may or may not have an end time.
+ */
+public class PersonalEvent extends Event {
+
+ protected LocalDateTime at;
+ protected LocalDateTime end = null;
+
+ public void setDateTime(LocalDateTime at) {
+ this.at = at;
+ }
+
+ public void setEndDateTime(LocalDateTime end) {
+ if (this.end != null) {
+ this.end = end;
+ }
+ }
+
+ /**
+ * Convert the information about this personal event to a string that is to be stored in a file.
+ *
+ * @return the result string to be stored
+ */
+ public String fileString() {
+ return "P//" + (isDone ? 1 : 0) + "//" + description + "//" + at + "//" + (end != null ? end + "//" : "")
+ + (location != null ? location.fileString() : link.fileString());
+ }
+
+ /**
+ * Provides the date of the Event.
+ *
+ * @return the LocalDate get from LocalDateTime
+ */
+ public LocalDate getDate() {
+ return LocalDate.from(at);
+ }
+
+ public LocalDate getEndDate() {
+ try {
+ return LocalDate.from(end);
+ } catch (NullPointerException e) {
+ return LocalDate.from(at);
+ }
+ }
+
+ public PersonalEvent(String description, Location location, LocalDateTime at) {
+ super(description, location);
+ this.at = at;
+ }
+
+ public PersonalEvent(String description, Location location, LocalDateTime at, LocalDateTime end)
+ throws EndBeforeStartEventException {
+ super(description, location);
+ this.at = at;
+ this.end = end;
+ if (!end.isAfter(at)) {
+ throw new EndBeforeStartEventException();
+ }
+ }
+
+ public PersonalEvent(String description, OnlineLocation location, LocalDateTime at) {
+ super(description, location);
+ this.at = at;
+ }
+
+ public PersonalEvent(String description, OnlineLocation location, LocalDateTime at, LocalDateTime end)
+ throws EndBeforeStartEventException {
+ super(description, location);
+ this.at = at;
+ this.end = end;
+ if (!end.isAfter(at)) {
+ throw new EndBeforeStartEventException();
+ }
+ }
+
+ /**
+ * Provides the date time of the personal event.
+ *
+ * @return the LocalDateTime get from LocalDateTime.
+ */
+ public LocalDateTime getStartDateTime() {
+ return LocalDateTime.from(at);
+ }
+
+ /**
+ * Provides the end date time of the personal event.
+ *
+ * @return the LocalDateTime get from LocalDateTime.
+ */
+ public LocalDateTime getEndDateTime() {
+ try {
+ return LocalDateTime.from(end);
+ } catch (NullPointerException e) {
+ return LocalDateTime.from(at);
+ }
+ }
+
+ /**
+ * Prepare the string to be printed in the list.
+ *
+ * @return the string required in a certain format.
+ */
+ public String toString() {
+ return "[P]" + super.toString() + " (at: " + at.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH':'mm")) + ")"
+ + (end != null ? "\n(end at: " + end.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH':'mm")) + ")" :
+ "")
+ + "\n" + (location != null ? location : link);
+ }
+
+ /**
+ * Provides the binary operator for checking whether 2 classes are the same.
+ */
+ @Override
+ public boolean equals(Object object) {
+ boolean isEqual = false;
+
+ if (object instanceof PersonalEvent) {
+ isEqual = (this.description.equalsIgnoreCase(((PersonalEvent) object).description))
+ && (this.link != null ? (this.link.equals(((PersonalEvent) object).link))
+ : (this.location.equals(((PersonalEvent) object).location)))
+ && (this.at.isEqual(((PersonalEvent) object).at));
+ }
+
+ return isEqual;
+ }
+
+ /**
+ * A copy constructor.
+ *
+ * @param anotherPersonalEvent the PersonalEvent to be copied.
+ */
+ public PersonalEvent(PersonalEvent anotherPersonalEvent) {
+ super(anotherPersonalEvent);
+ this.at = anotherPersonalEvent.at;
+ this.end = anotherPersonalEvent.end;
+ }
+
+ public PersonalEvent clone() {
+ return new PersonalEvent(this);
+ }
+}
diff --git a/src/main/java/event/SelfStudy.java b/src/main/java/event/SelfStudy.java
new file mode 100644
index 0000000000..7311044763
--- /dev/null
+++ b/src/main/java/event/SelfStudy.java
@@ -0,0 +1,64 @@
+package event;
+
+import exception.EndBeforeStartEventException;
+import location.Location;
+import location.OnlineLocation;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class SelfStudy extends PersonalEvent {
+ public SelfStudy(String description, Location location, LocalDateTime at) {
+ super(description, location, at);
+ }
+
+ public SelfStudy(String description, Location location, LocalDateTime at, LocalDateTime end)
+ throws EndBeforeStartEventException {
+ super(description, location, at, end);
+ }
+
+ public SelfStudy(String description, OnlineLocation location, LocalDateTime at) {
+ super(description, location, at);
+ }
+
+ public SelfStudy(String description, OnlineLocation location, LocalDateTime at, LocalDateTime end)
+ throws EndBeforeStartEventException {
+ super(description, location, at, end);
+ }
+
+ /**
+ * Prepare the string to be printed in the list.
+ *
+ * @return the string required in a certain format.
+ */
+ public String toString() {
+ return "[S]" + "[" + getStatus() + "]" + description + " (at: " + at.format(DateTimeFormatter.ofPattern(
+ "yyyy/MM/dd HH':'mm")) + ")"
+ + (end != null ? "\n(end at: " + end.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH':'mm")) + ")" :
+ "")
+ + "\n" + (location != null ? location : link);
+ }
+
+ /**
+ * Convert the information about this self study event to a string that is to be stored in a file.
+ *
+ * @return the result string to be stored
+ */
+ public String fileString() {
+ return "S//" + (isDone ? 1 : 0) + "//" + description + "//" + at + "//" + (end != null ? end + "//" : "")
+ + (location != null ? location.fileString() : link.fileString());
+ }
+
+ /**
+ * A copy constructor.
+ *
+ * @param anotherSelfStudy the SelfStudy to be copied.
+ */
+ public SelfStudy(SelfStudy anotherSelfStudy) {
+ super(anotherSelfStudy);
+ }
+
+ public SelfStudy clone() {
+ return new SelfStudy(this);
+ }
+}
diff --git a/src/main/java/eventlist/EventList.java b/src/main/java/eventlist/EventList.java
new file mode 100644
index 0000000000..07d01ba82e
--- /dev/null
+++ b/src/main/java/eventlist/EventList.java
@@ -0,0 +1,556 @@
+package eventlist;
+
+
+import event.Assignment;
+import event.Class;
+import event.Event;
+import event.PersonalEvent;
+import event.SelfStudy;
+import exception.DoneBeforeEndException;
+import exception.ExistingEventInListException;
+import exception.UndefinedEventException;
+import exception.EndBeforeStartEventException;
+import exception.EditNoEndTimeException;
+import exception.EmptyEventListException;
+import exception.NoClassWeekException;
+import location.Location;
+import location.OnlineLocation;
+
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.temporal.TemporalAdjusters;
+import java.util.ArrayList;
+import java.util.Comparator;
+
+
+import static java.util.stream.Collectors.toList;
+
+/**
+ * Contains the list of the events and provides ways to delete/add/mark as done events.
+ */
+public class EventList {
+ private final ArrayList events;
+
+ /**
+ * Construct the events as an empty ArrayList.
+ */
+ public EventList() {
+ events = new ArrayList();
+ }
+
+ /**
+ * When loading from the file, create the list as provided in the file.
+ *
+ * @param events provided by Storage::load()
+ * @see storage.Storage
+ */
+ public EventList(ArrayList events) {
+ this.events = events;
+ }
+
+ /**
+ * Adds an event to the list.
+ *
+ * @param eventToBeAdded may be Assignment/Class/Personal Event based on the usage
+ */
+ public void addEvent(Event eventToBeAdded) throws ExistingEventInListException {
+ if (events.contains(eventToBeAdded)) {
+ throw new ExistingEventInListException();
+ }
+
+ events.add(eventToBeAdded);
+ }
+
+ /**
+ * Mark a event as done.
+ *
+ * @param eventIndex the index of the event being done
+ * // * @throws UndefinedEventException the event is not defined but
+ * // the user want to mark it as done
+ */
+ public void doneEvent(int eventIndex) throws UndefinedEventException, DoneBeforeEndException {
+ try {
+ if (events.get(eventIndex).getEndDateTime().isAfter(LocalDateTime.now())
+ && !(events.get(eventIndex) instanceof Assignment)) {
+ throw new DoneBeforeEndException();
+ }
+ events.get(eventIndex).markAsDone();
+ } catch (IndexOutOfBoundsException e) {
+ throw new UndefinedEventException(eventIndex);
+ }
+ }
+
+ /**
+ * Edit the contents of an existing event.
+ *
+ * @param index the index of the event being edited.
+ * @param editInformation array containing command type and description.
+ * @param startEnd array containing start date and end date.
+ * @param location new location.
+ * @param onlineLocation new online location.
+ * @return Event new edited events
+ */
+ public Event editEvent(int index, String[] editInformation, LocalDateTime[] startEnd, Location location,
+ OnlineLocation onlineLocation) throws EndBeforeStartEventException, EditNoEndTimeException {
+ assert events != null;
+ // no change in event type
+ if (editInformation[0].isBlank()) {
+ editSameType(index, editInformation, startEnd, location, onlineLocation);
+ } else {
+ // create new event object with user input
+ editNewType(index, editInformation, startEnd, location, onlineLocation);
+ }
+
+ return events.get(index);
+ }
+
+ /**
+ * Edit the contents of an existing event. Will only be called when the event type is changed.
+ *
+ * @param index the index of the event being edited.
+ * @param editInformation array containing command type and description.
+ * @param startEnd array containing start date and end date.
+ * @param location new location.
+ * @param onlineLocation new online location.
+ */
+ private void editNewType(int index, String[] editInformation, LocalDateTime[] startEnd, Location location,
+ OnlineLocation onlineLocation) throws EditNoEndTimeException,
+ EndBeforeStartEventException {
+ Event newEvent;
+ String newDescription;
+ Location newLocation = null;
+ OnlineLocation newOnlineLocation = null;
+ LocalDateTime start;
+ LocalDateTime end = null;
+
+ // newDescription is set to the user input if it is not null. Otherwise, set it to the original value.
+ if (editInformation[1].isBlank()) {
+ newDescription = events.get(index).getDescription();
+ } else {
+ newDescription = editInformation[1];
+ }
+
+ // newLocation is set to the user input if it is not null. Otherwise, set it to the original value.
+ if (location == null && onlineLocation == null) {
+ if (events.get(index).getLocation() != null) {
+ newLocation = events.get(index).getLocation();
+ }
+ if (events.get(index).getLink() != null) {
+ newOnlineLocation = events.get(index).getLink();
+ }
+ } else if (location != null && onlineLocation == null) {
+ newLocation = location;
+ newOnlineLocation = null;
+ } else {
+ newLocation = null;
+ newOnlineLocation = onlineLocation;
+ }
+
+ // start and end are set to the user input if they are not null. Otherwise, set them to their original value.
+ if (startEnd[0] == null) {
+ if (events.get(index) instanceof Assignment) {
+ start = events.get(index).getEndDateTime();
+ } else {
+ start = events.get(index).getStartDateTime();
+ }
+ } else {
+ start = startEnd[0];
+ }
+
+ if (startEnd[1] == null) {
+ end = events.get(index).getEndDateTime();
+ if (editInformation[4].equals("nil")) {
+ end = null;
+ }
+
+ if (end == null && editInformation[0].equalsIgnoreCase("class")) {
+
+ throw new EditNoEndTimeException();
+ }
+ } else {
+ end = startEnd[1];
+ }
+
+ // create new event object using the new fields.
+ switch (editInformation[0]) {
+ case "assignment":
+ if (newLocation != null) {
+ newEvent = new Assignment(newDescription, newLocation, start);
+ } else {
+ newEvent = new Assignment(newDescription, newOnlineLocation, start);
+ }
+ break;
+ case "class":
+ assert end != null;
+ if (newLocation != null) {
+
+ newEvent = new Class(newDescription, newLocation, start, end);
+ } else {
+
+ newEvent = new Class(newDescription, newOnlineLocation, start, end);
+ }
+ break;
+ case "selfStudy":
+ if (newLocation != null) {
+ if (end == null) {
+ newEvent = new SelfStudy(newDescription, newLocation, start);
+ } else {
+ newEvent = new SelfStudy(newDescription, newLocation, start, end);
+ }
+ } else {
+ if (end == null) {
+ newEvent = new SelfStudy(newDescription, newOnlineLocation, start);
+ } else {
+ newEvent = new SelfStudy(newDescription, newOnlineLocation, start, end);
+ }
+ }
+ break;
+ default:
+ if (newLocation != null) {
+ if (end == null) {
+ newEvent = new PersonalEvent(newDescription, newLocation, start);
+ } else {
+ newEvent = new PersonalEvent(newDescription, newLocation, start, end);
+ }
+ } else {
+ if (end == null) {
+ newEvent = new PersonalEvent(newDescription, newOnlineLocation, start);
+ } else {
+ newEvent = new PersonalEvent(newDescription, newOnlineLocation, start, end);
+ }
+ }
+ break;
+ }
+ events.set(index, newEvent);
+ }
+
+ /**
+ * Edit the contents of an existing event. Will only be called when the event type remains the same.
+ *
+ * @param index the index of the event being edited.
+ * @param editInformation array containing command type and description.
+ * @param startEnd array containing start date and end date.
+ * @param location new location.
+ * @param onlineLocation new online location.
+ */
+ private void editSameType(int index, String[] editInformation, LocalDateTime[] startEnd, Location location,
+ OnlineLocation onlineLocation) {
+ // set new description
+ if (!editInformation[1].isBlank()) {
+ events.get(index).setDescription(editInformation[1]);
+ }
+
+ // set new location
+ if (location != null) {
+ events.get(index).setLocation(location);
+ events.get(index).setLink(null);
+ }
+ if (onlineLocation != null) {
+ events.get(index).setLink(onlineLocation);
+ events.get(index).setLocation(null);
+ }
+
+ // set new time
+ if (events.get(index) instanceof Assignment) {
+ if (startEnd[0] != null) {
+ (events.get(index)).setDateTime(startEnd[0]);
+ }
+ } else if (events.get(index) instanceof PersonalEvent) {
+ if (startEnd[0] != null) {
+ (events.get(index)).setDateTime(startEnd[0]);
+ }
+ if (startEnd[1] != null) {
+ (events.get(index)).setEndDateTime(startEnd[1]);
+ }
+ if (editInformation[4].equalsIgnoreCase("nil")) {
+ (events.get(index)).setEndDateTime(null);
+ }
+ } else if (events.get(index) instanceof Class) {
+ if (startEnd[0] != null) {
+ (events.get(index)).setDateTime(startEnd[0]);
+ }
+ if (startEnd[1] != null) {
+ (events.get(index)).setEndDateTime(startEnd[1]);
+ }
+ } else if (events.get(index) instanceof SelfStudy) {
+ if (startEnd[0] != null) {
+ (events.get(index)).setDateTime(startEnd[0]);
+ }
+ if (startEnd[1] != null) {
+ (events.get(index)).setEndDateTime(startEnd[1]);
+ }
+ if (editInformation[4].equalsIgnoreCase("nil")) {
+ (events.get(index)).setEndDateTime(null);
+ }
+ }
+ }
+
+ /**
+ * Sorts the events alphabetically.
+ *
+ * @param type the sorting criteria.
+ */
+ public void sortEvent(String type) {
+ assert events != null;
+ if (type.equalsIgnoreCase("description")) {
+ events.sort(Event.descriptionComparator);
+ } else if (type.equalsIgnoreCase("time")) {
+ events.sort(Comparator.comparing(Event::getEndDateTime));
+ } else {
+ events.sort(Event.locationComparator);
+ }
+ }
+
+ /**
+ * Gives the access to the list of events.
+ *
+ * @return the list to be printed.
+ */
+ public ArrayList getEventList() {
+ return events;
+ }
+
+ /**
+ * Returns how many events are in the list.
+ *
+ * @return the size of the ArrayList in the EventList object.
+ */
+ public int getSize() {
+ return events.size();
+ }
+
+ /**
+ * Remove the event indicated by the user.
+ */
+ public void remove(int eventIndex) {
+ assert events != null;
+ events.remove(eventIndex);
+ }
+
+ /**
+ * Returns the element at the specified position in this list.
+ *
+ * @param eventIndex index of the event to return.
+ * @return the event at the specified position in this list.
+ */
+ public Event get(int eventIndex) {
+ return events.get(eventIndex);
+ }
+
+ /**
+ * Filter the event list to find the events contain the information looking for by the user.
+ *
+ * @param filterString the keyword that the user is looking for.
+ * @return the filtered list. this list contains only the events that satisfy the requirement.
+ */
+ public ArrayList filterWith(String filterString) {
+ ArrayList filteredEventList = (ArrayList) events.stream()
+ .filter(s -> s.getDescription().contains(filterString))
+ .collect(toList());
+
+ return filteredEventList;
+ }
+
+ /**
+ * Filter the event list to find the events happen on the date looking for by the user.
+ *
+ * @param date the date that the user is looking for.
+ * @return the filtered list. this list contains only the events that satisfy the requirement.
+ */
+ public ArrayList filterDateWith(LocalDate date) {
+ ArrayList filteredEventList = (ArrayList) events.stream()
+ .filter(s -> (s.getDate().isEqual(date)
+ || (s.getDate().isBefore(date) && s.getEndDate().isAfter(date))))
+ .collect(toList());
+
+ return filteredEventList;
+ }
+
+ /**
+ * Filter the event list to find the events happen before the date looking for by the user.
+ *
+ * @param date the date that the user is looking for.
+ * @return the filtered list. this list contains only the events that satisfy the requirement.
+ */
+ public ArrayList filterDateBefore(LocalDate date) {
+ ArrayList filteredEventList = (ArrayList) events.stream()
+ .filter(s -> (s.getDate().compareTo(date) < 0))
+ .collect(toList());
+
+ return filteredEventList;
+ }
+
+ /**
+ * Filter the event list to find the academic related events happen on the date that have been done already.
+ *
+ * @param date the date that the user is looking for.
+ * @return he filtered list. this list contains only the events that satisfy the requirement.
+ */
+ public ArrayList filterDateDoneAcademicEventWith(LocalDate date) {
+ ArrayList filteredEventList = filterDateWith(date);
+ filteredEventList = (ArrayList) filteredEventList.stream()
+ .filter(s -> (s.isDone() && ((s instanceof Class) || (s instanceof SelfStudy))))
+ .collect(toList());
+ return filteredEventList;
+ }
+
+ /**
+ * Clear the ArrayList events if it is not empty.
+ *
+ * @throws EmptyEventListException when the user tries to clear a list that is already empty.
+ */
+ public void clearEvents() throws EmptyEventListException {
+ //assert events != null;
+ if (events == null) {
+ throw new EmptyEventListException();
+ } else {
+ events.clear();
+ }
+ }
+
+ /**
+ * Checks whether there is any conflicting events in terms of timing.
+ *
+ * @param event the new added event.
+ * @return the filtered event arraylist. If there is no conflict, return null.
+ */
+ public ArrayList checkConflictTiming(Event event) {
+ LocalDateTime eventStartDateTime = event.getStartDateTime();
+ LocalDateTime eventEndDateTime;
+ try {
+ eventEndDateTime = event.getEndDateTime();
+ } catch (NullPointerException e) {
+ eventEndDateTime = null;
+ }
+ ArrayList filteredEventList;
+ ArrayList filteredEventList2 = null;
+ try {
+ filteredEventList = (ArrayList) events.stream()
+ .filter(s -> s.getEndDateTime() != null)
+ .filter(s -> ((!(s instanceof Assignment))
+ && (s.getStartDateTime().isBefore(eventStartDateTime)
+ || s.getStartDateTime().isEqual(eventStartDateTime))
+ && (s.getEndDateTime().isAfter(eventStartDateTime)
+ || s.getEndDateTime().isEqual(eventStartDateTime))))
+ .collect(toList());
+ } catch (NullPointerException e) {
+ filteredEventList = null;
+ }
+ if (eventEndDateTime != null) {
+ //this considers when the events already in the list lie in the duration of the new event
+ try {
+ LocalDateTime finalEventEndDateTime = eventEndDateTime;
+ filteredEventList2 = (ArrayList) events.stream()
+ .filter(s -> ((!(s instanceof Assignment))
+ && (s.getStartDateTime().isAfter(eventStartDateTime)
+ || s.getStartDateTime().isEqual(eventStartDateTime))
+ && (s.getStartDateTime().isBefore(finalEventEndDateTime)
+ || s.getStartDateTime().isEqual(finalEventEndDateTime))))
+ .collect(toList());
+ filteredEventList2.removeAll(filteredEventList);
+ } catch (NullPointerException e) {
+ filteredEventList2 = null;
+ }
+ }
+ if (filteredEventList != null && filteredEventList2 != null) {
+ filteredEventList.addAll(filteredEventList2);
+ filteredEventList.remove(event);
+ }
+ return filteredEventList;
+ }
+
+ /**
+ * Filter the event list to find the events happen on the date that have not been done yet.
+ *
+ * @param date the date that the user is looking for.
+ * @return he filtered list. this list contains only the events that satisfy the requirement.
+ */
+ public ArrayList filterDateNotDoneWith(LocalDate date) {
+ ArrayList filteredEventList = filterDateWith(date);
+ filteredEventList = (ArrayList) filteredEventList.stream()
+ .filter(s -> ((!s.isDone()) && (s.getEndDate().isEqual(date))))
+ .collect(toList());
+ return filteredEventList;
+ }
+
+ /**
+ * Add all the classes happening in the current week for several weeks into the list.
+ *
+ * @param numWeeks number of weeks to repeat.
+ */
+ public void repeatAllClasses(int numWeeks) throws NoClassWeekException {
+ ArrayList filteredClassList;
+ //the filtered list are all the classes happening in the current week
+ try {
+ filteredClassList = (ArrayList) events.stream()
+ .filter(s -> ((isLocalDateInTheSameWeek(s.getDate(), LocalDate.now()))
+ && s instanceof Class))
+ .collect(toList());
+ } catch (NullPointerException e) {
+ throw new NoClassWeekException();
+ }
+ if (filteredClassList.size() == 0) {
+ throw new NoClassWeekException();
+ }
+
+ ArrayList copyList = new ArrayList<>();
+
+ for (int i = 1; i <= numWeeks; i++) {
+ filteredClassList.forEach(s -> copyList.add(s.clone()));
+ int finalI = i;
+ copyList.forEach(s -> s.setDateTime(s.getStartDateTime().plusWeeks(finalI)));
+ copyList.forEach(s -> s.setEndDateTime(s.getEndDateTime().plusWeeks(finalI)));
+ events.addAll(copyList);
+ copyList.clear();
+ }
+ }
+
+ //@@author Sunil Katti-reused
+ //Reused from https://stackoverflow.com/a/56246095 with minor modifications
+
+ /**
+ * Check whether 2 dates are of the same week.
+ *
+ * @param date1 the first date
+ * @param date2 the second date
+ * @return ture if they are of the same week. false otherwise.
+ */
+ public static boolean isLocalDateInTheSameWeek(LocalDate date1, LocalDate date2) {
+ assert date1 != null;
+ assert date2 != null;
+ LocalDate mondayBeforeDate1 = date1.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+ LocalDate sundayAfterDate1 = date1.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
+ return ((date2.isEqual(mondayBeforeDate1) || date2.isAfter(mondayBeforeDate1))
+ && (date2.isEqual(sundayAfterDate1) || date2.isBefore(sundayAfterDate1)));
+ }
+ //@@author
+
+ /**
+ * Add the selected event for several weeks into the list.
+ *
+ * @param numWeeks number of weeks to repeat.
+ */
+ public void repeatEvent(int eventIndex, int numWeeks) {
+ Event newEvent;
+ for (int i = 1; i <= numWeeks; i++) {
+ newEvent = events.get(eventIndex).clone();
+ newEvent.setDateTime(newEvent.getStartDateTime().plusWeeks(i));
+ newEvent.setEndDateTime(newEvent.getEndDateTime().plusWeeks(i));
+ events.add(newEvent);
+ }
+ }
+
+ /**
+ * Clear all events before a certain date.
+ *
+ * @param clearDate before which all events to be cleared
+ */
+ public void clearBefore(LocalDate clearDate) throws EmptyEventListException {
+ if (events != null) {
+ events.removeIf(event -> event.getEndDate().compareTo(clearDate) < 0);
+ } else {
+ throw new EmptyEventListException();
+ }
+ }
+}
diff --git a/src/main/java/exception/AssignmentException.java b/src/main/java/exception/AssignmentException.java
new file mode 100644
index 0000000000..1dabcd8e78
--- /dev/null
+++ b/src/main/java/exception/AssignmentException.java
@@ -0,0 +1,7 @@
+package exception;
+
+/**
+ * Represents the exceptions related to Assignment class.
+ */
+public abstract class AssignmentException extends InvalidCommandException {
+}
diff --git a/src/main/java/exception/ClassException.java b/src/main/java/exception/ClassException.java
new file mode 100644
index 0000000000..a2e145b109
--- /dev/null
+++ b/src/main/java/exception/ClassException.java
@@ -0,0 +1,7 @@
+package exception;
+
+/**
+ * Represents the exceptions related to Class class.
+ */
+public abstract class ClassException extends InvalidCommandException {
+}
diff --git a/src/main/java/exception/CreatingFileException.java b/src/main/java/exception/CreatingFileException.java
new file mode 100644
index 0000000000..c1b25bbfd3
--- /dev/null
+++ b/src/main/java/exception/CreatingFileException.java
@@ -0,0 +1,21 @@
+package exception;
+
+/**
+ * Represents the exception happen when the file is not created successfully.
+ */
+public class CreatingFileException extends NuScheduleException {
+ private final String filePath;
+
+ public CreatingFileException(String filePath) {
+ this.filePath = filePath;
+ }
+
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the error message.
+ */
+ public String getMessage() {
+ return "The file \"" + filePath + "\" is not created";
+ }
+}
diff --git a/src/main/java/exception/DataFileNotFoundException.java b/src/main/java/exception/DataFileNotFoundException.java
new file mode 100644
index 0000000000..3de0671e14
--- /dev/null
+++ b/src/main/java/exception/DataFileNotFoundException.java
@@ -0,0 +1,22 @@
+package exception;
+
+/**
+ * Represents the exception happen when the data file is found.
+ */
+public class DataFileNotFoundException extends NuScheduleException {
+ private String fileName;
+
+ public DataFileNotFoundException(String fileName) {
+ this.fileName = fileName;
+ }
+
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return fileName + "is not found. Did you forget to download the data folder provided in the release?";
+ }
+}
diff --git a/src/main/java/exception/DateFormatException.java b/src/main/java/exception/DateFormatException.java
new file mode 100644
index 0000000000..891e3c72d7
--- /dev/null
+++ b/src/main/java/exception/DateFormatException.java
@@ -0,0 +1,19 @@
+package exception;
+
+/**
+ * Represents the exception happens when the user trying to find the tasks on a certain date
+ * but the date is not given in the correct format.
+ */
+public class DateFormatException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced,
+ * gives suggestion to the user on how to solve the error.
+ *
+ * @return the message.
+ */
+ public String getMessage() {
+ return "You entered a date in a format that is not accepted by this function.\n"
+ + "The format should be \"yyyy-MM-dd\"\n"
+ + "For example, 2000-01-01";
+ }
+}
diff --git a/src/main/java/exception/DeleteException.java b/src/main/java/exception/DeleteException.java
new file mode 100644
index 0000000000..754cc56b58
--- /dev/null
+++ b/src/main/java/exception/DeleteException.java
@@ -0,0 +1,7 @@
+package exception;
+
+/**
+ * Represents the exceptions when performing delete.
+ */
+public abstract class DeleteException extends InvalidCommandException {
+}
diff --git a/src/main/java/exception/DeleteNumberFormatException.java b/src/main/java/exception/DeleteNumberFormatException.java
new file mode 100644
index 0000000000..7d13d687e3
--- /dev/null
+++ b/src/main/java/exception/DeleteNumberFormatException.java
@@ -0,0 +1,15 @@
+package exception;
+
+/**
+ * Represents the exceptions when performing delete to a task not labeled with an int.
+ */
+public class DeleteNumberFormatException extends DeleteException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the error message
+ */
+ public String getMessage() {
+ return "Please enter an integer after delete.";
+ }
+}
diff --git a/src/main/java/exception/DoneBeforeEndException.java b/src/main/java/exception/DoneBeforeEndException.java
new file mode 100644
index 0000000000..ba2872ec5f
--- /dev/null
+++ b/src/main/java/exception/DoneBeforeEndException.java
@@ -0,0 +1,17 @@
+package exception;
+
+/**
+ * Represents the case that the user want to mark an Event has an end time that is after the current time as done.
+ */
+public class DoneBeforeEndException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "The selected event ends at a later time. Perhaps you want to edit the end time of it, if you have "
+ + "really done it.";
+ }
+}
diff --git a/src/main/java/exception/DoneException.java b/src/main/java/exception/DoneException.java
new file mode 100644
index 0000000000..f684309ef1
--- /dev/null
+++ b/src/main/java/exception/DoneException.java
@@ -0,0 +1,7 @@
+package exception;
+
+/**
+ * Represents the exceptions when performing done.
+ */
+public abstract class DoneException extends InvalidCommandException {
+}
diff --git a/src/main/java/exception/DoneNumberFormatException.java b/src/main/java/exception/DoneNumberFormatException.java
new file mode 100644
index 0000000000..f1aad04563
--- /dev/null
+++ b/src/main/java/exception/DoneNumberFormatException.java
@@ -0,0 +1,15 @@
+package exception;
+
+/**
+ * Represents the exceptions when performing done to a task not labeled with an int.
+ */
+public class DoneNumberFormatException extends DoneException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the error message
+ */
+ public String getMessage() {
+ return "Please enter an integer after done.";
+ }
+}
diff --git a/src/main/java/exception/DoubleTimeAssignmentException.java b/src/main/java/exception/DoubleTimeAssignmentException.java
new file mode 100644
index 0000000000..1df23d6e3c
--- /dev/null
+++ b/src/main/java/exception/DoubleTimeAssignmentException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represent the case when the user enters an end time for an assignment.
+ */
+public class DoubleTimeAssignmentException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "Assignment should have only one time. If you want to indicate an exam, you may consider it as a class.";
+ }
+}
diff --git a/src/main/java/exception/EditIndexOutOfBoundsException.java b/src/main/java/exception/EditIndexOutOfBoundsException.java
new file mode 100644
index 0000000000..ab048baabf
--- /dev/null
+++ b/src/main/java/exception/EditIndexOutOfBoundsException.java
@@ -0,0 +1,8 @@
+package exception;
+
+public class EditIndexOutOfBoundsException extends NuScheduleException {
+ @Override
+ public String getMessage() {
+ return "Index provided is out of bound. Please provide a valid integer.";
+ }
+}
diff --git a/src/main/java/exception/EditNoEndTimeException.java b/src/main/java/exception/EditNoEndTimeException.java
new file mode 100644
index 0000000000..3213f7166b
--- /dev/null
+++ b/src/main/java/exception/EditNoEndTimeException.java
@@ -0,0 +1,9 @@
+package exception;
+
+public class EditNoEndTimeException extends NuScheduleException {
+
+ @Override
+ public String getMessage() {
+ return "This conversion requires a valid END time.";
+ }
+}
diff --git a/src/main/java/exception/EmptyAssignmentException.java b/src/main/java/exception/EmptyAssignmentException.java
new file mode 100644
index 0000000000..9239ac79de
--- /dev/null
+++ b/src/main/java/exception/EmptyAssignmentException.java
@@ -0,0 +1,15 @@
+package exception;
+
+/**
+ * Represents the case when the user want to create an empty Todo.
+ */
+public class EmptyAssignmentException extends AssignmentException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "OOPS!!! The description of a todo cannot be empty.";
+ }
+}
diff --git a/src/main/java/exception/EmptyClassException.java b/src/main/java/exception/EmptyClassException.java
new file mode 100644
index 0000000000..aeac0e4467
--- /dev/null
+++ b/src/main/java/exception/EmptyClassException.java
@@ -0,0 +1,15 @@
+package exception;
+
+/**
+ * Represents the case when the user want to create an empty Deadline.
+ */
+public class EmptyClassException extends ClassException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "OOPS!!! The description of a class cannot be empty.";
+ }
+}
diff --git a/src/main/java/exception/EmptyClearDateException.java b/src/main/java/exception/EmptyClearDateException.java
new file mode 100644
index 0000000000..fcd2248fe7
--- /dev/null
+++ b/src/main/java/exception/EmptyClearDateException.java
@@ -0,0 +1,15 @@
+package exception;
+
+/*
+* Represents the case when the user input clear before but no date is given
+* */
+public class EmptyClearDateException extends DeleteException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "OOPS!!! You should input the date before which you want to delete all events :)";
+ }
+}
diff --git a/src/main/java/exception/EmptyDeleteException.java b/src/main/java/exception/EmptyDeleteException.java
new file mode 100644
index 0000000000..6f8a63e5fa
--- /dev/null
+++ b/src/main/java/exception/EmptyDeleteException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the case when the user types delete but do not specify
+ * the task that should be deleted.
+ */
+public class EmptyDeleteException extends DeleteException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "OOPS!!! You should enter the index of the task you want to delete.";
+ }
+}
diff --git a/src/main/java/exception/EmptyDoneException.java b/src/main/java/exception/EmptyDoneException.java
new file mode 100644
index 0000000000..2b6faae821
--- /dev/null
+++ b/src/main/java/exception/EmptyDoneException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the case when the user types done but do not specify
+ * the task that should be done.
+ */
+public class EmptyDoneException extends DoneException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "OOPS!!! You should enter the index of the task you have done.";
+ }
+}
diff --git a/src/main/java/exception/EmptyEventException.java b/src/main/java/exception/EmptyEventException.java
new file mode 100644
index 0000000000..f20e5c5bd7
--- /dev/null
+++ b/src/main/java/exception/EmptyEventException.java
@@ -0,0 +1,15 @@
+package exception;
+
+/**
+ * Represents the exception when no description is provided for the event.
+ */
+public class EmptyEventException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "Event description is empty. Please give a title/description of the event.";
+ }
+}
diff --git a/src/main/java/exception/EmptyEventIndexException.java b/src/main/java/exception/EmptyEventIndexException.java
new file mode 100644
index 0000000000..71b2e21e02
--- /dev/null
+++ b/src/main/java/exception/EmptyEventIndexException.java
@@ -0,0 +1,7 @@
+package exception;
+
+public class EmptyEventIndexException extends NuScheduleException {
+ public String getMessage() {
+ return "Please provide a valid index.";
+ }
+}
diff --git a/src/main/java/exception/EmptyEventListException.java b/src/main/java/exception/EmptyEventListException.java
new file mode 100644
index 0000000000..59f44c7350
--- /dev/null
+++ b/src/main/java/exception/EmptyEventListException.java
@@ -0,0 +1,11 @@
+package exception;
+
+/**
+ * Represents the exception when the event list is empty but the user want to print or clear the list.
+ */
+public class EmptyEventListException extends NuScheduleException {
+ @Override
+ public String getMessage() {
+ return "Sorry, the list is empty.";
+ }
+}
diff --git a/src/main/java/exception/EmptyFindDateException.java b/src/main/java/exception/EmptyFindDateException.java
new file mode 100644
index 0000000000..bff47736f7
--- /dev/null
+++ b/src/main/java/exception/EmptyFindDateException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the case when the user types date but do not specify
+ * the date.
+ */
+public class EmptyFindDateException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "OOPS!!! You should enter the date you are looking for.";
+ }
+}
diff --git a/src/main/java/exception/EmptyFindException.java b/src/main/java/exception/EmptyFindException.java
new file mode 100644
index 0000000000..7cbbf05cce
--- /dev/null
+++ b/src/main/java/exception/EmptyFindException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the case when the user types find but do not specify
+ * the keyword.
+ */
+public class EmptyFindException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "OOPS!!! You should enter the keyword of the tasks you want to find.";
+ }
+}
diff --git a/src/main/java/exception/EmptyLocationException.java b/src/main/java/exception/EmptyLocationException.java
new file mode 100644
index 0000000000..18eb675e7a
--- /dev/null
+++ b/src/main/java/exception/EmptyLocationException.java
@@ -0,0 +1,15 @@
+package exception;
+
+/**
+ * Represents class when user does not input anything for locate command.
+ */
+public class EmptyLocationException extends InvalidCommandException {
+ /**
+ * Prepare message to be printed when the exception occur.
+ * @return
+ */
+ @Override
+ public String getMessage() {
+ return "Please do not leave the location input empty.";
+ }
+}
diff --git a/src/main/java/exception/EmptyPersonalEventException.java b/src/main/java/exception/EmptyPersonalEventException.java
new file mode 100644
index 0000000000..973ac88e77
--- /dev/null
+++ b/src/main/java/exception/EmptyPersonalEventException.java
@@ -0,0 +1,15 @@
+package exception;
+
+/**
+ * Represents the case when the user want to create an empty Event.
+ */
+public class EmptyPersonalEventException extends PersonalEventException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "OOPS!!! The description of an event cannot be empty.";
+ }
+}
diff --git a/src/main/java/exception/EmptyRepeatException.java b/src/main/java/exception/EmptyRepeatException.java
new file mode 100644
index 0000000000..d4075f18ef
--- /dev/null
+++ b/src/main/java/exception/EmptyRepeatException.java
@@ -0,0 +1,17 @@
+package exception;
+
+/**
+ * Represents when the user call repeat with about argument provided.
+ */
+public class EmptyRepeatException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "Please enter the arguments for repeat in the following format.\n "
+ + "\"repeat all NUMBER_OF_WEEKS\" OR \"repeat EVENT_INDEX NUMBER_OF_WEEKS\"";
+ }
+}
diff --git a/src/main/java/exception/EmptyStudyTimeDateException.java b/src/main/java/exception/EmptyStudyTimeDateException.java
new file mode 100644
index 0000000000..4711bae959
--- /dev/null
+++ b/src/main/java/exception/EmptyStudyTimeDateException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the case when the user types studyTime but do not specify
+ * the date.
+ */
+public class EmptyStudyTimeDateException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "OOPS!!! You should enter the date that you want to know your study time.";
+ }
+}
diff --git a/src/main/java/exception/EndBeforeStartEventException.java b/src/main/java/exception/EndBeforeStartEventException.java
new file mode 100644
index 0000000000..723e212a0f
--- /dev/null
+++ b/src/main/java/exception/EndBeforeStartEventException.java
@@ -0,0 +1,11 @@
+package exception;
+
+/**
+ * Represents the case when the user want to create an Event that ends before it starts.
+ */
+public class EndBeforeStartEventException extends NuScheduleException {
+ @Override
+ public String getMessage() {
+ return "Just like you cannot die before you exist, an event cannot end before it starts.";
+ }
+}
diff --git a/src/main/java/exception/ExistingEventInListException.java b/src/main/java/exception/ExistingEventInListException.java
new file mode 100644
index 0000000000..ae71f0eaf3
--- /dev/null
+++ b/src/main/java/exception/ExistingEventInListException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * represent the user trys to add an event that is already in the list.
+ */
+public class ExistingEventInListException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "Seems you have already added this event. Do not input duplicate events.";
+ }
+}
diff --git a/src/main/java/exception/InvalidCommandException.java b/src/main/java/exception/InvalidCommandException.java
new file mode 100644
index 0000000000..c83334c591
--- /dev/null
+++ b/src/main/java/exception/InvalidCommandException.java
@@ -0,0 +1,7 @@
+package exception;
+
+/**
+ * Represents the exceptions happen when the user input invalid command.
+ */
+public abstract class InvalidCommandException extends NuScheduleException {
+}
diff --git a/src/main/java/exception/InvalidEditLocationException.java b/src/main/java/exception/InvalidEditLocationException.java
new file mode 100644
index 0000000000..508c56ca1e
--- /dev/null
+++ b/src/main/java/exception/InvalidEditLocationException.java
@@ -0,0 +1,9 @@
+package exception;
+
+public class InvalidEditLocationException extends InvalidCommandException {
+ @Override
+ public String getMessage() {
+ return "Enter the location in the format /l LOCATION for offline location and /o LINK /p PASSWORD for "
+ + "online location.";
+ }
+}
diff --git a/src/main/java/exception/InvalidEditTypeException.java b/src/main/java/exception/InvalidEditTypeException.java
new file mode 100644
index 0000000000..d2f93017ce
--- /dev/null
+++ b/src/main/java/exception/InvalidEditTypeException.java
@@ -0,0 +1,8 @@
+package exception;
+
+public class InvalidEditTypeException extends InvalidCommandException {
+ @Override
+ public String getMessage() {
+ return "Event type can only be personalevent, class , selfStudy or assignment.";
+ }
+}
diff --git a/src/main/java/exception/InvalidEventIndexException.java b/src/main/java/exception/InvalidEventIndexException.java
new file mode 100644
index 0000000000..716b3a3875
--- /dev/null
+++ b/src/main/java/exception/InvalidEventIndexException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents exception when event index is out of list.
+ */
+public class InvalidEventIndexException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ @Override
+ public String getMessage() {
+ return "Please input an event number that is within the event list.";
+ }
+}
diff --git a/src/main/java/exception/InvalidLocationException.java b/src/main/java/exception/InvalidLocationException.java
new file mode 100644
index 0000000000..9ce92387bc
--- /dev/null
+++ b/src/main/java/exception/InvalidLocationException.java
@@ -0,0 +1,8 @@
+package exception;
+
+public class InvalidLocationException extends NuScheduleException {
+ @Override
+ public String getMessage() {
+ return "Please input a valid location or event number.";
+ }
+}
diff --git a/src/main/java/exception/InvalidNumWeekException.java b/src/main/java/exception/InvalidNumWeekException.java
new file mode 100644
index 0000000000..c288c04f5a
--- /dev/null
+++ b/src/main/java/exception/InvalidNumWeekException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the user call repeat but the number of weeks is entered in a wrong format.
+ */
+public class InvalidNumWeekException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "Please enter the number of weeks to repeat. This should be an integer between 1 and 50.";
+ }
+}
diff --git a/src/main/java/exception/InvalidSortCriteriaException.java b/src/main/java/exception/InvalidSortCriteriaException.java
new file mode 100644
index 0000000000..f77bbb449d
--- /dev/null
+++ b/src/main/java/exception/InvalidSortCriteriaException.java
@@ -0,0 +1,9 @@
+package exception;
+
+public class InvalidSortCriteriaException extends NuScheduleException {
+ @Override
+ public String getMessage() {
+ return "Invalid sorting criteria given. Possible sorting criteria includes"
+ + " description , location and time.";
+ }
+}
diff --git a/src/main/java/exception/LoadingException.java b/src/main/java/exception/LoadingException.java
new file mode 100644
index 0000000000..5cc0598960
--- /dev/null
+++ b/src/main/java/exception/LoadingException.java
@@ -0,0 +1,15 @@
+package exception;
+
+/**
+ * Represents the exception when the user edit the file in a wrong way.
+ */
+public class LoadingException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "You edited the file in a wrong format. Please check.";
+ }
+}
diff --git a/src/main/java/exception/NoClassTimeException.java b/src/main/java/exception/NoClassTimeException.java
new file mode 100644
index 0000000000..c7a637bd86
--- /dev/null
+++ b/src/main/java/exception/NoClassTimeException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the exception happens when the user trying to create a class
+ * without giving it a time.
+ */
+public class NoClassTimeException extends ClassException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ public String getMessage() {
+ return "OOPS!!! You should enter a time for class.";
+ }
+}
diff --git a/src/main/java/exception/NoClassTimeMarkerException.java b/src/main/java/exception/NoClassTimeMarkerException.java
new file mode 100644
index 0000000000..1cd4ad8f26
--- /dev/null
+++ b/src/main/java/exception/NoClassTimeMarkerException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the exception happens when the user trying to create a Class
+ * without using /t to give it a time.
+ */
+public class NoClassTimeMarkerException extends ClassException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ public String getMessage() {
+ return "OOPS!!! You should mark the time for a class with \"/t\"";
+ }
+}
diff --git a/src/main/java/exception/NoClassWeekException.java b/src/main/java/exception/NoClassWeekException.java
new file mode 100644
index 0000000000..53237c8554
--- /dev/null
+++ b/src/main/java/exception/NoClassWeekException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represent the case when the user type repeat all but there is no class in the current week.
+ */
+public class NoClassWeekException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "Seems there is no class in this week, so there is nothing for me to repeat.";
+ }
+}
diff --git a/src/main/java/exception/NoDateBeforeException.java b/src/main/java/exception/NoDateBeforeException.java
new file mode 100644
index 0000000000..b9a934f211
--- /dev/null
+++ b/src/main/java/exception/NoDateBeforeException.java
@@ -0,0 +1,17 @@
+package exception;
+
+/**
+ * Represents the case when the user input a date in clear before command but there is no event before the given date.
+ */
+
+public class NoDateBeforeException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "There is no events existing before the date given by you :(.";
+ }
+}
diff --git a/src/main/java/exception/NoEditEventDescriptionException.java b/src/main/java/exception/NoEditEventDescriptionException.java
new file mode 100644
index 0000000000..4cc2eb1e66
--- /dev/null
+++ b/src/main/java/exception/NoEditEventDescriptionException.java
@@ -0,0 +1,8 @@
+package exception;
+
+public class NoEditEventDescriptionException extends ClassException {
+ @Override
+ public String getMessage() {
+ return "Please provide the details for the new event to be added.";
+ }
+}
diff --git a/src/main/java/exception/NoEditTypeException.java b/src/main/java/exception/NoEditTypeException.java
new file mode 100644
index 0000000000..c4d2fd7771
--- /dev/null
+++ b/src/main/java/exception/NoEditTypeException.java
@@ -0,0 +1,8 @@
+package exception;
+
+public class NoEditTypeException extends NuScheduleException {
+ @Override
+ public String getMessage() {
+ return "Please provide the details for the new event to be added.";
+ }
+}
diff --git a/src/main/java/exception/NoEndTimeClassException.java b/src/main/java/exception/NoEndTimeClassException.java
new file mode 100644
index 0000000000..f291e98084
--- /dev/null
+++ b/src/main/java/exception/NoEndTimeClassException.java
@@ -0,0 +1,15 @@
+package exception;
+
+/**
+ * Represent the user want to input a class without give it an ending time.
+ */
+public class NoEndTimeClassException extends ClassException {
+ /**
+ * The message to be printed.
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "Every class should end at some time. Give it an ending, please. Mark it by \"/e\".";
+ }
+}
diff --git a/src/main/java/exception/NoEventDateException.java b/src/main/java/exception/NoEventDateException.java
new file mode 100644
index 0000000000..fddb1efcb4
--- /dev/null
+++ b/src/main/java/exception/NoEventDateException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the exception happens when the user trying to find a Event with a certain date,
+ * but such Event does not exist in the list.
+ */
+public class NoEventDateException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "Sorry, there isn't any event in the list on the given date.";
+ }
+}
diff --git a/src/main/java/exception/NoEventDateRemindException.java b/src/main/java/exception/NoEventDateRemindException.java
new file mode 100644
index 0000000000..02ad84554b
--- /dev/null
+++ b/src/main/java/exception/NoEventDateRemindException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the exception happens when the user trying to find a Event with a certain date,
+ * but such Event does not exist in the list.
+ */
+public class NoEventDateRemindException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "Sorry, there are no events in the list for today.";
+ }
+}
diff --git a/src/main/java/exception/NoEventDoneException.java b/src/main/java/exception/NoEventDoneException.java
new file mode 100644
index 0000000000..bd418ab705
--- /dev/null
+++ b/src/main/java/exception/NoEventDoneException.java
@@ -0,0 +1,17 @@
+package exception;
+
+/**
+ * Represents the exception when the users try to find the study time but he had not done any thing related to academics
+ * on that day.
+ */
+public class NoEventDoneException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "Seems you haven't done any thing related to academics on that day.";
+ }
+}
diff --git a/src/main/java/exception/NoEventLocationException.java b/src/main/java/exception/NoEventLocationException.java
new file mode 100644
index 0000000000..c7cebab4f2
--- /dev/null
+++ b/src/main/java/exception/NoEventLocationException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the exception when no location is provided when adding a new event.
+ */
+public class NoEventLocationException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "Please input a valid location and mark it with \"/l\" for underline locations or \"/o\" for online "
+ + "locations.";
+ }
+}
diff --git a/src/main/java/exception/NoEventLocationMarkerException.java b/src/main/java/exception/NoEventLocationMarkerException.java
new file mode 100644
index 0000000000..ee3ba1417d
--- /dev/null
+++ b/src/main/java/exception/NoEventLocationMarkerException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the exception happens when the user trying to create an event
+ * without using /l to give it a location.
+ */
+public class NoEventLocationMarkerException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ public String getMessage() {
+ return "Please mark the location of the event by \"/l\".";
+ }
+}
diff --git a/src/main/java/exception/NoEventOneMonthAgoException.java b/src/main/java/exception/NoEventOneMonthAgoException.java
new file mode 100644
index 0000000000..514bac8162
--- /dev/null
+++ b/src/main/java/exception/NoEventOneMonthAgoException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/*
+* Represents the case when there is no event happened one month ago but the user typed in autoclear
+* */
+public class NoEventOneMonthAgoException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "OOPS!! There is no events happened one month ago for you to auto clear :(";
+ }
+}
diff --git a/src/main/java/exception/NoEventTimeException.java b/src/main/java/exception/NoEventTimeException.java
new file mode 100644
index 0000000000..9a85c49fe9
--- /dev/null
+++ b/src/main/java/exception/NoEventTimeException.java
@@ -0,0 +1,15 @@
+package exception;
+
+/**
+ * Represents the exception when no date/time is inputted as expected.
+ */
+public class NoEventTimeException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "Please input the date/time.";
+ }
+}
diff --git a/src/main/java/exception/NoEventTimeMarkerException.java b/src/main/java/exception/NoEventTimeMarkerException.java
new file mode 100644
index 0000000000..e756a75ef4
--- /dev/null
+++ b/src/main/java/exception/NoEventTimeMarkerException.java
@@ -0,0 +1,15 @@
+package exception;
+
+/**
+ * Represents the exception where there is no time marker in the command.
+ */
+public class NoEventTimeMarkerException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ public String getMessage() {
+ return "Please mark the time of the event by \"/t\".";
+ }
+}
diff --git a/src/main/java/exception/NoMatchingEventException.java b/src/main/java/exception/NoMatchingEventException.java
new file mode 100644
index 0000000000..f2b44a79d7
--- /dev/null
+++ b/src/main/java/exception/NoMatchingEventException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the exception happens when the user trying to find a Task with a certain keyword, but such
+ * task does not exist in the list.
+ */
+public class NoMatchingEventException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "Sorry, there isn't such event in the list with the given keyword.";
+ }
+}
diff --git a/src/main/java/exception/NoPasswordException.java b/src/main/java/exception/NoPasswordException.java
new file mode 100644
index 0000000000..263a1a3941
--- /dev/null
+++ b/src/main/java/exception/NoPasswordException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the case when the user enter "/p" but did not enter password.
+ */
+public class NoPasswordException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "Seems you forget to enter the password. If there is no password needed, do not enter \"/p\"";
+ }
+}
diff --git a/src/main/java/exception/NoPersonalEventTimeException.java b/src/main/java/exception/NoPersonalEventTimeException.java
new file mode 100644
index 0000000000..2e621f51f4
--- /dev/null
+++ b/src/main/java/exception/NoPersonalEventTimeException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the exception happens when the user trying to create an Event
+ * without giving it a time.
+ */
+public class NoPersonalEventTimeException extends PersonalEventException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "OOPS!!! You should enter a time for event.";
+ }
+}
diff --git a/src/main/java/exception/NoPersonalEventTimeMakerException.java b/src/main/java/exception/NoPersonalEventTimeMakerException.java
new file mode 100644
index 0000000000..16a2a2222d
--- /dev/null
+++ b/src/main/java/exception/NoPersonalEventTimeMakerException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the exception happens when the user trying to create an Event
+ * without using \by to give it a time.
+ */
+public class NoPersonalEventTimeMakerException extends PersonalEventException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "OOPS!!! You should mark the time for an event with \"/at\"";
+ }
+}
diff --git a/src/main/java/exception/NoRepeatWeekException.java b/src/main/java/exception/NoRepeatWeekException.java
new file mode 100644
index 0000000000..1e8007a7aa
--- /dev/null
+++ b/src/main/java/exception/NoRepeatWeekException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represent when the user call repeat without provide the number of weeks to repeat.
+ */
+public class NoRepeatWeekException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "Please enter the number of weeks to repeat the selected event(s).";
+ }
+}
diff --git a/src/main/java/exception/NoSortCriteriaException.java b/src/main/java/exception/NoSortCriteriaException.java
new file mode 100644
index 0000000000..ff491f9315
--- /dev/null
+++ b/src/main/java/exception/NoSortCriteriaException.java
@@ -0,0 +1,9 @@
+package exception;
+
+public class NoSortCriteriaException extends NuScheduleException {
+ @Override
+ public String getMessage() {
+ return "No sorting criteria given. Possible sorting criteria includes"
+ + " description and time.";
+ }
+}
diff --git a/src/main/java/exception/NuScheduleException.java b/src/main/java/exception/NuScheduleException.java
new file mode 100644
index 0000000000..be462bf932
--- /dev/null
+++ b/src/main/java/exception/NuScheduleException.java
@@ -0,0 +1,10 @@
+package exception;
+
+public abstract class NuScheduleException extends Exception {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ public abstract String getMessage();
+}
diff --git a/src/main/java/exception/PersonalEventException.java b/src/main/java/exception/PersonalEventException.java
new file mode 100644
index 0000000000..befd64bc06
--- /dev/null
+++ b/src/main/java/exception/PersonalEventException.java
@@ -0,0 +1,7 @@
+package exception;
+
+/**
+ * Represents the exceptions related to PersonalEvent class.
+ */
+public abstract class PersonalEventException extends InvalidCommandException {
+}
diff --git a/src/main/java/exception/RepeatIndexFormatException.java b/src/main/java/exception/RepeatIndexFormatException.java
new file mode 100644
index 0000000000..2dee630b8a
--- /dev/null
+++ b/src/main/java/exception/RepeatIndexFormatException.java
@@ -0,0 +1,17 @@
+package exception;
+
+/**
+ * Represent the user call repeat but provide an invalid index for the event.
+ */
+public class RepeatIndexFormatException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "If you want to selected an event to repeat, enter the index of it. If you want to repeat all class "
+ + "in the current week, enter \"all\".";
+ }
+}
diff --git a/src/main/java/exception/TimeFormatException.java b/src/main/java/exception/TimeFormatException.java
new file mode 100644
index 0000000000..868d68cbb3
--- /dev/null
+++ b/src/main/java/exception/TimeFormatException.java
@@ -0,0 +1,18 @@
+package exception;
+
+/**
+ * Represents the exception when the date/time are entered incorrectly.
+ */
+public class TimeFormatException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced,
+ * gives suggestion to the user on how to solve the error.
+ *
+ * @return the message.
+ */
+ public String getMessage() {
+ return "You entered the time in a format that is not accepted by this program.\n"
+ + "The format should be \"yyyy-MM-dd HH:mm\", and both date and time should be valid.\n"
+ + "For example, 2000-01-01 00:00";
+ }
+}
diff --git a/src/main/java/exception/UndefinedEventException.java b/src/main/java/exception/UndefinedEventException.java
new file mode 100644
index 0000000000..bf774ffddb
--- /dev/null
+++ b/src/main/java/exception/UndefinedEventException.java
@@ -0,0 +1,27 @@
+package exception;
+
+/**
+ * Represents the case when the the user trying to operate (delete/edit/done)
+ * some events that does not exist.
+ */
+public class UndefinedEventException extends NuScheduleException {
+ private final int index;//Task label of the task
+
+ /**
+ * Create an exception according to the input of the user.
+ *
+ * @param index the label of the event that the user want to operate on.
+ */
+ public UndefinedEventException(int index) {
+ this.index = index;
+ }
+
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the error message.
+ */
+ public String getMessage() {
+ return "OOPS!!! There isn't a event labeled " + index;
+ }
+}
diff --git a/src/main/java/exception/UnknownErrorException.java b/src/main/java/exception/UnknownErrorException.java
new file mode 100644
index 0000000000..5ab8ac1ce2
--- /dev/null
+++ b/src/main/java/exception/UnknownErrorException.java
@@ -0,0 +1,11 @@
+package exception;
+
+/**
+ * Represents the exception when it should not happen.
+ */
+public class UnknownErrorException extends NuScheduleException {
+ @Override
+ public String getMessage() {
+ return "There shouldn't be such error.";
+ }
+}
diff --git a/src/main/java/exception/WritingFileException.java b/src/main/java/exception/WritingFileException.java
new file mode 100644
index 0000000000..d764b25732
--- /dev/null
+++ b/src/main/java/exception/WritingFileException.java
@@ -0,0 +1,15 @@
+package exception;
+
+/**
+ * Represents the exception when the file is not correctly written.
+ */
+public class WritingFileException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "Something went wrong when writing to the file.";
+ }
+}
diff --git a/src/main/java/exception/WrongAutoClearArgumentException.java b/src/main/java/exception/WrongAutoClearArgumentException.java
new file mode 100644
index 0000000000..c590333efc
--- /dev/null
+++ b/src/main/java/exception/WrongAutoClearArgumentException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the case when the user types autoClear but did not provide an arguement.
+ */
+public class WrongAutoClearArgumentException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "You should type either \"autoClear on\" or \"autoClear off\" to use this function.";
+ }
+}
diff --git a/src/main/java/exception/WrongCommandException.java b/src/main/java/exception/WrongCommandException.java
new file mode 100644
index 0000000000..ca20dc6480
--- /dev/null
+++ b/src/main/java/exception/WrongCommandException.java
@@ -0,0 +1,17 @@
+package exception;
+
+/**
+ * Represents the exception when an invalid command is inputted.
+ */
+public class WrongCommandException extends InvalidCommandException {
+
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return "OOPS!!! I'm sorry, but I don't know what that means :-(\n"
+ + "You may enter \"help\" for more information.";
+ }
+}
diff --git a/src/main/java/exception/WrongEditFormatException.java b/src/main/java/exception/WrongEditFormatException.java
new file mode 100644
index 0000000000..17d686a849
--- /dev/null
+++ b/src/main/java/exception/WrongEditFormatException.java
@@ -0,0 +1,16 @@
+package exception;
+
+/**
+ * Represents the exception when the index for edit is of a wrong format.
+ */
+public class WrongEditFormatException extends NuScheduleException {
+ /**
+ * Prepare the message to be printed when this exception is experienced.
+ *
+ * @return the message.
+ */
+ @Override
+ public String getMessage() {
+ return "Index of an even should be an integer.";
+ }
+}
diff --git a/src/main/java/location/Building.java b/src/main/java/location/Building.java
new file mode 100644
index 0000000000..055a01b502
--- /dev/null
+++ b/src/main/java/location/Building.java
@@ -0,0 +1,47 @@
+package location;
+
+import java.util.Arrays;
+
+/**
+ * Represents Building objects.
+ * Contains an array of Strings nearestBusStops which represents the bus stops nearby.
+ */
+public class Building extends Location {
+ private final String[] nearestBusStops;
+
+ public Building(String name, String[] nearestBusStops) {
+ super(name);
+ this.nearestBusStops = nearestBusStops;
+ this.type = LocationType.BUILDING;
+ }
+
+ /**
+ * Prepares string to be printed in a list.
+ *
+ * @return object to be printed in a certain format.
+ */
+ @Override
+ public String toString() {
+ return "(Building): " + name + "\nNearest bus stop(s): " + printNearestBusStops();
+ }
+
+ /**
+ * Convert the information about this Building to a string that is to be stored in a file.
+ *
+ * @return the result string to be stored.
+ */
+ public String fileString() {
+ String busStops = null;
+ for (String additionalInfo : nearestBusStops) {
+ busStops = additionalInfo + ",";
+ }
+ assert busStops != null;
+ return "BLK/" + name + "/" + busStops.substring(0, busStops.length() - 1);
+ }
+
+ private String printNearestBusStops() {
+ String str = Arrays.toString(nearestBusStops);
+ str = str.substring(1, str.indexOf("]"));
+ return str;
+ }
+}
diff --git a/src/main/java/location/BusStop.java b/src/main/java/location/BusStop.java
new file mode 100644
index 0000000000..0f2f883173
--- /dev/null
+++ b/src/main/java/location/BusStop.java
@@ -0,0 +1,31 @@
+package location;
+
+import java.util.Arrays;
+
+/**
+ * Represents bus stop objects.
+ * Contains String name which is the name of the bus stop and
+ * an array of Strings which is the list of buses available at the bus stop.
+ */
+public class BusStop {
+ private final String name;
+ private final String[] buses;
+
+ public BusStop(String name, String[] buses) {
+ this.name = name;
+ this.buses = buses;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Prepares string to be printed in a list.
+ *
+ * @return object to be printed in a certain format.
+ */
+ public String toString() {
+ return name + "\nBuses Available: " + Arrays.toString(buses);
+ }
+}
diff --git a/src/main/java/location/Hostel.java b/src/main/java/location/Hostel.java
new file mode 100644
index 0000000000..9105256caa
--- /dev/null
+++ b/src/main/java/location/Hostel.java
@@ -0,0 +1,47 @@
+package location;
+
+import java.util.Arrays;
+
+/**
+ * Represents Hostel objects.
+ * Contains an array of Strings nearestBusStops which represents the bus stops nearby.
+ */
+public class Hostel extends Location {
+ String[] nearestBusStops;
+
+ public Hostel(String name, String[] nearestBusStops) {
+ super(name);
+ this.type = LocationType.HOSTEL;
+ this.nearestBusStops = nearestBusStops;
+ }
+
+ /**
+ * Prepares string to be printed in a list.
+ *
+ * @return object to be printed in a certain format.
+ */
+ @Override
+ public String toString() {
+ return "(Hostel): " + name + "\nNearest bus stop(s): " + printNearestBusStops();
+ }
+
+ /**
+ * Convert the information about this Hostel to a string that is to be stored in a file.
+ *
+ * @return the result string to be stored.
+ */
+ public String fileString() {
+ String busStops = null;
+ for (String additionalInfo : nearestBusStops) {
+ busStops = additionalInfo + ",";
+ }
+ assert busStops != null;
+ return "H/" + name + "/" + busStops.substring(0, busStops.length() - 1);
+ }
+
+ private String printNearestBusStops() {
+ String str = Arrays.toString(nearestBusStops);
+ str = str.substring(1, str.indexOf("]"));
+ return str;
+ }
+}
diff --git a/src/main/java/location/LectureTheatre.java b/src/main/java/location/LectureTheatre.java
new file mode 100644
index 0000000000..e8fa54d1d2
--- /dev/null
+++ b/src/main/java/location/LectureTheatre.java
@@ -0,0 +1,34 @@
+package location;
+
+/**
+ * Represents lecture theatre objects.
+ * Contains a String nearestBuilding which represents the name of nearest building.
+ */
+public class LectureTheatre extends Location {
+ private final String nearestBuilding;
+
+ public LectureTheatre(String name, String nearestBuilding) {
+ super(name);
+ this.type = LocationType.LT;
+ this.nearestBuilding = nearestBuilding;
+ }
+
+ /**
+ * Prepares string to be printed in a list.
+ *
+ * @return object to be printed in a certain format.
+ */
+ @Override
+ public String toString() {
+ return "(Lecture Theatre): " + name + "\nNearest building: " + nearestBuilding;
+ }
+
+ /**
+ * Convert the information about this LT to a string that is to be stored in a file.
+ *
+ * @return the result string to be stored.
+ */
+ public String fileString() {
+ return "L/" + name + "/" + nearestBuilding;
+ }
+}
diff --git a/src/main/java/location/Location.java b/src/main/java/location/Location.java
new file mode 100644
index 0000000000..f70d97a3a5
--- /dev/null
+++ b/src/main/java/location/Location.java
@@ -0,0 +1,66 @@
+package location;
+
+
+/**
+ * Represents location objects.
+ * Contains String name, which is the name of location, and type of location.
+ */
+public class Location {
+ protected String name;
+ protected LocationType type;
+ // private int[] coordinates = new int[2]; // will implement in version 2.0
+
+ public Location(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ protected String printType() {
+ String str;
+ switch (type) {
+ case BUILDING:
+ str = "Building";
+ break;
+ case HOSTEL:
+ str = "Hostel";
+ break;
+ case LT:
+ str = "Lecture Theatre";
+ break;
+ case OUT_OF_NUS:
+ str = "Out of NUS";
+ break;
+ default:
+ str = "ERROR";
+ }
+
+ return str;
+ }
+
+ public String toString() {
+ return "(" + printType() + ")" + name;
+ }
+
+ /**
+ * All location class objects should have this methods, except BusStop.
+ *
+ * @return the string to be wrote in the file.
+ */
+ public String fileString() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ boolean isEqual = false;
+
+ if (object instanceof Location) {
+ isEqual = (this.name.equals(((Location) object).name));
+ }
+
+ return isEqual;
+ }
+}
diff --git a/src/main/java/location/LocationType.java b/src/main/java/location/LocationType.java
new file mode 100644
index 0000000000..177e2a9b46
--- /dev/null
+++ b/src/main/java/location/LocationType.java
@@ -0,0 +1,8 @@
+package location;
+
+public enum LocationType {
+ BUILDING,
+ HOSTEL,
+ LT,
+ OUT_OF_NUS
+}
diff --git a/src/main/java/location/OnlineLocation.java b/src/main/java/location/OnlineLocation.java
new file mode 100644
index 0000000000..ef0c873e6e
--- /dev/null
+++ b/src/main/java/location/OnlineLocation.java
@@ -0,0 +1,71 @@
+package location;
+
+import event.Assignment;
+
+/**
+ * Virtual location is also location!
+ * This class represents the online meetings (e.g. zoom sessions) for people to attend, or the link to submit
+ * assignment.
+ * This format should be /o url /p pwd, or /o url, since not all sessions need a password, and the submission link
+ * does not require a password.
+ */
+public class OnlineLocation {
+ private final String link;
+ private String password;
+
+ /**
+ * the constructor of the object if the meeting does not need pwd.
+ *
+ * @param link the url of the online meeting
+ */
+ public OnlineLocation(String link) {
+ assert link != null;
+ this.link = link;
+ }
+
+ /**
+ * the constructor of the object if the meeting needs pwd.
+ *
+ * @param link the url of the online meeting
+ * @param pwd the password of the online meeting
+ */
+ public OnlineLocation(String link, String pwd) {
+ assert link != null;
+ assert pwd != null;
+ this.link = link;
+ this.password = pwd;
+ }
+
+ /**
+ * Returns the details of the online location.
+ *
+ * @return the link of the location. If there is password, return the password also.
+ */
+ public String toString() {
+ return "link: " + link + (password != null ? " password: " + password : "");
+ }
+
+ /**
+ * Returns the details of the location to be printed in a file.
+ *
+ * @return the link of the meeting. If there is password, return the password also.
+ */
+ public String fileString() {
+ return "online//" + link + (password != null ? "//" + password : "");
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ boolean isEqual = false;
+
+ if (object instanceof OnlineLocation) {
+ isEqual = (this.link.equals(((OnlineLocation) object).link));
+ }
+
+ return isEqual;
+ }
+
+ public String getLink() {
+ return link;
+ }
+}
diff --git a/src/main/java/location/OutOfNuS.java b/src/main/java/location/OutOfNuS.java
new file mode 100644
index 0000000000..b239ab6281
--- /dev/null
+++ b/src/main/java/location/OutOfNuS.java
@@ -0,0 +1,26 @@
+package location;
+
+public class OutOfNuS extends Location {
+ public OutOfNuS(String name) {
+ super(name);
+ }
+
+ /**
+ * Prepares string to be printed in a list.
+ *
+ * @return object to be printed in a certain format.
+ */
+ @Override
+ public String toString() {
+ return "(Out of NUS): " + name;
+ }
+
+ /**
+ * Convert the information about this location to a string that is to be stored in a file.
+ *
+ * @return the result string to be stored.
+ */
+ public String fileString() {
+ return "OUT/" + name;
+ }
+}
diff --git a/src/main/java/locationlist/BusStopList.java b/src/main/java/locationlist/BusStopList.java
new file mode 100644
index 0000000000..94759b933f
--- /dev/null
+++ b/src/main/java/locationlist/BusStopList.java
@@ -0,0 +1,28 @@
+package locationlist;
+
+import location.BusStop;
+
+import java.util.ArrayList;
+
+public class BusStopList {
+ private final ArrayList busStopList = new ArrayList<>();
+
+ public ArrayList getBusStopList() {
+ return busStopList;
+ }
+
+ /**
+ * Flag to check if the bus stop exists.
+ *
+ * @param name name of bus stop to be checked
+ * @return boolean value of if the bus stop exist in the list
+ */
+ public boolean checkExistence(String name) {
+ for (BusStop busStop : busStopList) {
+ if (name.equals(busStop.getName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/locationlist/LocationList.java b/src/main/java/locationlist/LocationList.java
new file mode 100644
index 0000000000..6602e36479
--- /dev/null
+++ b/src/main/java/locationlist/LocationList.java
@@ -0,0 +1,70 @@
+package locationlist;
+
+import location.Location;
+import location.OutOfNuS;
+
+import java.util.ArrayList;
+
+public class LocationList {
+ private final ArrayList locationList = new ArrayList<>();
+
+ public ArrayList getLocationList() {
+ return locationList;
+ }
+
+ /**
+ * Flag to check if location exists.
+ *
+ * @param name name of the location to be checked
+ * @return boolean value of if the location is found in the location list
+ */
+ public boolean checkValidLocation(String name) {
+ for (Location location : locationList) {
+ String input = name.toLowerCase().replaceAll("\\s","");
+ if (input.equals(location.getName().toLowerCase().replaceAll("\\s",""))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Finds location in the list based on the name input.
+ *
+ * @param name String that represents name of location to find
+ * @return Location that is found in the list to be returned
+ */
+ public Location findLocation(String name) {
+ Location locationReturned = null;
+ int i = 0;
+ String input = name.toLowerCase().replaceAll("\\s","");
+ for (Location location : locationList) {
+ if (input.equalsIgnoreCase(location.getName().toLowerCase().replaceAll("\\s",""))) {
+ locationReturned = locationList.get(i);
+ return locationReturned;
+ }
+ i++;
+ }
+
+ if (locationReturned == null) {
+ locationReturned = new OutOfNuS(name);
+ locationList.add(locationReturned);
+ }
+ return locationReturned;
+ }
+
+ /**
+ * Method to check if string can be converted to an integer.
+ *
+ * @param input String to be converted
+ * @return flag if string can be converted
+ */
+ public boolean checkIfInteger(String input) {
+ try {
+ Integer.parseInt(input);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/parser/Parser.java b/src/main/java/parser/Parser.java
new file mode 100644
index 0000000000..dda1b9df93
--- /dev/null
+++ b/src/main/java/parser/Parser.java
@@ -0,0 +1,743 @@
+package parser;
+
+import command.AddCommand;
+import command.ClearCommand;
+import command.Command;
+import command.DeleteCommand;
+import command.DoneCommand;
+import command.EditCommand;
+import command.ExitCommand;
+import command.FindCommand;
+import command.FindDateCommand;
+import command.HelpCommand;
+import command.LocateCommand;
+import command.PrintAreaLocationsCommand;
+import command.PrintFullListCommand;
+import command.PrintLocationCommand;
+import command.ReminderCommand;
+import command.RepeatCommand;
+import command.SortCommand;
+import command.AutoClearCommand;
+import command.ClearBeforeCommand;
+
+import command.StudyTimeCommand;
+import command.UserInfoCommand;
+import event.Assignment;
+import event.Class;
+import event.PersonalEvent;
+import event.SelfStudy;
+import exception.DateFormatException;
+import exception.DeleteNumberFormatException;
+import exception.DoneNumberFormatException;
+import exception.DoubleTimeAssignmentException;
+import exception.EmptyDeleteException;
+import exception.EmptyDoneException;
+import exception.EmptyEventException;
+import exception.EmptyEventIndexException;
+import exception.EmptyFindDateException;
+import exception.EmptyFindException;
+import exception.EmptyLocationException;
+import exception.EmptyRepeatException;
+import exception.EmptyStudyTimeDateException;
+import exception.InvalidEditLocationException;
+import exception.InvalidEditTypeException;
+import exception.InvalidEventIndexException;
+import exception.InvalidLocationException;
+import exception.InvalidNumWeekException;
+import exception.InvalidSortCriteriaException;
+import exception.WrongAutoClearArgumentException;
+import exception.NoEndTimeClassException;
+import exception.NoEventLocationException;
+import exception.NoEventTimeException;
+import exception.NoEventTimeMarkerException;
+import exception.NoPasswordException;
+import exception.NoRepeatWeekException;
+import exception.NoSortCriteriaException;
+import exception.NuScheduleException;
+import exception.RepeatIndexFormatException;
+import exception.TimeFormatException;
+import exception.UndefinedEventException;
+import exception.UnknownErrorException;
+import exception.WrongCommandException;
+import exception.WrongEditFormatException;
+import exception.EmptyClearDateException;
+import location.Building;
+import location.Hostel;
+import location.LectureTheatre;
+import location.Location;
+import location.OnlineLocation;
+import location.OutOfNuS;
+import locationlist.LocationList;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeParseException;
+
+
+/**
+ * This class contains one function -- parse, to call the respective command function according to the user input.
+ */
+public abstract class Parser {
+ public static final String EXIT = "bye";
+ public static final String PRINT_EVENT_LIST = "list";
+ public static final String PRINT_LOCATION_LIST = "locations";
+ public static final String LOCATE_EVENT = "locate";
+ public static final String EVENT_DONE = "done";
+ public static final String ASSIGNMENT = "assignment";
+ public static final String CLASS = "class";
+ public static final String PERSONAL_EVENT = "personalEvent";
+ public static final String EVENT_DELETE = "delete";
+ public static final String EVENT_FIND = "find";
+ public static final String EDIT = "edit";
+ public static final String TIME_MARKER = "/t";
+ public static final String SINGLE_SPACE = " ";
+ public static final String LOCATION_MARKER = "/l";
+ public static final String EVENT_FIND_DATE = "date";
+ public static final String HELP = "help";
+ public static final String CLEAR = "clear";
+ public static final String SORT = "sort";
+ public static final String END_TIME_MARKER = "/e";
+ public static final String ONLINE_LOCATION_MARKER = "/o";
+ public static final String PASSWORD_MARKER = "/p";
+ public static final String REMIND = "reminder";
+ public static final String STUDY_TIME = "studyTime";
+ public static final String SELF_STUDY = "selfStudy";
+ public static final String REPEAT = "repeat";
+ public static final String ALL = "all";
+ public static final String AUTO_CLEAR = "autoClear";
+ public static final String CLEAR_BEFORE = "clearBefore";
+ public static final String FOS = "FOS";
+ public static final String FOE = "FOE";
+ public static final String SDE = "SDE";
+ public static final String SOC = "SOC";
+ public static final String BIZ = "BIZ";
+ public static final String HOSTEL = "HOSTEL";
+ public static final String FASS = "FASS";
+
+
+ /**
+ * This function calls the correct command the user want to perform, by returning a Command object.
+ *
+ * @param fullCommand the full string of user input
+ * @return the specific Command object to perform what the user want to do
+ * @throws NuScheduleException includes all exceptions may happen during parsing
+ */
+
+ public static Command parse(String fullCommand, LocationList locations, int size) throws NuScheduleException {
+
+ //deletes all the starting and ending spaces
+ fullCommand = fullCommand.trim();
+ // this block deals with single word command
+ switch (fullCommand) {
+ case EXIT:
+ return new ExitCommand();
+ case PRINT_EVENT_LIST:
+ return new PrintFullListCommand();
+ case PRINT_LOCATION_LIST:
+ return new PrintLocationCommand();
+ case HELP:
+ return new HelpCommand();
+ case CLEAR:
+ return new ClearCommand();
+ case REMIND:
+ return new ReminderCommand();
+ default:
+ break;
+ }
+
+ String[] words = fullCommand.split(SINGLE_SPACE);
+
+ //this block deals with user info
+ switch (words[0]) {
+ case "student":
+ case "professor":
+ return new UserInfoCommand(fullCommand.substring(words[0].length() + 1), words[0]);
+ default:
+ break;
+ }
+
+ //this block deals with auto clear command
+ if (words[0].equalsIgnoreCase(AUTO_CLEAR)) {
+ try {
+ fullCommand = fullCommand.substring(AUTO_CLEAR.length() + 1).trim();
+ } catch (StringIndexOutOfBoundsException e) {
+ throw new WrongAutoClearArgumentException();
+ }
+ if (fullCommand.equalsIgnoreCase("ON")) {
+ return new AutoClearCommand(true);
+ } else if (fullCommand.equalsIgnoreCase("OFF")) {
+ return new AutoClearCommand(false);
+ } else {
+ throw new WrongAutoClearArgumentException();
+ }
+ }
+
+ //this block deals with print locations in the area command
+ if (fullCommand.equalsIgnoreCase(FOS) || fullCommand.equalsIgnoreCase(FOE)
+ || fullCommand.equalsIgnoreCase(SDE) || fullCommand.equalsIgnoreCase(SOC)
+ || fullCommand.equalsIgnoreCase(BIZ) || fullCommand.equalsIgnoreCase(HOSTEL)
+ || fullCommand.equalsIgnoreCase(FASS)) {
+ return new PrintAreaLocationsCommand(fullCommand);
+ }
+
+ //this block deals with locate command
+ if (words[0].equalsIgnoreCase(LOCATE_EVENT)) {
+ String input = "";
+ int i;
+ for (i = 1; i < words.length; i++) {
+ input = input.concat(words[i]);
+ int j = i;
+ if (j++ != words.length) {
+ input = input.concat(" ");
+ }
+ }
+ if (words.length == 1) {
+ throw new EmptyLocationException();
+ } else if (locations.checkIfInteger(words[1])) {
+ int eventNum = Integer.parseInt(words[1]) - 1;
+ if (eventNum >= size || eventNum < 0) {
+ throw new InvalidEventIndexException();
+ } else {
+ return new LocateCommand(words[1]);
+ }
+ } else if (!locations.checkValidLocation(input)) {
+ throw new InvalidLocationException();
+ } else {
+ return new LocateCommand(input);
+ }
+ }
+ if (words[0].equalsIgnoreCase(LOCATE_EVENT) && words.length > 1) {
+ return new LocateCommand(words[1]);
+ } else if (words[0].equalsIgnoreCase(LOCATE_EVENT) && words.length == 1) {
+ throw new EmptyLocationException();
+ }
+
+ //this block deals with find command
+ if (words[0].equalsIgnoreCase(EVENT_FIND)) {
+ if (fullCommand.substring(4).isBlank()) {
+ throw new EmptyFindException();
+ }
+ return new FindCommand(fullCommand.substring(5));
+ }
+
+ //this block deals with find date command
+ if (words[0].equalsIgnoreCase(EVENT_FIND_DATE)) {
+ if (fullCommand.substring(4).isBlank()) {
+ throw new EmptyFindDateException();
+ }
+ try {
+ return new FindDateCommand(LocalDate.parse(fullCommand.substring(5)));
+ } catch (DateTimeParseException e) {
+ throw new DateFormatException();
+ }
+ }
+
+ //this block deals with study time command
+ if (words[0].equalsIgnoreCase(STUDY_TIME)) {
+ if (fullCommand.substring(9).isBlank()) {
+ throw new EmptyStudyTimeDateException();
+ }
+ try {
+ return new StudyTimeCommand(LocalDate.parse(fullCommand.substring(10)));
+ } catch (DateTimeParseException e) {
+ throw new DateFormatException();
+ }
+ }
+
+ int eventIndex;
+
+ //this block deals with done command
+ if (words[0].equalsIgnoreCase(EVENT_DONE)) {
+ if (fullCommand.substring(4).isBlank()) {
+ throw new EmptyDoneException();
+ }
+ try {
+ eventIndex = Integer.parseInt(fullCommand.substring(5).trim()) - 1;
+ } catch (NumberFormatException e) {
+ throw new DoneNumberFormatException();
+ }
+ return new DoneCommand(eventIndex);
+ }
+
+ //this block deals with delete command
+ if (words[0].equalsIgnoreCase(EVENT_DELETE)) {
+ if (fullCommand.substring(6).isBlank()) {
+ throw new EmptyDeleteException();
+ }
+ try {
+ eventIndex = Integer.parseInt(fullCommand.substring(7)) - 1;
+ } catch (NumberFormatException e) {
+ throw new DeleteNumberFormatException();
+ }
+ return new DeleteCommand(eventIndex);
+ }
+
+ //this block deals with sorting
+ if (words[0].equalsIgnoreCase(SORT)) {
+ if (fullCommand.length() == 4) {
+ throw new NoSortCriteriaException();
+ }
+ String type = words[1].trim().toLowerCase();
+ switch (type) {
+ case "description":
+ case "time":
+ case "location":
+ return new SortCommand(type);
+ default:
+ throw new InvalidSortCriteriaException();
+ }
+ }
+
+ //this block deals with repeat Events
+ if (words[0].equalsIgnoreCase(REPEAT)) {
+ if (fullCommand.substring(6).isBlank()) {
+ throw new EmptyRepeatException();
+ }
+ fullCommand = fullCommand.substring(6).trim();
+ String[] controlWords = fullCommand.split(SINGLE_SPACE);
+ if (fullCommand.substring(controlWords[0].length()).isBlank()) {
+ throw new NoRepeatWeekException();
+ }
+ int numWeeks;
+ try {
+ numWeeks = Integer.parseInt(fullCommand.substring(controlWords[0].length()).trim());
+ } catch (NumberFormatException e) {
+ throw new InvalidNumWeekException();
+ }
+ if (numWeeks <= 0 || numWeeks > 50) {
+ throw new InvalidNumWeekException();
+ }
+ if (controlWords[0].equalsIgnoreCase(ALL)) {
+ return new RepeatCommand(true, numWeeks);
+ } else {
+ int index;
+ try {
+ index = Integer.parseInt(controlWords[0]);
+ } catch (NumberFormatException e) {
+ throw new RepeatIndexFormatException();
+ }
+ return new RepeatCommand(index - 1, numWeeks);
+ }
+ }
+
+ //this block deals with clear before
+ if (words[0].equalsIgnoreCase(CLEAR_BEFORE)) {
+ if (fullCommand.substring(11).isBlank()) {
+ throw new EmptyClearDateException();
+ }
+ try {
+ return new ClearBeforeCommand(LocalDate.parse(fullCommand.substring(12)));
+ } catch (DateTimeParseException e) {
+ throw new DateFormatException();
+ }
+ }
+
+ //these variables are used by either Edit or Add
+ //the position of /t
+ int startTimeDividerPosition = fullCommand.indexOf(TIME_MARKER);
+ //the position of the space when the user enters a date time in the format yyyy-mm-dd HH:mm
+ int timeDivider;
+ //the position of /et
+ int endTimeDividerPosition = fullCommand.indexOf(END_TIME_MARKER);
+ //the position of /l
+ int locationDividerPosition = fullCommand.indexOf(LOCATION_MARKER);
+ //the position of /o
+ int onlineLocationDividerPosition = fullCommand.indexOf(ONLINE_LOCATION_MARKER);
+ //the position of /p
+ int pwdDividerPosition = fullCommand.indexOf(PASSWORD_MARKER);
+ String startDateTime;
+ Location location = null;
+ OnlineLocation onlineLocation = null;
+ String endDateTime;
+ //the position of the space when the user enters an ending date time in the format yyyy-mm-dd HH:mm
+ int endingTimeDivider;
+
+
+ //this block deals with edit command
+ if (words[0].equalsIgnoreCase(EDIT)) {
+ if (fullCommand.length() == 4) {
+ throw new EmptyEventIndexException();
+ }
+
+ try {
+ eventIndex = Integer.parseInt(fullCommand.substring(5).trim()) - 1;
+ } catch (NumberFormatException e) {
+ throw new WrongEditFormatException();
+ }
+
+ // Check if the index exists
+ if (eventIndex + 1 > size || eventIndex == -1) {
+ throw new UndefinedEventException(eventIndex + 1);
+ }
+
+ String[] editInformation = EditCommand.newEditInformation();
+ LocalDateTime[] startEnd = new LocalDateTime[2];
+
+
+ if (!editInformation[0].isBlank()) {
+ if (!editInformation[0].equalsIgnoreCase(ASSIGNMENT) && !editInformation[0].equalsIgnoreCase(CLASS)
+ && !editInformation[0].equalsIgnoreCase(PERSONAL_EVENT)
+ && !editInformation[0].equalsIgnoreCase(SELF_STUDY)) {
+
+ throw new InvalidEditTypeException();
+ }
+ }
+
+
+ // user input validation for location
+ if (!editInformation[2].isBlank()) {
+ editInformation[2] = editInformation[2].trim();
+ if (editInformation[2].startsWith(LOCATION_MARKER)) {
+ location = parseLocation(editInformation[2].substring(3), locations);
+ } else if (editInformation[2].startsWith(ONLINE_LOCATION_MARKER)) {
+ int pwdPos = editInformation[2].indexOf(PASSWORD_MARKER);
+ if (pwdPos == -1) {
+ onlineLocation =
+ new OnlineLocation(editInformation[2].substring(3).trim());
+ } else {
+ onlineLocation =
+ new OnlineLocation(editInformation[2].substring(3, pwdPos - 1).trim(),
+ editInformation[2].substring(pwdPos + 3).trim());
+ }
+ } else {
+ throw new InvalidEditLocationException();
+
+ }
+ }
+
+
+ // user input validation for start and end time
+ if (!editInformation[3].isBlank()) {
+ if (editInformation[3].length() != 16) {
+ throw new TimeFormatException();
+ }
+ startDateTime = editInformation[3].substring(0, 10) + "T" + editInformation[3].substring(11);
+ try {
+ startEnd[0] = LocalDateTime.parse(startDateTime);
+ //System.out.println(startEnd[0]);
+ } catch (DateTimeException e) {
+ throw new TimeFormatException();
+ }
+ }
+
+ if (!editInformation[4].isBlank()) {
+ if (!editInformation[4].equals("nil")) {
+ if (editInformation[4].length() != 16) {
+ throw new TimeFormatException();
+ }
+ startDateTime = editInformation[4].substring(0, 10) + "T" + editInformation[4].substring(11);
+ try {
+ startEnd[1] = LocalDateTime.parse(startDateTime);
+ //System.out.println(startEnd[1]);
+ } catch (DateTimeException e) {
+ throw new TimeFormatException();
+ }
+ }
+ }
+
+ return new EditCommand(eventIndex, editInformation, startEnd, location, onlineLocation);
+
+ }
+
+ String description;
+ //this block deals with add command
+ //we shall check that the user input is not meant for any other command beforehand
+ //because the default block will throw an exception.
+ // i.e. when this block is entered, the parser will not go to any other blocks
+ if (words[0].equals(ASSIGNMENT) || words[0].equals(CLASS)
+ || words[0].equals(PERSONAL_EVENT) || words[0].equals(SELF_STUDY)) {
+ if (fullCommand.substring(words[0].length()).isBlank()) {
+ throw new EmptyEventException();
+ }
+
+ if (startTimeDividerPosition == -1) {
+ throw new NoEventTimeMarkerException();
+ }
+
+ if (locationDividerPosition == -1 && onlineLocationDividerPosition == -1) {
+ throw new NoEventLocationException();
+ }
+
+ if (fullCommand.substring(words[0].length(), startTimeDividerPosition).isBlank()) {
+ throw new EmptyEventException();
+ }
+
+ if (locationDividerPosition != -1) {
+ if (fullCommand.substring(startTimeDividerPosition + 2, locationDividerPosition - 1).isBlank()) {
+ throw new NoEventTimeException();
+ }
+ if (fullCommand.substring(locationDividerPosition + 2).isBlank()) {
+ throw new NoEventLocationException();
+ }
+ } else {
+ if (fullCommand.substring(startTimeDividerPosition + 2, onlineLocationDividerPosition - 1)
+ .isBlank()) {
+ throw new NoEventTimeException();
+ }
+ if (fullCommand.substring(onlineLocationDividerPosition + 2).isBlank()) {
+ throw new NoEventLocationException();
+ }
+
+ }
+ description = fullCommand.substring(words[0].length() + 1, startTimeDividerPosition - 1).trim();
+
+ //this deals with the event holding offline
+ if (locationDividerPosition != -1) {
+ try {
+ timeDivider = fullCommand.substring(startTimeDividerPosition + 3).indexOf(SINGLE_SPACE);
+ location = parseLocation(fullCommand.substring(locationDividerPosition + 3), locations);
+
+ switch (words[0]) {
+ case ASSIGNMENT:
+ if (endTimeDividerPosition != -1) {
+ throw new DoubleTimeAssignmentException();
+ }
+ startDateTime = getStartDateTime(fullCommand, startTimeDividerPosition, timeDivider,
+ locationDividerPosition);
+
+ return new AddCommand(new Assignment(description, location,
+ LocalDateTime.parse(startDateTime)));
+ case CLASS:
+ if (endTimeDividerPosition == -1) {
+ throw new NoEndTimeClassException();
+ }
+
+ startDateTime = getStartDateTime(fullCommand, startTimeDividerPosition, timeDivider,
+ endTimeDividerPosition);
+
+ endingTimeDivider = fullCommand.substring(endTimeDividerPosition + 3,
+ locationDividerPosition - 1).indexOf(SINGLE_SPACE);
+
+ //if the user does not input the date of the ending time, by default it ends at the same
+ // day as the starting time
+ endDateTime = getEndDateTime(fullCommand, startTimeDividerPosition, timeDivider,
+ endTimeDividerPosition, locationDividerPosition, endingTimeDivider);
+
+ return new AddCommand(new Class(description, location, LocalDateTime.parse(startDateTime),
+ LocalDateTime.parse(endDateTime)));
+ case PERSONAL_EVENT:
+ case SELF_STUDY:
+ if (endTimeDividerPosition == -1) {
+ startDateTime = getStartDateTime(fullCommand, startTimeDividerPosition, timeDivider,
+ locationDividerPosition);
+ if (words[0].equalsIgnoreCase(PERSONAL_EVENT)) {
+ return new AddCommand(new PersonalEvent(description, location,
+ LocalDateTime.parse(startDateTime)));
+ } else {
+ return new AddCommand(new SelfStudy(description, location,
+ LocalDateTime.parse(startDateTime)));
+ }
+ } else {
+ startDateTime = getStartDateTime(fullCommand, startTimeDividerPosition, timeDivider,
+ endTimeDividerPosition);
+
+ endingTimeDivider = fullCommand.substring(endTimeDividerPosition + 3,
+ locationDividerPosition - 1).indexOf(SINGLE_SPACE);
+
+ //if the user does not input the date of the ending time, by default it ends at the same
+ // day as the starting time
+ endDateTime = getEndDateTime(fullCommand, startTimeDividerPosition, timeDivider,
+ endTimeDividerPosition, locationDividerPosition, endingTimeDivider);
+ if (words[0].equalsIgnoreCase(PERSONAL_EVENT)) {
+ return new AddCommand(new PersonalEvent(description, location,
+ LocalDateTime.parse(startDateTime),
+ LocalDateTime.parse(endDateTime)));
+ } else {
+ return new AddCommand(new SelfStudy(description, location,
+ LocalDateTime.parse(startDateTime),
+ LocalDateTime.parse(endDateTime)));
+ }
+ }
+ default:
+ break;
+ }
+ } catch (DateTimeParseException | StringIndexOutOfBoundsException e) {
+ throw new TimeFormatException();
+
+ }
+ } else { //this deals with the event holding online
+ try {
+ timeDivider = fullCommand.substring(startTimeDividerPosition + 3).indexOf(SINGLE_SPACE);
+ OnlineLocation virtualLocation;
+ if (pwdDividerPosition == -1) {
+ virtualLocation =
+ new OnlineLocation(fullCommand.substring(onlineLocationDividerPosition + 3));
+ } else {
+ try {
+ if (fullCommand.substring(onlineLocationDividerPosition + 2, pwdDividerPosition - 1)
+ .isBlank()) {
+ throw new NoEventLocationException();
+ }
+ } catch (NullPointerException | StringIndexOutOfBoundsException e) {
+ throw new NoEventLocationException();
+ }
+ if (fullCommand.substring(pwdDividerPosition + 2).isBlank()) {
+ throw new NoPasswordException();
+ }
+ virtualLocation =
+ new OnlineLocation(fullCommand.substring(onlineLocationDividerPosition + 3,
+ pwdDividerPosition - 1), fullCommand.substring(pwdDividerPosition + 3));
+ }
+
+ switch (words[0]) {
+ case ASSIGNMENT:
+ if (endTimeDividerPosition != -1) {
+ throw new DoubleTimeAssignmentException();
+ }
+ startDateTime = getStartDateTime(fullCommand, startTimeDividerPosition, timeDivider,
+ onlineLocationDividerPosition);
+
+ return new AddCommand(new Assignment(description, virtualLocation,
+ LocalDateTime.parse(startDateTime)));
+ case CLASS:
+ if (endTimeDividerPosition == -1) {
+ throw new NoEndTimeClassException();
+ }
+ startDateTime = getStartDateTime(fullCommand, startTimeDividerPosition, timeDivider,
+ endTimeDividerPosition);
+
+ endingTimeDivider = fullCommand.substring(endTimeDividerPosition + 3,
+ onlineLocationDividerPosition - 1).indexOf(SINGLE_SPACE);
+
+ endDateTime = getEndDateTime(fullCommand, startTimeDividerPosition, timeDivider,
+ endTimeDividerPosition, onlineLocationDividerPosition, endingTimeDivider);
+
+ return new AddCommand(new Class(description, virtualLocation,
+ LocalDateTime.parse(startDateTime),
+ LocalDateTime.parse(endDateTime)));
+ case PERSONAL_EVENT:
+ case SELF_STUDY:
+ if (endTimeDividerPosition == -1) {
+ startDateTime = getStartDateTime(fullCommand, startTimeDividerPosition, timeDivider,
+ onlineLocationDividerPosition);
+ if (words[0].equalsIgnoreCase(PERSONAL_EVENT)) {
+ return new AddCommand(new PersonalEvent(description, virtualLocation,
+ LocalDateTime.parse(startDateTime)));
+ } else {
+ return new AddCommand(new SelfStudy(description, virtualLocation,
+ LocalDateTime.parse(startDateTime)));
+ }
+ } else {
+ startDateTime = getStartDateTime(fullCommand, startTimeDividerPosition, timeDivider,
+ endTimeDividerPosition);
+
+ endingTimeDivider = fullCommand.substring(endTimeDividerPosition + 3,
+ onlineLocationDividerPosition - 1).indexOf(SINGLE_SPACE);
+
+ endDateTime = getEndDateTime(fullCommand, startTimeDividerPosition, timeDivider,
+ endTimeDividerPosition, onlineLocationDividerPosition, endingTimeDivider);
+ if (words[0].equalsIgnoreCase(PERSONAL_EVENT)) {
+ return new AddCommand(new PersonalEvent(description, virtualLocation,
+ LocalDateTime.parse(startDateTime),
+ LocalDateTime.parse(endDateTime)));
+ } else {
+ return new AddCommand(new SelfStudy(description, virtualLocation,
+ LocalDateTime.parse(startDateTime),
+ LocalDateTime.parse(endDateTime)));
+ }
+ }
+ default:
+ break;
+ }
+ } catch (DateTimeParseException | StringIndexOutOfBoundsException e) {
+ throw new TimeFormatException();
+ }
+
+ }
+ } else {
+ throw new WrongCommandException();
+ }
+
+ assert false;//nothing should reach here
+ throw new UnknownErrorException();
+ }
+
+ /**
+ * return the EndDateTime. if the date is not specified, by default, it ends at the same date as the starting date.
+ *
+ * @param fullCommand the full command provided by user
+ * @param startTimeDividerPosition index of "/t"
+ * @param timeDivider index of " " in the start time
+ * @param endTimeDividerPosition index of "/e"
+ * @param locationDividerPosition index of "/o" or "/l"
+ * @param endingTimeDivider index of " " in the end date time, may be -1
+ * @return a string in the format "yyyy-MM-dd HH:mm" that can be parsed into a LocalDateTime object
+ */
+ private static String getEndDateTime(String fullCommand, int startTimeDividerPosition, int timeDivider,
+ int endTimeDividerPosition, int locationDividerPosition,
+ int endingTimeDivider) {
+ return (endingTimeDivider != -1 ? fullCommand.substring(endTimeDividerPosition + 3,
+ endTimeDividerPosition + 3 + endingTimeDivider) :
+ fullCommand.substring(startTimeDividerPosition + 3,
+ startTimeDividerPosition + 3 + timeDivider))
+ + "T"
+ + (endingTimeDivider != -1 ? fullCommand.substring(endTimeDividerPosition + 3 + endingTimeDivider + 1,
+ locationDividerPosition - 1) : fullCommand.substring(endTimeDividerPosition + 3,
+ locationDividerPosition - 1));
+ }
+
+ /**
+ * return the StartDateTime.
+ *
+ * @param fullCommand the full command provided by user
+ * @param startTimeDividerPosition index of "/t"
+ * @param timeDivider index of " " in the start time
+ * @param endTimeDividerPosition index of "/e"
+ * @return a string in the format "yyyy-MM-dd HH:mm" that can be parsed into a LocalDateTime object
+ */
+ private static String getStartDateTime(String fullCommand, int startTimeDividerPosition, int timeDivider,
+ int endTimeDividerPosition) {
+ return fullCommand.substring(startTimeDividerPosition + 3,
+ startTimeDividerPosition + 3 + timeDivider)
+ + "T"
+ + fullCommand.substring(startTimeDividerPosition + 3 + timeDivider + 1,
+ endTimeDividerPosition - 1);
+ }
+
+ /**
+ * This method parses the inputted location.
+ *
+ * @param input the string inputted by the user.
+ * @return the parsed location.
+ */
+ public static Location parseLocation(String input, LocationList locations) {
+ assert locations != null;
+ Location location;
+ String[] info = input.split("/");
+ // parse location from event.txt file
+ try {
+ String[] additionalInfo = info[2].split(",");
+ switch (info[0]) {
+ case "BLK":
+ location = new Building(info[1], additionalInfo);
+ break;
+ case "H":
+ location = new Hostel(info[1], additionalInfo);
+ break;
+ case "L":
+ location = new LectureTheatre(info[1], info[2]);
+ break;
+ case "OUT":
+ location = new OutOfNuS(info[1]);
+ break;
+ default:
+ location = new OutOfNuS(info[0]);
+ break;
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ if (input.contains("/")) {
+ location = new OutOfNuS(info[1]);
+ locations.getLocationList().add(location);
+ }
+ // parse location from user input
+ // System.out.print("Invalid Location Format.");
+ location = locations.findLocation(input.trim());
+ if (location == null) {
+ location = new OutOfNuS(input.trim());
+ }
+ }
+ return location;
+ }
+}
+
diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java
deleted file mode 100644
index 5c74e68d59..0000000000
--- a/src/main/java/seedu/duke/Duke.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package seedu.duke;
-
-import java.util.Scanner;
-
-public class Duke {
- /**
- * Main entry-point for the java.duke.Duke application.
- */
- public static void main(String[] args) {
- String logo = " ____ _ \n"
- + "| _ \\ _ _| | _____ \n"
- + "| | | | | | | |/ / _ \\\n"
- + "| |_| | |_| | < __/\n"
- + "|____/ \\__,_|_|\\_\\___|\n";
- System.out.println("Hello from\n" + logo);
- System.out.println("What is your name?");
-
- Scanner in = new Scanner(System.in);
- System.out.println("Hello " + in.nextLine());
- }
-}
diff --git a/src/main/java/storage/Storage.java b/src/main/java/storage/Storage.java
new file mode 100644
index 0000000000..696c16d591
--- /dev/null
+++ b/src/main/java/storage/Storage.java
@@ -0,0 +1,371 @@
+package storage;
+
+import event.Event;
+import event.Assignment;
+import event.Class;
+import event.PersonalEvent;
+import event.SelfStudy;
+import exception.CreatingFileException;
+import exception.DataFileNotFoundException;
+import exception.EndBeforeStartEventException;
+import exception.LoadingException;
+import exception.WritingFileException;
+import location.Building;
+import location.BusStop;
+import location.Hostel;
+import location.LectureTheatre;
+import location.Location;
+
+import location.OnlineLocation;
+import location.OutOfNuS;
+import locationlist.LocationList;
+import parser.Parser;
+import usercommunication.UserInfo;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeParseException;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+/**
+ * This class creates the folder and file path if it's not already created, and
+ * prepare the data in the file to be used.
+ */
+public class Storage {
+ public static final String REGEX_IN_FILE = "//";
+ public static final String ONLINE = "online";
+ private final String[] filePaths;
+ //filePaths[0] will be the events data file. filePath[1] will be the user info file
+
+ /**
+ * Set the filepath
according to the user input.
+ *
+ * @param filePaths is the paths of the files
+ */
+ public Storage(String... filePaths) throws CreatingFileException {
+ this.filePaths = filePaths;
+ createFolderAndFIle(this.filePaths[0]);
+ createFolderAndFIle(this.filePaths[1]);
+ }
+
+ /**
+ * Creates the folder and file if not already crated.
+ *
+ * @param filePath the String of the relative path
+ */
+ private static void createFolderAndFIle(String filePath) throws CreatingFileException {
+ File dataFile = new File(filePath);
+ File directory = dataFile.getParentFile();
+ if (!directory.exists()) {
+ directory.mkdirs();
+ }
+
+ try {
+ dataFile.createNewFile();
+ } catch (IOException e) {
+ throw new CreatingFileException(filePath);
+ }
+ }
+
+
+ /**
+ * Save the data of the Event list to the file.
+ *
+ * @param events the list of Events provided by a variable from a EventList object
+ * @throws WritingFileException represents the file is not correctly written
+ */
+ public void writeFile(ArrayList events) throws WritingFileException {
+ try {
+ FileWriter fw = new FileWriter(filePaths[0]);
+ for (Event event : events) {
+ fw.write(event.fileString());
+ fw.write(System.lineSeparator());
+ }
+ fw.close();
+ } catch (IOException e) {
+ throw new WritingFileException();
+ }
+ }
+
+ /**
+ * Save the data of the user info.
+ *
+ * @param userInfo name and type of the user
+ * @throws WritingFileException Represents the exception when the file is not correctly written.
+ */
+ public void writeUserInfo(UserInfo userInfo) throws WritingFileException {
+ try {
+ FileWriter fw = new FileWriter(filePaths[1]);
+ fw.write(userInfo.fileString());
+ fw.close();
+ } catch (IOException e) {
+ throw new WritingFileException();
+ }
+ }
+
+ /**
+ * Prepares the data in the file as an UserInfo, which is used to construct the userInfo.
+ *
+ * @return the name and type of the user
+ * @throws LoadingException represents the Events is not correctly created
+ */
+ public UserInfo loadUserInfo() throws LoadingException {
+ UserInfo userInfo = new UserInfo();
+ try {
+ Scanner s = new Scanner(new File(filePaths[1]));
+ if (s.hasNext()) {
+ String[] words = s.nextLine().split(REGEX_IN_FILE);
+ userInfo = new UserInfo(words[0], words[1], (Integer.parseInt(words[2]) != 0));
+ }
+ } catch (FileNotFoundException e) {
+ System.out.println("file not found");
+ } catch (IndexOutOfBoundsException | NumberFormatException e) {
+ throw new LoadingException();
+ }
+ return userInfo;
+ }
+
+ /**
+ * Prepares the data in the file as an ArrayList, which is used to construct the EventList.
+ *
+ * @return the Events in an ArrayList
+ * @throws LoadingException represents the Events is not correctly created
+ * @throws EndBeforeStartEventException Represents the case when the user want to create an Event that ends
+ * before it starts.
+ */
+ public ArrayList loadEvents(LocationList locations) throws LoadingException, EndBeforeStartEventException {
+ ArrayList events = new ArrayList<>();
+ File dataFile = new File(filePaths[0]);
+ String description;
+ try {
+ Scanner s = new Scanner(dataFile);
+ while (s.hasNext()) {
+ String[] words = s.nextLine().split(REGEX_IN_FILE);
+ description = words[2].trim();
+ switch (words[0]) {
+ case "C":
+ try {
+ if (!words[5].equalsIgnoreCase(ONLINE)) {
+ events.add(new Class(description, Parser.parseLocation(words[5], locations),
+ LocalDateTime.parse(words[3]), LocalDateTime.parse(words[4])));
+ } else {
+ if (words.length >= 8) {
+ events.add(new Class(description, new OnlineLocation(words[6], words[7]),
+ LocalDateTime.parse(words[3]), LocalDateTime.parse(words[4])));
+ } else {
+ events.add(new Class(description, new OnlineLocation(words[6]),
+ LocalDateTime.parse(words[3]), LocalDateTime.parse(words[4])));
+ }
+ }
+ } catch (DateTimeParseException | StringIndexOutOfBoundsException e) {
+ throw new LoadingException();
+ }
+ if (Integer.parseInt(words[1]) == 1) {
+ events.get(events.size() - 1).markAsDone();
+ }
+ break;
+ case "A":
+ try {
+ if (!words[4].equalsIgnoreCase(ONLINE)) {
+ events.add(new Assignment(description, Parser.parseLocation(words[4], locations),
+ LocalDateTime.parse(words[3])));
+ } else {
+ events.add(new Assignment(description, new OnlineLocation(words[5]),
+ LocalDateTime.parse(words[3])));
+ }
+ } catch (DateTimeParseException | StringIndexOutOfBoundsException e) {
+ throw new LoadingException();
+ }
+ if (Integer.parseInt(words[1]) == 1) {
+ events.get(events.size() - 1).markAsDone();
+ }
+ break;
+ case "P":
+ try {
+ switch (words.length) {
+ case 5:
+ events.add(new PersonalEvent(description, Parser.parseLocation(words[4], locations),
+ LocalDateTime.parse(words[3])));
+ break;
+ case 6:
+ if (!words[4].equalsIgnoreCase(ONLINE)) {
+ events.add(new PersonalEvent(description, Parser.parseLocation(words[5], locations),
+ LocalDateTime.parse(words[3]), LocalDateTime.parse(words[4])));
+ } else {
+ events.add(new PersonalEvent(description, new OnlineLocation(words[5]),
+ LocalDateTime.parse(words[3])));
+ }
+ break;
+ case 7:
+ if (words[4].equalsIgnoreCase(ONLINE)) {
+ events.add(new PersonalEvent(description, new OnlineLocation(words[5], words[6]),
+ LocalDateTime.parse(words[3])));
+ } else if (words[5].equalsIgnoreCase(ONLINE)) {
+ events.add(new PersonalEvent(description, new OnlineLocation(words[6]),
+ LocalDateTime.parse(words[3]), LocalDateTime.parse(words[4])));
+ } else {
+ throw new LoadingException();
+ }
+ break;
+ case 8:
+ events.add(new PersonalEvent(description, new OnlineLocation(words[6], words[7]),
+ LocalDateTime.parse(words[3]), LocalDateTime.parse(words[4])));
+ break;
+ default:
+ throw new LoadingException();
+ }
+
+ } catch (DateTimeParseException | StringIndexOutOfBoundsException e) {
+ throw new LoadingException();
+ }
+ if (Integer.parseInt(words[1]) == 1) {
+ events.get(events.size() - 1).markAsDone();
+ }
+ break;
+ case "S":
+ try {
+ switch (words.length) {
+ case 5:
+ events.add(new SelfStudy(description, Parser.parseLocation(words[4], locations),
+ LocalDateTime.parse(words[3])));
+ break;
+ case 6:
+ if (!words[4].equalsIgnoreCase(ONLINE)) {
+ events.add(new SelfStudy(description, Parser.parseLocation(words[5], locations),
+ LocalDateTime.parse(words[3]), LocalDateTime.parse(words[4])));
+ } else {
+ events.add(new SelfStudy(description, new OnlineLocation(words[5]),
+ LocalDateTime.parse(words[3])));
+ }
+ break;
+ case 7:
+ if (words[4].equalsIgnoreCase(ONLINE)) {
+ events.add(new SelfStudy(description, new OnlineLocation(words[5], words[6]),
+ LocalDateTime.parse(words[3])));
+ } else if (words[5].equalsIgnoreCase(ONLINE)) {
+ events.add(new SelfStudy(description, new OnlineLocation(words[6]),
+ LocalDateTime.parse(words[3]), LocalDateTime.parse(words[4])));
+ } else {
+ throw new LoadingException();
+ }
+ break;
+ case 8:
+ events.add(new SelfStudy(description, new OnlineLocation(words[6], words[7]),
+ LocalDateTime.parse(words[3]), LocalDateTime.parse(words[4])));
+ break;
+ default:
+ throw new LoadingException();
+ }
+
+ } catch (DateTimeParseException | StringIndexOutOfBoundsException e) {
+ throw new LoadingException();
+ }
+ if (Integer.parseInt(words[1]) == 1) {
+ events.get(events.size() - 1).markAsDone();
+ }
+ break;
+ default:
+ throw new LoadingException();
+ }
+ }
+ } catch (FileNotFoundException e) {
+ System.out.println("file not found");
+ } catch (IndexOutOfBoundsException | NumberFormatException e) {
+ throw new LoadingException();
+ }
+
+ return events;
+ }
+
+ /**
+ * Loads data from bus_stop text file to an ArrayList, which is stored in a BusStopList.
+ *
+ * @param busStopList ArrayList of BusStops in BusStopList
+ */
+ public void loadBusStopData(ArrayList busStopList) {
+ Scanner s = new Scanner(busStopData);
+
+ while (s.hasNext()) {
+ String input = s.nextLine();
+ String[] split = input.split(":", 2);
+ String name = split[0];
+ String[] buses = split[1].split(",");
+ BusStop stop = new BusStop(name, buses);
+ busStopList.add(stop);
+ }
+ }
+
+ /**
+ * Loads data from location text file into an ArrayList, which is stored in a LocationList.
+ *
+ * @param locationList ArrayList of Locations in LocationList
+ */
+ public void loadLocationData(ArrayList locationList) {
+ Scanner s = new Scanner(locationData);
+
+ while (s.hasNext()) {
+ String input = s.nextLine();
+ // info[0] = type, info[1] = name, info[2] = nearest buildings/bus stops
+ String[] info = input.split("/");
+ String[] additionalInfo = info[2].split(",");
+ Location location = null;
+ switch (info[0]) {
+ case "BLK":
+ location = new Building(info[1], additionalInfo);
+ break;
+ case "H":
+ location = new Hostel(info[1], additionalInfo);
+ break;
+ case "L":
+ location = new LectureTheatre(info[1], info[2]);
+ break;
+ case "OUT":
+ location = new OutOfNuS(info[1]);
+ break;
+ default:
+ break;
+ }
+ if (location != null) {
+ locationList.add(location);
+ } else {
+ System.out.println("Invalid Location Type");
+ }
+ }
+ }
+
+ private String locationData = "BLK/EA/EA\n"
+ + "BLK/EA/Information Technology\n" + "BLK/E1A/EA\n" + "BLK/EW1/EA,Information Technology\n"
+ + "BLK/EW1A/EA\n" + "BLK/E2/EA\n" + "BLK/E3/EA,Raffles Hall\n" + "BLK/E3A/EA\n"
+ + "BLK/E4/Information Technology\n" + "BLK/E4A/Opp YIH,YIH\n" + "BLK/E5/Information Technology\n"
+ + "BLK/E5A/Raffles Hall\n" + "BLK/E6/Opp YIH,YIH\n" + "BLK/IT/Information Technology,CLB\n"
+ + "BLK/AS1/CLB,LT13\n" + "BLK/AS2/Ventus,LT13\n" + "BLK/AS3/Ventus,LT13\n"
+ + "BLK/AS4/LT13,AS5\n" + "BLK/AS5/AS5\n" + "BLK/AS6/CLB,COM2\n" + "BLK/AS7/Ventus,LT13\n" + "BLK/AS8/CLB\n"
+ + "BLK/SDE1/IT\n" + "BLK/SDE2/IT\n" + "BLK/SDE3/EA\n" + "BLK/SDE4/IT\n" + "BLK/CELC/IT\n" + "BLK/S1/LT27\n"
+ + "BLK/S2/LT27\n" + "BLK/S3/LT27\n" + "BLK/S4/LT27\n" + "BLK/S5/LT27\n" + "BLK/S6/LT27\n" + "BLK/S7/LT27\n"
+ + "BLK/S8/LT27\n" + "BLK/S9/LT27\n" + "BLK/S10/LT27\n" + "BLK/S11/LT27\n" + "BLK/S12/LT27\n"
+ + "BLK/S13/LT27\n" + "BLK/S14/LT27\n" + "BLK/S15/LT27\n" + "BLK/S16/LT27\n" + "BLK/S17/S17,LT27\n"
+ + "BLK/MD1/LT27\n" + "BLK/MD2/LT27\n" + "BLK/MD3/LT27\n" + "BLK/MD4/LT27\n" + "BLK/MD5/LT27\n"
+ + "BLK/MD6/LT27\n" + "BLK/MD7/LT27\n" + "BLK/MD8/LT27\n" + "BLK/MD9/LT27\n" + "BLK/MD10/LT27\n"
+ + "BLK/MD11/LT27\n" + "BLK/COM1/COM2\n" + "BLK/COM2/COM2\n" + "BLK/BIZ1/BIZ2,COM2\n" + "BLK/BIZ2/BIZ2\n"
+ + "BLK/Shaw Foundation Alumni House/Opp NUSSU\n" + "H/Raffles Hall/Raffles Hall,NUS Museum\n"
+ + "H/Kent Ridge Hall/Opp HSSML\n" + "H/King Edward VII Hall/PGP\n" + "H/Sheares Hall/Opp HSSML\n"
+ + "H/Eusoff Hall/Ventus\n" + "H/Temasek Hall/Opp NUSSU\n" + "H/Cinnamon College/UTown\n"
+ + "H/College of Alice and Peter Tan/UTown\n" + "H/Residental College 4/UTown\n" + "H/RVRC/Opp UHC\n"
+ + "H/Tembusu College/UTown\n" + "H/Prince George's Park/PGP\n" + "H/UTown Residence/UTown\n"
+ + "L/LT1/E2\n" + "L/LT2/E2\n" + "L/LT6/E4\n" + "L/LT7/EA\n" + "L/LT7A/EA\n" + "L/LT8/AS5\n" + "L/LT9/AS1\n"
+ + "L/LT10/AS1\n" + "L/LT11/AS2\n" + "L/LT12/AS3\n" + "L/LT13/AS3\n" + "L/LT14/AS6\n" + "L/LT15/AS6\n"
+ + "L/LT16/COM2\n" + "L/LT17/COM2\n" + "L/LT18/COM2\n" + "L/LT19/COM2\n" + "L/LT20/S3\n" + "L/LT21/S5\n"
+ + "L/LT24/MD4\n" + "L/LT25/MD7\n" + "L/LT26/MD9\n" + "L/LT27/LT27\n" + "L/LT28/LT27\n" + "L/LT29/LT27\n"
+ + "L/LT31/S16\n" + "L/LT32/S1\n" + "L/LT33/S17\n" + "L/LT34/S17";
+
+ private String busStopData = "EA:B2,C,BTC2\n"
+ + "Raffles Hall:B2,C\n" + "Information Technology:A2,B1,B2,D1\n" + "Opp YIH:A2,B1,B2,D1\n"
+ + "NUS Museum:A2,BTC1,BTC2,C,D1,D2\n" + "YIH:A1,B1,BTC1,D1\n" + "CLB:A1,B1,BTC1,D1\n"
+ + "LT13:A1,B,D1,BTC1\n" + "AS5:A1,B,D1,BTC1\n" + "Ventus:A2,A2E,B,D1\n" + "BIZ2:A1,A1E,D1,BTC1\n"
+ + "Opp NUSSU:A2,D1\n" + "Opp HSSML:A2,D1\n" + "Opp UHC:A1,C,D2\n" + "COM2:A1,A2,B,D1\n"
+ + "UTown:D1,D2,B1,B1,C,BTC\n" + "PGP:A1\n" + "LT27:A1,A1E,C,D2\n" + "S17:A2,A2E,C,D2";
+}
diff --git a/src/main/java/ui/UI.java b/src/main/java/ui/UI.java
new file mode 100644
index 0000000000..32b6d80f0b
--- /dev/null
+++ b/src/main/java/ui/UI.java
@@ -0,0 +1,474 @@
+package ui;
+
+
+import event.Event;
+import exception.EmptyEventListException;
+import location.BusStop;
+import location.Location;
+import usercommunication.UserInfo;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+/**
+ * UI receives all user inputs, and produces outputs show to the user.
+ */
+public class UI {
+
+ public static final String LOGO =
+ " _ _ _ _ ____ _ _ _\n"
+ + "| | | | | | | / ___| | | | | | |\n"
+ + "| \\ | | | | |/ / | | | | | |\n"
+ + "| |\\\\ | | | | |\\ \\ | | ___ | | | | ___\n"
+ + "| | \\\\ | | | | | \\ \\ ___| |______ /___\\ ____| |_ _| |/___\\\n"
+ + "| | \\\\ | | | | | \\ \\ /___| ____ ||___||| __ | | | | ||___||\n"
+ + "| | \\\\| | | | | \\ \\ // | | | | ___/ | | | | | | | | ___/\n"
+ + "| | \\ | |______| |___/ / \\\\___| | | |\\____ | |__| | |__| | |\\____\n"
+ + "|_| |_|__________|____/ \\___|_| |_|\\___/ |______|\\___,_|_|\\___/\n";
+ public static final String LINE_DIVIDER = "____________________________________________________________";
+ public static final String EXIT_MESSAGE = "Bye. Hope to see you again soon!";
+ private final Scanner in;
+
+ public UI() {
+ in = new Scanner(System.in);
+ }
+
+ public String[] readEditCommand() {
+ String[] editFields = {"TYPE: ", "DESC: ", "LOCATION: ", "START: ", "END: "};
+ String[] editInformation = new String[5];
+ System.out.println("Enter the edits for each component. Leave as blank if no edits are to be made.");
+ // populate edit information with user data
+ for (int i = 0; i < 5; i++) {
+ System.out.print(editFields[i]);
+ editInformation[i] = in.nextLine().trim();
+ }
+ return editInformation;
+ }
+
+
+ /**
+ * Reads the user input line by line.
+ *
+ * @return the string of the line
+ */
+ public String readCommand() {
+ return in.nextLine();
+ }
+
+ /**
+ * Prints the logo of NUSchedule and greet the user.
+ */
+ public void printGreetingMessage(UserInfo userInfo) {
+ printLine();
+ if (userInfo.getName().isBlank()) {
+ System.out.println("I am NUSchedule! What's your name?");
+ } else {
+ helloWithName(userInfo.getName());
+ }
+
+ System.out.println("Hello from\n" + LOGO);
+ System.out.println("What can I do for you?");
+ }
+
+ /**
+ * Prints the separator.
+ */
+ public void printLine() {
+ System.out.println(LINE_DIVIDER);
+ }
+
+ /**
+ * Prints all the events with labels, based on the input list.
+ *
+ * @param events an ArrayList of events to be printed one by one.
+ */
+ public void printEventList(ArrayList events) throws EmptyEventListException {
+ int numPrintedEvents = 0;
+ if (events.size() == 0) {
+ throw new EmptyEventListException();
+ } else {
+ try {
+ System.out.println("Here are the Events in your list:");
+ for (Event event : events) {
+ numPrintedEvents++;
+ System.out.println(numPrintedEvents + ". " + event.toString());
+ }
+ } catch (NullPointerException e) {
+ System.out.println("The list is empty.");
+ }
+ }
+ }
+
+ /**
+ * Prints all the Events of the filtered list with labels, based on the input list.
+ *
+ * @param events an ArrayList of Events to be printed one by one.
+ */
+ public void printFilteredEventList(ArrayList events) {
+ int numPrintedEvents = 0;
+
+ System.out.println("Here are the matching Events in your list:");
+ for (Event event : events) {
+ numPrintedEvents++;
+ System.out.println(numPrintedEvents + ". " + event.toString());
+ }
+ }
+
+ /**
+ * Shows the error message when experiencing exceptions.
+ *
+ * @param message the message get from the error.
+ */
+ public void showError(String message) {
+ System.out.println(message);
+ }
+
+ /**
+ * Shows the error message during loading. Since the general IO exception is
+ * handled when executing the process, the error leads to this would be the file
+ * is edited in a wrong way.
+ */
+ public void showLoadingError() {
+ System.out.println("You edit the file in a wrong format. Please check.");
+ }
+
+ /**
+ * Call when exit the program.
+ */
+ public void printExitMessage() {
+ System.out.println(EXIT_MESSAGE);
+ }
+
+ /**
+ * Take in a size and prints the total number of Events.
+ *
+ * @param size number of events in the list.
+ */
+ public void printNumEvent(int size) {
+ System.out.println("Now you have " + size + " Events in the list.");
+ }
+
+ /**
+ * Prints the message when the user mark some Event as done.
+ *
+ * @param event the Event being done
+ */
+ public void printDoneMessage(Event event) {
+ System.out.println("Nice! I've marked this Event as done: ");
+ System.out.println(event.toString());
+ }
+
+ /**
+ * Prints the message when the user deletes some Event.
+ *
+ * @param event the Event being deleted
+ */
+ public void printDeleteMessage(Event event) {
+ System.out.println("Noted. I've removed this Event: ");
+ System.out.println(event.toString());
+ }
+
+ /**
+ * Prints the message when the user adds some Event.
+ *
+ * @param eventAdded the Event being added
+ */
+ public void printAddEventMessage(Event eventAdded) {
+ System.out.println("I've added this Event: ");
+ System.out.println(eventAdded.toString());
+ }
+
+ /**
+ * Prints the message when the user adds some Event.
+ *
+ * @param eventEdited the Event being edited
+ */
+ public void printEditEventMessage(Event eventEdited) {
+ System.out.println("The event has been edited.");
+ }
+
+ /**
+ * Prints the message when the user sorts the events.
+ */
+ public void printSortEventMessage() {
+ System.out.println("Got it. The events have been sorted.");
+ }
+
+ /**
+ * Prints all the Events of the filtered list with labels, based on the input list.
+ *
+ * @param filteredEventList an ArrayList of Events to be printed one by one.
+ */
+ public void printFilteredDateEventList(ArrayList filteredEventList) {
+ int numPrintedEvents = 0;
+
+ System.out.println(" Here are the Events on the given date in your list:");
+ for (Event event : filteredEventList) {
+ numPrintedEvents++;
+ System.out.println(numPrintedEvents + ". " + event.toString());
+ }
+ }
+
+ /**
+ * Prints all the locations stored in the location list with nearest bus stops.
+ *
+ * @param locationsList an Array List of Locations to be printed.
+ */
+ public void printLocationList(ArrayList locationsList) {
+ int i = 1;
+ System.out.println("Lists of locations: ");
+ for (Location location : locationsList) {
+ System.out.println(i + ". " + location);
+ i++;
+ }
+ }
+
+
+ /**
+ * Prints all the bus stops stored in the bus stop list with buses that goes there.
+ *
+ * @param busStopList an Array List of Bus Stops to be printed
+ */
+ public void printBusStopList(ArrayList busStopList) {
+ int i = 1;
+ System.out.println("List of bus stops: ");
+ for (BusStop busStop : busStopList) {
+ System.out.println(i + ". " + busStop);
+ i++;
+ }
+ }
+
+ /**
+ * Prints the help information when user input command 'help'.
+ * Relevant command information with reference to the current user guide draft.
+ */
+ public void printHelp() {
+ System.out.println("Current version: v2.1");
+ System.out.println("Below are all the commands and brief descriptions of their functions in the form of "
+ + "command - function: ");
+ System.out.println("help - view all the commands");
+ System.out.println("assignment - add an assignment event with content, deadline and location");
+ System.out.println("class - add a class event with content, deadline and location");
+ System.out.println("personalEvent - add a personal event with content, deadline and location");
+ System.out.println("selfStudy - add a self directed study event");
+ System.out.println("edit - edit event information");
+ System.out.println("locate - find location information");
+ System.out.println("locations - view all the locations available");
+ System.out.println("list - view all events added");
+ System.out.println("clear - clear all events");
+ System.out.println("reminder - show events of the day");
+ System.out.println("autoClear - clear all events one month ago");
+ System.out.println("clearBefore - clear all events before the date input");
+ System.out.println("studyTime - show the amount of study time detected by the program of the day");
+ System.out.println("sort - sort all events according to the criteria given");
+ System.out.println("repeat - repeat events that have previously happened");
+ System.out.println("done - mark a certain task/event as done");
+ System.out.println("date - show all events on the date given");
+ System.out.println("There will be more upcoming features in later versions.");
+ System.out.println("For more information, please refer to detailed user guide: "
+ + "https://ay2021s1-cs2113t-f14-4.github.io/tp/");
+ }
+
+ /**
+ * Prints the message when the user clears the list.
+ */
+ public void printClearEventsSuccessful() {
+ System.out.println("Clear successful. The list is now empty.");
+ }
+
+ /**
+ * Prints all the Events of the filtered list with labels, based on the input list.
+ * Called for printing the events that having conflict timing with the new event added.
+ *
+ * @param conflictEvents an ArrayList of Events to be printed one by one.
+ */
+ public void printConflictEvents(ArrayList conflictEvents) {
+ if (conflictEvents == null) {
+ return;
+ }
+ if (conflictEvents.size() == 0) {
+ return;
+ }
+ int numPrintedEvents = 0;
+ System.out.println("You have some events that happen concurrently. Please prepared for multi-thread. "
+ + "\n"
+ + "Here are the Events in your list that have overlaps with your newly added/edited event:");
+ for (Event event : conflictEvents) {
+ numPrintedEvents++;
+ System.out.println(numPrintedEvents + ". " + event.toString());
+ }
+ System.out.println("\nBut nonetheless...");
+ }
+
+ public void helloWithName(String name) {
+ System.out.println("Hi " + name + ", nice to see you.");
+ }
+
+ /**
+ * Prints the amount of time the person spent on study on that day.
+ *
+ * @param filteredEventList the list that contains events that are academic related, happen on that day, and have
+ * been done.
+ * @param date the date that the user want to know his or her study time.
+ */
+ public void printStudyTime(ArrayList filteredEventList, LocalDate date) {
+ int hour = 0;
+ int minute = 0;
+ int startHour;
+ int endHour;
+ int startMinute;
+ int endMinute;
+ for (Event event : filteredEventList) {
+ if (event.getDate().isBefore(date)) {
+ startHour = 0;
+ startMinute = 0;
+ } else {
+ startHour = event.getStartDateTime().getHour();
+ startMinute = event.getStartDateTime().getMinute();
+ }
+
+ if (event.getEndDate().isAfter(date)) {
+ endHour = 24;
+ endMinute = 0;
+ } else {
+ endHour = event.getEndDateTime().getHour();
+ endMinute = event.getEndDateTime().getMinute();
+ }
+
+ hour += endHour - startHour;
+ minute += endMinute - startMinute;
+ }
+
+ hour += minute / 60;
+ minute %= 60;
+
+ System.out.println("The amount of time you spent on study on that day is:\n"
+ + hour + " hour(s) " + minute + " minute(s)");
+ }
+
+ /**
+ * Print the Not Done events today.
+ *
+ * @param filteredEventList The events that are not done today.
+ */
+ public void printRemindEventList(ArrayList filteredEventList) {
+ int numPrintedEvents = 0;
+
+ System.out.println("Here are the events that you should do today:");
+ for (Event event : filteredEventList) {
+ numPrintedEvents++;
+ System.out.println(numPrintedEvents + ". " + event.toString());
+ }
+ }
+
+ /**
+ * Print the success message after repeating all classes in the current week.
+ *
+ * @param numWeeks number of weeks to repeat.
+ */
+ public void printRepeatAll(int numWeeks) {
+ System.out.println("All classes in this week have been repeated for " + numWeeks + " weeks.");
+ }
+
+ /**
+ * Print the success message after repeating the selected event.
+ *
+ * @param numWeeks number of weeks to repeat.
+ */
+ public void printRepeatEvent(int numWeeks) {
+ System.out.println("The selected event has been repeated for " + numWeeks + " weeks.");
+ }
+
+ /**
+ * Print the success message after the user input autoClear on.
+ */
+ public void printAutoClearOn() {
+ System.out.println("Great! Your event happens one month ago will be auto-cleared from the next time you open "
+ + "this app onwards.");
+ }
+
+ /**
+ * Print the success message after the user successfully clear all events before a certain date.
+ */
+ public void printClearBefore(LocalDate clearDate) {
+ System.out.println("Great! You have cleared all events before " + clearDate.toString());
+ }
+
+ public void printFassLocations() {
+ System.out.println("Locations exist at FASS are: \n"
+ + "BLK/AS1~8 \n"
+ + "L/LT8~15"
+ );
+ }
+
+ public void printSdeLocations() {
+ System.out.println("Locations exist at SDE are: \n"
+ + "BLK/SDE1~4 \n"
+ + "BLK/CELC"
+ );
+ }
+
+ public void printFosLocations() {
+ System.out.println("Locations exist at FOS are: \n"
+ + "BLK/S1~17 \n"
+ + "BLK/MD1~11 \n"
+ + "L/LT20~34"
+ );
+ }
+
+ public void printFoeLocations() {
+ System.out.println("Locations exist at FOE are: \n"
+ + "BLK/E1~E6 \n"
+ + "BLK/EA \n"
+ + "BLK/E1A \n"
+ + "BLK/E2A \n"
+ + "BLK/E3A \n"
+ + "BLK/E4A \n"
+ + "BLK/EW1 \n"
+ + "BLK/EW2 \n"
+ + "BLK/IT \n"
+ + "L/LT1~7 \n"
+ + "L/LT7A"
+ );
+ }
+
+ public void printHostelLocations() {
+ System.out.println("Hostels in NUS are: \n"
+ + "H/Raffles Hall \n"
+ + "H/Kent Ridge Hall \n"
+ + "H/King Edward VII Hall \n"
+ + "H/Sheares Hall \n"
+ + "H/Temasek Hall \n"
+ + "H/Eusoff Hall \n"
+ + "H/Cinnamon College \n"
+ + "H/College of Alice & Peter Tan \n"
+ + "H/Residential College 4 \n"
+ + "H/Ridge View Residential College \n"
+ + "H/Tembusu College \n"
+ + "H/Kuok Foundation House \n"
+ + "H/Prince George’s Park \n"
+ + "H/UTown Residence"
+ );
+ }
+
+ public void printSocAndBizLocations() {
+ System.out.println("Locations exist at SOC or BIZ are: \n"
+ + "L/LT16~LT19 \n"
+ + "BLK/COM1 \n"
+ + "BLK/COM2 \n"
+ + "BLK/BIZ1 \n"
+ + "BLK/BIZ2 \n"
+ + "BLK/Shaw Foundation Alumni House \n"
+ + "BLK/I Cube");
+
+ }
+
+ /**
+ * Print the success message after the user input autoClear off.
+ */
+ public void printAutoClearOff() {
+ System.out.println("Great! Your event happens one month ago will not be auto-cleared now.");
+ }
+}
+
diff --git a/src/main/java/usercommunication/UserInfo.java b/src/main/java/usercommunication/UserInfo.java
new file mode 100644
index 0000000000..264791fab4
--- /dev/null
+++ b/src/main/java/usercommunication/UserInfo.java
@@ -0,0 +1,51 @@
+package usercommunication;
+
+/**
+ * Represents the personal information about the user.
+ */
+public class UserInfo {
+ protected String name = "";
+ protected UserType type = UserType.UNKNOWN;
+ protected boolean isAutoClear = false;
+
+ public boolean isAutoClear() {
+ return isAutoClear;
+ }
+
+ public void setAutoClear(boolean isAutoClear) {
+ this.isAutoClear = isAutoClear;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setType(String userType) {
+ if (userType.equalsIgnoreCase("PROFESSOR")) {
+ this.type = UserType.PROFESSOR;
+ } else if (userType.equalsIgnoreCase("STUDENT")) {
+ this.type = UserType.STUDENT;
+ }
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public UserInfo() {
+ }
+
+ public UserInfo(String name, String type, boolean isAutoClear) {
+ this.name = name;
+ if (type.equalsIgnoreCase("PROFESSOR")) {
+ this.type = UserType.PROFESSOR;
+ } else if (type.equalsIgnoreCase("STUDENT")) {
+ this.type = UserType.STUDENT;
+ }
+ this.isAutoClear = isAutoClear;
+ }
+
+ public String fileString() {
+ return name + "//" + type + "//" + (isAutoClear ? 1 : 0);
+ }
+}
diff --git a/src/main/java/usercommunication/UserType.java b/src/main/java/usercommunication/UserType.java
new file mode 100644
index 0000000000..1e4f1a36c1
--- /dev/null
+++ b/src/main/java/usercommunication/UserType.java
@@ -0,0 +1,7 @@
+package usercommunication;
+
+public enum UserType {
+ PROFESSOR,
+ STUDENT,
+ UNKNOWN
+}
diff --git a/src/test/java/command/AddCommandTest.java b/src/test/java/command/AddCommandTest.java
new file mode 100644
index 0000000000..c7f9232284
--- /dev/null
+++ b/src/test/java/command/AddCommandTest.java
@@ -0,0 +1,35 @@
+package command;
+
+import exception.EmptyEventException;
+import exception.EmptyEventIndexException;
+import exception.NoEventLocationException;
+import exception.NoEventLocationMarkerException;
+import exception.NoEventTimeMarkerException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import parser.Parser;
+
+
+class AddCommandTest {
+
+ @Test
+ void execute_NoDescriptionGiven_EmptyEventException() {
+ Assertions.assertThrows(EmptyEventException.class, () -> {
+ Command d = Parser.parse("class", null, 0);
+ });
+ }
+
+ @Test
+ void execute_NoTimeMarkerGiven_NoEventTimeMarkerException() {
+ Assertions.assertThrows(NoEventTimeMarkerException.class, () -> {
+ Command d = Parser.parse("class something", null,0);
+ });
+ }
+
+ @Test
+ void execute_NoLocationMarkerGiven_NoEventLocationException() {
+ Assertions.assertThrows(NoEventLocationException.class, () -> {
+ Command d = Parser.parse("class something /t 2020-02-02 20:00", null,0);
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/command/DeleteCommandTest.java b/src/test/java/command/DeleteCommandTest.java
new file mode 100644
index 0000000000..bb0a4f695d
--- /dev/null
+++ b/src/test/java/command/DeleteCommandTest.java
@@ -0,0 +1,20 @@
+package command;
+
+import exception.DeleteException;
+import exception.DeleteNumberFormatException;
+import exception.UndefinedEventException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import parser.Parser;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class DeleteCommandTest {
+
+ @Test
+ void execute_InvalidIndexGiven_DeleteNumberFormatException() {
+ Assertions.assertThrows(DeleteNumberFormatException.class,() -> {
+ Command c = Parser.parse("delete f", null,0);
+ });
+ }
+}
diff --git a/src/test/java/command/EditCommandTest.java b/src/test/java/command/EditCommandTest.java
new file mode 100644
index 0000000000..8deea86066
--- /dev/null
+++ b/src/test/java/command/EditCommandTest.java
@@ -0,0 +1,151 @@
+package command;
+
+import event.Assignment;
+import event.Class;
+import event.PersonalEvent;
+import event.SelfStudy;
+import eventlist.EventList;
+import exception.CreatingFileException;
+import exception.DataFileNotFoundException;
+import exception.EmptyEventIndexException;
+import exception.UndefinedEventException;
+import exception.WrongEditFormatException;
+import location.Location;
+import location.OnlineLocation;
+import locationlist.BusStopList;
+import locationlist.LocationList;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import exception.NuScheduleException;
+import parser.Parser;
+import storage.Storage;
+import ui.UI;
+import usercommunication.UserInfo;
+
+import java.time.LocalDateTime;
+
+
+class EditCommandTest {
+
+ @Test
+ void execute_NoIndexSpecified_emptyEventIndexException() throws NuScheduleException {
+
+ Assertions.assertThrows(EmptyEventIndexException.class, () -> {
+ Command d = Parser.parse("edit", null, 0);
+ });
+
+ }
+
+ @Test
+ void execute_InputIsNotInteger_WrongEditFormatException() {
+ Assertions.assertThrows(WrongEditFormatException.class, () -> {
+ Command c = Parser.parse("edit c", null, 0);
+ });
+ }
+
+
+ @Test
+ void execute_IndexOutOfBounds_UndefinedEventException() throws CreatingFileException, DataFileNotFoundException {
+ Storage storage = new Storage("data/events.txt", "data/UserInfo.txt");
+ LocationList locations = new LocationList();
+ storage.loadLocationData(locations.getLocationList());
+ Assertions.assertThrows(UndefinedEventException.class, () -> {
+ Parser.parse("edit 1", locations, 0)
+ .execute(new EventList(), new LocationList(), new BusStopList(), new UI(), storage, new UserInfo());
+ });
+ }
+
+ @Test
+ void execute_ChangeDescription_DescriptionChanged() throws NuScheduleException {
+ EventList events = new EventList();
+ Location location = new Location("location");
+ LocalDateTime by = LocalDateTime.parse("2020-02-02T20:00");
+ event.Event existing = new Assignment("existing", location, by);
+ events.addEvent(existing);
+ String[] editInformation = {"", "something", "", "", ""};
+ LocalDateTime[] startEnd = new LocalDateTime[2];
+
+ Command c = new EditCommand(0, editInformation, startEnd, null, null);
+ Storage storage = new Storage("data/events.txt", "data/UserInfo.txt");
+ c.execute(events, new LocationList(), new BusStopList(), new UI(), storage, new UserInfo());
+ Assertions.assertEquals("something", events.get(0).getDescription());
+ }
+
+ @Test
+ void execute_ChangeType_EventTypeChanged() throws NuScheduleException {
+ EventList events = new EventList();
+ Location location = new Location("location");
+ LocalDateTime start = LocalDateTime.parse("2020-02-02T20:00");
+ LocalDateTime end = LocalDateTime.parse("2020-02-02T21:00");
+ event.Event existing = new Class("existing", location, start, end);
+ events.addEvent(existing);
+ String[] editInformation = {"personalEvent", "", "", "", ""};
+ LocalDateTime[] startEnd = new LocalDateTime[2];
+
+ Command c = new EditCommand(0, editInformation, startEnd, null, null);
+ Storage storage = new Storage("data/events.txt", "data/UserInfo.txt");
+ c.execute(events, new LocationList(), new BusStopList(), new UI(), storage, new UserInfo());
+ Assertions.assertTrue(events.get(0) instanceof PersonalEvent);
+
+ editInformation[0] = "class";
+ Command d = new EditCommand(0, editInformation, startEnd, null, null);
+ d.execute(events, new LocationList(), new BusStopList(), new UI(), storage, new UserInfo());
+ Assertions.assertTrue(events.get(0) instanceof Class);
+
+ editInformation[0] = "selfStudy";
+ Command e = new EditCommand(0, editInformation, startEnd, null, null);
+ e.execute(events, new LocationList(), new BusStopList(), new UI(), storage, new UserInfo());
+ Assertions.assertTrue(events.get(0) instanceof SelfStudy);
+
+ editInformation[0] = "assignment";
+ Command f = new EditCommand(0, editInformation, startEnd, null, null);
+ f.execute(events, new LocationList(), new BusStopList(), new UI(), storage, new UserInfo());
+ Assertions.assertTrue(events.get(0) instanceof Assignment);
+ }
+
+ @Test
+ void editEvent_changeLocation_LocationChanged() throws NuScheduleException {
+ EventList events = new EventList();
+ Location location = new Location("location");
+ LocalDateTime start = LocalDateTime.parse("2020-02-02T20:00");
+ LocalDateTime end = LocalDateTime.parse("2020-02-02T21:00");
+ event.Event existing = new Class("existing", location, start, end);
+ events.addEvent(existing);
+ String[] editInformation = {"", "", "", "", ""};
+ LocalDateTime[] startEnd = new LocalDateTime[2];
+ Location location1 = new Location("location1");
+ OnlineLocation onlineLocation = new OnlineLocation("zoom.com");
+ events.editEvent(0, editInformation, startEnd, location1, null);
+ Assertions.assertEquals(events.get(0).getLocation().getName(), "location1");
+ events.editEvent(0, editInformation, startEnd, null, onlineLocation);
+ Assertions.assertEquals(events.get(0).getLink().getLink(), "zoom.com");
+ }
+
+ @Test
+ void editEvent_changeTime_StartEndTimeChanged() throws NuScheduleException {
+ EventList events = new EventList();
+ Location location = new Location("location");
+ LocalDateTime start = LocalDateTime.parse("2020-02-02T20:00");
+ LocalDateTime end = LocalDateTime.parse("2020-02-02T21:00");
+ event.Event existing = new PersonalEvent("existing", location, start, end);
+ events.addEvent(existing);
+
+ start = LocalDateTime.parse("2020-02-02T19:00");
+ end = LocalDateTime.parse("2020-02-02T22:00");
+ LocalDateTime[] startEnd = new LocalDateTime[2];
+ startEnd[0] = start;
+ startEnd[1] = end;
+ String[] editInformation = {"", "", "", "", ""};
+ events.editEvent(0, editInformation, startEnd, null, null);
+ Assertions.assertEquals(events.get(0).getStartDateTime(), start);
+ Assertions.assertEquals(events.get(0).getEndDateTime(), end);
+
+ editInformation[4] = "nil";
+ Command c = new EditCommand(0, editInformation, startEnd, null, null);
+ Storage storage = new Storage("data/events.txt", "data/UserInfo.txt");
+ c.execute(events, new LocationList(), new BusStopList(), new UI(), storage, new UserInfo());
+ // end set to null, getEndDate will get start if end is null
+ Assertions.assertEquals(start, events.get(0).getEndDateTime());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/command/FindCommandTest.java b/src/test/java/command/FindCommandTest.java
new file mode 100644
index 0000000000..158942e041
--- /dev/null
+++ b/src/test/java/command/FindCommandTest.java
@@ -0,0 +1,32 @@
+package command;
+
+import exception.DateFormatException;
+import exception.EmptyFindDateException;
+import exception.EmptyFindException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import parser.Parser;
+
+public class FindCommandTest {
+
+ @Test
+ void execute_NoDescriptionGiven_EmptyEventException() {
+ Assertions.assertThrows(EmptyFindException.class, () -> {
+ Command c = Parser.parse("find", null,0);
+ });
+ }
+
+ @Test
+ void execute_NoDateGiven_EmptyFindDateException() {
+ Assertions.assertThrows(EmptyFindDateException.class, () -> {
+ Command c = Parser.parse("date", null,0);
+ });
+ }
+
+ @Test
+ void execute_InvalidTimeDate_DateFormatException() {
+ Assertions.assertThrows(DateFormatException.class, () -> {
+ Command c = Parser.parse("date 2100", null,0);
+ });
+ }
+}
diff --git a/src/test/java/command/LocateCommandTest.java b/src/test/java/command/LocateCommandTest.java
new file mode 100644
index 0000000000..22c9401089
--- /dev/null
+++ b/src/test/java/command/LocateCommandTest.java
@@ -0,0 +1,34 @@
+package command;
+
+import exception.EmptyLocationException;
+import exception.InvalidEventIndexException;
+import exception.InvalidLocationException;
+import locationlist.LocationList;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import parser.Parser;
+
+public class LocateCommandTest {
+ private LocationList locations = new LocationList();
+
+ @Test
+ void execute_EmptyLocation_EmptyLocationException() {
+ Assertions.assertThrows(EmptyLocationException.class, () -> {
+ Command d = Parser.parse("locate", null, 0);
+ });
+ }
+
+ @Test
+ void execute_InvalidEventIndex_InvalidEventIndexException() {
+ Assertions.assertThrows(InvalidEventIndexException.class, () -> {
+ Command d = Parser.parse("locate -1", locations, 0);
+ });
+ }
+
+ @Test
+ void execute_LocationNotFound_InvalidLocationException() {
+ Assertions.assertThrows(InvalidLocationException.class, () -> {
+ Command d = Parser.parse("locate home", locations, 0);
+ });
+ }
+}
diff --git a/src/test/java/command/SortCommandTest.java b/src/test/java/command/SortCommandTest.java
new file mode 100644
index 0000000000..7c6967060c
--- /dev/null
+++ b/src/test/java/command/SortCommandTest.java
@@ -0,0 +1,95 @@
+package command;
+
+import event.Assignment;
+import event.Class;
+import eventlist.EventList;
+import exception.InvalidSortCriteriaException;
+import exception.NoSortCriteriaException;
+import exception.NuScheduleException;
+import location.Location;
+import location.OnlineLocation;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import parser.Parser;
+
+import java.time.LocalDateTime;
+import java.util.Arrays;
+
+
+class SortCommandTest {
+
+ @Test
+ void execute_NoSortCriteria_NoSortCriteriaException() {
+ Assertions.assertThrows(NoSortCriteriaException.class, () -> {
+ Command d = Parser.parse("sort", null,0);
+ });
+ }
+
+ @Test
+ void execute_InvalidSortCriteria_InvalidSortCriteriaException() {
+ Assertions.assertThrows(InvalidSortCriteriaException.class, () -> {
+ Command d = Parser.parse("sort something", null,0);
+ });
+ }
+
+ @Test
+ void execute_descriptionCriteriaGiven_SortByDescription() throws NuScheduleException {
+ EventList events = new EventList();
+ Location location = new Location("location");
+ String[] descriptions = {"eeeee", "ddddd", "ccccc", "bbbbb", "aaaaa"};
+ LocalDateTime by = LocalDateTime.parse("2020-02-02T20:00");
+ for (int i = 0; i < 5; i++) {
+ events.addEvent(new Assignment(descriptions[i], location, by));
+ }
+ events.sortEvent("description");
+ Arrays.sort(descriptions);
+ for (int i = 0; i < 5; i++) {
+ Assertions.assertEquals(descriptions[i], events.get(i).getDescription());
+ }
+ }
+
+ @Test
+ void execute_timeCriteriaGiven_SortByEndTime() throws NuScheduleException {
+ EventList events = new EventList();
+ Location location = new Location("location");
+ LocalDateTime[] bys = {LocalDateTime.parse("2020-02-02T20:00"), LocalDateTime.parse("2020-02-02T19:00"),
+ LocalDateTime.parse("2020-02-02T18:00")};
+ for (int i = 0; i < 3; i++) {
+ events.addEvent(new Assignment("description", location, bys[i]));
+ }
+ events.sortEvent("time");
+ Arrays.sort(bys);
+ for (int i = 0; i < 3; i++) {
+ Assertions.assertEquals(bys[i], events.get(i).getStartDateTime());
+ }
+ }
+
+ @Test
+ void execute_locationCriteriaGiven_SortByLocation() throws NuScheduleException {
+ EventList events = new EventList();
+ Location[] locations = {new Location("cccc"), new Location("bbbb"), new Location("aaaa")};
+ OnlineLocation[] onlineLocation = {new OnlineLocation("cccc.com"), new OnlineLocation("bbbb.com"),
+ new OnlineLocation("aaaa.com")};
+ LocalDateTime start = LocalDateTime.parse("2020-02-02T20:00");
+ LocalDateTime end = LocalDateTime.parse("2020-02-02T21:00");
+ int j = 0;
+ int k = 0;
+ for (int i = 0; i < 6; i++) {
+ if (i % 2 == 0) {
+ events.addEvent(new Class("description", locations[j], start, end));
+ j++;
+ } else {
+ events.addEvent(new Class("description", onlineLocation[k], start, end));
+ k++;
+ }
+ }
+ events.sortEvent("location");
+ // by locations will be sorted on top of online locations
+ Assertions.assertEquals("aaaa", events.get(0).getLocation().getName());
+ Assertions.assertEquals("bbbb", events.get(1).getLocation().getName());
+ Assertions.assertEquals("cccc", events.get(2).getLocation().getName());
+ Assertions.assertEquals("aaaa.com", events.get(3).getLink().getLink());
+ Assertions.assertEquals("bbbb.com", events.get(4).getLink().getLink());
+ Assertions.assertEquals("cccc.com", events.get(5).getLink().getLink());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/duke/DukeTest.java b/src/test/java/test/NuScheduleTest.java
similarity index 82%
rename from src/test/java/seedu/duke/DukeTest.java
rename to src/test/java/test/NuScheduleTest.java
index 2dda5fd651..b090ba5b8b 100644
--- a/src/test/java/seedu/duke/DukeTest.java
+++ b/src/test/java/test/NuScheduleTest.java
@@ -1,10 +1,10 @@
-package seedu.duke;
-
-import static org.junit.jupiter.api.Assertions.assertTrue;
+package test;
import org.junit.jupiter.api.Test;
-class DukeTest {
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class NuScheduleTest {
@Test
public void sampleTest() {
assertTrue(true);
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
deleted file mode 100644
index 892cb6cae7..0000000000
--- a/text-ui-test/EXPECTED.TXT
+++ /dev/null
@@ -1,9 +0,0 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
-
-What is your name?
-Hello James Gosling
diff --git a/text-ui-test/data/bus_stops.txt b/text-ui-test/data/bus_stops.txt
new file mode 100644
index 0000000000..2151b17204
--- /dev/null
+++ b/text-ui-test/data/bus_stops.txt
@@ -0,0 +1,7 @@
+EA:B2,C,BTC2
+Raffles Hall:B2,C
+Information Technology:A2,B1,B2,D1
+Opp YIH:A2,B1,B2,D1
+NUS Museum:A2,BTC1,BTC2,C,D1,D2
+YIH:A1,B1,BTC1,D1
+CLB:A1,B1,BTC1,D1
\ No newline at end of file
diff --git a/text-ui-test/data/locations.txt b/text-ui-test/data/locations.txt
new file mode 100644
index 0000000000..64a3bb1a09
--- /dev/null
+++ b/text-ui-test/data/locations.txt
@@ -0,0 +1,20 @@
+BLK/EA/EA
+BLK/EA/Information Technology
+BLK/E1A/EA
+BLK/EW1/EA,Information Technology
+BLK/EW1A/EA
+BLK/E2/EA
+BLK/E3/EA,Raffles Hall
+BLK/E3A/EA
+BLK/E4/Information Technology
+BLK/E4A/Opp YIH,YIH
+BLK/E5/Information Technology
+BLK/E5A/Raffles Hall
+BLK/E6/Opp YIH,YIH
+BLK/IT/Information Technology,CLB
+H/Raffles Hall/Raffles Hall,NUS Museum
+L/LT1/E2
+L/LT2/E2
+L/LT6/E4
+L/LT7/EA
+L/LT7A/EA
\ No newline at end of file
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
deleted file mode 100644
index f6ec2e9f95..0000000000
--- a/text-ui-test/input.txt
+++ /dev/null
@@ -1 +0,0 @@
-James Gosling
\ No newline at end of file
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
deleted file mode 100644
index 25ac7a2989..0000000000
--- a/text-ui-test/runtest.bat
+++ /dev/null
@@ -1,19 +0,0 @@
-@echo off
-setlocal enableextensions
-pushd %~dp0
-
-cd ..
-call gradlew clean shadowJar
-
-cd build\libs
-for /f "tokens=*" %%a in (
- 'dir /b *.jar'
-) do (
- set jarloc=%%a
-)
-
-java -jar %jarloc% < ..\..\text-ui-test\input.txt > ..\..\text-ui-test\ACTUAL.TXT
-
-cd ..\..\text-ui-test
-
-FC ACTUAL.TXT EXPECTED.TXT >NUL && ECHO Test passed! || Echo Test failed!
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
deleted file mode 100755
index 1dcbd12021..0000000000
--- a/text-ui-test/runtest.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env bash
-
-# change to script directory
-cd "${0%/*}"
-
-cd ..
-./gradlew clean shadowJar
-
-cd text-ui-test
-
-java -jar $(find ../build/libs/ -mindepth 1 -print -quit) < input.txt > ACTUAL.TXT
-
-cp EXPECTED.TXT EXPECTED-UNIX.TXT
-dos2unix EXPECTED-UNIX.TXT ACTUAL.TXT
-diff EXPECTED-UNIX.TXT ACTUAL.TXT
-if [ $? -eq 0 ]
-then
- echo "Test passed!"
- exit 0
-else
- echo "Test failed!"
- exit 1
-fi