:information_source: **Note:** If a command fails its execution, it will not call `Model#commitAddressBook()`, so the address book state will not be saved into the `addressBookStateList`.
+This command is then executed to return `CommandResult` which is either shown on the result display of the GUI as:
-
+* "You're free!"
+* Or "Sorry, you're not free. Entries occupying that time interval listed below!". The occupying entries are shown in
+ the entry list at the main window.
-Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoAddressBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous address book state, and restores the address book to that state.
+The following activity diagram summarizes what happens when a user executes the new command:
-
+
-:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The `undo` command uses `Model#canUndoAddressBook()` to check if this is the case. If so, it will return an error to the user rather
-than attempting to perform the undo.
+The implementation of this command is similar to the List Command but requires a new predicate class to be created.
+A `ListOccupyingEntryPredicate` class is implemented that provides a predicate that accepts user provided start and end
+interval. The predicate is provided to `ModelManager#updateFilteredEntryList` and updates the entry list according to
+the condition under `ListOccupyingEntryPredicate#test`.
+The following sequence diagram outlines how the free operation works:
+
+
+
+
:information_source: **Note:** Details about creation of `ListOccupyingEntryPredicate`
+has been omitted for simplicity.
-The following sequence diagram shows how the undo operation works:
+### Merge Schedule and Task
-
+The merger attempts to combine the functionalities of both the Task and Schedule classes. \
+As the Task and Schedule classes are similar in features, we can merge them into an Entry class for maintainability.
-
:information_source: **Note:** The lifeline for `UndoCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+
-
+Previously, we allowed schedules and tasks to be added separately through using two commands, `sadd` and `tadd`. \
+Combining them into an Entry task, we implement an "eadd" command.
-The `redo` command does the opposite — it calls `Model#redoAddressBook()`, which shifts the `currentStatePointer` once to the right, pointing to the previously undone state, and restores the address book to that state.
+Below, we can see the before and after activity diagrams involving this merger.
-
:information_source: **Note:** If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone AddressBook states to restore. The `redo` command uses `Model#canRedoAddressBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
+**Before:** \
+
-
+**After:** \
+
-Step 5. The user then decides to execute the command `list`. Commands that do not modify the address book, such as `list`, will usually not call `Model#commitAddressBook()`, `Model#undoAddressBook()` or `Model#redoAddressBook()`. Thus, the `addressBookStateList` remains unchanged.
+### Filtering entries via tags
-
+Following the proposal above, there were no commands that utilise the tags attached to the objects. Hence, this proposal
+aims to allow filtering these entries via their tags.
-Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add n/David …` command. This is the behavior that most modern desktop applications follow.
+The Model class will be required to implement the `updateFilteredEntryList` which can incorporate
+`updateFilteredTaskList` or `updateFilteredScheduleList` implemented in the previous two classes. This method will then
+accept an argument of type `EntryTagContainsKeywordsPredicate`.
-
+The following diagram omits the parser object created, namely `FilterEntryCommandParser` for simplicity.
-The following activity diagram summarizes what happens when a user executes a new command:
+
-
+**Design consideration**
-#### Design consideration:
+1. Allow filtering by more than one tag.
+1. Decide whether the filtering above considers Union or Intersection of tags.
-##### Aspect: How undo & redo executes
+### List entry feature
-* **Alternative 1 (current choice):** Saves the entire address book.
- * Pros: Easy to implement.
- * Cons: May have performance issues in terms of memory usage.
+The list entry mechanism allows users to see all of their entries, or see them by day or by week.
-* **Alternative 2:** Individual command knows how to undo/redo by
- itself.
- * Pros: Will use less memory (e.g. for `delete`, just save the person being deleted).
- * Cons: We must ensure that the implementation of each individual command are correct.
+An outline of the proposed implementation is as follows:
-_{more aspects and alternatives to be added}_
+The `TeachingAssistantParser` should accept command word `elist` and eventually return a `ListEntryCommand`
+back to `LogicManager`. This command can take in one of these three arguments: an empty string, the string “day” or the
+string “week”. The arguments will be parsed by the `ListEntryCommandParser` to determine the behaviour of
+`ListEntryFormatPredicate`. Then, `updateFilteredEntryList` method in the `Model` interface is called, passing in the
+`ListEntryFormatPredicate` as an argument.
-### \[Proposed\] Data archiving
+The following activity diagram (Fig 2.3.1) summarizes what happens when a user executes the list entry command.
-_{Explain here how the data archiving feature will be implemented}_
+
+Fig 2.3.1
+The following sequence diagram (Fig 2.3.2) shows how the list entry operation works:
---------------------------------------------------------------------------------------------------------------------
+
+Fig 2.3.2
+
+### Clear overdue entry feature
+
+Clear overdue entry feature allows users to quickly discard entries that are no longer relevant. i.e. entries with end
+dates that have passed.
+
+An outline of the implementation is as follows:
+
+The `TeachingAssistantParser` should accept another case of command word `eclear` which eventually returns a
+`ClearOverdueEntryCommand` back to `LogicManager`. This command has no arguments and will immediately call
+`clearOverdueEntries` method in `Model` interface. Finally, a new `CommandResult` is created to handle the result of
+this command.
+
+The following sequence diagram (Fig 2.3.3) shows how clear overdue entry command works:
+
+
-## **Documentation, logging, testing, configuration, dev-ops**
+Fig 2.3.3
+
+The following activity diagram (Fig 2.3.4) shows how `Model` executes `clearOverdueEntries`:
+
+
+
+---
+
+# Documentation, logging, testing, configuration, dev-ops
* [Documentation guide](Documentation.md)
* [Testing guide](Testing.md)
@@ -228,129 +317,362 @@ _{Explain here how the data archiving feature will be implemented}_
* [Configuration guide](Configuration.md)
* [DevOps guide](DevOps.md)
---------------------------------------------------------------------------------------------------------------------
+---
-## **Appendix: Requirements**
+# Appendix: Requirements
-### Product scope
+## Product Scope
**Target user profile**:
-* has a need to manage a significant number of contacts
-* prefer desktop apps over other types
-* can type fast
-* prefers typing to mouse interactions
-* is reasonably comfortable using CLI apps
+* Are JC/Secondary school teachers
+* Do not have their schedules and students' contacts digitalised
+* Prefer to use typing over mouse/voice commands
+
+**Value proposition**: efficient tool to keep track of schedules (i.e. entries) as well as find and add student contact
+information easily
+
+---
+
+## User Stories
-**Value proposition**: manage contacts faster than a typical mouse/GUI driven app
+### Contacts
+Priority | As a... | I want to... | So that I can...
+--- | --- | --- | ---
+high | teacher | add a contact | have a consolidated list of contacts that I require
+high | teacher | delete a contact | remove a contact I no longer need
+medium | teacher | edit a contact | modify contact details without going through the tedious process of removing and re-adding the contact
+high | teacher | find a contact based on name | quickly find the details of a specific contact I need
+high | teacher | list all contacts | keep track of the contacts of all the people I have saved
+medium | teacher | filter contacts via tags | categorise and find a group of contacts easily
-### User stories
+### Entries
-Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
+Priority | As a... | I want to... | So that I can...
+--- | --- | --- | ---
+high | teacher | add an entry | have a consolidated list of entries representing my schedule
+high | teacher | delete an entry | remove entries that have been cancelled
+medium | teacher | edit an entry | modify entry details without going through the tedious process of removing and re-adding the entry; in case an entry has been rescheduled
+high | teacher | list my entries according to day/week | view my entries in a more organised way
+high | teacher | find an entry based on name | see the details of an entry I have saved
+low | teacher | view all entries in my schedule for a specific time period | check if I am free during that timing
+medium | teacher | filter entries via tags | categorise and find entries easily
+medium | teacher | clear all entries that have passed | easily see ongoing or future entries without past entries cluttering the list
-| Priority | As a … | I want to … | So that I can… |
-| -------- | ------------------------------------------ | ------------------------------ | ---------------------------------------------------------------------- |
-| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App |
-| `* * *` | user | add a new person | |
-| `* * *` | user | delete a person | remove entries that I no longer need |
-| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list |
-| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident |
-| `*` | user with many persons in the address book | sort persons by name | locate a person easily |
+### Others
-*{More to be added}*
+Priority | As a... | I want to... | So that I can...
+--------- | --------- | -------------- | -----------------
+high | forgetful teacher | be prompted for the User Guide | refer to it and type all commands without memorising their syntax
+low | first time user | clear all my contacts and entries from teaching assistant | clear all sample data easily
-### Use cases
+---
+
+## Use Cases
-(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
+(For all use cases below, the **System** is the `Teaching Assistant` and the **Actor** is the `user`, unless specified
+otherwise)
-**Use case: Delete a person**
+### Use case: UC01 - Add a contact
**MSS**
-1. User requests to list persons
-2. AddressBook shows a list of persons
-3. User requests to delete a specific person in the list
-4. AddressBook deletes the person
+1. User requests to add a contact
+2. Teaching Assistant adds the contact into the list
- Use case ends.
+ Use case ends.
**Extensions**
-* 2a. The list is empty.
+* 2a. The given field(s) are invalid.
+
+ * 2a1. Teaching Assistant shows an error message
+
+ Use case ends.
+
+
+* 2b. The contact to be added already exists in Teaching Assistant.
+
+ * 2b1. Teaching Assistant shows an error message.
+
+ Use case ends.
+
+
+
+### Use case: UC02 - Delete an Entry
+
+**MSS**
+
+1. User requests to list entries **(UC03)**
+2. Teaching Assistant shows a list of entries
+3. User requests to delete a specific entry in the list
+4. Teaching Assistant deletes the specified entry
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list of entries is empty.
Use case ends.
-* 3a. The given index is invalid.
+* 3a. The given index is invalid
+ * 3a1. Teaching Assistant shows an error message.
- * 3a1. AddressBook shows an error message.
+ Use case ends.
- Use case resumes at step 2.
+
-*{More to be added}*
+### Use case: UC03 - List entries
-### Non-Functional Requirements
+**MSS**
-1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed.
-2. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
-3. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
+1. User requests to list entries.
+2. Teaching Assistant shows a list of entries.
-*{More to be added}*
+ Use case ends.
-### Glossary
+**Extensions**
-* **Mainstream OS**: Windows, Linux, Unix, OS-X
-* **Private contact detail**: A contact detail that is not meant to be shared with others
+* 1a. User requests to list entries that occurs today.
---------------------------------------------------------------------------------------------------------------------
+ * 1a1. Teaching Assistant shows a list of entries that happen today.
-## **Appendix: Instructions for manual testing**
+ Use case ends.
-Given below are instructions to test the app manually.
+* 1b. User requests to list entries that occurs this week.
-
:information_source: **Note:** These instructions only provide a starting point for testers to work on;
-testers are expected to do more *exploratory* testing.
+ * 1b1. Teaching Assistant shows a list of entries that occurs this week
-
+ Use case ends.
-### Launch and shutdown
+* 1c. The given parameter is invalid.
-1. Initial launch
+ * 1c1. Teaching Assistant shows an error message.
- 1. Download the jar file and copy into an empty folder
+ Use case ends.
- 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
+
-1. Saving window preferences
+### Use case: UC04 - Check if user is free on a given timeslot
- 1. Resize the window to an optimum size. Move the window to a different location. Close the window.
+**MSS**
- 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained.
+1. User requests to if he/she is free on a given timeslot.
+2. Teaching Assistant replies that the user is free.
-1. _{ more test cases … }_
+ Use case ends.
-### Deleting a person
+* 1a. The given timeslot is invalid.
-1. Deleting a person while all persons are being shown
+ * 1a1. Teaching Assistant shows an error message.
- 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
+ Use case ends
- 1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated.
+* 1b. The user is not free on the given timeslot.
- 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.
+ * 1b1. Teaching Assistant replies that the user is not free.
- 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous.
+ * 1b2. Teaching Assistant shows a list of entries that coincide with the given timeslot.
-1. _{ more test cases … }_
+ Use case ends
-### Saving data
+### Use case: UC05 - Find a contact
-1. Dealing with missing/corrupted data files
+**MSS**
- 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
+1. User requests to find a contact with specified keyword(s)
+2. Teaching Assistant replies to the user contacts that matches the keyword(s)
+
+ Use case ends.
+
+* 1a. The given keyword(s) are invalid
+
+ * 1a1. Teaching Assistant shows an error message.
+
+ Use case ends
+
+* 2a. No contact matches the specified keyword(s).
+
+ * 2a1. Teaching Assistant shows an empty list.
+
+ Use case ends
+
+---
+
+## Non-Functional Requirements
+
+1. Should work on any mainstream OS as long as it has Java 11 or above installed.
+2. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be
+ able to accomplish most of the tasks faster using commands than using the mouse.
+3. The system should be usable by a novice who has never used virtual management applications.
+4. The user interface should be intuitive enough for users who are not IT-savvy.
+5. The product is offered as an open source software.
+
+---
+
+## Glossary
+
+### JC
+
+Junior College (JC) is the post-secondary education level where students are preparing for university. JC is also the
+high-school equivalent in other countries. Hence, JC teachers may be packed with consultation schedules which can
+leverage our software.
+
+### Mainstream OS
+
+Mainstream operating systems are the current operating systems with a significant market share, namely Windows, Linux,
+Unix, and OS-X.
+
+### MSS
+
+Main Success Scenario (MSS) defines the optimal outcome of our commands, i.e. in the case where no errors occurred.
+
+---
-1. _{ more test cases … }_
+# Appendix: Instructions for manual testing
+
+### Adding an entry
+
+1. Adding an entry while all entries are being shown.
+ 1. Prerequisites: The entry should not already exist in the entry list and the new entry's start and end datetime
+ should not overlap with existing entries. List all entries using the `elist` command.
+ 1. Test case: `eadd n/Meeting sd/2021-12-12 13:00 ed/2021-12-12 14:00`
+ Expected: The entry is added to the entry list. Success message with details of the added entry is shown in the
+ result window.
+ 1. Test case: `eadd n/Meeting sd/2021-12-12 19:00 ed/2021-12-12 13:00`
+ Expected: The entry is not added. Error message is shown in the result display indicating that start datetime has
+ to be before end datetime.
+
+### Finding an entry
+
+1. Finding an entry while all entries are being shown.
+ 1. Prerequisites: There should be entries present in the entry list. List all entries using the `elist` command.
+ 1. Test case: `efind Meeting`
+ Expected: Assuming that there is an entry named "Meeting", a message indicating how many entries are listed is
+ shown in the result window. Entry list will only list the entry with the matching name.
+ 1. Test case: `efind Random`
+ Expected: Assuming that there are no entries named Random, a message shown in the result display will indicate 0
+ entries being listed. Entry list will be empty.
+
+### Filtering tags
+
+1. Filtering tags while all entries are being shown.
+ 1. Prerequisites: There should be entries with tags present. List all entries using the `elist` command.
+ 1. Test case: `efilter consultation`
+ Expected: Assuming there is only one entry that has the tag `consultation`, a message is shown in the result
+ display indicating 1 entry is being listed. Entry list will only list the entry with the matching tag.
+ 1. Test case: `efilter CCA Tennis`
+ Expected: Assuming there is only one entry that has both tags `CCA` and `Tennis`, a message is shown in the
+ result display indicating 1 entry is being listed. Entry list will only list the entry with the matching tags.
+
+### Editing an entry
+
+1. Editing an existing entry while all entries are being shown.
+ 1. Prerequisites: There should be entries present in the entry list. List all entries using the `elist` command.
+ 1. Test case: `eedit 1 p/97865534`
+ Expected: The entry that is numbered "1." is edited such that the previous phone number is now changed to the new
+ one specified. Details of the edited entry is shown in the result display.
+ 1. Test case: `eedit 1`
+ Expected: No entry is edited. Error details shown in the result display indicating at least one field should be
+ given.
+
+### Listing entries
+
+1. Listing entries while there are entries present and are not currently all listed.
+ 1. Prerequisites: There should be entries present in the entry list but not all of them are seen.
+ 1. Test case: `elist`
+ Expected: Success message indicating how many entries are listed is shown in the result display. All entries that
+ are present are shown in the entry list.
+ 1. Test case: `elist day`
+ Expected: A message indicating how many entries are listed is shown in the result display. All entries that have
+ the same date as the current date are shown in the entry list.
+ 1. Test case: `elist week`
+ Expected: A message indicating how many entries are listed is shown in the result display. All entries that have
+ date 6 days from the current date or same date as current date are shown in the entry list.
+
+### Checking if interval is free
+
+1. Checking if an interval is free while there are entries present.
+ 1. Prerequisites: There should be entries present in the entry list. The start and end datetime field provided
+ should fall within the datetime of at least one entry to test the "Not free" response.
+ 1. Test case: `free sd/2021-12-12 13:00 ed/2021-12-12 14:00`
+ Expected: Assuming there is only one entry that falls within this interval, message indicating the interval is
+ not free is shown in the result display. Entry list will only list the entry that occupies the interval.
+ 1. Test case: `free sd/2021-11-13 13:00 ed/2021-11-13 14:00`
+ Expected: Assuming there are no entries that falls within this interval, message indicating the interval is free
+ is shown in the result display. Entry list will be empty.
+
+### Deleting entries
+
+1. Deleting an entry while all entries are being shown.
+ 1. Prerequisites: List all entries using the `elist` command. Multiple entries in the list.
+ 1. Test case: `edelete 0`
+ Expected: No entry is deleted. Error details shown in the result display. Entry list remains the same.
+ 1. Test case: `edelete 1`
+ Expected: The entry that is numbered "1." is deleted from the entry list. Details of the deleted entry is shown
+ in the result display.
+
+### Clearing overdue entries
+
+1. Clearing overdue entries while there are overdue entries present.
+ 1. Prerequisites: There should be overdue entries (shown as a red entry box) in the entry list.
+ 1. Test case: `eclear`
+ Expected: Success message is shown. All entries that are before current date and time should be deleted.
+
+### Adding a contact
+
+1. Adding a contact while all contacts are being shown.
+ 1. Prerequisites: The contact should not already exist in the list. List all contacts using the `clist` command.
+ 1. Test case: `cadd n/Danny Tan p/98765432 e/danny@email.com`
+ Expected: The contact is added into the contact list. Success message with details of the added contact is shown in the
+ result window.
+ 1. Doing the exact same command one more time will fail with an error message as duplicated contacts are not allowed to be added into the list
+
+### Finding contacts
+
+1. Finding contacts while all contacts are being shown
+ 1. Prerequisites: There should be at least a contact present in the contact list. List all contacts using the `clist` command.
+ 1. Test case: `cfind Danny`
+ Expected: Assuming that there is at least a contact named "Danny", a message indicating how many contacts are listed is
+ shown in the result window. Contact list will only list the contacts with the matching name.
+ 1. Test case: `cfind Random`
+ Expected: Assuming that there are no contacts named "Random", a message shown in the result display will indicate 0
+ contacts being listed. Contact list will be empty.
+
+### Filtering contacts via tags
+
+1. Filtering tags while all contacts are being shown.
+ 1. Prerequisites: There should be contacts with tags present. List all contacts using the `clist` command.
+ 1. Test case: `cfilter friend`
+ Expected: Assuming there is only one contact that has the tag `friend`, a message is shown in the result
+ display indicating 1 contact is being listed. Contact list will only list the contact with the matching tag.
+ 1. Test case: `cfilter family important`
+ Expected: Assuming there is only one contact that has both the tags `family` and `important`, a message is shown in the
+ result display indicating 1 contact is being listed. Contact list will only list the contact with the matching tags.
+
+### Editing a contact
+
+1. Editing an existing contact while all contacts are being shown.
+ 1. Prerequisites: There should be contacts present in the contact list. List all contacts using the `clist` command.
+ 1. Test case: `cedit 1 n/Amy Toh`
+ Expected: The contact that is numbered "1." is edited such that the previous name is now changed to the new
+ one specified. Details of the edited contact is shown in the result display.
+ 1. Test case: `cedit 1 n/Amy Toh p/98761234`
+ Expected: The contact that is numbered "1." is edited such that the previous name and phone number
+ are now changed to the new ones specified. Details of the edited contact is shown in the result display.
+ 1. Test case: `cedit 1`
+ Expected: No contact will be edited. Error details shown in the result display indicating at least one field should be
+ given.
+
+### Deleting a contact
+
+1. Deleting a contact while all contacts are being shown.
+ 1. Prerequisites: List all contacts using the `clist` command. Contact list must not be empty.
+ 1. Test case: `cdelete 0`
+ Expected: No contact is deleted. Error details regarding the invalid argument will be
+ shown in the result display. Contact list remains the same.
+ 1. Test case: `cdelete 1`
+ Expected: The contact that is numbered "1." is deleted from the contact list. Details of the deleted contact is shown
+ in the result display.
diff --git a/docs/SettingUp.md b/docs/SettingUp.md
index 77667c6d581..c9a7ff40488 100644
--- a/docs/SettingUp.md
+++ b/docs/SettingUp.md
@@ -23,7 +23,7 @@ If you plan to use Intellij IDEA (highly recommended):
1. **Import the project as a Gradle project**: Follow the guide [_[se-edu/guides] IDEA: Importing a Gradle project_](https://se-education.org/guides/tutorials/intellijImportGradleProject.html) to import the project into IDEA.
:exclamation: Note: Importing a Gradle project is slightly different from importing a normal Java project.
1. **Verify the setup**:
- 1. Run the `seedu.address.Main` and try a few commands.
+ 1. Run the `seedu.ta.Main` and try a few commands.
1. [Run the tests](Testing.md) to ensure they all pass.
--------------------------------------------------------------------------------------------------------------------
@@ -45,10 +45,10 @@ If you plan to use Intellij IDEA (highly recommended):
1. **Learn the design**
- When you are ready to start coding, we recommend that you get some sense of the overall design by reading about [AddressBook’s architecture](DeveloperGuide.md#architecture).
+ When you are ready to start coding, we recommend that you get some sense of the overall design by reading about [Teaching Assistant’s architecture](DeveloperGuide.md#architecture).
1. **Do the tutorials**
- These tutorials will help you get acquainted with the codebase.
+ These tutorials will help you get acquainted with the Address Book 3 codebase, which is what our codebase was derived from.
* [Tracing code](tutorials/TracingCode.md)
* [Removing fields](tutorials/RemovingFields.md)
diff --git a/docs/Testing.md b/docs/Testing.md
index 8a99e82438a..95c872948b2 100644
--- a/docs/Testing.md
+++ b/docs/Testing.md
@@ -29,8 +29,8 @@ There are two ways to run tests.
This project has three types of tests:
1. *Unit tests* targeting the lowest level methods/classes.
- e.g. `seedu.address.commons.StringUtilTest`
+ e.g. `seedu.ta.commons.util.StringUtilTest`
1. *Integration tests* that are checking the integration of multiple code units (those code units are assumed to be working).
- e.g. `seedu.address.storage.StorageManagerTest`
-1. Hybrids of unit and integration tests. These test are checking multiple code units as well as how the are connected together.
- e.g. `seedu.address.logic.LogicManagerTest`
+ e.g. `seedu.ta.storage.StorageManagerTest`
+1. Hybrids of unit and integration tests. These test are checking multiple code units as well as how they are connected together.
+ e.g. `seedu.ta.logic.LogicManagerTest`
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 3716f3ca8a4..e0e131301fe 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,192 +1,594 @@
---
-layout: page
+layout: page
title: User Guide
---
-AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized for use via a Command Line Interface** (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, AB3 can get your contact management tasks done faster than traditional GUI apps.
+Welcome to the User Guide of _Teaching Assistant_!
-* Table of Contents
-{:toc}
+Are you a JC/Secondary school teacher, having troubles keeping track of all your consultations, meetings and your
+students' contacts? No worries! Our application, _Teaching Assistant_ will provide an all-in-one platform for you to
+organise your entries (schedules) and contacts!
---------------------------------------------------------------------------------------------------------------------
+We target JC/Secondary school teachers as they are the teachers who have a greater need to contact their students
+compared to primary school schools, yet do not have a standardised platform for communication unlike teachers
+in tertiary schools.
-## Quick start
+_Teaching Assistant_ mainly uses a Command Line Interface ([CLI](#terminology)). For users who type fast, they can use
+this application more efficiently than other applications that heavily use Graphical User Interface ([GUI](#terminology)).
-1. Ensure you have Java `11` or above installed in your Computer.
+If you are interested, jump to [Quick Start](#quick-start) to learn how to learn how to start using
+_Teaching Assistant_.
-1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases).
+An image of our UI is shown below!
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+
-1. Double-click the file to start the app. The GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
- 
+---
+
+- [Quick Start](#quick-start)
+- [Structure of User Guide](#structure-of-the-user-guide)
+ - [Reading this User Guide](#reading-this-user-guide)
+ - [Terminology](#terminology)
+ - [General Syntax and Symbols](#general-syntax)
+- [Features](#features)
+ - [Viewing help: `help`](#viewing-help-help)
+ - [Contact](#adding-a-contact-cadd)
+ - [Add: `cadd`](#adding-a-contact-cadd)
+ - [Find: `cfind`](#finding-a-contact-cfind)
+ - [Filter: `cfilter`](#filter-contact-tags-cfilter)
+ - [Edit: `cedit`](#editing-a-contact-cedit)
+ - [List: `clist`](#listing-contacts-clist)
+ - [Delete: `cdelete`](#deleting-a-contact-cdelete)
+ - [Entry](#adding-an-entry-eadd)
+ - [Add: `eadd`](#adding-an-entry-eadd)
+ - [Find: `efind`](#finding-an-entry-efind)
+ - [Filter: `efilter`](#filter-entry-tags-efilter)
+ - [Edit: `eedit`](#editing-an-entry-eedit)
+ - [List: `elist`](#listing-entries-elist)
+ - [Free: `free`](#checking-if-time-interval-is-free-free)
+ - [Delete: `edelete`](#deleting-an-entry-edelete)
+ - [Clear: `eclear`](#clearing-overdue-entries-eclear)
+ - [Clear: `clear`](#clearing-all-data-clear)
+ - [Exit: `exit`](#exiting-the-program-exit)
+ - [Saving the data](#saving-the-data)
+ - [Editing the data file](#editing-the-data-file)
+- [FAQ](#faq)
+- [Command Summary](#command-summary)
+
+---
+
+## Quick Start
-1. Type the command in the command box and press Enter to execute it. e.g. typing **`help`** and pressing Enter will open the help window.
+1. Ensure you have Java 11 installed in your computer. You may install it [here](https://www.oracle.com/sg/java/technologies/javase-jdk11-downloads.html).
+1. Download the latest `teachingAssistant.jar` [here](https://github.com/AY2021S2-CS2103T-W13-4/tp/releases).
+1. Copy the file to the folder you want to use as the *home folder* for your Teaching Assistant.
+1. Double-click the file to start the app. The GUI similar to the image above should appear.
+1. Type the command in the command box and press Enter to execute it.
Some example commands you can try:
+ * **`clist`**: Lists all contacts in Teaching Assistant.
+ * **`cadd n/Danny Tan p/98765432 e/danny@email.com`**: Adds a contact named `Danny Tan` to Teaching Assistant.
+ * **`efind consultation`**: Finds an entry named `consultation` or entries that have `consultation` in their names
+ in Teaching Assistant.
+ * **`exit`**: Exits the app.
+1. Refer to the [Features](#features) below for details of each command.
- * **`list`** : Lists all contacts.
+---
- * **`add`**`n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` : Adds a contact named `John Doe` to the Address Book.
+## Structure of the User Guide
- * **`delete`**`3` : Deletes the 3rd contact shown in the current list.
+Worried about how tedious it will be to read this document? Not to worry! We have structured this User Guide in a way
+that makes it easy and quick for you to find what you need. In this next subsection,
+[Reading this User Guide](#reading-this-user-guide), you can find some tips we have on how to read this guide. The
+next section, [Features](#features), documents the main functionalities of _Teaching Assistant_ and how to use them.
- * **`clear`** : Deletes all contacts.
+The main functions of _Teaching Assistant_ can be summmarised as the following:
+* Contact management
+* Entry (schedules) management
- * **`exit`** : Exits the app.
+If you prefer a brief overview of all the commands, head over to [command summary](#command-summary) which provides you
+with a table of all available commands.
-1. Refer to the [Features](#features) below for details of each command.
+### Reading this User Guide
+This section introduces you to some technical terms and syntax that will be used throughout the User Guide.
+You may want to read through this section thoroughly first before moving on to the next sections.
---------------------------------------------------------------------------------------------------------------------
+##### Terminology
+The image of our GUI is shown below, annotated with descriptions of each GUI component we refer to in this User Guide.
-## Features
+
-
+The table below defines some technical terminology used throughout the User Guide.
-**:information_source: Notes about the command format:**
+Terms | Meaning
+----------------- | -------------------
+CLI | Command Line Interface. In the context of _Teaching Assistant_, this refers to the command box where you can type your commands.
+GUI | Graphical User Interface. It refers to the part of the application you interact with through graphical features such as buttons.
+JSON | JavaScript Object Notation. Your Teaching Assistant data is stored as a JSON file format. You can find out more on their official website [here](https://www.json.org/json-en.html)!
-* Words in `UPPER_CASE` are the parameters to be supplied by the user.
- e.g. in `add n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`.
+##### General Syntax
+The table below explains the general syntax used throughout the User Guide.
-* Items in square brackets are optional.
- e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`.
+Syntax | Meaning
+----------------- | -------------------
+`command` | This markup is used to specify text that can be entered into the command box.
+:bulb: | This icon indicates that the following text is a tip.
+:exclamation: | This icon indicates that the following text is a warning.
+:information_source: | This icon indicates that the following text is a note.
-* Items with `…` after them can be used multiple times including zero times.
- e.g. `[t/TAG]…` can be used as ` ` (i.e. 0 times), `t/friend`, `t/friend t/family` etc.
+---
-* Parameters can be in any order.
- e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable.
+## Features
-* If a parameter is expected only once in the command but you specified it multiple times, only the last occurrence of the parameter will be taken.
- e.g. if you specify `p/12341234 p/56785678`, only `p/56785678` will be taken.
+**:information_source: Notes about the command format:**
-* Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be ignored.
- e.g. if the command specifies `help 123`, it will be interpreted as `help`.
+* Words in `UPPER_CASE` are the parameters to be supplied by the user. e.g. in `cadd n/NAME`, `NAME` is a parameter which
+ can be used as `cadd n/Danny Tan`.
+* Items in the square brackets are optional. Users can choose to leave the field empty.
+* Items with `...` after them can be used multiple times including zero times. e.g. `[t/TAG]...` can be used as ` `
+ (i.e. 0 times), t/friend, t/friend t/family etc.
+* Parameters can be in any order. e.g. if the command specifies `n/NAME p/NUMBER`, `p/NUMBER n/NAME` is also
+ acceptable.
+* If a parameter is expected only once in the command but you specified it multiple times, only the last occurrence of
+ the parameter will be taken. e.g. if you specify `p/12341234 p/56785678`, only `p/56785678` will be taken.
+* Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be
+ ignored. e.g. if the command specifies `help 123`, it will be interpreted as `help`.
-
+---
+
+### Viewing help: `help`
-### Viewing help : `help`
+Shows a message explaining how to access the help page.
-Shows a message explaning how to access the help page.
+**Format**: `help`
-
+**Breakdown**:
+* Command word - `help`
-Format: `help`
+Scenario:
+You are using Teaching Assistant but forget the formats of the commands you want to execute. This command is the only
+one you need to remember! It will bring you to this document.
+
+---
+### Adding a contact: `cadd`
-### Adding a person: `add`
+Adds a contact into Teaching Assistant.
-Adds a person to the address book.
+**Format**: `cadd n/NAME p/NUMBER e/EMAIL [t/TAG]...`
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
+**Breakdown**:
+* Command word - `cadd`
+* Prefixes - `n/`, `p/`, `e/`, `t/`
+* Parameters - `NAME`, `NUMBER`, `EMAIL`, `TAG`
:bulb: **Tip:**
-A person can have any number of tags (including 0)
+An entry's name can be tagged to a contact to easily filter for contacts related an entry.
-Examples:
-* `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01`
-* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567 t/criminal`
+Example(s):
+
+* `cadd n/Danny Tan p/98765432 e/danny@email.com t/student t/english t/consultation1`
+* `cadd n/Amy Yeoh p/12345678 e/amy@email.com t/Colleague t/OwesMoney t/meeting1`
+
+Scenario:
+You want to save the contact details of your students so that you can easily obtain their details when you want to
+reach out to them.
+
+### Finding a contact: `cfind`
+
+Finds all contacts whose name contain all of the specified keywords and displays them as a list.
+
+**Format**: `cfind KEYWORD [MORE_KEYWORDS]...`
+
+**Breakdown**:
+* Command word - `cfind`
+* Parameters - `KEYWORD`, `MORE_KEYWORDS`
+
+
+* Only names are searched.
+* The search is case-insensitive e.g. `amy` will match `Amy`.
+* Only full words will be matched e.g. `Dan` will not match `Danny`.
+* Only contacts matching all keywords will be returned (i.e. AND search). E.g. `Danny Tan` will only return `Danny Tan`.
+* The order of the keywords does not matter. e.g. `Danny Tan` will match `Tan Danny`.
+
+Example(s):
+
+* `cfind Danny` returns `danny` and `Danny Tan`
+* `cfind amy yeoh` returns only `Amy Yeoh`
+
+Below is an illustration of entering `cfind yeoh` on a sample Teaching Assistant:
+
+
+
+Scenario:
+Your student had booked a consultation with you and you want to find his/her contact details by name without scrolling
+through the entire contact list so that you can remind him/her of the arrangement as the date of the consultation draws
+nearer.
+
+### Filter contact tags: `cfilter`
+
+Filters all contacts that have the tags of the specified keywords and displays them as a list with index numbers.
+
+**Format**: `cfilter KEYWORD [MORE_KEYWORDS]...`
+
+**Breakdown**:
+* Command word - `cfilter`
+* Parameters - `KEYWORD`, `MORE_KEYWORDS`
+
+* Only tags are searched.
+* The filtering is case-insensitive e.g. `Student` will match `student`.
+* Only full words will be matched e.g. `Friend` will not match `Friends`.
+* If more than one keyword is provided, only contacts with all the keywords provided will be displayed.
+ E.g. `filter colleagues friends` will only return a contact with both tags `colleagues` and `friends`. Contacts with
+ only one of the 2 keywords will not be displayed.
+* The order of the keywords does not matter. e.g. `colleagues friends` will match `friends colleagues`.
-### Listing all persons : `list`
+Example(s):
-Shows a list of all persons in the address book.
+* `cfilter student english`
+* `cfilter colleague`
-Format: `list`
+Scenario:
+Your students have decided on the roles and responsibilities they will be taking up in your class (e.g. chairperson,
+english representative). You can add a tag to their contact to identify their roles. Then, you can find their contact
+details easily by filtering contacts via tags.
-### Editing a person : `edit`
+### Editing a contact: `cedit`
-Edits an existing person in the address book.
+Edits an existing contact with the specified index in Teaching Assistant.
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
+**Format**: `cedit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [t/TAG]...`
-* Edits the person at the specified `INDEX`. The index refers to the index number shown in the displayed person list. The index **must be a positive integer** 1, 2, 3, …
+**Breakdown**:
+* Command word - `cedit`
+* Prefixes - `n/`, `p/`, `e/`, `t/`
+* Parameters - `INDEX`, `NAME`, `NUMBER`, `EMAIL`, `TAG`
+
+
+* `INDEX` refers to the index numer shown in the displayed entry list.
+* `INDEX` must be a positive integer 1,2,3, ...
* At least one of the optional fields must be provided.
* Existing values will be updated to the input values.
-* When editing tags, the existing tags of the person will be removed i.e adding of tags is not cumulative.
-* You can remove all the person’s tags by typing `t/` without
- specifying any tags after it.
+* When editing tags, the existing tags of the contact will be removed i.e. adding of tags is not cumulative.
+* You can remove all the contact’s tags by typing `t/` without specifying any tags after it.
-Examples:
-* `edit 1 p/91234567 e/johndoe@example.com` Edits the phone number and email address of the 1st person to be `91234567` and `johndoe@example.com` respectively.
-* `edit 2 n/Betsy Crower t/` Edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags.
+Example(s):
-### Locating persons by name: `find`
+* `cedit 1 p/91234567 e/alexyeoh@example.com` Edits the phone number and email address of the contact corresponding to
+ index 1 and to `p/91234567` and `alexyeoh@example.com` respectively.
+* `cedit 1 n/Bernice Yu Xiao Ling t/` Edits the name of the contact corresponding to index 1 to be `Bernice Yu Xiao Ling`
+ and clears all existing tags.
+
+Below is an illustration of entering `cedit 1 n/Bernice Yu Xiao Ling t/` into a sample Teaching Assistant:
-Finds persons whose names contain any of the given keywords.
+
+Scenario:
+Your student had recently changed his/her phone number and you want to update his/her contact details without the
+hassle of deleting his/her old contact and then subsequently adding a new updated contact.
-Format: `find KEYWORD [MORE_KEYWORDS]`
+### Listing contacts: `clist`
-* The search is case-insensitive. e.g `hans` will match `Hans`
-* The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans`
-* Only the name is searched.
-* Only full words will be matched e.g. `Han` will not match `Hans`
-* Persons matching at least one keyword will be returned (i.e. `OR` search).
- e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang`
+Lists all the contacts in Teaching Assistant.
-Examples:
-* `find John` returns `john` and `John Doe`
-* `find alex david` returns `Alex Yeoh`, `David Li`
- 
+**Format**: `clist`
-### Deleting a person : `delete`
+**Breakdown**:
+* Command word - `clist`
-Deletes the specified person from the address book.
+Scenario: You want to look at all the contacts you have saved.
-Format: `delete INDEX`
+### Deleting a contact: `cdelete`
-* Deletes the person at the specified `INDEX`.
-* The index refers to the index number shown in the displayed person list.
-* The index **must be a positive integer** 1, 2, 3, …
+Deletes an existing contact with the specified index in Teaching Assistant.
-Examples:
-* `list` followed by `delete 2` deletes the 2nd person in the address book.
-* `find Betsy` followed by `delete 1` deletes the 1st person in the results of the `find` command.
+**Format**: `cdelete INDEX`
-### Clearing all entries : `clear`
+**Breakdown**:
+* Command word - `cdelete`
+* Parameters - `INDEX`
-Clears all entries from the address book.
-Format: `clear`
+* `INDEX` refers to the index number shown in the displayed contact list.
+* `INDEX` must be a positive integer 1, 2, 3, ...
-### Exiting the program : `exit`
+Example(s):
-Exits the program.
+* `cdelete 1`
-Format: `exit`
+Scenario: Your students have long graduated and you will not be contacting them anymore. You want to remove their
+contacts to make space for the contacts of your new students.
-### Saving the data
+---
-AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+### Adding an entry: `eadd`
-### Editing the data file
+Adds a new entry into Teaching Assistant.
-AddressBook data are saved as a JSON file `[JAR file location]/data/addressbook.json`. Advanced users are welcome to update data directly by editing that data file.
+**Format**: `eadd n/NAME sd/START_DATE ed/END_DATE [t/TAG]...`
-
:exclamation: **Caution:**
-If your changes to the data file makes its format invalid, AddressBook will discard all data and start with an empty data file at the next run.
+**Breakdown**:
+* Command word - `eadd`
+* Prefixes - `n/`, `sd/`, `ed/`, `t/`
+* Parameters - `NAME`, `START_DATE`, `END_DATE`, `TAG`
+
+
+* `START DATE` and `END DATE` are in the format `yyyy-mm-dd HH:MM`.
+* `START DATE` should be before `END DATE`.
+* Entries cannot overlap. i.e. Entries with overlapping timings will not be added.
+* Addition of entries which start and end in the past are allowed but the GUI will show a red entry card.
+
+Example(s):
+
+* `eadd n/meeting sd/2021-06-06 21:00 ed/2021-06-06 23:00 t/meeting t/needprep`
+* `eadd n/consultation 1 sd/2021-06-07 22:00 ed/2021-06-07 23:00 t/consultation`
+
+Below is an illustration of entering `eadd n/consultation 1 sd/2021-06-07 22:00 ed/2021-06-07 23:00 t/consultation`
+into a sample Teaching Assistant:
+
+
+
+Scenario: You want to add entries into Teaching Assistant to keep track of your schedule.
+
+### Finding an entry: `efind`
+
+Finds all entries whose name contain all of the specified keywords and displays them as a list.
+
+**Format**: `efind KEYWORD [MORE_KEYWORDS]...`
+
+**Breakdown**:
+* Command word - `efind`
+* Parameters - `KEYWORD`, `MORE_KEYWORDS`
+
+
+* Only names are searched.
+* The search is case-insensitive e.g. `meeting` will match `Meeting`.
+* Only full words will be matched e.g. `meeting` will not match `meetings`.
+* Only entries matching all keywords will be returned (i.e. AND search). E.g. `meeting 1` will only return
+ `meeting 1`.
+* The order of the keywords does not matter. e.g. `teaching assistant` will match `assistant teaching`.
+
+Example(s):
+
+* `efind consultation` returns `consultation 1` and `consultation 2`
+* `efind consultation 2` returns only `consultation 2`
+
+Scenario: You remember you added a school event entry into Teaching Assistant in the past but forgot its date.
+You can find an entry's details by its name without scrolling through the entire entry list.
+
+### Filter entry tags: `efilter`
+
+Filters all entries that have the tags of the specified keywords and displays them as a list.
+
+**Format**: `efilter KEYWORD [MORE_KEYWORDS]...`
+
+**Breakdown**:
+* Command word - `efilter`
+* Parameters - `KEYWORD`, `MORE_KEYWORDS`
+
+
+* Only tags are searched.
+* The filtering is case-insensitive e.g. `meeting` will match `Meeting`.
+* Only full words will be matched e.g. `meeting` will not match `meetings`.
+* If more than one keyword is provided, only entries with all the keywords provided will be displayed.
+ E.g. `filter meeting needprep` will only return an entry with both tags `meeting` and `needprep`. Entries with only one
+ of the 2 keywords will not be displayed.
+* The order of the keywords does not matter. e.g. `meeting needprep` will match `needprep meeting`.
+
+Example(s):
+
+* `efilter meeting`
+* `efilter meeting needprep`
+
+Below is an example of entering `efliter history` into a sample Teaching Assistant:
+
+
+
+Scenario: You want to filter your entries via the consultation tag you have added to your entries in the past, so that
+you can plan ahead and prepare for your upcoming consultations.
+
+### Editing an entry: `eedit`
+
+Edits an existing entry with the specified index in Teaching Assistant.
+
+**Format**: `eedit INDEX [n/NAME] [sd/START_DATE] [ed/END_DATE] [t/TAG]...`
+
+**Breakdown**:
+* Command word - `eedit`
+* Prefixes - `n/`, `sd/`, `ed/`, `t/`
+* Parameters - `INDEX`, `NAME`, `START_DATE`, `END_DATE`, `TAG`
+
+
+* `INDEX` refers to the index numer shown in the displayed entry list.
+* `INDEX` must be a positive integer 1,2,3, ...
+* At least one of the optional fields must be provided.
+* Existing values will be updated to the input values.
+* When editing tags, the existing tags of the entry will be removed i.e. adding of tags is not cumulative.
+* You can remove all the entry’s tags by typing t/ without specifying any tags after it.
+
+Example(s):
+
+* `eedit 1 sd/2021-06-07 13:00 ed/2021-06-07 14:00` Edits the start and end dates of the entry corresponding to index 1 to
+ be `2021-06-07 13:00` and `2021-06-07 14:00` respectively.
+* `eedit 1 t/` Edits the entry corresponding to index 1 by clearing all existing tags.
+
+Scenario: The Head of Department (HOD) just rescheduled a department meeting. You want to edit an entry's start and end
+dates without first deleting it and then subsequently adding a new entry with the updated dates.
+
+### Listing entries: `elist`
+
+Lists all entries in Teaching Assistant by displaying them as a list sorted by date. Entries can also be listed by day/week.
+
+**Format**: `elist [FORMAT]`
+
+**Breakdown**:
+* Command word - `elist`
+* Parameters - `FORMAT`
+
+
+* No argument: listing all entries
+* `FORMAT` is only restricted to the following cases
+ * `day`: listing entries for today
+ * `week`: listing entries for today as well as the next 6 days
+
+Example(s):
+
+* `elist`
+* `elist day`
+* `elist week`
+
+Below is an illustration of entering `elist week` into a sample Teaching Assistant (The current date is 2021-04-12):
+
+
+
+Scenario: You want to see what is in store for you today so that you can mentally prepare yourself for the busy day ahead.
+
+### Checking if time interval is free: `free`
+
+Indicates if an interval is free. If free, a message indicating that will be shown. If not, entries occupying that
+interval will be shown in the entry list.
+
+**Format**: `free sd/START_DATE ed/END_DATE`
+
+**Breakdown**:
+* Command word - `free`
+* Prefixes - `sd/`, `ed/`
+* Parameters - `START_DATE`, `END_DATE`
+
+
+* `START DATE` and `END DATE` are in the format `yyyy-mm-dd HH:MM`.
+* `START DATE` should be before `END DATE`.
+
+Example(s):
+
+* `free sd/2021-06-06 21:30 ed/2021-06-06 22:30` if the time interval is free, entry list will be empty and _"You're
+ free!"_ message is shown. If not, a message _"Sorry, you're not free. Entries occupying that time interval listed
+ below!"_ will be shown, accompanied by occupying entries in the entry list.
+
+Below is an illustration of entering `free sd/2021-06-06 21:30 ed/2021-06-06 22:30` into a sample Teaching Assistant
+where there are no entries between the given timeslot:
+
+
+
+
+Scenario: Your student just approached you to book a consultation and asks if you are available at a specific timing.
+
+### Deleting an entry: `edelete`
+
+Deletes an existing entry with the specified index in Teaching Assistant.
+
+**Format**: `edelete INDEX`
+
+**Breakdown**:
+* Command word - `edelete`
+* Parameters - `INDEX`
+
+
+* `INDEX` refers to the index number shown in the displayed contact list.
+* `INDEX` must be a positive integer 1, 2, 3, ...
+
+Example(s):
+
+* `edelete 1`
+
+Scenario: A school event you are involved in has been cancelled because of Covid-19 restrictions. You want to delete
+this entry from your schedule.
+
+### Clearing overdue entries: `eclear`
+
+Clears all entries that are overdue.
+
+**Format**: `eclear`
+
+**Breakdown**:
+* Command word - `eclear`
+* An Entry is considered overdue if it has an end date and time that is before current date and time.
+
+Scenario: You still have a lot of entries from the past that you no longer need, and want to quickly remove those
+outdated entries to not clutter the entry list.
+
+---
+
+### Clearing all data: `clear`
+
+Clears all contacts and entries from Teaching Assistant.
+
+**Format**: `clear`
+
+**Breakdown**:
+* Command word - `clear`
+
+Scenario: You opened Teaching Assistant for the first time and want to start using it. You want to clear the sample
+data given before you proceed.
+
+### Exiting the program: `exit`
+
+
:bulb: **Tip:**
+You can still safely exit Teaching Assistant by clicking the close button on the top right of Teaching Assistant, so no worries!
-### Archiving data files `[coming in v2.0]`
+Exits the program.
-_Details coming soon ..._
+**Format**: `exit`
---------------------------------------------------------------------------------------------------------------------
+**Breakdown**:
+* Command word - `exit`
-## FAQ
+Scenario: You survived yet another hectic day! Use this command to exit the app.
-**Q**: How do I transfer my data to another Computer?
-**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.
+---
---------------------------------------------------------------------------------------------------------------------
+### Saving the data
+Teaching Assistant data is saved in the hard disc automatically after any command that changes the data is executed.
+There is no need to save data manually.
+
+### Editing the data file
+Teaching Assistant data is saved as a JSON file `[JAR file location]/data/teachingassistant.json`. Advanced users are
+welcome to update data directly by editing that data file.
+
+
:exclamation: **Caution:**
+If your changes to the data file makes its format invalid, Teaching Assistant will discard all data and start with an empty data file at the next run.
+
+
+---
+
+### FAQ
+**Q**: How do I transfer my data to another computer?
+**A**: Install Teaching Assistant in the other computer and overwrite the empty data file it creates with the file that
+contains the data of your previous Teaching Assistant home folder.
+
+---
## Command summary
-Action | Format, Examples
---------|------------------
-**Add** | `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
e.g., `add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/friend t/colleague`
+### Others
+
+Action | Format
+------- | ------------------
+**View all commands** | `help`
**Clear** | `clear`
-**Delete** | `delete INDEX`
e.g., `delete 3`
-**Edit** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
e.g.,`edit 2 n/James Lee e/jameslee@example.com`
-**Find** | `find KEYWORD [MORE_KEYWORDS]`
e.g., `find James Jake`
-**List** | `list`
-**Help** | `help`
+**Exit** | `exit`
+
+### Contacts
+
+Action | Format
+-------- | ------------------
+**Add** | `cadd n/NAME p/NUMBER e/EMAIL [t/TAG]...`
+**Find** | `cfind KEYWORD [MORE_KEYWORDS]...`
+**Filter tags** | `cfilter KEYWORD [MORE_KEYWORDS]...`
+**Edit** | `cedit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [t/TAG]...`
+**List** | `clist`
+**Delete** | `cdelete INDEX`
+
+### Entries
+
+Action | Format
+-------- | ------------------
+**Add** | `eadd n/NAME sd/START_DATE ed/END_DATE [t/TAG]...`
+**Find** | `efind KEYWORD [MORE_KEYWORDS]...`
+**Filter tags** | `efilter KEYWORD [MORE_KEYWORDS]...`
+**Edit** | `eedit INDEX [n/NAME] [sd/START_DATE] [ed/END_DATE] [t/TAG]...`
+**List** | `elist [FORMAT]`
+**Check if free** | `free sd/START_DATE ed/END_DATE`
+**Delete** | `edelete INDEX`
+**Clear overdue entries** | `eclear`
+
diff --git a/docs/_config.yml b/docs/_config.yml
index 6bd245d8f4e..b3db3a02e1e 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,4 +1,4 @@
-title: "AB-3"
+title: "Teaching Assistant"
theme: minima
header_pages:
@@ -8,7 +8,7 @@ header_pages:
markdown: kramdown
-repository: "se-edu/addressbook-level3"
+repository: "AY2021S2-CS2103T-W13-4/tp"
github_icon: "images/github-icon.png"
plugins:
diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml
index ef81d18c337..6a88d520cc2 100644
--- a/docs/diagrams/ArchitectureSequenceDiagram.puml
+++ b/docs/diagrams/ArchitectureSequenceDiagram.puml
@@ -2,24 +2,24 @@
!include style.puml
Actor User as user USER_COLOR
-Participant ":UI" as ui UI_COLOR
+Participant ":Ui" as ui UI_COLOR
Participant ":Logic" as logic LOGIC_COLOR
Participant ":Model" as model MODEL_COLOR
Participant ":Storage" as storage STORAGE_COLOR
-user -[USER_COLOR]> ui : "delete 1"
+user -[USER_COLOR]> ui : "cdelete 1"
activate ui UI_COLOR
-ui -[UI_COLOR]> logic : execute("delete 1")
+ui -[UI_COLOR]> logic : execute("cdelete 1")
activate logic LOGIC_COLOR
-logic -[LOGIC_COLOR]> model : deletePerson(p)
+logic -[LOGIC_COLOR]> model : deleteContact(c)
activate model MODEL_COLOR
model -[MODEL_COLOR]-> logic
deactivate model
-logic -[LOGIC_COLOR]> storage : saveAddressBook(addressBook)
+logic -[LOGIC_COLOR]> storage : saveTeachingAssistant(teachingAssistant)
activate storage STORAGE_COLOR
storage -[STORAGE_COLOR]> storage : Save to file
diff --git a/docs/diagrams/ClearOverdueEntryCommandActivityDiagram.puml b/docs/diagrams/ClearOverdueEntryCommandActivityDiagram.puml
new file mode 100644
index 00000000000..fadb86b2c85
--- /dev/null
+++ b/docs/diagrams/ClearOverdueEntryCommandActivityDiagram.puml
@@ -0,0 +1,14 @@
+@startuml
+
+start
+
+repeat
+ :Model checks entry;
+ if () then ([Entry End date has passed])
+ :Delete the entry;
+ else ([else])
+ endif
+repeat while () is ([else])
+->[No entries left];
+stop
+@enduml
diff --git a/docs/diagrams/ClearOverdueSequenceDiagram.puml b/docs/diagrams/ClearOverdueSequenceDiagram.puml
new file mode 100644
index 00000000000..211e184fe3c
--- /dev/null
+++ b/docs/diagrams/ClearOverdueSequenceDiagram.puml
@@ -0,0 +1,51 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":TeachingAssistantParser" as TeachingAssistantParser LOGIC_COLOR
+participant ":ClearOverdueEntryCommand" as ClearOverdueEntryCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("eclear")
+activate LogicManager
+
+LogicManager -> TeachingAssistantParser : parseCommand("eclear")
+activate TeachingAssistantParser
+
+create ClearOverdueEntryCommand
+TeachingAssistantParser -> ClearOverdueEntryCommand
+activate ClearOverdueEntryCommand
+
+ClearOverdueEntryCommand --> TeachingAssistantParser
+deactivate ClearOverdueEntryCommand
+
+TeachingAssistantParser --> LogicManager
+deactivate TeachingAssistantParser
+
+LogicManager -> ClearOverdueEntryCommand : execute()
+activate ClearOverdueEntryCommand
+
+ClearOverdueEntryCommand -> Model : clearOverdueEntries()
+activate Model
+
+Model --> ClearOverdueEntryCommand
+deactivate Model
+
+create CommandResult
+ClearOverdueEntryCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> ClearOverdueEntryCommand
+deactivate CommandResult
+
+ClearOverdueEntryCommand --> LogicManager : result
+deactivate ClearOverdueEntryCommand
+[<-- LogicManager
+
+@enduml
diff --git a/docs/diagrams/DeleteContactCommandActivityDiagram.puml b/docs/diagrams/DeleteContactCommandActivityDiagram.puml
new file mode 100644
index 00000000000..493ad68689d
--- /dev/null
+++ b/docs/diagrams/DeleteContactCommandActivityDiagram.puml
@@ -0,0 +1,17 @@
+@startuml
+'https://plantuml.com/activity-diagram-beta
+
+start
+:User executes "cdelete" and specifies
+the id of the contact to be deleted;
+if () then ([id is valid])
+ : GUI shows information of
+ contact that was deleted
+ and the updated list of contacts;
+else ([id is invalid])
+ : GUI shows a prompt to help user
+ type in the right command;
+endif;
+stop
+
+@enduml
diff --git a/docs/diagrams/DeleteContactCommandSequenceDiagram.puml b/docs/diagrams/DeleteContactCommandSequenceDiagram.puml
new file mode 100644
index 00000000000..5af6cf783d0
--- /dev/null
+++ b/docs/diagrams/DeleteContactCommandSequenceDiagram.puml
@@ -0,0 +1,69 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":TeachingAssistantParser" as TeachingAssistantParser LOGIC_COLOR
+participant ":DeleteContactCommandParser" as DeleteContactCommandParser LOGIC_COLOR
+participant "d:DeleteContactCommand" as DeleteContactCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("cdelete 1")
+activate LogicManager
+
+LogicManager -> TeachingAssistantParser : parseCommand("cdelete 1")
+activate TeachingAssistantParser
+
+create DeleteContactCommandParser
+TeachingAssistantParser -> DeleteContactCommandParser
+activate DeleteContactCommandParser
+
+DeleteContactCommandParser --> TeachingAssistantParser
+deactivate DeleteContactCommandParser
+
+TeachingAssistantParser -> DeleteContactCommandParser : parse("1")
+activate DeleteContactCommandParser
+
+create DeleteContactCommand
+DeleteContactCommandParser -> DeleteContactCommand
+activate DeleteContactCommand
+
+DeleteContactCommand --> DeleteContactCommandParser : d
+deactivate DeleteContactCommand
+
+DeleteContactCommandParser --> TeachingAssistantParser : d
+deactivate DeleteContactCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+DeleteContactCommandParser -[hidden]-> TeachingAssistantParser
+destroy DeleteContactCommandParser
+
+TeachingAssistantParser --> LogicManager : d
+deactivate TeachingAssistantParser
+
+LogicManager -> DeleteContactCommand : execute()
+activate DeleteContactCommand
+
+DeleteContactCommand -> Model : deleteContact(1)
+activate Model
+
+Model --> DeleteContactCommand
+deactivate Model
+
+create CommandResult
+DeleteContactCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> DeleteContactCommand
+deactivate CommandResult
+
+DeleteContactCommand --> LogicManager : result
+deactivate DeleteContactCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml
index 1dc2311b245..5af6cf783d0 100644
--- a/docs/diagrams/DeleteSequenceDiagram.puml
+++ b/docs/diagrams/DeleteSequenceDiagram.puml
@@ -3,9 +3,9 @@
box Logic LOGIC_COLOR_T1
participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
-participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR
-participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR
+participant ":TeachingAssistantParser" as TeachingAssistantParser LOGIC_COLOR
+participant ":DeleteContactCommandParser" as DeleteContactCommandParser LOGIC_COLOR
+participant "d:DeleteContactCommand" as DeleteContactCommand LOGIC_COLOR
participant ":CommandResult" as CommandResult LOGIC_COLOR
end box
@@ -13,56 +13,56 @@ box Model MODEL_COLOR_T1
participant ":Model" as Model MODEL_COLOR
end box
-[-> LogicManager : execute("delete 1")
+[-> LogicManager : execute("cdelete 1")
activate LogicManager
-LogicManager -> AddressBookParser : parseCommand("delete 1")
-activate AddressBookParser
+LogicManager -> TeachingAssistantParser : parseCommand("cdelete 1")
+activate TeachingAssistantParser
-create DeleteCommandParser
-AddressBookParser -> DeleteCommandParser
-activate DeleteCommandParser
+create DeleteContactCommandParser
+TeachingAssistantParser -> DeleteContactCommandParser
+activate DeleteContactCommandParser
-DeleteCommandParser --> AddressBookParser
-deactivate DeleteCommandParser
+DeleteContactCommandParser --> TeachingAssistantParser
+deactivate DeleteContactCommandParser
-AddressBookParser -> DeleteCommandParser : parse("1")
-activate DeleteCommandParser
+TeachingAssistantParser -> DeleteContactCommandParser : parse("1")
+activate DeleteContactCommandParser
-create DeleteCommand
-DeleteCommandParser -> DeleteCommand
-activate DeleteCommand
+create DeleteContactCommand
+DeleteContactCommandParser -> DeleteContactCommand
+activate DeleteContactCommand
-DeleteCommand --> DeleteCommandParser : d
-deactivate DeleteCommand
+DeleteContactCommand --> DeleteContactCommandParser : d
+deactivate DeleteContactCommand
-DeleteCommandParser --> AddressBookParser : d
-deactivate DeleteCommandParser
+DeleteContactCommandParser --> TeachingAssistantParser : d
+deactivate DeleteContactCommandParser
'Hidden arrow to position the destroy marker below the end of the activation bar.
-DeleteCommandParser -[hidden]-> AddressBookParser
-destroy DeleteCommandParser
+DeleteContactCommandParser -[hidden]-> TeachingAssistantParser
+destroy DeleteContactCommandParser
-AddressBookParser --> LogicManager : d
-deactivate AddressBookParser
+TeachingAssistantParser --> LogicManager : d
+deactivate TeachingAssistantParser
-LogicManager -> DeleteCommand : execute()
-activate DeleteCommand
+LogicManager -> DeleteContactCommand : execute()
+activate DeleteContactCommand
-DeleteCommand -> Model : deletePerson(1)
+DeleteContactCommand -> Model : deleteContact(1)
activate Model
-Model --> DeleteCommand
+Model --> DeleteContactCommand
deactivate Model
create CommandResult
-DeleteCommand -> CommandResult
+DeleteContactCommand -> CommandResult
activate CommandResult
-CommandResult --> DeleteCommand
+CommandResult --> DeleteContactCommand
deactivate CommandResult
-DeleteCommand --> LogicManager : result
-deactivate DeleteCommand
+DeleteContactCommand --> LogicManager : result
+deactivate DeleteContactCommand
[<--LogicManager
deactivate LogicManager
diff --git a/docs/diagrams/EntryActivityDiagram.puml b/docs/diagrams/EntryActivityDiagram.puml
new file mode 100644
index 00000000000..fbf3178ec30
--- /dev/null
+++ b/docs/diagrams/EntryActivityDiagram.puml
@@ -0,0 +1,7 @@
+@startuml
+start
+:User executes "eadd";
+:Instantiates an Entry object;
+:Saves to Storage;
+stop
+@enduml
diff --git a/docs/diagrams/EntryClassDiagram.puml b/docs/diagrams/EntryClassDiagram.puml
new file mode 100644
index 00000000000..c5b8cfeb9a1
--- /dev/null
+++ b/docs/diagrams/EntryClassDiagram.puml
@@ -0,0 +1,48 @@
+@startuml
+skinparam arrowThickness 1.1
+skinparam classAttributeIconSize 0
+
+hide circle
+
+class EntryName {
+ + {static} NAME_CONSTRAINTS : String
+ + {static} VALIDATION_REGEX : String
+ + name : String
+
+ + {static} isValidName() : boolean
+ + EntryName(String)
+}
+
+class EntryDate {
+ + {static} DATE_CONSTRAINTS : String
+ + value : LocalDateTime
+
+ + {static} isValidDate() : boolean
+ + DateTime(String)
+}
+
+class Tag {
+ + {static} MESSAGE_CONSTRAINTS : String
+ + {static} VALIDATION_REGEX : String
+ + tagName : string
+
+ + {static} isValidTagName() : boolean
+ + Tag(String)
+}
+
+class Entry {
+ - entryName: EntryName
+ - startDate : EntryDate
+ - endDate : EntryDate
+ - tags : HashSet
+
+ + Entry(...)
+}
+
+Entry -right-> "1" EntryName
+Entry -down-> "2" EntryDate
+EntryDate -right[hidden]-> Tag
+EntryName -down[hidden]-> Tag
+Entry -> "*" Tag
+
+@enduml
diff --git a/docs/diagrams/FilterEntrySequenceDiagram.puml b/docs/diagrams/FilterEntrySequenceDiagram.puml
new file mode 100644
index 00000000000..292847ade0e
--- /dev/null
+++ b/docs/diagrams/FilterEntrySequenceDiagram.puml
@@ -0,0 +1,44 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant "f:FilterEntryCommand" as FilterEntryCommand LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("efilter tag")
+activate LogicManager
+
+LogicManager -> AddressBookParser : parseCommand("efilter tag")
+activate AddressBookParser
+
+create FilterEntryCommand
+AddressBookParser -> FilterEntryCommand
+activate FilterEntryCommand
+
+FilterEntryCommand -> AddressBookParser
+deactivate FilterEntryCommand
+
+AddressBookParser --> LogicManager : f
+deactivate AddressBookParser
+
+LogicManager -> FilterEntryCommand : execute()
+activate FilterEntryCommand
+
+FilterEntryCommand -> Model : updateFilteredEntryList(predicate)
+activate Model
+
+Model --> FilterEntryCommand
+deactivate Model
+
+FilterEntryCommand --> LogicManager
+deactivate FilterEntryCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/FreeIntervalActivityDiagram.puml b/docs/diagrams/FreeIntervalActivityDiagram.puml
new file mode 100644
index 00000000000..e55186d3b36
--- /dev/null
+++ b/docs/diagrams/FreeIntervalActivityDiagram.puml
@@ -0,0 +1,13 @@
+@startuml
+'https://plantuml.com/activity-diagram-beta
+
+start
+:User executes "free" and specifies interval;
+if () then ([free])
+ :GUI shows free message to user;
+else ([not free])
+ :GUI shows entries occupying interval;
+endif
+stop
+
+@enduml
diff --git a/docs/diagrams/FreeIntervalSequenceDiagram.puml b/docs/diagrams/FreeIntervalSequenceDiagram.puml
new file mode 100644
index 00000000000..22d5ee5dc17
--- /dev/null
+++ b/docs/diagrams/FreeIntervalSequenceDiagram.puml
@@ -0,0 +1,45 @@
+@startuml
+'https://plantuml.com/sequence-diagram
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":TeachingAssistantParser" as TeachingAssistantParser LOGIC_COLOR
+participant ":FreeCommandParser" as FreeCommandParser LOGIC_COLOR
+participant "c:FreeCommand" as FreeCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+autoactivate on
+[-> LogicManager : execute("free")
+LogicManager -> TeachingAssistantParser : parseCommand("free")
+
+create FreeCommandParser
+TeachingAssistantParser -> FreeCommandParser
+return
+
+TeachingAssistantParser -> FreeCommandParser : parse(start, end)
+
+create FreeCommand
+FreeCommandParser -> FreeCommand
+return
+FreeCommandParser --> TeachingAssistantParser
+TeachingAssistantParser --> LogicManager : c
+destroy FreeCommandParser
+
+LogicManager -> FreeCommand : execute()
+FreeCommand -> Model : updateFilteredEntryList(predicate)
+return
+
+create CommandResult
+FreeCommand -> CommandResult
+return
+FreeCommand --> LogicManager : result
+
+[<-- LogicManager
+
+@enduml
diff --git a/docs/diagrams/ListEntryActivityDiagram.puml b/docs/diagrams/ListEntryActivityDiagram.puml
new file mode 100644
index 00000000000..66e885ff5bf
--- /dev/null
+++ b/docs/diagrams/ListEntryActivityDiagram.puml
@@ -0,0 +1,15 @@
+@startuml
+start
+:User executes "elist" and specifies arguments;
+
+if () then ([argument is empty])
+ :GUI lists all user's entries;
+else ([else])
+ if () then ([argument is "day"])
+ :GUI lists user's entries by day;
+ else ([else])
+ :GUI lists user's entries by week;
+ endif
+endif
+stop
+@enduml
diff --git a/docs/diagrams/ListEntrySequenceDiagram.puml b/docs/diagrams/ListEntrySequenceDiagram.puml
new file mode 100644
index 00000000000..4758c2a7129
--- /dev/null
+++ b/docs/diagrams/ListEntrySequenceDiagram.puml
@@ -0,0 +1,60 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":TeachingAssistantParser" as TeachingAssistantParser LOGIC_COLOR
+participant ":ListEntryFormatPredicate" as ListEntryFormatPredicate LOGIC_COLOR
+participant ":ListEntryCommand" as ListEntryCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("elist day")
+activate LogicManager
+
+LogicManager -> TeachingAssistantParser : parseCommand("elist day")
+activate TeachingAssistantParser
+
+create ListEntryFormatPredicate
+TeachingAssistantParser -> ListEntryFormatPredicate
+activate ListEntryFormatPredicate
+
+ListEntryFormatPredicate --> TeachingAssistantParser
+deactivate ListEntryFormatPredicate
+
+create ListEntryCommand
+TeachingAssistantParser -> ListEntryCommand
+activate ListEntryCommand
+
+ListEntryCommand --> TeachingAssistantParser
+deactivate ListEntryCommand
+
+TeachingAssistantParser --> LogicManager : command
+deactivate TeachingAssistantParser
+
+LogicManager-> ListEntryCommand : execute()
+activate ListEntryCommand
+
+ListEntryCommand -> Model : updateFilteredEntryList(predicate)
+activate Model
+
+Model --> ListEntryCommand
+deactivate Model
+
+create CommandResult
+ListEntryCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> ListEntryCommand
+deactivate CommandResult
+
+ListEntryCommand --> LogicManager : commandResult
+deactivate ListEntryCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml
index 016ef33e2e2..618646b70c2 100644
--- a/docs/diagrams/LogicClassDiagram.puml
+++ b/docs/diagrams/LogicClassDiagram.puml
@@ -8,7 +8,7 @@ package Logic {
package Parser {
Interface Parser <>
-Class AddressBookParser
+Class TeachingAssistantParser
Class XYZCommandParser
Class CliSyntax
Class ParserUtil
@@ -35,8 +35,8 @@ Class HiddenOutside #FFFFFF
HiddenOutside ..> Logic
LogicManager .up.|> Logic
-LogicManager -->"1" AddressBookParser
-AddressBookParser .left.> XYZCommandParser: creates >
+LogicManager -->"1" TeachingAssistantParser
+TeachingAssistantParser .left.> XYZCommandParser: creates >
XYZCommandParser ..> XYZCommand : creates >
XYZCommandParser ..|> Parser
@@ -53,7 +53,7 @@ LogicManager .left.> Command : executes >
LogicManager --> Model
Command .right.> Model
-note right of XYZCommand: XYZCommand = AddCommand, \nFindCommand, etc
+note right of XYZCommand: XYZCommand = AddContactCommand, \nEditEntryCommand, etc
Logic ..> CommandResult
LogicManager .down.> CommandResult
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 3eae5326a82..cb1d520943a 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -5,52 +5,63 @@ skinparam arrowColor MODEL_COLOR
skinparam classBackgroundColor MODEL_COLOR
Package Model <>{
-Interface ReadOnlyAddressBook <>
+Interface ReadOnlyTeachingAssistant <>
Interface Model <>
Interface ObservableList <>
-Class AddressBook
-Class ReadOnlyAddressBook
+Class TeachingAssistant
+Class ReadOnlyTeachingAssistant
Class Model
Class ModelManager
Class UserPrefs
Class ReadOnlyUserPrefs
-Package Person {
-Class Person
-Class Address
-Class Email
-Class Name
-Class Phone
-Class UniquePersonList
+Package Contact {
+Class Contact
+Class ContactEmail
+Class ContactName
+Class ContactPhone
+Class UniqueContactList
}
Package Tag {
Class Tag
}
+
+Package Entry {
+Class Entry
+Class EntryName
+Class EntryDate
+Class NonOverlappingEntryList
+}
+
}
Class HiddenOutside #FFFFFF
HiddenOutside ..> Model
-AddressBook .up.|> ReadOnlyAddressBook
+TeachingAssistant .up.|> ReadOnlyTeachingAssistant
ModelManager .up.|> Model
Model .right.> ObservableList
-ModelManager o--> "1" AddressBook
+ModelManager o--> "1" TeachingAssistant
ModelManager o-left-> "1" UserPrefs
UserPrefs .up.|> ReadOnlyUserPrefs
-AddressBook *--> "1" UniquePersonList
-UniquePersonList o--> "*" Person
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
-Person *--> "*" Tag
+TeachingAssistant *--> "1" UniqueContactList
+TeachingAssistant *--> "1" NonOverlappingEntryList
+UniqueContactList o--> "*" Contact
+NonOverlappingEntryList o--> "*" Entry
+Contact *--> ContactName
+Contact *--> ContactPhone
+Contact *--> ContactEmail
+Contact *--> "*" Tag
+Entry *--> EntryName
+Entry *--> EntryDate
+Entry *--> "*" Tag
-Name -[hidden]right-> Phone
-Phone -[hidden]right-> Address
-Address -[hidden]right-> Email
+ContactName -[hidden]right-> ContactPhone
+ContactPhone -[hidden]right-> ContactEmail
-ModelManager ----->" ~* filtered list" Person
+ModelManager ----->" ~* filtered list" Contact
+ModelManager ----->" ~* filtered list" Entry
@enduml
diff --git a/docs/diagrams/ScheduleAndTaskActivityDiagram.puml b/docs/diagrams/ScheduleAndTaskActivityDiagram.puml
new file mode 100644
index 00000000000..3550a429722
--- /dev/null
+++ b/docs/diagrams/ScheduleAndTaskActivityDiagram.puml
@@ -0,0 +1,11 @@
+@startuml
+start
+:User executes "sadd" or "tadd";
+if () then (["sadd"])
+ :Instantiates a Schedule object;
+else ([else])
+ :Instantiates a Task object;
+endif
+ :Saves to Storage;
+stop
+@enduml
diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml
index 6adb2e156bf..eb096e1c4bc 100644
--- a/docs/diagrams/StorageClassDiagram.puml
+++ b/docs/diagrams/StorageClassDiagram.puml
@@ -6,19 +6,21 @@ skinparam classBackgroundColor STORAGE_COLOR
Interface Storage <>
Interface UserPrefsStorage <>
-Interface AddressBookStorage <>
+Interface TeachingAssistantStorage <>
Class StorageManager
Class JsonUserPrefsStorage
-Class JsonAddressBookStorage
+Class JsonTeachingAssistantStorage
StorageManager .left.|> Storage
StorageManager o-right-> UserPrefsStorage
-StorageManager o--> AddressBookStorage
+StorageManager o--> TeachingAssistantStorage
JsonUserPrefsStorage .left.|> UserPrefsStorage
-JsonAddressBookStorage .left.|> AddressBookStorage
-JsonAddressBookStorage .down.> JsonSerializableAddressBookStorage
-JsonSerializableAddressBookStorage .right.> JsonSerializablePerson
-JsonSerializablePerson .right.> JsonAdaptedTag
+JsonTeachingAssistantStorage .left.|> TeachingAssistantStorage
+JsonTeachingAssistantStorage .down.> JsonSerializableTeachingAssistantStorage
+JsonSerializableTeachingAssistantStorage .right.> JsonAdaptedContact
+JsonSerializableTeachingAssistantStorage .down.> JsonAdaptedEntry
+JsonAdaptedContact .down.> JsonAdaptedTag
+JsonAdaptedEntry .right.> JsonAdaptedTag
@enduml
diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml
index 92746f9fcf7..21e53c6dc49 100644
--- a/docs/diagrams/UiClassDiagram.puml
+++ b/docs/diagrams/UiClassDiagram.puml
@@ -11,10 +11,12 @@ Class UiManager
Class MainWindow
Class HelpWindow
Class ResultDisplay
-Class PersonListPanel
-Class PersonCard
+Class ContactListPanel
+Class ContactCard
Class StatusBarFooter
Class CommandBox
+Class EntryCard
+Class EntryListPanel
}
package Model <> {
@@ -33,25 +35,31 @@ UiManager -down-> MainWindow
MainWindow --> HelpWindow
MainWindow *-down-> CommandBox
MainWindow *-down-> ResultDisplay
-MainWindow *-down-> PersonListPanel
+MainWindow *-down-> ContactListPanel
+MainWindow *-down-> EntryListPanel
MainWindow *-down-> StatusBarFooter
-PersonListPanel -down-> PersonCard
+ContactListPanel --down-> ContactCard
+EntryListPanel -down-> EntryCard
MainWindow -left-|> UiPart
ResultDisplay --|> UiPart
CommandBox --|> UiPart
-PersonListPanel --|> UiPart
-PersonCard --|> UiPart
+ContactListPanel --|> UiPart
+ContactCard --|> UiPart
+EntryListPanel --|> UiPart
+EntryCard --|> UiPart
StatusBarFooter --|> UiPart
HelpWindow -down-|> UiPart
-PersonCard ..> Model
+ContactCard ..> Model
+EntryCard ..> Model
UiManager -right-> Logic
MainWindow -left-> Logic
-PersonListPanel -[hidden]left- HelpWindow
+ContactListPanel -[hidden]left- HelpWindow
+EntryListPanel -[hidden]left- HelpWindow
HelpWindow -[hidden]left- CommandBox
CommandBox -[hidden]left- ResultDisplay
ResultDisplay -[hidden]left- StatusBarFooter
diff --git a/docs/diagrams/style.puml b/docs/diagrams/style.puml
index fad8b0adeaa..9f2efb771df 100644
--- a/docs/diagrams/style.puml
+++ b/docs/diagrams/style.puml
@@ -71,5 +71,4 @@ skinparam DefaultTextAlignment center
skinparam packageStyle Rectangle
hide footbox
-hide members
hide circle
diff --git a/docs/images/AddEntryExample.png b/docs/images/AddEntryExample.png
new file mode 100644
index 00000000000..eaa290ef7f2
Binary files /dev/null and b/docs/images/AddEntryExample.png differ
diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png
index 2f1346869d0..d2194c1c35e 100644
Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ
diff --git a/docs/images/ClearOverdueEntryCommandActivityDiagram.png b/docs/images/ClearOverdueEntryCommandActivityDiagram.png
new file mode 100644
index 00000000000..1cb3fb493bc
Binary files /dev/null and b/docs/images/ClearOverdueEntryCommandActivityDiagram.png differ
diff --git a/docs/images/ClearOverdueSequenceDiagram.png b/docs/images/ClearOverdueSequenceDiagram.png
new file mode 100644
index 00000000000..e85faa46c9e
Binary files /dev/null and b/docs/images/ClearOverdueSequenceDiagram.png differ
diff --git a/docs/images/DeleteContactCommandActivityDiagram.png b/docs/images/DeleteContactCommandActivityDiagram.png
new file mode 100644
index 00000000000..06a4032503f
Binary files /dev/null and b/docs/images/DeleteContactCommandActivityDiagram.png differ
diff --git a/docs/images/DeleteContactCommandSequenceDiagram.png b/docs/images/DeleteContactCommandSequenceDiagram.png
new file mode 100644
index 00000000000..d8aa49114c2
Binary files /dev/null and b/docs/images/DeleteContactCommandSequenceDiagram.png differ
diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png
index fa327b39618..0a1c722532f 100644
Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ
diff --git a/docs/images/EditContactExample.png b/docs/images/EditContactExample.png
new file mode 100644
index 00000000000..d29cb822b1a
Binary files /dev/null and b/docs/images/EditContactExample.png differ
diff --git a/docs/images/EntryActivityDiagram.png b/docs/images/EntryActivityDiagram.png
new file mode 100644
index 00000000000..726571ac425
Binary files /dev/null and b/docs/images/EntryActivityDiagram.png differ
diff --git a/docs/images/EntryClassDiagram.png b/docs/images/EntryClassDiagram.png
new file mode 100644
index 00000000000..49ba01ff85e
Binary files /dev/null and b/docs/images/EntryClassDiagram.png differ
diff --git a/docs/images/FilterEntrySequenceDiagram.png b/docs/images/FilterEntrySequenceDiagram.png
new file mode 100644
index 00000000000..659a7dd98bb
Binary files /dev/null and b/docs/images/FilterEntrySequenceDiagram.png differ
diff --git a/docs/images/FilterTagExample.png b/docs/images/FilterTagExample.png
new file mode 100644
index 00000000000..5d44f19bd61
Binary files /dev/null and b/docs/images/FilterTagExample.png differ
diff --git a/docs/images/FindContactExample.png b/docs/images/FindContactExample.png
new file mode 100644
index 00000000000..018dfedfbbc
Binary files /dev/null and b/docs/images/FindContactExample.png differ
diff --git a/docs/images/FreeExample.png b/docs/images/FreeExample.png
new file mode 100644
index 00000000000..44efaa9062a
Binary files /dev/null and b/docs/images/FreeExample.png differ
diff --git a/docs/images/FreeIntervalActivityDiagram.png b/docs/images/FreeIntervalActivityDiagram.png
new file mode 100644
index 00000000000..5969c8624a9
Binary files /dev/null and b/docs/images/FreeIntervalActivityDiagram.png differ
diff --git a/docs/images/FreeIntervalSequenceDiagram.png b/docs/images/FreeIntervalSequenceDiagram.png
new file mode 100644
index 00000000000..58581e0eb58
Binary files /dev/null and b/docs/images/FreeIntervalSequenceDiagram.png differ
diff --git a/docs/images/ListEntryActivityDiagram.png b/docs/images/ListEntryActivityDiagram.png
new file mode 100644
index 00000000000..82c4522672a
Binary files /dev/null and b/docs/images/ListEntryActivityDiagram.png differ
diff --git a/docs/images/ListEntrySequenceDiagram.png b/docs/images/ListEntrySequenceDiagram.png
new file mode 100644
index 00000000000..bc4e13ced49
Binary files /dev/null and b/docs/images/ListEntrySequenceDiagram.png differ
diff --git a/docs/images/ListEntryWeek.png b/docs/images/ListEntryWeek.png
new file mode 100644
index 00000000000..0494893790c
Binary files /dev/null and b/docs/images/ListEntryWeek.png differ
diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png
index b9e853cef12..a345d030fda 100644
Binary files a/docs/images/LogicClassDiagram.png and b/docs/images/LogicClassDiagram.png differ
diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png
index ffd17662d41..009d4549998 100644
Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ
diff --git a/docs/images/RJ1.png b/docs/images/RJ1.png
new file mode 100644
index 00000000000..f29faf5c3b0
Binary files /dev/null and b/docs/images/RJ1.png differ
diff --git a/docs/images/ScheduleAndTaskActivityDiagram.png b/docs/images/ScheduleAndTaskActivityDiagram.png
new file mode 100644
index 00000000000..b44938eedb6
Binary files /dev/null and b/docs/images/ScheduleAndTaskActivityDiagram.png differ
diff --git a/docs/images/Screenshot (117).png b/docs/images/Screenshot (117).png
new file mode 100644
index 00000000000..29ef702cb83
Binary files /dev/null and b/docs/images/Screenshot (117).png differ
diff --git a/docs/images/Screenshot (118).png b/docs/images/Screenshot (118).png
new file mode 100644
index 00000000000..759ed988330
Binary files /dev/null and b/docs/images/Screenshot (118).png differ
diff --git a/docs/images/Screenshot (119).png b/docs/images/Screenshot (119).png
new file mode 100644
index 00000000000..0653f5ce3cd
Binary files /dev/null and b/docs/images/Screenshot (119).png differ
diff --git a/docs/images/Screenshot (124).png b/docs/images/Screenshot (124).png
new file mode 100644
index 00000000000..a5300c5c8b5
Binary files /dev/null and b/docs/images/Screenshot (124).png differ
diff --git a/docs/images/Screenshot (125).png b/docs/images/Screenshot (125).png
new file mode 100644
index 00000000000..86e99ee5ca5
Binary files /dev/null and b/docs/images/Screenshot (125).png differ
diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png
index d87c1216820..54164b49e82 100644
Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ
diff --git a/docs/images/Ui.png b/docs/images/Ui.png
index 5bd77847aa2..39552e54a90 100644
Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ
diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png
index 7b4b3dbea45..50acebc28fc 100644
Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ
diff --git a/docs/images/annotatedUi.png b/docs/images/annotatedUi.png
new file mode 100644
index 00000000000..0aa242fc7cb
Binary files /dev/null and b/docs/images/annotatedUi.png differ
diff --git a/docs/images/goatygoatygoat.png b/docs/images/goatygoatygoat.png
new file mode 100644
index 00000000000..5296836f8c3
Binary files /dev/null and b/docs/images/goatygoatygoat.png differ
diff --git a/docs/images/kevinlohjunyong.png b/docs/images/kevinlohjunyong.png
new file mode 100644
index 00000000000..099ecf20017
Binary files /dev/null and b/docs/images/kevinlohjunyong.png differ
diff --git a/docs/images/lrj689.png b/docs/images/lrj689.png
new file mode 100644
index 00000000000..fe7c72fec1c
Binary files /dev/null and b/docs/images/lrj689.png differ
diff --git a/docs/images/nicholastanvis.png b/docs/images/nicholastanvis.png
new file mode 100644
index 00000000000..3b7ee70fa08
Binary files /dev/null and b/docs/images/nicholastanvis.png differ
diff --git a/docs/images/tsh22.png b/docs/images/tsh22.png
new file mode 100644
index 00000000000..e19ce61a374
Binary files /dev/null and b/docs/images/tsh22.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..5e6269efc56 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,19 +1,23 @@
---
layout: page
-title: AddressBook Level-3
+title: Teaching Assistant
---
-[](https://github.com/se-edu/addressbook-level3/actions)
-[](https://codecov.io/gh/se-edu/addressbook-level3)
+[](https://github.com/AY2021S2-CS2103T-W13-4/tp/actions)
+[](https://codecov.io/gh/AY2021S2-CS2103T-W13-4/tp)

-**AddressBook is a desktop application for managing your contact details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
-
-* If you are interested in using AddressBook, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
-* If you are interested about developing AddressBook, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
+Welcome to our website! _Teaching Assistant_ is a desktop application that helps **JC/Secondary school teachers** have an efficient tool to keep
+track of their **contacts and other entries like tasks or schedules easily.** While it has a GUI, most of the user interactions
+relies on typing commands as user inputs.
+* If you are interested in using _Teaching Assistant_, head over to the [_Quick Start_ section of the **User
+ Guide**](UserGuide.html#quick-start).
+* If you are interested about developing _Teaching Assistant_, the [**Developer Guide**](DeveloperGuide.html) is a good place to
+ start.
**Acknowledgements**
-* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5)
+* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson)
+ , [JUnit5](https://github.com/junit-team/junit5)
diff --git a/docs/team/goatygoatygoat.md b/docs/team/goatygoatygoat.md
new file mode 100644
index 00000000000..dfe488260eb
--- /dev/null
+++ b/docs/team/goatygoatygoat.md
@@ -0,0 +1,81 @@
+---
+layout: page
+title: Shen Yang's Project Portfolio Page
+---
+
+## Project: Teaching Assistant
+
+Teaching Assistant is a desktop application used for managing contacts and entries for JC/Secondary school teachers.
+The user interacts with it using a Command Line Interface (CLI), and it has a Graphical User Interface (GUI) created
+with JavaFX. It is written in Java, and has about 10 (tbc) kLoC.
+
+Given below are my contributions to the project.
+* **New Feature**: Added the finalised feature to allow users to list all their contacts.
+ * What it does: Allows users to list of all their contacts.
+ * Justification: This feature is essential as the find and filter features lists a subset of all contacts. In order
+ to revert the contact list to show all contacts, this feature is needed.
+ * Pull request [\#207](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/207)
+
+* **New Feature**: Added the finalised feature to allow users to find their contacts by name.
+ * What it does: Allows users to find their contacts by name.
+ * Justification: This feature is important as without this, users have to scroll through the whole contact list to
+ find the details of a contact they need.
+ * Highlights: The original AB3 implementation for this feature uses a OR search to search for contacts by name,
+ which I felt needed to be changed as it does not feel intuitive, especially in the context of searching for names.
+ Hence, I changed the implementation to use an AND search instead.
+ * Pull request [\#207](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/207)
+
+* **New Feature**: Added the finalised feature to allow users to filter their contacts by tags.
+ * What it does: Allows users to filter their contacts via tags.
+ * Justification: This feature is useful when users do not remember the names of their contacts, but remember a
+ characteristic of them that they have previously tagged to their contact. It is also useful for finding more than
+ one contact at once.
+ * Pull request [\#207](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/207)
+
+* **New Feature**: Added an early version of the feature which allows users to list their entries.
+ * What it does: Allows users to list all their entries, or list them by day or week.
+ * Justification: This feature is useful when users have a lot of entries and only want to look at their daily or
+ weekly entries to avoid confusing themselves.
+
+* **New Feature**: Added an early version of the feature to allow users to find their entries by name.
+ * What it does: Allows users to find their entries by name.
+ * Justification: This feature is important as without this, users have to scroll through the whole entry list to
+ find the details of an entry they need.
+
+* **New Feature**: Added an early version of the feature to allow users to filter their entries by tags.
+ * What it does: Allows users to filter their entries via tags.
+ * Justification: This feature is useful when users do not remember the names of their entries, but remember
+ their category that they have previously tagged to their entry. It is also useful for finding more than
+ one entry at once.
+
+* **Code contributed**: [RepoSense Link](https://nus-cs2103-ay2021s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&since=&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=false&tabOpen=true&tabType=authorship&tabAuthor=goatygoatygoat&tabRepo=AY2021S2-CS2103T-W13-4%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false)
+
+* **Project management**:
+ * Managed the code quality of the project
+ (Pull request [\#249](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/249)).
+ * Managed the assigning and tracking of project tasks.
+
+* **Enhancements to existing features**:
+ * Wrote additional tests for existing features that I had finalised
+ (Pull request [\#207](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/207)).
+
+* **Documentation**:
+ * User Guide:
+ * Added the initial introduction of the User Guide
+ (Pull request [\#17](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/17)).
+ * Fixed most documentation bugs found in the PE dry run
+ (Pull request [\#199](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/199)).
+ * Added FAQ, saving and editing data features, modified command summary, breakdown of command formats, scenarios
+ (Pull request [\#227](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/227)).
+ * Developer Guide:
+ * Added the initial Product Scope and Glossary of the Developer Guide
+ (Pull request [\#20](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/20)).
+ * Added the implementation of the `elist` feature
+ (Pull requests [\#85](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/85), [\#253](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/253)).
+ * Added Documentation, logging, testing, configuration, dev-ops section in the Developer Guide and updated the User Stories
+ (Pull request [\#253](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/253)).
+
+* **Community**:
+ * PRs reviewed (with non-trivial review comments): [\#181](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/181),
+ [\#114](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/114)
+ * Added PPP files with template for the team: [\#211](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/211)
diff --git a/docs/team/kevinlohjunyong.md b/docs/team/kevinlohjunyong.md
new file mode 100644
index 00000000000..009badcac65
--- /dev/null
+++ b/docs/team/kevinlohjunyong.md
@@ -0,0 +1,41 @@
+---
+layout: page
+title: Kevin Loh Jun Yong's Project Portfolio Page
+---
+
+## Project: Teaching Assistant
+
+Teaching Assistant is a desktop application used for managing contacts and entries for JC/Secondary school teachers.
+The user interacts with it using a Command Line Interface (CLI), and it has a Graphical User Interface (GUI) created
+with JavaFX. It is written in Java, and has about 10 (tbc) kLoC.
+
+Given below are my contributions to the project.
+* **New Feature**:
+ * I had developed the `DeleteContactCommand`, `AddContactCommand`,
+ `DeleteContactCommandParser` and `AddContactCommandParser`, etc. I was
+ also responsible for refactoring various files [\#208](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/208/files)
+ [\#89](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/89/files)
+
+ * Additionally, I was in charge of schedules [\#52](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/52)
+ [\#23](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/23)
+
+* **Code contributed**: [RepoSense Link](https://nus-cs2103-ay2021s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&since=&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=false&tabOpen=true&tabType=authorship&tabAuthor=KevinLohJunYong&tabRepo=AY2021S2-CS2103T-W13-4%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false)
+
+
+* **Testing**:
+
+ * I did tests for `AddContactCommand`, `DeleteContactCommand`
+ and their corresponding parsers (i.e `AddContactCommandParser` and
+ `DeleteContactCommandParser`)
+ * I thought of how to write the code as elegantly as possible [\#208](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/208/files)
+
+* **Documentation**:
+
+ * I contributed to the developer guide by in the Delete Contact Command section.
+ I had explained about the `DeleteContactCommand` and I
+ wrote plantUML code to generate the Activity Diagram and Sequence Diagram [\#245](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/245/files)
+
+* **Community**
+
+ * i had attended all the team meetings and contributed to discussions.
+
diff --git a/docs/team/lrj689.md b/docs/team/lrj689.md
new file mode 100644
index 00000000000..050685f66b2
--- /dev/null
+++ b/docs/team/lrj689.md
@@ -0,0 +1,51 @@
+---
+layout: page
+title: Lee Rong Jieh's Project Portfolio Page
+---
+
+## Project: Teaching Assistant
+
+Teaching Assistant is a desktop application used for managing contacts and entries for JC/Secondary school teachers.
+The user interacts with it using a Command Line Interface (CLI), and it has a Graphical User Interface (GUI) created
+with JavaFX. It is written in Java, and has about 10 (tbc) kLoC.
+
+Given below are my contributions to the project.
+* **Code contributed**: [RepoSense Link](https://nus-cs2103-ay2021s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&since=&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=false&tabOpen=true&tabType=authorship&tabAuthor=lrj689&tabRepo=AY2021S2-CS2103T-W13-4%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false)
+* **Enhancements implemented**:
+ * Task class and its respective attribute classes (Which was updated to Entry class).
+ * Task, Schedule, Entry class storage functionality.
+ * Delete Task command and other dependencies(Which later became delete entry command).
+ * Clear overdue entries command and other dependencies.
+ * List Entry command by day/week/all and other dependencies.
+ * Test code for storage.
+ * Test code for other feature implementations mentioned above.
+
+* **Contributions to the UG**:
+ * Task section (Later updated to Entry section)
+ * Illustrations for command examples.
+
+* **Contributions to DG**:
+ * Implementation for ClearOverdueCommand
+ * Use Cases
+
+* **Contributions to team-based tasks**:
+ * Contributing issues in issue tracker
+ * Removing code not needed for final product
+ * Released V1.2.1
+
+* **Review/mentoring contributions**:
+ * Reviewed most pull requests. [Pull Request page](https://github.com/AY2021S2-CS2103T-W13-4/tp/pulls)
+ * Provided suggestions in prs.
+ * [PR comment](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/183)
+ * [PR comment 2](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/208)
+
+* **Contributions to DG extracts**:
+ * 
+ * .png)
+ * .png)
+ * .png)
+
+* **Contributions to UG extracts**:
+ * .png)
+ * .png)
+
diff --git a/docs/team/nicholastanvis.md b/docs/team/nicholastanvis.md
new file mode 100644
index 00000000000..b9feb0e4ac6
--- /dev/null
+++ b/docs/team/nicholastanvis.md
@@ -0,0 +1,90 @@
+---
+layout: page
+title: Nicholas Tanvis's Project Portfolio Page
+---
+
+# Project: Teaching Assistant
+
+## Overview
+Teaching Assistant is a desktop application used for managing contacts and entries for JC/Secondary school teachers.
+The user interacts with it using a Command Line Interface (CLI), and it has a Graphical User Interface (GUI) created
+with JavaFX. It is written in Java, and has about 10 (tbc) kLoC.
+
+## Summary of Contributions
+Given below are some of my major contributions to the project.
+* **Code contributed**: [RepoSense Link](https://nus-cs2103-ay2021s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&since=&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=false&tabOpen=true&tabType=authorship&tabAuthor=nicholastanvis&tabRepo=AY2021S2-CS2103T-W13-4%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false)
+* **Enhancements implemented**:
+ * Add Schedule class in [#45](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/45)
+ * Add and find schedule commands in [#54](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/54)
+ * Delete schedule command in [#60](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/60)
+ * Refactor Schedule and Task classes into a single Entry class in [#90](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/90)
+ * Delete entry command in [#94](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/94) and [#102](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/102)
+ * Edit entry command in [#112](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/112)
+ * Find and Filter entry command tests in [#192](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/192) and [#200](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/200)
+ * Refactor Person class into Contact class in [#181](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/181)
+ * Refactor all tests in [#243](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/243)
+ * Implement add and edit entry command parsers
+ * Fix styling
+ * Look after the entire test suite
+* **Documentation**:
+ * Developer Guide
+ * User Stories [#22](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/22)
+ * One implementation [#80](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/80)
+ * Architecture, Getting Started in [#231](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/231)
+ * Table of Contents, Appendix: Manual testing [#262](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/262)
+ * User Guide
+ * Quick Start, Table in Contents in [#87](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/87)
+* **Review Contributions**:
+ * Major refactoring problems in [#89](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/89)
+ * Missing PlantUML diagrams in [#245](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/245)
+ * Enforce UML diagram standard in [#248](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/248)
+
+## Contributions to the Developer Guide (Extracts)
+
+### Architecture Sequence Diagram
+
+
+---
+
+### Delete Contact Sequence Diagram
+
+
+---
+
+### Entry Activity Diagram
+
+
+---
+
+### Entry Class Diagram
+
+
+---
+
+### Filter Entry Sequence Diagram
+
+
+---
+
+### Logic Class Diagram
+
+
+---
+
+### Model Class Diagram
+
+
+---
+
+### Schedule and Task Activity Diagram
+
+
+---
+
+### Storage Class Diagram
+
+
+---
+
+### Ui Class Diagram
+
diff --git a/docs/team/tsh22.md b/docs/team/tsh22.md
new file mode 100644
index 00000000000..f85ebc7b917
--- /dev/null
+++ b/docs/team/tsh22.md
@@ -0,0 +1,76 @@
+---
+layout: page title: Toh Sihui's Project Portfolio Page
+---
+
+## Project: Teaching Assistant
+
+Teaching Assistant is a desktop application used for managing contacts and entries for JC/Secondary school teachers. The
+user interacts with it using a Command Line Interface (CLI), and it has a Graphical User Interface (GUI) created with
+JavaFX. It is written in Java, and has about 10 (tbc) kLoC.
+
+Given below are my contributions to the project.
+
+* **New Feature**: Added a free command. ([#98](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/98), #191)
+ * What it does: Allows the user to check if a certain datetime interval is free or occupied.
+ * Justification: This feature improves the product for our target users. Teachers can have many items on their entry
+ list. This feature allows them to conveniently find out if they are available for a consultation with a student,
+ for instance, rather than having to check each entry individually.
+* **Code
+ contributed**: [RepoSense Link](https://nus-cs2103-ay2021s2.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&since=&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=false&tabOpen=true&tabType=authorship&tabAuthor=tsh22&tabRepo=AY2021S2-CS2103T-W13-4%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false)
+* **Team-based tasks**:
+ 1. Set up branch protection rules.
+ 1. Necessary general code enhancements ([#237](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/237)
+ , [#228](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/228)
+ , [#240](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/240)):
+ 1. Refactored AddressBook instances to TeachingAssistant.
+ 1. Removed Person class.
+ 1. Update Ui.png when necessary ([#10](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/10)
+ , [#113](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/113))
+ 1. Enable assertions in build.gradle file ([#81](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/81))
+ 1. Linked team's portfolio page in AboutUs page ([#214](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/214))
+ 1. Updated AboutUs page with personal photo and github
+ link ([#6](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/6))
+ 1. Updated website contents to match project ([#13](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/13))
+* **Enhancements to existing features**:
+ 1. Updated the GUI ([#59](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/59)
+ , [#92](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/92)
+ , [#182](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/182)
+ , [#188](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/188)
+ , [#189](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/189)
+ , [#205](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/205))
+ 1. Link GUI to show contacts instead of persons (#228)
+ 1. Added testing for ListOccupyingEntryPredicate ([#216](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/216))
+ 1. Added testing for GuiSettings ([#205](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/205))
+ 1. Added testing for Edit Contact Command, Parser and
+ ParserUtil ([#204](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/204))
+ 1. Added testing for Free Command ([#191](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/191))
+ 1. Added testing for EntryDate ([#191](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/191)
+ , [#247](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/247))
+ 1. Started out the implementation of Edit Entry
+ Command ([#101](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/101))
+ 1. [Removed implementation] Implemented Edit Contact with
+ name ([#105](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/105))
+ 1. [Removed implementation] Added Find Task command ([#50](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/50))
+* **Documentation**:
+ * User Guide:
+ * Updated User Guide for PE Dry-Run ([#114](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/114)).
+ * Added "Structure of User Guide" section ([#242](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/242))
+ * Updated "Command Summary" section of User Guide in previous
+ updates ([#15](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/15)
+ , [#82](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/82))
+ * Developer Guide:
+ * Added implementation details of the `free`
+ feature. ([#21](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/21)
+ , [#84](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/84)
+ , [#241](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/241))
+ * Added manual testing section for entry commands (#259)
+* **Community**:
+ * PRs reviewed (not a complete list): [#257](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/257)
+ , [#227](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/227)
+ , [#249](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/249)
+ , [#245](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/245)
+ , [#215](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/215)
+ , [#208](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/208)
+ , [#199](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/199)
+ , [#258](https://github.com/AY2021S2-CS2103T-W13-4/tp/pull/258)
+
diff --git a/docs/tutorials/AddRemark.md b/docs/tutorials/AddRemark.md
index 64c9b1f91de..29496ce6b66 100644
--- a/docs/tutorials/AddRemark.md
+++ b/docs/tutorials/AddRemark.md
@@ -23,9 +23,9 @@ For now, let’s keep `RemarkCommand` as simple as possible and print some outpu
**`RemarkCommand.java`:**
``` java
-package seedu.address.logic.commands;
+package seedu.ta.logic.commands;
-import seedu.address.model.Model;
+import seedu.ta.model.Model;
/**
* Changes the remark of an existing person in the address book.
@@ -89,7 +89,7 @@ Let’s change `RemarkCommand` to parse input from the user.
We start by modifying the constructor of `RemarkCommand` to accept an `Index` and a `String`. While we are at it, let’s change the error message to echo the values. While this is not a replacement for tests, it is an obvious way to tell if our code is functioning as intended.
``` java
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.ta.commons.util.CollectionUtil.requireAllNonNull;
//...
public class RemarkCommand extends Command {
//...
@@ -139,7 +139,7 @@ Your code should look something like [this](https://github.com/se-edu/addressboo
Now let’s move on to writing a parser that will extract the index and remark from the input provided by the user.
-Create a `RemarkCommandParser` class in the `seedu.address.logic.parser` package. The class must extend the `Parser` interface.
+Create a `RemarkCommandParser` class in the `seedu.ta.logic.parser` package. The class must extend the `Parser` interface.

@@ -226,7 +226,7 @@ Now that we have all the information that we need, let’s lay the groundwork fo
### Add a new `Remark` class
-Create a new `Remark` in `seedu.address.model.person`. Since a `Remark` is a field that is similar to `Address`, we can reuse a significant bit of code.
+Create a new `Remark` in `seedu.ta.model.person`. Since a `Remark` is a field that is similar to `Address`, we can reuse a significant bit of code.
A copy-paste and search-replace later, you should have something like [this](https://github.com/se-edu/addressbook-level3/commit/4516e099699baa9e2d51801bd26f016d812dedcc#diff-af2f075d24dfcd333876f0fbce321f25). Note how `Remark` has no constrains and thus does not require input
validation.
@@ -239,7 +239,7 @@ Let’s change `RemarkCommand` and `RemarkCommandParser` to use the new `Remark`
Without getting too deep into `fxml`, let’s go on a 5 minute adventure to get some placeholder text to show up for each person.
-Simply add the following to [`seedu.address.ui.PersonCard`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-0c6b6abcfac8c205e075294f25e851fe).
+Simply add the following to [`seedu.ta.ui.PersonCard`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-0c6b6abcfac8c205e075294f25e851fe).
**`PersonCard.java`:**
diff --git a/docs/tutorials/RemovingFields.md b/docs/tutorials/RemovingFields.md
index aa8e0baaad9..ea961c432ef 100644
--- a/docs/tutorials/RemovingFields.md
+++ b/docs/tutorials/RemovingFields.md
@@ -20,7 +20,7 @@ Fortunately, IntelliJ IDEA provides a robust refactoring tool that can identify
### Assisted refactoring
-The `address` field in `Person` is actually an instance of the `seedu.address.model.person.Address` class. Since removing the `Address` class will break the application, we start by identifying `Address`'s usages. This allows us to see code that depends on `Address` to function properly and edit them on a case-by-case basis. Right-click the `Address` class and select `Refactor` \> `Safe Delete` through the menu.
+The `address` field in `Person` is actually an instance of the `seedu.ta.model.person.Address` class. Since removing the `Address` class will break the application, we start by identifying `Address`'s usages. This allows us to see code that depends on `Address` to function properly and edit them on a case-by-case basis. Right-click the `Address` class and select `Refactor` \> `Safe Delete` through the menu.

diff --git a/docs/tutorials/TracingCode.md b/docs/tutorials/TracingCode.md
index bd34ed498cd..6f3dde45f0e 100644
--- a/docs/tutorials/TracingCode.md
+++ b/docs/tutorials/TracingCode.md
@@ -32,7 +32,7 @@ Before we proceed, ensure that you have done the following:
## Setting a break point
-As you know, the first step of debugging is to put in a breakpoint where you want the debugger to pause the execution. For example, if you are trying to understand how the App starts up, you would put a breakpoint in the first statement of the `main` method. In our case, we would want to begin the tracing at the very point where the App start processing user input (i.e., somewhere in the UI component), and then trace through how the execution proceeds through the UI component. However, the execution path through a GUI is often somewhat obscure due to various *event-driven mechanisms* used by GUI frameworks, which happens to be the case here too. Therefore, let us put the breakpoint where the UI transfers control to the Logic component. According to the sequence diagram, the UI component yields control to the Logic component through a method named `execute`. Searching through the code base for `execute()` yields a promising candidate in `seedu.address.ui.CommandBox.CommandExecutor`.
+As you know, the first step of debugging is to put in a breakpoint where you want the debugger to pause the execution. For example, if you are trying to understand how the App starts up, you would put a breakpoint in the first statement of the `main` method. In our case, we would want to begin the tracing at the very point where the App start processing user input (i.e., somewhere in the UI component), and then trace through how the execution proceeds through the UI component. However, the execution path through a GUI is often somewhat obscure due to various *event-driven mechanisms* used by GUI frameworks, which happens to be the case here too. Therefore, let us put the breakpoint where the UI transfers control to the Logic component. According to the sequence diagram, the UI component yields control to the Logic component through a method named `execute`. Searching through the code base for `execute()` yields a promising candidate in `seedu.ta.ui.CommandBox.CommandExecutor`.

diff --git a/src/main/java/seedu/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java
deleted file mode 100644
index 1deb3a1e469..00000000000
--- a/src/main/java/seedu/address/commons/core/Messages.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package seedu.address.commons.core;
-
-/**
- * Container for user visible messages.
- */
-public class Messages {
-
- public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
- public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
- public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid";
- public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!";
-
-}
diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java
deleted file mode 100644
index 92cd8fa605a..00000000000
--- a/src/main/java/seedu/address/logic/Logic.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package seedu.address.logic;
-
-import java.nio.file.Path;
-
-import javafx.collections.ObservableList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.logic.commands.CommandResult;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
-
-/**
- * API of the Logic component
- */
-public interface Logic {
- /**
- * Executes the command and returns the result.
- * @param commandText The command as entered by the user.
- * @return the result of the command execution.
- * @throws CommandException If an error occurs during command execution.
- * @throws ParseException If an error occurs during parsing.
- */
- CommandResult execute(String commandText) throws CommandException, ParseException;
-
- /**
- * Returns the AddressBook.
- *
- * @see seedu.address.model.Model#getAddressBook()
- */
- ReadOnlyAddressBook getAddressBook();
-
- /** Returns an unmodifiable view of the filtered list of persons */
- ObservableList getFilteredPersonList();
-
- /**
- * Returns the user prefs' address book file path.
- */
- Path getAddressBookFilePath();
-
- /**
- * Returns the user prefs' GUI settings.
- */
- GuiSettings getGuiSettings();
-
- /**
- * Set the user prefs' GUI settings.
- */
- void setGuiSettings(GuiSettings guiSettings);
-}
diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java
deleted file mode 100644
index 71656d7c5c8..00000000000
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
-import seedu.address.model.person.Person;
-
-/**
- * Adds a person to the address book.
- */
-public class AddCommand extends Command {
-
- public static final String COMMAND_WORD = "add";
-
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the address book. "
- + "Parameters: "
- + PREFIX_NAME + "NAME "
- + PREFIX_PHONE + "PHONE "
- + PREFIX_EMAIL + "EMAIL "
- + PREFIX_ADDRESS + "ADDRESS "
- + "[" + PREFIX_TAG + "TAG]...\n"
- + "Example: " + COMMAND_WORD + " "
- + PREFIX_NAME + "John Doe "
- + PREFIX_PHONE + "98765432 "
- + PREFIX_EMAIL + "johnd@example.com "
- + PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 "
- + PREFIX_TAG + "friends "
- + PREFIX_TAG + "owesMoney";
-
- public static final String MESSAGE_SUCCESS = "New person added: %1$s";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book";
-
- private final Person toAdd;
-
- /**
- * Creates an AddCommand to add the specified {@code Person}
- */
- public AddCommand(Person person) {
- requireNonNull(person);
- toAdd = person;
- }
-
- @Override
- public CommandResult execute(Model model) throws CommandException {
- requireNonNull(model);
-
- if (model.hasPerson(toAdd)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
- }
-
- model.addPerson(toAdd);
- return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof AddCommand // instanceof handles nulls
- && toAdd.equals(((AddCommand) other).toAdd));
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
deleted file mode 100644
index 02fd256acba..00000000000
--- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.List;
-
-import seedu.address.commons.core.Messages;
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
-import seedu.address.model.person.Person;
-
-/**
- * Deletes a person identified using it's displayed index from the address book.
- */
-public class DeleteCommand extends Command {
-
- public static final String COMMAND_WORD = "delete";
-
- public static final String MESSAGE_USAGE = COMMAND_WORD
- + ": Deletes the person identified by the index number used in the displayed person list.\n"
- + "Parameters: INDEX (must be a positive integer)\n"
- + "Example: " + COMMAND_WORD + " 1";
-
- public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s";
-
- private final Index targetIndex;
-
- public DeleteCommand(Index targetIndex) {
- this.targetIndex = targetIndex;
- }
-
- @Override
- public CommandResult execute(Model model) throws CommandException {
- requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
-
- if (targetIndex.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
- }
-
- Person personToDelete = lastShownList.get(targetIndex.getZeroBased());
- model.deletePerson(personToDelete);
- return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, personToDelete));
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof DeleteCommand // instanceof handles nulls
- && targetIndex.equals(((DeleteCommand) other).targetIndex)); // state check
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java
deleted file mode 100644
index 7e36114902f..00000000000
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ /dev/null
@@ -1,226 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-
-import seedu.address.commons.core.Messages;
-import seedu.address.commons.core.index.Index;
-import seedu.address.commons.util.CollectionUtil;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Edits the details of an existing person in the address book.
- */
-public class EditCommand extends Command {
-
- public static final String COMMAND_WORD = "edit";
-
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the person identified "
- + "by the index number used in the displayed person list. "
- + "Existing values will be overwritten by the input values.\n"
- + "Parameters: INDEX (must be a positive integer) "
- + "[" + PREFIX_NAME + "NAME] "
- + "[" + PREFIX_PHONE + "PHONE] "
- + "[" + PREFIX_EMAIL + "EMAIL] "
- + "[" + PREFIX_ADDRESS + "ADDRESS] "
- + "[" + PREFIX_TAG + "TAG]...\n"
- + "Example: " + COMMAND_WORD + " 1 "
- + PREFIX_PHONE + "91234567 "
- + PREFIX_EMAIL + "johndoe@example.com";
-
- public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Person: %1$s";
- public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book.";
-
- private final Index index;
- private final EditPersonDescriptor editPersonDescriptor;
-
- /**
- * @param index of the person in the filtered person list to edit
- * @param editPersonDescriptor details to edit the person with
- */
- public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) {
- requireNonNull(index);
- requireNonNull(editPersonDescriptor);
-
- this.index = index;
- this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor);
- }
-
- @Override
- public CommandResult execute(Model model) throws CommandException {
- requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
-
- if (index.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
- }
-
- Person personToEdit = lastShownList.get(index.getZeroBased());
- Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
-
- if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
- }
-
- model.setPerson(personToEdit, editedPerson);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson));
- }
-
- /**
- * Creates and returns a {@code Person} with the details of {@code personToEdit}
- * edited with {@code editPersonDescriptor}.
- */
- private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) {
- assert personToEdit != null;
-
- Name updatedName = editPersonDescriptor.getName().orElse(personToEdit.getName());
- Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone());
- Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail());
- Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress());
- Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags());
-
- return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags);
- }
-
- @Override
- public boolean equals(Object other) {
- // short circuit if same object
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof EditCommand)) {
- return false;
- }
-
- // state check
- EditCommand e = (EditCommand) other;
- return index.equals(e.index)
- && editPersonDescriptor.equals(e.editPersonDescriptor);
- }
-
- /**
- * Stores the details to edit the person with. Each non-empty field value will replace the
- * corresponding field value of the person.
- */
- public static class EditPersonDescriptor {
- private Name name;
- private Phone phone;
- private Email email;
- private Address address;
- private Set tags;
-
- public EditPersonDescriptor() {}
-
- /**
- * Copy constructor.
- * A defensive copy of {@code tags} is used internally.
- */
- public EditPersonDescriptor(EditPersonDescriptor toCopy) {
- setName(toCopy.name);
- setPhone(toCopy.phone);
- setEmail(toCopy.email);
- setAddress(toCopy.address);
- setTags(toCopy.tags);
- }
-
- /**
- * Returns true if at least one field is edited.
- */
- public boolean isAnyFieldEdited() {
- return CollectionUtil.isAnyNonNull(name, phone, email, address, tags);
- }
-
- public void setName(Name name) {
- this.name = name;
- }
-
- public Optional getName() {
- return Optional.ofNullable(name);
- }
-
- public void setPhone(Phone phone) {
- this.phone = phone;
- }
-
- public Optional getPhone() {
- return Optional.ofNullable(phone);
- }
-
- public void setEmail(Email email) {
- this.email = email;
- }
-
- public Optional getEmail() {
- return Optional.ofNullable(email);
- }
-
- public void setAddress(Address address) {
- this.address = address;
- }
-
- public Optional getAddress() {
- return Optional.ofNullable(address);
- }
-
- /**
- * Sets {@code tags} to this object's {@code tags}.
- * A defensive copy of {@code tags} is used internally.
- */
- public void setTags(Set tags) {
- this.tags = (tags != null) ? new HashSet<>(tags) : null;
- }
-
- /**
- * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException}
- * if modification is attempted.
- * Returns {@code Optional#empty()} if {@code tags} is null.
- */
- public Optional> getTags() {
- return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
- }
-
- @Override
- public boolean equals(Object other) {
- // short circuit if same object
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof EditPersonDescriptor)) {
- return false;
- }
-
- // state check
- EditPersonDescriptor e = (EditPersonDescriptor) other;
-
- return getName().equals(e.getName())
- && getPhone().equals(e.getPhone())
- && getEmail().equals(e.getEmail())
- && getAddress().equals(e.getAddress())
- && getTags().equals(e.getTags());
- }
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java
deleted file mode 100644
index d6b19b0a0de..00000000000
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-
-import seedu.address.commons.core.Messages;
-import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-
-/**
- * Finds and lists all persons in address book whose name contains any of the argument keywords.
- * Keyword matching is case insensitive.
- */
-public class FindCommand extends Command {
-
- public static final String COMMAND_WORD = "find";
-
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of "
- + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
- + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
- + "Example: " + COMMAND_WORD + " alice bob charlie";
-
- private final NameContainsKeywordsPredicate predicate;
-
- public FindCommand(NameContainsKeywordsPredicate predicate) {
- this.predicate = predicate;
- }
-
- @Override
- public CommandResult execute(Model model) {
- requireNonNull(model);
- model.updateFilteredPersonList(predicate);
- return new CommandResult(
- String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof FindCommand // instanceof handles nulls
- && predicate.equals(((FindCommand) other).predicate)); // state check
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java
deleted file mode 100644
index 84be6ad2596..00000000000
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
-
-import seedu.address.model.Model;
-
-/**
- * Lists all persons in the address book to the user.
- */
-public class ListCommand extends Command {
-
- public static final String COMMAND_WORD = "list";
-
- public static final String MESSAGE_SUCCESS = "Listed all persons";
-
-
- @Override
- public CommandResult execute(Model model) {
- requireNonNull(model);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(MESSAGE_SUCCESS);
- }
-}
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
deleted file mode 100644
index 3b8bfa035e8..00000000000
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import java.util.Set;
-import java.util.stream.Stream;
-
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Parses input arguments and creates a new AddCommand object
- */
-public class AddCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the AddCommand
- * and returns an AddCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public AddCommand parse(String args) throws ParseException {
- ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
-
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
- || !argMultimap.getPreamble().isEmpty()) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
- }
-
- Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
- Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get());
- Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get());
- Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get());
- Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
-
- Person person = new Person(name, phone, email, address, tagList);
-
- return new AddCommand(person);
- }
-
- /**
- * Returns true if none of the prefixes contains empty {@code Optional} values in the given
- * {@code ArgumentMultimap}.
- */
- private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
- return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
deleted file mode 100644
index 1e466792b46..00000000000
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.commands.ClearCommand;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.commands.DeleteCommand;
-import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.ExitCommand;
-import seedu.address.logic.commands.FindCommand;
-import seedu.address.logic.commands.HelpCommand;
-import seedu.address.logic.commands.ListCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
-
-/**
- * Parses user input.
- */
-public class AddressBookParser {
-
- /**
- * Used for initial separation of command word and args.
- */
- private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)");
-
- /**
- * Parses user input into command for execution.
- *
- * @param userInput full user input string
- * @return the command based on the user input
- * @throws ParseException if the user input does not conform the expected format
- */
- public Command parseCommand(String userInput) throws ParseException {
- final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
- if (!matcher.matches()) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
- }
-
- final String commandWord = matcher.group("commandWord");
- final String arguments = matcher.group("arguments");
- switch (commandWord) {
-
- case AddCommand.COMMAND_WORD:
- return new AddCommandParser().parse(arguments);
-
- case EditCommand.COMMAND_WORD:
- return new EditCommandParser().parse(arguments);
-
- case DeleteCommand.COMMAND_WORD:
- return new DeleteCommandParser().parse(arguments);
-
- case ClearCommand.COMMAND_WORD:
- return new ClearCommand();
-
- case FindCommand.COMMAND_WORD:
- return new FindCommandParser().parse(arguments);
-
- case ListCommand.COMMAND_WORD:
- return new ListCommand();
-
- case ExitCommand.COMMAND_WORD:
- return new ExitCommand();
-
- case HelpCommand.COMMAND_WORD:
- return new HelpCommand();
-
- default:
- throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
- }
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
deleted file mode 100644
index 522b93081cc..00000000000
--- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.DeleteCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
-
-/**
- * Parses input arguments and creates a new DeleteCommand object
- */
-public class DeleteCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the DeleteCommand
- * and returns a DeleteCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public DeleteCommand parse(String args) throws ParseException {
- try {
- Index index = ParserUtil.parseIndex(args);
- return new DeleteCommand(index);
- } catch (ParseException pe) {
- throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE), pe);
- }
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
deleted file mode 100644
index 845644b7dea..00000000000
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package seedu.address.logic.parser;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Optional;
-import java.util.Set;
-
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.tag.Tag;
-
-/**
- * Parses input arguments and creates a new EditCommand object
- */
-public class EditCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the EditCommand
- * and returns an EditCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public EditCommand parse(String args) throws ParseException {
- requireNonNull(args);
- ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
-
- Index index;
-
- try {
- index = ParserUtil.parseIndex(argMultimap.getPreamble());
- } catch (ParseException pe) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe);
- }
-
- EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
- if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
- editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
- }
- if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
- editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
- }
- if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
- editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
- }
- if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
- editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
- }
- parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
-
- if (!editPersonDescriptor.isAnyFieldEdited()) {
- throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
- }
-
- return new EditCommand(index, editPersonDescriptor);
- }
-
- /**
- * Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty.
- * If {@code tags} contain only one element which is an empty string, it will be parsed into a
- * {@code Set} containing zero tags.
- */
- private Optional> parseTagsForEdit(Collection tags) throws ParseException {
- assert tags != null;
-
- if (tags.isEmpty()) {
- return Optional.empty();
- }
- Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
- return Optional.of(ParserUtil.parseTags(tagSet));
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
deleted file mode 100644
index 4fb71f23103..00000000000
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-
-import java.util.Arrays;
-
-import seedu.address.logic.commands.FindCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-
-/**
- * Parses input arguments and creates a new FindCommand object
- */
-public class FindCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the FindCommand
- * and returns a FindCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public FindCommand parse(String args) throws ParseException {
- String trimmedArgs = args.trim();
- if (trimmedArgs.isEmpty()) {
- throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
- }
-
- String[] nameKeywords = trimmedArgs.split("\\s+");
-
- return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
deleted file mode 100644
index b117acb9c55..00000000000
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package seedu.address.logic.parser;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-import seedu.address.commons.core.index.Index;
-import seedu.address.commons.util.StringUtil;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Contains utility methods used for parsing strings in the various *Parser classes.
- */
-public class ParserUtil {
-
- public static final String MESSAGE_INVALID_INDEX = "Index is not a non-zero unsigned integer.";
-
- /**
- * Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be
- * trimmed.
- * @throws ParseException if the specified index is invalid (not non-zero unsigned integer).
- */
- public static Index parseIndex(String oneBasedIndex) throws ParseException {
- String trimmedIndex = oneBasedIndex.trim();
- if (!StringUtil.isNonZeroUnsignedInteger(trimmedIndex)) {
- throw new ParseException(MESSAGE_INVALID_INDEX);
- }
- return Index.fromOneBased(Integer.parseInt(trimmedIndex));
- }
-
- /**
- * Parses a {@code String name} into a {@code Name}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code name} is invalid.
- */
- public static Name parseName(String name) throws ParseException {
- requireNonNull(name);
- String trimmedName = name.trim();
- if (!Name.isValidName(trimmedName)) {
- throw new ParseException(Name.MESSAGE_CONSTRAINTS);
- }
- return new Name(trimmedName);
- }
-
- /**
- * Parses a {@code String phone} into a {@code Phone}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code phone} is invalid.
- */
- public static Phone parsePhone(String phone) throws ParseException {
- requireNonNull(phone);
- String trimmedPhone = phone.trim();
- if (!Phone.isValidPhone(trimmedPhone)) {
- throw new ParseException(Phone.MESSAGE_CONSTRAINTS);
- }
- return new Phone(trimmedPhone);
- }
-
- /**
- * Parses a {@code String address} into an {@code Address}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code address} is invalid.
- */
- public static Address parseAddress(String address) throws ParseException {
- requireNonNull(address);
- String trimmedAddress = address.trim();
- if (!Address.isValidAddress(trimmedAddress)) {
- throw new ParseException(Address.MESSAGE_CONSTRAINTS);
- }
- return new Address(trimmedAddress);
- }
-
- /**
- * Parses a {@code String email} into an {@code Email}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code email} is invalid.
- */
- public static Email parseEmail(String email) throws ParseException {
- requireNonNull(email);
- String trimmedEmail = email.trim();
- if (!Email.isValidEmail(trimmedEmail)) {
- throw new ParseException(Email.MESSAGE_CONSTRAINTS);
- }
- return new Email(trimmedEmail);
- }
-
- /**
- * Parses a {@code String tag} into a {@code Tag}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code tag} is invalid.
- */
- public static Tag parseTag(String tag) throws ParseException {
- requireNonNull(tag);
- String trimmedTag = tag.trim();
- if (!Tag.isValidTagName(trimmedTag)) {
- throw new ParseException(Tag.MESSAGE_CONSTRAINTS);
- }
- return new Tag(trimmedTag);
- }
-
- /**
- * Parses {@code Collection tags} into a {@code Set}.
- */
- public static Set parseTags(Collection tags) throws ParseException {
- requireNonNull(tags);
- final Set tagSet = new HashSet<>();
- for (String tagName : tags) {
- tagSet.add(parseTag(tagName));
- }
- return tagSet;
- }
-}
diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java
deleted file mode 100644
index 1a943a0781a..00000000000
--- a/src/main/java/seedu/address/model/AddressBook.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package seedu.address.model;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.List;
-
-import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.UniquePersonList;
-
-/**
- * Wraps all data at the address-book level
- * Duplicates are not allowed (by .isSamePerson comparison)
- */
-public class AddressBook implements ReadOnlyAddressBook {
-
- private final UniquePersonList persons;
-
- /*
- * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
- * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
- *
- * Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication
- * among constructors.
- */
- {
- persons = new UniquePersonList();
- }
-
- public AddressBook() {}
-
- /**
- * Creates an AddressBook using the Persons in the {@code toBeCopied}
- */
- public AddressBook(ReadOnlyAddressBook toBeCopied) {
- this();
- resetData(toBeCopied);
- }
-
- //// list overwrite operations
-
- /**
- * Replaces the contents of the person list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
- */
- public void setPersons(List persons) {
- this.persons.setPersons(persons);
- }
-
- /**
- * Resets the existing data of this {@code AddressBook} with {@code newData}.
- */
- public void resetData(ReadOnlyAddressBook newData) {
- requireNonNull(newData);
-
- setPersons(newData.getPersonList());
- }
-
- //// person-level operations
-
- /**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
- */
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return persons.contains(person);
- }
-
- /**
- * Adds a person to the address book.
- * The person must not already exist in the address book.
- */
- public void addPerson(Person p) {
- persons.add(p);
- }
-
- /**
- * Replaces the given person {@code target} in the list with {@code editedPerson}.
- * {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
- */
- public void setPerson(Person target, Person editedPerson) {
- requireNonNull(editedPerson);
-
- persons.setPerson(target, editedPerson);
- }
-
- /**
- * Removes {@code key} from this {@code AddressBook}.
- * {@code key} must exist in the address book.
- */
- public void removePerson(Person key) {
- persons.remove(key);
- }
-
- //// util methods
-
- @Override
- public String toString() {
- return persons.asUnmodifiableObservableList().size() + " persons";
- // TODO: refine later
- }
-
- @Override
- public ObservableList getPersonList() {
- return persons.asUnmodifiableObservableList();
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof AddressBook // instanceof handles nulls
- && persons.equals(((AddressBook) other).persons));
- }
-
- @Override
- public int hashCode() {
- return persons.hashCode();
- }
-}
diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java
deleted file mode 100644
index d54df471c1f..00000000000
--- a/src/main/java/seedu/address/model/Model.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package seedu.address.model;
-
-import java.nio.file.Path;
-import java.util.function.Predicate;
-
-import javafx.collections.ObservableList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.model.person.Person;
-
-/**
- * The API of the Model component.
- */
-public interface Model {
- /** {@code Predicate} that always evaluate to true */
- Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true;
-
- /**
- * Replaces user prefs data with the data in {@code userPrefs}.
- */
- void setUserPrefs(ReadOnlyUserPrefs userPrefs);
-
- /**
- * Returns the user prefs.
- */
- ReadOnlyUserPrefs getUserPrefs();
-
- /**
- * Returns the user prefs' GUI settings.
- */
- GuiSettings getGuiSettings();
-
- /**
- * Sets the user prefs' GUI settings.
- */
- void setGuiSettings(GuiSettings guiSettings);
-
- /**
- * Returns the user prefs' address book file path.
- */
- Path getAddressBookFilePath();
-
- /**
- * Sets the user prefs' address book file path.
- */
- void setAddressBookFilePath(Path addressBookFilePath);
-
- /**
- * Replaces address book data with the data in {@code addressBook}.
- */
- void setAddressBook(ReadOnlyAddressBook addressBook);
-
- /** Returns the AddressBook */
- ReadOnlyAddressBook getAddressBook();
-
- /**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
- */
- boolean hasPerson(Person person);
-
- /**
- * Deletes the given person.
- * The person must exist in the address book.
- */
- void deletePerson(Person target);
-
- /**
- * Adds the given person.
- * {@code person} must not already exist in the address book.
- */
- void addPerson(Person person);
-
- /**
- * Replaces the given person {@code target} with {@code editedPerson}.
- * {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
- */
- void setPerson(Person target, Person editedPerson);
-
- /** Returns an unmodifiable view of the filtered person list */
- ObservableList getFilteredPersonList();
-
- /**
- * Updates the filter of the filtered person list to filter by the given {@code predicate}.
- * @throws NullPointerException if {@code predicate} is null.
- */
- void updateFilteredPersonList(Predicate predicate);
-}
diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java
deleted file mode 100644
index 0650c954f5c..00000000000
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package seedu.address.model;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.nio.file.Path;
-import java.util.function.Predicate;
-import java.util.logging.Logger;
-
-import javafx.collections.ObservableList;
-import javafx.collections.transformation.FilteredList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.model.person.Person;
-
-/**
- * Represents the in-memory model of the address book data.
- */
-public class ModelManager implements Model {
- private static final Logger logger = LogsCenter.getLogger(ModelManager.class);
-
- private final AddressBook addressBook;
- private final UserPrefs userPrefs;
- private final FilteredList filteredPersons;
-
- /**
- * Initializes a ModelManager with the given addressBook and userPrefs.
- */
- public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) {
- super();
- requireAllNonNull(addressBook, userPrefs);
-
- logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs);
-
- this.addressBook = new AddressBook(addressBook);
- this.userPrefs = new UserPrefs(userPrefs);
- filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
- }
-
- public ModelManager() {
- this(new AddressBook(), new UserPrefs());
- }
-
- //=========== UserPrefs ==================================================================================
-
- @Override
- public void setUserPrefs(ReadOnlyUserPrefs userPrefs) {
- requireNonNull(userPrefs);
- this.userPrefs.resetData(userPrefs);
- }
-
- @Override
- public ReadOnlyUserPrefs getUserPrefs() {
- return userPrefs;
- }
-
- @Override
- public GuiSettings getGuiSettings() {
- return userPrefs.getGuiSettings();
- }
-
- @Override
- public void setGuiSettings(GuiSettings guiSettings) {
- requireNonNull(guiSettings);
- userPrefs.setGuiSettings(guiSettings);
- }
-
- @Override
- public Path getAddressBookFilePath() {
- return userPrefs.getAddressBookFilePath();
- }
-
- @Override
- public void setAddressBookFilePath(Path addressBookFilePath) {
- requireNonNull(addressBookFilePath);
- userPrefs.setAddressBookFilePath(addressBookFilePath);
- }
-
- //=========== AddressBook ================================================================================
-
- @Override
- public void setAddressBook(ReadOnlyAddressBook addressBook) {
- this.addressBook.resetData(addressBook);
- }
-
- @Override
- public ReadOnlyAddressBook getAddressBook() {
- return addressBook;
- }
-
- @Override
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return addressBook.hasPerson(person);
- }
-
- @Override
- public void deletePerson(Person target) {
- addressBook.removePerson(target);
- }
-
- @Override
- public void addPerson(Person person) {
- addressBook.addPerson(person);
- updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- }
-
- @Override
- public void setPerson(Person target, Person editedPerson) {
- requireAllNonNull(target, editedPerson);
-
- addressBook.setPerson(target, editedPerson);
- }
-
- //=========== Filtered Person List Accessors =============================================================
-
- /**
- * Returns an unmodifiable view of the list of {@code Person} backed by the internal list of
- * {@code versionedAddressBook}
- */
- @Override
- public ObservableList getFilteredPersonList() {
- return filteredPersons;
- }
-
- @Override
- public void updateFilteredPersonList(Predicate predicate) {
- requireNonNull(predicate);
- filteredPersons.setPredicate(predicate);
- }
-
- @Override
- public boolean equals(Object obj) {
- // short circuit if same object
- if (obj == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(obj instanceof ModelManager)) {
- return false;
- }
-
- // state check
- ModelManager other = (ModelManager) obj;
- return addressBook.equals(other.addressBook)
- && userPrefs.equals(other.userPrefs)
- && filteredPersons.equals(other.filteredPersons);
- }
-
-}
diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
deleted file mode 100644
index 6ddc2cd9a29..00000000000
--- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package seedu.address.model;
-
-import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-
-/**
- * Unmodifiable view of an address book
- */
-public interface ReadOnlyAddressBook {
-
- /**
- * Returns an unmodifiable view of the persons list.
- * This list will not contain any duplicate persons.
- */
- ObservableList getPersonList();
-
-}
diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/person/Address.java
deleted file mode 100644
index 60472ca22a0..00000000000
--- a/src/main/java/seedu/address/model/person/Address.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Person's address in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)}
- */
-public class Address {
-
- public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values, and it should not be blank";
-
- /*
- * The first character of the address must not be a whitespace,
- * otherwise " " (a blank string) becomes a valid input.
- */
- public static final String VALIDATION_REGEX = "[^\\s].*";
-
- public final String value;
-
- /**
- * Constructs an {@code Address}.
- *
- * @param address A valid address.
- */
- public Address(String address) {
- requireNonNull(address);
- checkArgument(isValidAddress(address), MESSAGE_CONSTRAINTS);
- value = address;
- }
-
- /**
- * Returns true if a given string is a valid email.
- */
- public static boolean isValidAddress(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public String toString() {
- return value;
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Address // instanceof handles nulls
- && value.equals(((Address) other).value)); // state check
- }
-
- @Override
- public int hashCode() {
- return value.hashCode();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/seedu/address/model/person/Email.java
deleted file mode 100644
index a5bbe0b6a5f..00000000000
--- a/src/main/java/seedu/address/model/person/Email.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Person's email in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidEmail(String)}
- */
-public class Email {
-
- private static final String SPECIAL_CHARACTERS = "!#$%&'*+/=?`{|}~^.-";
- public static final String MESSAGE_CONSTRAINTS = "Emails should be of the format local-part@domain "
- + "and adhere to the following constraints:\n"
- + "1. The local-part should only contain alphanumeric characters and these special characters, excluding "
- + "the parentheses, (" + SPECIAL_CHARACTERS + ") .\n"
- + "2. This is followed by a '@' and then a domain name. "
- + "The domain name must:\n"
- + " - be at least 2 characters long\n"
- + " - start and end with alphanumeric characters\n"
- + " - consist of alphanumeric characters, a period or a hyphen for the characters in between, if any.";
- // alphanumeric and special characters
- private static final String LOCAL_PART_REGEX = "^[\\w" + SPECIAL_CHARACTERS + "]+";
- private static final String DOMAIN_FIRST_CHARACTER_REGEX = "[^\\W_]"; // alphanumeric characters except underscore
- private static final String DOMAIN_MIDDLE_REGEX = "[a-zA-Z0-9.-]*"; // alphanumeric, period and hyphen
- private static final String DOMAIN_LAST_CHARACTER_REGEX = "[^\\W_]$";
- public static final String VALIDATION_REGEX = LOCAL_PART_REGEX + "@"
- + DOMAIN_FIRST_CHARACTER_REGEX + DOMAIN_MIDDLE_REGEX + DOMAIN_LAST_CHARACTER_REGEX;
-
- public final String value;
-
- /**
- * Constructs an {@code Email}.
- *
- * @param email A valid email address.
- */
- public Email(String email) {
- requireNonNull(email);
- checkArgument(isValidEmail(email), MESSAGE_CONSTRAINTS);
- value = email;
- }
-
- /**
- * Returns if a given string is a valid email.
- */
- public static boolean isValidEmail(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public String toString() {
- return value;
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Email // instanceof handles nulls
- && value.equals(((Email) other).value)); // state check
- }
-
- @Override
- public int hashCode() {
- return value.hashCode();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/seedu/address/model/person/Name.java
deleted file mode 100644
index 79244d71cf7..00000000000
--- a/src/main/java/seedu/address/model/person/Name.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Person's name in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidName(String)}
- */
-public class Name {
-
- public static final String MESSAGE_CONSTRAINTS =
- "Names should only contain alphanumeric characters and spaces, and it should not be blank";
-
- /*
- * The first character of the address must not be a whitespace,
- * otherwise " " (a blank string) becomes a valid input.
- */
- public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
-
- public final String fullName;
-
- /**
- * Constructs a {@code Name}.
- *
- * @param name A valid name.
- */
- public Name(String name) {
- requireNonNull(name);
- checkArgument(isValidName(name), MESSAGE_CONSTRAINTS);
- fullName = name;
- }
-
- /**
- * Returns true if a given string is a valid name.
- */
- public static boolean isValidName(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
-
- @Override
- public String toString() {
- return fullName;
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Name // instanceof handles nulls
- && fullName.equals(((Name) other).fullName)); // state check
- }
-
- @Override
- public int hashCode() {
- return fullName.hashCode();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
deleted file mode 100644
index c9b5868427c..00000000000
--- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package seedu.address.model.person;
-
-import java.util.List;
-import java.util.function.Predicate;
-
-import seedu.address.commons.util.StringUtil;
-
-/**
- * Tests that a {@code Person}'s {@code Name} matches any of the keywords given.
- */
-public class NameContainsKeywordsPredicate implements Predicate {
- private final List keywords;
-
- public NameContainsKeywordsPredicate(List keywords) {
- this.keywords = keywords;
- }
-
- @Override
- public boolean test(Person person) {
- return keywords.stream()
- .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword));
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof NameContainsKeywordsPredicate // instanceof handles nulls
- && keywords.equals(((NameContainsKeywordsPredicate) other).keywords)); // state check
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java
deleted file mode 100644
index 8ff1d83fe89..00000000000
--- a/src/main/java/seedu/address/model/person/Person.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package seedu.address.model.person;
-
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
-
-import seedu.address.model.tag.Tag;
-
-/**
- * Represents a Person in the address book.
- * Guarantees: details are present and not null, field values are validated, immutable.
- */
-public class Person {
-
- // Identity fields
- private final Name name;
- private final Phone phone;
- private final Email email;
-
- // Data fields
- private final Address address;
- private final Set tags = new HashSet<>();
-
- /**
- * Every field must be present and not null.
- */
- public Person(Name name, Phone phone, Email email, Address address, Set tags) {
- requireAllNonNull(name, phone, email, address, tags);
- this.name = name;
- this.phone = phone;
- this.email = email;
- this.address = address;
- this.tags.addAll(tags);
- }
-
- public Name getName() {
- return name;
- }
-
- public Phone getPhone() {
- return phone;
- }
-
- public Email getEmail() {
- return email;
- }
-
- public Address getAddress() {
- return address;
- }
-
- /**
- * Returns an immutable tag set, which throws {@code UnsupportedOperationException}
- * if modification is attempted.
- */
- public Set getTags() {
- return Collections.unmodifiableSet(tags);
- }
-
- /**
- * Returns true if both persons have the same name.
- * This defines a weaker notion of equality between two persons.
- */
- public boolean isSamePerson(Person otherPerson) {
- if (otherPerson == this) {
- return true;
- }
-
- return otherPerson != null
- && otherPerson.getName().equals(getName());
- }
-
- /**
- * Returns true if both persons have the same identity and data fields.
- * This defines a stronger notion of equality between two persons.
- */
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- if (!(other instanceof Person)) {
- return false;
- }
-
- Person otherPerson = (Person) other;
- return otherPerson.getName().equals(getName())
- && otherPerson.getPhone().equals(getPhone())
- && otherPerson.getEmail().equals(getEmail())
- && otherPerson.getAddress().equals(getAddress())
- && otherPerson.getTags().equals(getTags());
- }
-
- @Override
- public int hashCode() {
- // use this method for custom fields hashing instead of implementing your own
- return Objects.hash(name, phone, email, address, tags);
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append(getName())
- .append("; Phone: ")
- .append(getPhone())
- .append("; Email: ")
- .append(getEmail())
- .append("; Address: ")
- .append(getAddress());
-
- Set tags = getTags();
- if (!tags.isEmpty()) {
- builder.append("; Tags: ");
- tags.forEach(builder::append);
- }
- return builder.toString();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java
deleted file mode 100644
index 0fee4fe57e6..00000000000
--- a/src/main/java/seedu/address/model/person/UniquePersonList.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.util.Iterator;
-import java.util.List;
-
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import seedu.address.model.person.exceptions.DuplicatePersonException;
-import seedu.address.model.person.exceptions.PersonNotFoundException;
-
-/**
- * A list of persons that enforces uniqueness between its elements and does not allow nulls.
- * A person is considered unique by comparing using {@code Person#isSamePerson(Person)}. As such, adding and updating of
- * persons uses Person#isSamePerson(Person) for equality so as to ensure that the person being added or updated is
- * unique in terms of identity in the UniquePersonList. However, the removal of a person uses Person#equals(Object) so
- * as to ensure that the person with exactly the same fields will be removed.
- *
- * Supports a minimal set of list operations.
- *
- * @see Person#isSamePerson(Person)
- */
-public class UniquePersonList implements Iterable {
-
- private final ObservableList internalList = FXCollections.observableArrayList();
- private final ObservableList internalUnmodifiableList =
- FXCollections.unmodifiableObservableList(internalList);
-
- /**
- * Returns true if the list contains an equivalent person as the given argument.
- */
- public boolean contains(Person toCheck) {
- requireNonNull(toCheck);
- return internalList.stream().anyMatch(toCheck::isSamePerson);
- }
-
- /**
- * Adds a person to the list.
- * The person must not already exist in the list.
- */
- public void add(Person toAdd) {
- requireNonNull(toAdd);
- if (contains(toAdd)) {
- throw new DuplicatePersonException();
- }
- internalList.add(toAdd);
- }
-
- /**
- * Replaces the person {@code target} in the list with {@code editedPerson}.
- * {@code target} must exist in the list.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the list.
- */
- public void setPerson(Person target, Person editedPerson) {
- requireAllNonNull(target, editedPerson);
-
- int index = internalList.indexOf(target);
- if (index == -1) {
- throw new PersonNotFoundException();
- }
-
- if (!target.isSamePerson(editedPerson) && contains(editedPerson)) {
- throw new DuplicatePersonException();
- }
-
- internalList.set(index, editedPerson);
- }
-
- /**
- * Removes the equivalent person from the list.
- * The person must exist in the list.
- */
- public void remove(Person toRemove) {
- requireNonNull(toRemove);
- if (!internalList.remove(toRemove)) {
- throw new PersonNotFoundException();
- }
- }
-
- public void setPersons(UniquePersonList replacement) {
- requireNonNull(replacement);
- internalList.setAll(replacement.internalList);
- }
-
- /**
- * Replaces the contents of this list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
- */
- public void setPersons(List persons) {
- requireAllNonNull(persons);
- if (!personsAreUnique(persons)) {
- throw new DuplicatePersonException();
- }
-
- internalList.setAll(persons);
- }
-
- /**
- * Returns the backing list as an unmodifiable {@code ObservableList}.
- */
- public ObservableList asUnmodifiableObservableList() {
- return internalUnmodifiableList;
- }
-
- @Override
- public Iterator iterator() {
- return internalList.iterator();
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof UniquePersonList // instanceof handles nulls
- && internalList.equals(((UniquePersonList) other).internalList));
- }
-
- @Override
- public int hashCode() {
- return internalList.hashCode();
- }
-
- /**
- * Returns true if {@code persons} contains only unique persons.
- */
- private boolean personsAreUnique(List persons) {
- for (int i = 0; i < persons.size() - 1; i++) {
- for (int j = i + 1; j < persons.size(); j++) {
- if (persons.get(i).isSamePerson(persons.get(j))) {
- return false;
- }
- }
- }
- return true;
- }
-}
diff --git a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java b/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
deleted file mode 100644
index d7290f59442..00000000000
--- a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package seedu.address.model.person.exceptions;
-
-/**
- * Signals that the operation will result in duplicate Persons (Persons are considered duplicates if they have the same
- * identity).
- */
-public class DuplicatePersonException extends RuntimeException {
- public DuplicatePersonException() {
- super("Operation would result in duplicate persons");
- }
-}
diff --git a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java b/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
deleted file mode 100644
index fa764426ca7..00000000000
--- a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package seedu.address.model.person.exceptions;
-
-/**
- * Signals that the operation is unable to find the specified person.
- */
-public class PersonNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java
deleted file mode 100644
index 1806da4facf..00000000000
--- a/src/main/java/seedu/address/model/util/SampleDataUtil.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package seedu.address.model.util;
-
-import java.util.Arrays;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Contains utility methods for populating {@code AddressBook} with sample data.
- */
-public class SampleDataUtil {
- public static Person[] getSamplePersons() {
- return new Person[] {
- new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"),
- new Address("Blk 30 Geylang Street 29, #06-40"),
- getTagSet("friends")),
- new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"),
- new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"),
- getTagSet("colleagues", "friends")),
- new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"),
- new Address("Blk 11 Ang Mo Kio Street 74, #11-04"),
- getTagSet("neighbours")),
- new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"),
- new Address("Blk 436 Serangoon Gardens Street 26, #16-43"),
- getTagSet("family")),
- new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"),
- new Address("Blk 47 Tampines Street 20, #17-35"),
- getTagSet("classmates")),
- new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"),
- new Address("Blk 45 Aljunied Street 85, #11-31"),
- getTagSet("colleagues"))
- };
- }
-
- public static ReadOnlyAddressBook getSampleAddressBook() {
- AddressBook sampleAb = new AddressBook();
- for (Person samplePerson : getSamplePersons()) {
- sampleAb.addPerson(samplePerson);
- }
- return sampleAb;
- }
-
- /**
- * Returns a tag set containing the list of strings given.
- */
- public static Set getTagSet(String... strings) {
- return Arrays.stream(strings)
- .map(Tag::new)
- .collect(Collectors.toSet());
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/AddressBookStorage.java b/src/main/java/seedu/address/storage/AddressBookStorage.java
deleted file mode 100644
index 4599182b3f9..00000000000
--- a/src/main/java/seedu/address/storage/AddressBookStorage.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.model.ReadOnlyAddressBook;
-
-/**
- * Represents a storage for {@link seedu.address.model.AddressBook}.
- */
-public interface AddressBookStorage {
-
- /**
- * Returns the file path of the data file.
- */
- Path getAddressBookFilePath();
-
- /**
- * Returns AddressBook data as a {@link ReadOnlyAddressBook}.
- * Returns {@code Optional.empty()} if storage file is not found.
- * @throws DataConversionException if the data in storage is not in the expected format.
- * @throws IOException if there was any problem when reading from the storage.
- */
- Optional readAddressBook() throws DataConversionException, IOException;
-
- /**
- * @see #getAddressBookFilePath()
- */
- Optional readAddressBook(Path filePath) throws DataConversionException, IOException;
-
- /**
- * Saves the given {@link ReadOnlyAddressBook} to the storage.
- * @param addressBook cannot be null.
- * @throws IOException if there was any problem writing to the file.
- */
- void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException;
-
- /**
- * @see #saveAddressBook(ReadOnlyAddressBook)
- */
- void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException;
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
deleted file mode 100644
index a6321cec2ea..00000000000
--- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package seedu.address.storage;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Jackson-friendly version of {@link Person}.
- */
-class JsonAdaptedPerson {
-
- public static final String MISSING_FIELD_MESSAGE_FORMAT = "Person's %s field is missing!";
-
- private final String name;
- private final String phone;
- private final String email;
- private final String address;
- private final List tagged = new ArrayList<>();
-
- /**
- * Constructs a {@code JsonAdaptedPerson} with the given person details.
- */
- @JsonCreator
- public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
- @JsonProperty("email") String email, @JsonProperty("address") String address,
- @JsonProperty("tagged") List tagged) {
- this.name = name;
- this.phone = phone;
- this.email = email;
- this.address = address;
- if (tagged != null) {
- this.tagged.addAll(tagged);
- }
- }
-
- /**
- * Converts a given {@code Person} into this class for Jackson use.
- */
- public JsonAdaptedPerson(Person source) {
- name = source.getName().fullName;
- phone = source.getPhone().value;
- email = source.getEmail().value;
- address = source.getAddress().value;
- tagged.addAll(source.getTags().stream()
- .map(JsonAdaptedTag::new)
- .collect(Collectors.toList()));
- }
-
- /**
- * Converts this Jackson-friendly adapted person object into the model's {@code Person} object.
- *
- * @throws IllegalValueException if there were any data constraints violated in the adapted person.
- */
- public Person toModelType() throws IllegalValueException {
- final List personTags = new ArrayList<>();
- for (JsonAdaptedTag tag : tagged) {
- personTags.add(tag.toModelType());
- }
-
- if (name == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()));
- }
- if (!Name.isValidName(name)) {
- throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS);
- }
- final Name modelName = new Name(name);
-
- if (phone == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName()));
- }
- if (!Phone.isValidPhone(phone)) {
- throw new IllegalValueException(Phone.MESSAGE_CONSTRAINTS);
- }
- final Phone modelPhone = new Phone(phone);
-
- if (email == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()));
- }
- if (!Email.isValidEmail(email)) {
- throw new IllegalValueException(Email.MESSAGE_CONSTRAINTS);
- }
- final Email modelEmail = new Email(email);
-
- if (address == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName()));
- }
- if (!Address.isValidAddress(address)) {
- throw new IllegalValueException(Address.MESSAGE_CONSTRAINTS);
- }
- final Address modelAddress = new Address(address);
-
- final Set modelTags = new HashSet<>(personTags);
- return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags);
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java b/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
deleted file mode 100644
index dfab9daaa0d..00000000000
--- a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package seedu.address.storage;
-
-import static java.util.Objects.requireNonNull;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-import java.util.logging.Logger;
-
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.commons.util.FileUtil;
-import seedu.address.commons.util.JsonUtil;
-import seedu.address.model.ReadOnlyAddressBook;
-
-/**
- * A class to access AddressBook data stored as a json file on the hard disk.
- */
-public class JsonAddressBookStorage implements AddressBookStorage {
-
- private static final Logger logger = LogsCenter.getLogger(JsonAddressBookStorage.class);
-
- private Path filePath;
-
- public JsonAddressBookStorage(Path filePath) {
- this.filePath = filePath;
- }
-
- public Path getAddressBookFilePath() {
- return filePath;
- }
-
- @Override
- public Optional readAddressBook() throws DataConversionException {
- return readAddressBook(filePath);
- }
-
- /**
- * Similar to {@link #readAddressBook()}.
- *
- * @param filePath location of the data. Cannot be null.
- * @throws DataConversionException if the file is not in the correct format.
- */
- public Optional readAddressBook(Path filePath) throws DataConversionException {
- requireNonNull(filePath);
-
- Optional jsonAddressBook = JsonUtil.readJsonFile(
- filePath, JsonSerializableAddressBook.class);
- if (!jsonAddressBook.isPresent()) {
- return Optional.empty();
- }
-
- try {
- return Optional.of(jsonAddressBook.get().toModelType());
- } catch (IllegalValueException ive) {
- logger.info("Illegal values found in " + filePath + ": " + ive.getMessage());
- throw new DataConversionException(ive);
- }
- }
-
- @Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, filePath);
- }
-
- /**
- * Similar to {@link #saveAddressBook(ReadOnlyAddressBook)}.
- *
- * @param filePath location of the data. Cannot be null.
- */
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
- requireNonNull(addressBook);
- requireNonNull(filePath);
-
- FileUtil.createIfMissing(filePath);
- JsonUtil.saveJsonFile(new JsonSerializableAddressBook(addressBook), filePath);
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
deleted file mode 100644
index 5efd834091d..00000000000
--- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package seedu.address.storage;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonRootName;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
-
-/**
- * An Immutable AddressBook that is serializable to JSON format.
- */
-@JsonRootName(value = "addressbook")
-class JsonSerializableAddressBook {
-
- public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s).";
-
- private final List persons = new ArrayList<>();
-
- /**
- * Constructs a {@code JsonSerializableAddressBook} with the given persons.
- */
- @JsonCreator
- public JsonSerializableAddressBook(@JsonProperty("persons") List persons) {
- this.persons.addAll(persons);
- }
-
- /**
- * Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use.
- *
- * @param source future changes to this will not affect the created {@code JsonSerializableAddressBook}.
- */
- public JsonSerializableAddressBook(ReadOnlyAddressBook source) {
- persons.addAll(source.getPersonList().stream().map(JsonAdaptedPerson::new).collect(Collectors.toList()));
- }
-
- /**
- * Converts this address book into the model's {@code AddressBook} object.
- *
- * @throws IllegalValueException if there were any data constraints violated.
- */
- public AddressBook toModelType() throws IllegalValueException {
- AddressBook addressBook = new AddressBook();
- for (JsonAdaptedPerson jsonAdaptedPerson : persons) {
- Person person = jsonAdaptedPerson.toModelType();
- if (addressBook.hasPerson(person)) {
- throw new IllegalValueException(MESSAGE_DUPLICATE_PERSON);
- }
- addressBook.addPerson(person);
- }
- return addressBook;
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/seedu/address/storage/Storage.java
deleted file mode 100644
index beda8bd9f11..00000000000
--- a/src/main/java/seedu/address/storage/Storage.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
-
-/**
- * API of the Storage component
- */
-public interface Storage extends AddressBookStorage, UserPrefsStorage {
-
- @Override
- Optional readUserPrefs() throws DataConversionException, IOException;
-
- @Override
- void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException;
-
- @Override
- Path getAddressBookFilePath();
-
- @Override
- Optional readAddressBook() throws DataConversionException, IOException;
-
- @Override
- void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException;
-
-}
diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/address/storage/StorageManager.java
deleted file mode 100644
index 79868290974..00000000000
--- a/src/main/java/seedu/address/storage/StorageManager.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-import java.util.logging.Logger;
-
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
-
-/**
- * Manages storage of AddressBook data in local storage.
- */
-public class StorageManager implements Storage {
-
- private static final Logger logger = LogsCenter.getLogger(StorageManager.class);
- private AddressBookStorage addressBookStorage;
- private UserPrefsStorage userPrefsStorage;
-
- /**
- * Creates a {@code StorageManager} with the given {@code AddressBookStorage} and {@code UserPrefStorage}.
- */
- public StorageManager(AddressBookStorage addressBookStorage, UserPrefsStorage userPrefsStorage) {
- super();
- this.addressBookStorage = addressBookStorage;
- this.userPrefsStorage = userPrefsStorage;
- }
-
- // ================ UserPrefs methods ==============================
-
- @Override
- public Path getUserPrefsFilePath() {
- return userPrefsStorage.getUserPrefsFilePath();
- }
-
- @Override
- public Optional readUserPrefs() throws DataConversionException, IOException {
- return userPrefsStorage.readUserPrefs();
- }
-
- @Override
- public void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException {
- userPrefsStorage.saveUserPrefs(userPrefs);
- }
-
-
- // ================ AddressBook methods ==============================
-
- @Override
- public Path getAddressBookFilePath() {
- return addressBookStorage.getAddressBookFilePath();
- }
-
- @Override
- public Optional readAddressBook() throws DataConversionException, IOException {
- return readAddressBook(addressBookStorage.getAddressBookFilePath());
- }
-
- @Override
- public Optional readAddressBook(Path filePath) throws DataConversionException, IOException {
- logger.fine("Attempting to read data from file: " + filePath);
- return addressBookStorage.readAddressBook(filePath);
- }
-
- @Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, addressBookStorage.getAddressBookFilePath());
- }
-
- @Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
- logger.fine("Attempting to write to data file: " + filePath);
- addressBookStorage.saveAddressBook(addressBook, filePath);
- }
-
-}
diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/seedu/address/ui/PersonListPanel.java
deleted file mode 100644
index f4c501a897b..00000000000
--- a/src/main/java/seedu/address/ui/PersonListPanel.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package seedu.address.ui;
-
-import java.util.logging.Logger;
-
-import javafx.collections.ObservableList;
-import javafx.fxml.FXML;
-import javafx.scene.control.ListCell;
-import javafx.scene.control.ListView;
-import javafx.scene.layout.Region;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.model.person.Person;
-
-/**
- * Panel containing the list of persons.
- */
-public class PersonListPanel extends UiPart {
- private static final String FXML = "PersonListPanel.fxml";
- private final Logger logger = LogsCenter.getLogger(PersonListPanel.class);
-
- @FXML
- private ListView personListView;
-
- /**
- * Creates a {@code PersonListPanel} with the given {@code ObservableList}.
- */
- public PersonListPanel(ObservableList personList) {
- super(FXML);
- personListView.setItems(personList);
- personListView.setCellFactory(listView -> new PersonListViewCell());
- }
-
- /**
- * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code PersonCard}.
- */
- class PersonListViewCell extends ListCell {
- @Override
- protected void updateItem(Person person, boolean empty) {
- super.updateItem(person, empty);
-
- if (empty || person == null) {
- setGraphic(null);
- setText(null);
- } else {
- setGraphic(new PersonCard(person, getIndex() + 1).getRoot());
- }
- }
- }
-
-}
diff --git a/src/main/java/seedu/address/AppParameters.java b/src/main/java/seedu/ta/AppParameters.java
similarity index 93%
rename from src/main/java/seedu/address/AppParameters.java
rename to src/main/java/seedu/ta/AppParameters.java
index ab552c398f3..8f1e43f63a5 100644
--- a/src/main/java/seedu/address/AppParameters.java
+++ b/src/main/java/seedu/ta/AppParameters.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.ta;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -7,8 +7,8 @@
import java.util.logging.Logger;
import javafx.application.Application;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.util.FileUtil;
+import seedu.ta.commons.core.LogsCenter;
+import seedu.ta.commons.util.FileUtil;
/**
* Represents the parsed command-line parameters given to the application.
diff --git a/src/main/java/seedu/address/Main.java b/src/main/java/seedu/ta/Main.java
similarity index 97%
rename from src/main/java/seedu/address/Main.java
rename to src/main/java/seedu/ta/Main.java
index 052a5068631..9fcb42ae1d1 100644
--- a/src/main/java/seedu/address/Main.java
+++ b/src/main/java/seedu/ta/Main.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.ta;
import javafx.application.Application;
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/ta/MainApp.java
similarity index 67%
rename from src/main/java/seedu/address/MainApp.java
rename to src/main/java/seedu/ta/MainApp.java
index e5cfb161b73..7e2759d5742 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/seedu/ta/MainApp.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.ta;
import java.io.IOException;
import java.nio.file.Path;
@@ -7,29 +7,29 @@
import javafx.application.Application;
import javafx.stage.Stage;
-import seedu.address.commons.core.Config;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.core.Version;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.commons.util.ConfigUtil;
-import seedu.address.commons.util.StringUtil;
-import seedu.address.logic.Logic;
-import seedu.address.logic.LogicManager;
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
-import seedu.address.model.util.SampleDataUtil;
-import seedu.address.storage.AddressBookStorage;
-import seedu.address.storage.JsonAddressBookStorage;
-import seedu.address.storage.JsonUserPrefsStorage;
-import seedu.address.storage.Storage;
-import seedu.address.storage.StorageManager;
-import seedu.address.storage.UserPrefsStorage;
-import seedu.address.ui.Ui;
-import seedu.address.ui.UiManager;
+import seedu.ta.commons.core.Config;
+import seedu.ta.commons.core.LogsCenter;
+import seedu.ta.commons.core.Version;
+import seedu.ta.commons.exceptions.DataConversionException;
+import seedu.ta.commons.util.ConfigUtil;
+import seedu.ta.commons.util.StringUtil;
+import seedu.ta.logic.Logic;
+import seedu.ta.logic.LogicManager;
+import seedu.ta.model.Model;
+import seedu.ta.model.ModelManager;
+import seedu.ta.model.ReadOnlyTeachingAssistant;
+import seedu.ta.model.ReadOnlyUserPrefs;
+import seedu.ta.model.TeachingAssistant;
+import seedu.ta.model.UserPrefs;
+import seedu.ta.model.util.SampleDataUtil;
+import seedu.ta.storage.JsonTeachingAssistantStorage;
+import seedu.ta.storage.JsonUserPrefsStorage;
+import seedu.ta.storage.Storage;
+import seedu.ta.storage.StorageManager;
+import seedu.ta.storage.TeachingAssistantStorage;
+import seedu.ta.storage.UserPrefsStorage;
+import seedu.ta.ui.Ui;
+import seedu.ta.ui.UiManager;
/**
* Runs the application.
@@ -48,7 +48,7 @@ public class MainApp extends Application {
@Override
public void init() throws Exception {
- logger.info("=============================[ Initializing AddressBook ]===========================");
+ logger.info("=============================[ Initializing TeachingAssistant ]===========================");
super.init();
AppParameters appParameters = AppParameters.parse(getParameters());
@@ -56,8 +56,9 @@ public void init() throws Exception {
UserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(config.getUserPrefsFilePath());
UserPrefs userPrefs = initPrefs(userPrefsStorage);
- AddressBookStorage addressBookStorage = new JsonAddressBookStorage(userPrefs.getAddressBookFilePath());
- storage = new StorageManager(addressBookStorage, userPrefsStorage);
+ TeachingAssistantStorage teachingAssistantStorage =
+ new JsonTeachingAssistantStorage(userPrefs.getTeachingAssistantFilePath());
+ storage = new StorageManager(teachingAssistantStorage, userPrefsStorage);
initLogging(config);
@@ -69,25 +70,26 @@ public void init() throws Exception {
}
/**
- * Returns a {@code ModelManager} with the data from {@code storage}'s address book and {@code userPrefs}.
- * The data from the sample address book will be used instead if {@code storage}'s address book is not found,
- * or an empty address book will be used instead if errors occur when reading {@code storage}'s address book.
+ * Returns a {@code ModelManager} with the data from {@code storage}'s teaching assistant and {@code userPrefs}.
+ *
The data from the sample teaching assistant will be used instead if {@code storage}'s teaching assistant
+ * is not found, or an empty teaching assistant will be used instead if errors occur when reading {@code storage}'s
+ * teaching assistant.
*/
private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
- Optional addressBookOptional;
- ReadOnlyAddressBook initialData;
+ Optional teachingAssistantOptional;
+ ReadOnlyTeachingAssistant initialData;
try {
- addressBookOptional = storage.readAddressBook();
- if (!addressBookOptional.isPresent()) {
- logger.info("Data file not found. Will be starting with a sample AddressBook");
+ teachingAssistantOptional = storage.readTeachingAssistant();
+ if (!teachingAssistantOptional.isPresent()) {
+ logger.info("Data file not found. Will be starting with a sample TeachingAssistant");
}
- initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook);
+ initialData = teachingAssistantOptional.orElseGet(SampleDataUtil::getSampleTeachingAssistant);
} catch (DataConversionException e) {
- logger.warning("Data file not in the correct format. Will be starting with an empty AddressBook");
- initialData = new AddressBook();
+ logger.warning("Data file not in the correct format. Will be starting with an empty TeachingAssistant");
+ initialData = new TeachingAssistant();
} catch (IOException e) {
- logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook");
- initialData = new AddressBook();
+ logger.warning("Problem while reading from the file. Will be starting with an empty TeachingAssistant");
+ initialData = new TeachingAssistant();
}
return new ModelManager(initialData, userPrefs);
@@ -151,7 +153,7 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
+ "Using default user prefs");
initializedPrefs = new UserPrefs();
} catch (IOException e) {
- logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook");
+ logger.warning("Problem while reading from the file. Will be starting with an empty TeachingAssistant");
initializedPrefs = new UserPrefs();
}
@@ -167,13 +169,13 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
@Override
public void start(Stage primaryStage) {
- logger.info("Starting AddressBook " + MainApp.VERSION);
+ logger.info("Starting TeachingAssistant " + MainApp.VERSION);
ui.start(primaryStage);
}
@Override
public void stop() {
- logger.info("============================ [ Stopping Address Book ] =============================");
+ logger.info("============================ [ Stopping Teaching Assistant ] =============================");
try {
storage.saveUserPrefs(model.getUserPrefs());
} catch (IOException e) {
diff --git a/src/main/java/seedu/address/commons/core/Config.java b/src/main/java/seedu/ta/commons/core/Config.java
similarity index 97%
rename from src/main/java/seedu/address/commons/core/Config.java
rename to src/main/java/seedu/ta/commons/core/Config.java
index 91145745521..b809e2e7282 100644
--- a/src/main/java/seedu/address/commons/core/Config.java
+++ b/src/main/java/seedu/ta/commons/core/Config.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.ta.commons.core;
import java.nio.file.Path;
import java.nio.file.Paths;
diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/seedu/ta/commons/core/GuiSettings.java
similarity index 93%
rename from src/main/java/seedu/address/commons/core/GuiSettings.java
rename to src/main/java/seedu/ta/commons/core/GuiSettings.java
index ba33653be67..3b37e7eef80 100644
--- a/src/main/java/seedu/address/commons/core/GuiSettings.java
+++ b/src/main/java/seedu/ta/commons/core/GuiSettings.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.ta.commons.core;
import java.awt.Point;
import java.io.Serializable;
@@ -10,8 +10,8 @@
*/
public class GuiSettings implements Serializable {
- private static final double DEFAULT_HEIGHT = 600;
- private static final double DEFAULT_WIDTH = 740;
+ private static final double DEFAULT_HEIGHT = 700;
+ private static final double DEFAULT_WIDTH = 1000;
private final double windowWidth;
private final double windowHeight;
diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/seedu/ta/commons/core/LogsCenter.java
similarity index 97%
rename from src/main/java/seedu/address/commons/core/LogsCenter.java
rename to src/main/java/seedu/ta/commons/core/LogsCenter.java
index 431e7185e76..353fa56fe91 100644
--- a/src/main/java/seedu/address/commons/core/LogsCenter.java
+++ b/src/main/java/seedu/ta/commons/core/LogsCenter.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.ta.commons.core;
import java.io.IOException;
import java.util.Arrays;
@@ -18,7 +18,7 @@
public class LogsCenter {
private static final int MAX_FILE_COUNT = 5;
private static final int MAX_FILE_SIZE_IN_BYTES = (int) (Math.pow(2, 20) * 5); // 5MB
- private static final String LOG_FILE = "addressbook.log";
+ private static final String LOG_FILE = "teachingassistant.log";
private static Level currentLogLevel = Level.INFO;
private static final Logger logger = LogsCenter.getLogger(LogsCenter.class);
private static FileHandler fileHandler;
diff --git a/src/main/java/seedu/ta/commons/core/Messages.java b/src/main/java/seedu/ta/commons/core/Messages.java
new file mode 100644
index 00000000000..0867d9f9377
--- /dev/null
+++ b/src/main/java/seedu/ta/commons/core/Messages.java
@@ -0,0 +1,21 @@
+package seedu.ta.commons.core;
+
+/**
+ * Container for user visible messages.
+ */
+public class Messages {
+ public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
+ public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
+ public static final String MESSAGE_INVALID_ENTRY_INDEX = "The entry index provided is invalid";
+ public static final String MESSAGE_INVALID_CONTACT_DISPLAYED_INDEX = "The contact index provided is invalid";
+ public static final String MESSAGE_ENTRY_START_DATE_IN_PAST = "Time travel is not allowed! Please provide a valid"
+ + " date time!";
+ public static final String MESSAGE_INVALID_DATE_RANGE = "The start date/time must be strictly before"
+ + " the end date/time!";
+ public static final String MESSAGE_CONTACTS_LISTED_OVERVIEW = "%1$d contacts listed!";
+ public static final String MESSAGE_ENTRIES_LISTED_OVERVIEW = "%1$d entries listed!";
+ public static final String MESSAGE_OVERLAPPING_ENTRY = "This entry has dates that overlap with other"
+ + " existing entries!";
+ public static final String MESSAGE_DUPLICATE_CONTACT = "The contact provided already exists in the address book.";
+ public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
+}
diff --git a/src/main/java/seedu/address/commons/core/Version.java b/src/main/java/seedu/ta/commons/core/Version.java
similarity index 98%
rename from src/main/java/seedu/address/commons/core/Version.java
rename to src/main/java/seedu/ta/commons/core/Version.java
index 12142ec1e32..f3a4ba022c4 100644
--- a/src/main/java/seedu/address/commons/core/Version.java
+++ b/src/main/java/seedu/ta/commons/core/Version.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.ta.commons.core;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
diff --git a/src/main/java/seedu/address/commons/core/index/Index.java b/src/main/java/seedu/ta/commons/core/index/Index.java
similarity index 97%
rename from src/main/java/seedu/address/commons/core/index/Index.java
rename to src/main/java/seedu/ta/commons/core/index/Index.java
index 19536439c09..17c90931010 100644
--- a/src/main/java/seedu/address/commons/core/index/Index.java
+++ b/src/main/java/seedu/ta/commons/core/index/Index.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core.index;
+package seedu.ta.commons.core.index;
/**
* Represents a zero-based or one-based index.
diff --git a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java b/src/main/java/seedu/ta/commons/exceptions/DataConversionException.java
similarity index 84%
rename from src/main/java/seedu/address/commons/exceptions/DataConversionException.java
rename to src/main/java/seedu/ta/commons/exceptions/DataConversionException.java
index 1f689bd8e3f..026c9f943b9 100644
--- a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java
+++ b/src/main/java/seedu/ta/commons/exceptions/DataConversionException.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.exceptions;
+package seedu.ta.commons.exceptions;
/**
* Represents an error during conversion of data from one format to another
diff --git a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java b/src/main/java/seedu/ta/commons/exceptions/IllegalValueException.java
similarity index 93%
rename from src/main/java/seedu/address/commons/exceptions/IllegalValueException.java
rename to src/main/java/seedu/ta/commons/exceptions/IllegalValueException.java
index 19124db485c..dd4b7015359 100644
--- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java
+++ b/src/main/java/seedu/ta/commons/exceptions/IllegalValueException.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.exceptions;
+package seedu.ta.commons.exceptions;
/**
* Signals that some given data does not fulfill some constraints.
diff --git a/src/main/java/seedu/address/commons/util/AppUtil.java b/src/main/java/seedu/ta/commons/util/AppUtil.java
similarity index 94%
rename from src/main/java/seedu/address/commons/util/AppUtil.java
rename to src/main/java/seedu/ta/commons/util/AppUtil.java
index 87aa89c0326..4ef3ae0924d 100644
--- a/src/main/java/seedu/address/commons/util/AppUtil.java
+++ b/src/main/java/seedu/ta/commons/util/AppUtil.java
@@ -1,9 +1,9 @@
-package seedu.address.commons.util;
+package seedu.ta.commons.util;
import static java.util.Objects.requireNonNull;
import javafx.scene.image.Image;
-import seedu.address.MainApp;
+import seedu.ta.MainApp;
/**
* A container for App specific utility functions
diff --git a/src/main/java/seedu/address/commons/util/CollectionUtil.java b/src/main/java/seedu/ta/commons/util/CollectionUtil.java
similarity index 96%
rename from src/main/java/seedu/address/commons/util/CollectionUtil.java
rename to src/main/java/seedu/ta/commons/util/CollectionUtil.java
index eafe4dfd681..b29ebd6cd07 100644
--- a/src/main/java/seedu/address/commons/util/CollectionUtil.java
+++ b/src/main/java/seedu/ta/commons/util/CollectionUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.ta.commons.util;
import static java.util.Objects.requireNonNull;
diff --git a/src/main/java/seedu/address/commons/util/ConfigUtil.java b/src/main/java/seedu/ta/commons/util/ConfigUtil.java
similarity index 77%
rename from src/main/java/seedu/address/commons/util/ConfigUtil.java
rename to src/main/java/seedu/ta/commons/util/ConfigUtil.java
index f7f8a2bd44c..0129d7db739 100644
--- a/src/main/java/seedu/address/commons/util/ConfigUtil.java
+++ b/src/main/java/seedu/ta/commons/util/ConfigUtil.java
@@ -1,11 +1,11 @@
-package seedu.address.commons.util;
+package seedu.ta.commons.util;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
-import seedu.address.commons.core.Config;
-import seedu.address.commons.exceptions.DataConversionException;
+import seedu.ta.commons.core.Config;
+import seedu.ta.commons.exceptions.DataConversionException;
/**
* A class for accessing the Config File.
diff --git a/src/main/java/seedu/address/commons/util/FileUtil.java b/src/main/java/seedu/ta/commons/util/FileUtil.java
similarity index 98%
rename from src/main/java/seedu/address/commons/util/FileUtil.java
rename to src/main/java/seedu/ta/commons/util/FileUtil.java
index b1e2767cdd9..370c60a46c6 100644
--- a/src/main/java/seedu/address/commons/util/FileUtil.java
+++ b/src/main/java/seedu/ta/commons/util/FileUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.ta.commons.util;
import java.io.IOException;
import java.nio.file.Files;
diff --git a/src/main/java/seedu/address/commons/util/JsonUtil.java b/src/main/java/seedu/ta/commons/util/JsonUtil.java
similarity index 97%
rename from src/main/java/seedu/address/commons/util/JsonUtil.java
rename to src/main/java/seedu/ta/commons/util/JsonUtil.java
index 8ef609f055d..9b8628e2521 100644
--- a/src/main/java/seedu/address/commons/util/JsonUtil.java
+++ b/src/main/java/seedu/ta/commons/util/JsonUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.ta.commons.util;
import static java.util.Objects.requireNonNull;
@@ -20,8 +20,8 @@
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.exceptions.DataConversionException;
+import seedu.ta.commons.core.LogsCenter;
+import seedu.ta.commons.exceptions.DataConversionException;
/**
* Converts a Java object instance to JSON and vice versa
diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/ta/commons/util/StringUtil.java
similarity index 95%
rename from src/main/java/seedu/address/commons/util/StringUtil.java
rename to src/main/java/seedu/ta/commons/util/StringUtil.java
index 61cc8c9a1cb..4eb28502191 100644
--- a/src/main/java/seedu/address/commons/util/StringUtil.java
+++ b/src/main/java/seedu/ta/commons/util/StringUtil.java
@@ -1,7 +1,7 @@
-package seedu.address.commons.util;
+package seedu.ta.commons.util;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
+import static seedu.ta.commons.util.AppUtil.checkArgument;
import java.io.PrintWriter;
import java.io.StringWriter;
diff --git a/src/main/java/seedu/ta/logic/Logic.java b/src/main/java/seedu/ta/logic/Logic.java
new file mode 100644
index 00000000000..e394cba1350
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/Logic.java
@@ -0,0 +1,55 @@
+package seedu.ta.logic;
+
+import java.nio.file.Path;
+
+import javafx.collections.ObservableList;
+import seedu.ta.commons.core.GuiSettings;
+import seedu.ta.logic.commands.CommandResult;
+import seedu.ta.logic.commands.exceptions.CommandException;
+import seedu.ta.logic.parser.exceptions.ParseException;
+import seedu.ta.model.ReadOnlyTeachingAssistant;
+import seedu.ta.model.contact.Contact;
+import seedu.ta.model.entry.Entry;
+
+/**
+ * API of the Logic component.
+ */
+public interface Logic {
+
+ /**
+ * Executes the command and returns the result.
+ * @param commandText The command as entered by the user.
+ * @return the result of the command execution.
+ * @throws CommandException If an error occurs during command execution.
+ * @throws ParseException If an error occurs during parsing.
+ */
+ CommandResult execute(String commandText) throws CommandException, ParseException;
+
+ /**
+ * Returns the TeachingAssistant.
+ *
+ * @see seedu.ta.model.Model#getTeachingAssistant()
+ */
+ ReadOnlyTeachingAssistant getTeachingAssistant();
+
+ /** Returns an unmodifiable view of the filtered list of contacts. */
+ ObservableList getFilteredContactList();
+
+ /** Returns an unmodifiable view of the filtered list of entries. */
+ ObservableList getFilteredEntryList();
+
+ /**
+ * Returns the user prefs' Teaching Assistant file path.
+ */
+ Path getTeachingAssistantFilePath();
+
+ /**
+ * Returns the user prefs' GUI settings.
+ */
+ GuiSettings getGuiSettings();
+
+ /**
+ * Set the user prefs' GUI settings.
+ */
+ void setGuiSettings(GuiSettings guiSettings);
+}
diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/ta/logic/LogicManager.java
similarity index 52%
rename from src/main/java/seedu/address/logic/LogicManager.java
rename to src/main/java/seedu/ta/logic/LogicManager.java
index 9d9c6d15bdc..bedbd16b4fd 100644
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ b/src/main/java/seedu/ta/logic/LogicManager.java
@@ -1,32 +1,35 @@
-package seedu.address.logic;
+package seedu.ta.logic;
import java.io.IOException;
import java.nio.file.Path;
import java.util.logging.Logger;
import javafx.collections.ObservableList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.commands.CommandResult;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.logic.parser.AddressBookParser;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.Model;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
-import seedu.address.storage.Storage;
+import seedu.ta.commons.core.GuiSettings;
+import seedu.ta.commons.core.LogsCenter;
+import seedu.ta.logic.commands.Command;
+import seedu.ta.logic.commands.CommandResult;
+import seedu.ta.logic.commands.exceptions.CommandException;
+import seedu.ta.logic.parser.TeachingAssistantParser;
+import seedu.ta.logic.parser.exceptions.ParseException;
+import seedu.ta.model.Model;
+import seedu.ta.model.ReadOnlyTeachingAssistant;
+import seedu.ta.model.contact.Contact;
+import seedu.ta.model.entry.Entry;
+import seedu.ta.storage.Storage;
/**
* The main LogicManager of the app.
*/
public class LogicManager implements Logic {
+
public static final String FILE_OPS_ERROR_MESSAGE = "Could not save data to file: ";
+
private final Logger logger = LogsCenter.getLogger(LogicManager.class);
private final Model model;
private final Storage storage;
- private final AddressBookParser addressBookParser;
+ private final TeachingAssistantParser teachingAssistantParser;
/**
* Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}.
@@ -34,7 +37,7 @@ public class LogicManager implements Logic {
public LogicManager(Model model, Storage storage) {
this.model = model;
this.storage = storage;
- addressBookParser = new AddressBookParser();
+ teachingAssistantParser = new TeachingAssistantParser();
}
@Override
@@ -42,11 +45,11 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
logger.info("----------------[USER COMMAND][" + commandText + "]");
CommandResult commandResult;
- Command command = addressBookParser.parseCommand(commandText);
+ Command command = teachingAssistantParser.parseCommand(commandText);
commandResult = command.execute(model);
try {
- storage.saveAddressBook(model.getAddressBook());
+ storage.saveTeachingAssistant(model.getTeachingAssistant());
} catch (IOException ioe) {
throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe);
}
@@ -55,18 +58,23 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
}
@Override
- public ReadOnlyAddressBook getAddressBook() {
- return model.getAddressBook();
+ public ReadOnlyTeachingAssistant getTeachingAssistant() {
+ return model.getTeachingAssistant();
+ }
+
+ @Override
+ public ObservableList getFilteredContactList() {
+ return model.getFilteredContactList();
}
@Override
- public ObservableList getFilteredPersonList() {
- return model.getFilteredPersonList();
+ public ObservableList getFilteredEntryList() {
+ return model.getFilteredEntryList();
}
@Override
- public Path getAddressBookFilePath() {
- return model.getAddressBookFilePath();
+ public Path getTeachingAssistantFilePath() {
+ return model.getTeachingAssistantFilePath();
}
@Override
diff --git a/src/main/java/seedu/ta/logic/commands/AddContactCommand.java b/src/main/java/seedu/ta/logic/commands/AddContactCommand.java
new file mode 100644
index 00000000000..3c08d164ba3
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/commands/AddContactCommand.java
@@ -0,0 +1,65 @@
+package seedu.ta.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.commons.core.Messages.MESSAGE_DUPLICATE_CONTACT;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_TAG;
+
+import seedu.ta.logic.commands.exceptions.CommandException;
+import seedu.ta.model.Model;
+import seedu.ta.model.contact.Contact;
+
+/**
+ * Adds a contact to Teaching Assistant.
+ */
+public class AddContactCommand extends Command {
+
+ public static final String COMMAND_WORD = "cadd";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a contact to Teaching Assistant. "
+ + "Parameters: "
+ + PREFIX_NAME + "NAME "
+ + PREFIX_PHONE + "PHONE "
+ + PREFIX_EMAIL + "EMAIL "
+ + "[" + PREFIX_TAG + "TAG]...\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_NAME + "Danny Tan "
+ + PREFIX_PHONE + "98765432 "
+ + PREFIX_EMAIL + "danny@email.com "
+ + PREFIX_TAG + "student "
+ + PREFIX_TAG + "english "
+ + PREFIX_TAG + "consultation1";
+
+ public static final String MESSAGE_SUCCESS = "New contact added: %1$s";
+
+ private final Contact toAdd;
+
+ /**
+ * Creates an AddContactCommand to add the specified {@code Contact}.
+ */
+ public AddContactCommand(Contact contact) {
+ requireNonNull(contact);
+ toAdd = contact;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (model.hasContact(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_CONTACT);
+ }
+
+ model.addContact(toAdd);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddContactCommand // instanceof handles nulls
+ && toAdd.equals(((AddContactCommand) other).toAdd));
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/commands/AddEntryCommand.java b/src/main/java/seedu/ta/logic/commands/AddEntryCommand.java
new file mode 100644
index 00000000000..a2cb4eab9d7
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/commands/AddEntryCommand.java
@@ -0,0 +1,64 @@
+package seedu.ta.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.commons.core.Messages.MESSAGE_OVERLAPPING_ENTRY;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_END_DATE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_START_DATE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_TAG;
+
+import seedu.ta.logic.commands.exceptions.CommandException;
+import seedu.ta.model.Model;
+import seedu.ta.model.entry.Entry;
+
+/**
+ * Adds an Entry to Teaching Assistant.
+ */
+public class AddEntryCommand extends Command {
+
+ public static final String COMMAND_WORD = "eadd";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds an entry to Teaching Assistant. "
+ + "Parameters: "
+ + PREFIX_NAME + "NAME "
+ + PREFIX_START_DATE + "START DATE "
+ + PREFIX_END_DATE + "END DATE "
+ + "[" + PREFIX_TAG + "TAG]...\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_NAME + "meeting "
+ + PREFIX_START_DATE + "2021-06-06 21:00 "
+ + PREFIX_END_DATE + "2021-06-06 23:00 "
+ + PREFIX_TAG + "meeting "
+ + PREFIX_TAG + "needprep";
+
+ public static final String MESSAGE_SUCCESS = "New entry added: %1$s";
+
+ private final Entry toAdd;
+
+ /**
+ * Creates an AddEntryCommand to add the specified {@code Entry}.
+ */
+ public AddEntryCommand(Entry entry) {
+ requireNonNull(entry);
+ toAdd = entry;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (model.isOverlappingEntry(toAdd)) {
+ throw new CommandException(MESSAGE_OVERLAPPING_ENTRY);
+ }
+
+ model.addEntry(toAdd);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this
+ || (other instanceof AddEntryCommand
+ && toAdd.equals(((AddEntryCommand) other).toAdd));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/ta/logic/commands/ClearCommand.java
similarity index 51%
rename from src/main/java/seedu/address/logic/commands/ClearCommand.java
rename to src/main/java/seedu/ta/logic/commands/ClearCommand.java
index 9c86b1fa6e4..7dc48b1815d 100644
--- a/src/main/java/seedu/address/logic/commands/ClearCommand.java
+++ b/src/main/java/seedu/ta/logic/commands/ClearCommand.java
@@ -1,23 +1,23 @@
-package seedu.address.logic.commands;
+package seedu.ta.logic.commands;
import static java.util.Objects.requireNonNull;
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
+import seedu.ta.model.Model;
+import seedu.ta.model.TeachingAssistant;
/**
- * Clears the address book.
+ * Clears the data in Teaching Assistant.
*/
public class ClearCommand extends Command {
public static final String COMMAND_WORD = "clear";
- public static final String MESSAGE_SUCCESS = "Address book has been cleared!";
+ public static final String MESSAGE_SUCCESS = "Teaching Assistant has been cleared!";
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
- model.setAddressBook(new AddressBook());
+ model.setTeachingAssistant(new TeachingAssistant());
return new CommandResult(MESSAGE_SUCCESS);
}
}
diff --git a/src/main/java/seedu/ta/logic/commands/ClearOverdueEntryCommand.java b/src/main/java/seedu/ta/logic/commands/ClearOverdueEntryCommand.java
new file mode 100644
index 00000000000..0a12acfce3b
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/commands/ClearOverdueEntryCommand.java
@@ -0,0 +1,22 @@
+package seedu.ta.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.ta.model.Model;
+
+/**
+ * Clears all overdue entries in Teaching Assistant.
+ */
+public class ClearOverdueEntryCommand extends Command {
+
+ public static final String COMMAND_WORD = "eclear";
+
+ public static final String MESSAGE_SUCCESS = "All overdue entries have been cleared!";
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.clearOverdueEntries();
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/seedu/ta/logic/commands/Command.java
similarity index 77%
rename from src/main/java/seedu/address/logic/commands/Command.java
rename to src/main/java/seedu/ta/logic/commands/Command.java
index 64f18992160..444f74256b2 100644
--- a/src/main/java/seedu/address/logic/commands/Command.java
+++ b/src/main/java/seedu/ta/logic/commands/Command.java
@@ -1,7 +1,7 @@
-package seedu.address.logic.commands;
+package seedu.ta.logic.commands;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
+import seedu.ta.logic.commands.exceptions.CommandException;
+import seedu.ta.model.Model;
/**
* Represents a command with hidden internal logic and the ability to be executed.
@@ -12,9 +12,8 @@ public abstract class Command {
* Executes the command and returns the result message.
*
* @param model {@code Model} which the command should operate on.
- * @return feedback message of the operation result for display
+ * @return feedback message of the operation result for display.
* @throws CommandException If an error occurs during command execution.
*/
public abstract CommandResult execute(Model model) throws CommandException;
-
}
diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/ta/logic/commands/CommandResult.java
similarity index 95%
rename from src/main/java/seedu/address/logic/commands/CommandResult.java
rename to src/main/java/seedu/ta/logic/commands/CommandResult.java
index 92f900b7916..831a61a878c 100644
--- a/src/main/java/seedu/address/logic/commands/CommandResult.java
+++ b/src/main/java/seedu/ta/logic/commands/CommandResult.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.commands;
+package seedu.ta.logic.commands;
import static java.util.Objects.requireNonNull;
@@ -9,6 +9,7 @@
*/
public class CommandResult {
+ /** Feedback should be shown to the user. */
private final String feedbackToUser;
/** Help information should be shown to the user. */
@@ -52,7 +53,6 @@ public boolean equals(Object other) {
return true;
}
- // instanceof handles nulls
if (!(other instanceof CommandResult)) {
return false;
}
@@ -67,5 +67,4 @@ public boolean equals(Object other) {
public int hashCode() {
return Objects.hash(feedbackToUser, showHelp, exit);
}
-
}
diff --git a/src/main/java/seedu/ta/logic/commands/DeleteContactCommand.java b/src/main/java/seedu/ta/logic/commands/DeleteContactCommand.java
new file mode 100644
index 00000000000..02b987d1685
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/commands/DeleteContactCommand.java
@@ -0,0 +1,56 @@
+package seedu.ta.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import seedu.ta.commons.core.Messages;
+import seedu.ta.commons.core.index.Index;
+import seedu.ta.logic.commands.exceptions.CommandException;
+import seedu.ta.model.Model;
+import seedu.ta.model.contact.Contact;
+
+/**
+ * Deletes a contact identified using its displayed index from the contact list in Teaching Assistant.
+ */
+public class DeleteContactCommand extends Command {
+
+ public static final String COMMAND_WORD = "cdelete";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the contact identified by the index number used in the displayed contact list.\n"
+ + "Parameters: INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ public static final String MESSAGE_DELETE_CONTACT_SUCCESS = "Deleted contact: %1$s";
+
+ private final Index targetIndex;
+
+ /**
+ * Creates a DeleteContactCommand to delete the contact at the specified {@code targetIndex}.
+ */
+ public DeleteContactCommand(Index targetIndex) {
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredContactList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_CONTACT_DISPLAYED_INDEX);
+ }
+
+ Contact contactToDelete = lastShownList.get(targetIndex.getZeroBased());
+ model.deleteContact(contactToDelete);
+ return new CommandResult(String.format(MESSAGE_DELETE_CONTACT_SUCCESS, contactToDelete));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof DeleteContactCommand // instanceof handles nulls
+ && targetIndex.equals(((DeleteContactCommand) other).targetIndex)); // state check
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/commands/DeleteEntryCommand.java b/src/main/java/seedu/ta/logic/commands/DeleteEntryCommand.java
new file mode 100644
index 00000000000..2760e097081
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/commands/DeleteEntryCommand.java
@@ -0,0 +1,56 @@
+package seedu.ta.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import seedu.ta.commons.core.Messages;
+import seedu.ta.commons.core.index.Index;
+import seedu.ta.logic.commands.exceptions.CommandException;
+import seedu.ta.model.Model;
+import seedu.ta.model.entry.Entry;
+
+/**
+ * Deletes an entry identified using its displayed index from the entry list in Teaching Assistant.
+ */
+public class DeleteEntryCommand extends Command {
+
+ public static final String COMMAND_WORD = "edelete";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the entry identified by the given index in the list.\n"
+ + "Parameters: INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ public static final String MESSAGE_DELETE_ENTRY_SUCCESS = "Deleted Entry: %1$s";
+
+ private final Index targetIndex;
+
+ /**
+ * Creates a DeleteEntryCommand to delete the entry at the specified {@code targetIndex}.
+ */
+ public DeleteEntryCommand(Index targetIndex) {
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredEntryList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_ENTRY_INDEX);
+ }
+
+ Entry entryToDelete = lastShownList.get(targetIndex.getZeroBased());
+ model.deleteEntry(entryToDelete);
+ return new CommandResult(String.format(MESSAGE_DELETE_ENTRY_SUCCESS, entryToDelete));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this
+ || (other instanceof DeleteEntryCommand
+ && targetIndex.equals(((DeleteEntryCommand) other).targetIndex));
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/commands/EditContactCommand.java b/src/main/java/seedu/ta/logic/commands/EditContactCommand.java
new file mode 100644
index 00000000000..9cc2a5c9269
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/commands/EditContactCommand.java
@@ -0,0 +1,211 @@
+package seedu.ta.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.commons.core.Messages.MESSAGE_DUPLICATE_CONTACT;
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_CONTACT_DISPLAYED_INDEX;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.ta.model.Model.PREDICATE_SHOW_ALL_CONTACTS;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import seedu.ta.commons.core.index.Index;
+import seedu.ta.commons.util.CollectionUtil;
+import seedu.ta.logic.commands.exceptions.CommandException;
+import seedu.ta.model.Model;
+import seedu.ta.model.contact.Contact;
+import seedu.ta.model.contact.ContactEmail;
+import seedu.ta.model.contact.ContactName;
+import seedu.ta.model.contact.ContactPhone;
+import seedu.ta.model.tag.Tag;
+
+/**
+ * Edits the details of an existing contact in Teaching Assistant.
+ */
+public class EditContactCommand extends Command {
+
+ public static final String COMMAND_WORD = "cedit";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the contact identified "
+ + "by index used in the displayed contact list. Index must be a positive integer. "
+ + "Existing values will be overwritten by the input values.\n"
+ + "Parameters: INDEX "
+ + "[" + PREFIX_NAME + "NAME] "
+ + "[" + PREFIX_PHONE + "PHONE] "
+ + "[" + PREFIX_EMAIL + "EMAIL] "
+ + "[" + PREFIX_TAG + "TAG]...\n"
+ + "Example: " + COMMAND_WORD
+ + " 1 "
+ + PREFIX_PHONE + "91234567 "
+ + PREFIX_EMAIL + "alexyeoh@example.com";
+
+ public static final String MESSAGE_EDIT_CONTACT_SUCCESS = "Edited Contact: %1$s";
+
+ private final Index targetIndex;
+
+ private final EditContactDescriptor editContactDescriptor;
+
+ /**
+ * Creates an EditContactCommand to edit the contact corresponding to the specified {@code Index}
+ * with the details as specified by the {@code editContactDescriptor}.
+ */
+ public EditContactCommand(Index targetIndex, EditContactDescriptor editContactDescriptor) {
+ requireNonNull(targetIndex);
+ requireNonNull(editContactDescriptor);
+
+ this.targetIndex = targetIndex;
+ this.editContactDescriptor = new EditContactDescriptor(editContactDescriptor);
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredContactList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(MESSAGE_INVALID_CONTACT_DISPLAYED_INDEX);
+ }
+
+ Contact contactToEdit = lastShownList.get(targetIndex.getZeroBased());
+ Contact editedContact = createEditedContact(contactToEdit, editContactDescriptor);
+
+ if (!contactToEdit.isSameContact(editedContact) && model.hasContact(editedContact)) {
+ throw new CommandException(MESSAGE_DUPLICATE_CONTACT);
+ }
+
+ model.setContact(contactToEdit, editedContact);
+ model.updateFilteredContactList(PREDICATE_SHOW_ALL_CONTACTS);
+ return new CommandResult(String.format(MESSAGE_EDIT_CONTACT_SUCCESS, editedContact));
+ }
+
+ /**
+ * Creates and returns a {@code Contact} with the details of {@code contactToEdit}
+ * edited with {@code editContactDescriptor}.
+ */
+ private static Contact createEditedContact(Contact contactToEdit, EditContactDescriptor editContactDescriptor) {
+ assert contactToEdit != null;
+
+ ContactName updatedName = editContactDescriptor.getName().orElse(contactToEdit.getName());
+ ContactPhone updatedPhone = editContactDescriptor.getPhone().orElse(contactToEdit.getPhone());
+ ContactEmail updatedEmail = editContactDescriptor.getEmail().orElse(contactToEdit.getEmail());
+ Set updatedTags = editContactDescriptor.getTags().orElse(contactToEdit.getTags());
+
+ return new Contact(updatedName, updatedPhone, updatedEmail, updatedTags);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditContactCommand)) {
+ return false;
+ }
+
+ // state check
+ EditContactCommand otherEditContactCommand = (EditContactCommand) other;
+ return targetIndex.equals(otherEditContactCommand.targetIndex)
+ && editContactDescriptor.equals(otherEditContactCommand.editContactDescriptor);
+ }
+
+ /**
+ * Stores the details needed to edit the contact. Each non-empty field value will replace the
+ * corresponding field value of the contact.
+ */
+ public static class EditContactDescriptor {
+ private ContactName name;
+ private ContactPhone phone;
+ private ContactEmail email;
+ private Set tags;
+
+ public EditContactDescriptor() {}
+
+ /**
+ * Copy constructor.
+ * A defensive copy of {@code tags} is used internally.
+ */
+ public EditContactDescriptor(EditContactDescriptor toCopy) {
+ setName(toCopy.name);
+ setPhone(toCopy.phone);
+ setEmail(toCopy.email);
+ setTags(toCopy.tags);
+ }
+
+ /**
+ * Returns true if at least one field is edited.
+ */
+ public boolean isAnyFieldEdited() {
+ return CollectionUtil.isAnyNonNull(name, phone, email, tags);
+ }
+
+ public void setName(ContactName name) {
+ this.name = name;
+ }
+
+ public Optional getName() {
+ return Optional.ofNullable(name);
+ }
+
+ public void setPhone(ContactPhone phone) {
+ this.phone = phone;
+ }
+
+ public Optional getPhone() {
+ return Optional.ofNullable(phone);
+ }
+
+ public void setEmail(ContactEmail email) {
+ this.email = email;
+ }
+
+ public Optional getEmail() {
+ return Optional.ofNullable(email);
+ }
+
+ /**
+ * Sets {@code tags} to this object's {@code tags}.
+ * A defensive copy of {@code tags} is used internally.
+ */
+ public void setTags(Set tags) {
+ this.tags = (tags != null) ? new HashSet<>(tags) : null;
+ }
+
+ /**
+ * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ * Returns {@code Optional#empty()} if {@code tags} is null.
+ */
+ public Optional> getTags() {
+ return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditContactDescriptor)) {
+ return false;
+ }
+
+ // state check
+ EditContactDescriptor otherEditContactDescriptor = (EditContactDescriptor) other;
+ return getName().equals(otherEditContactDescriptor.getName())
+ && getPhone().equals(otherEditContactDescriptor.getPhone())
+ && getEmail().equals(otherEditContactDescriptor.getEmail())
+ && getTags().equals(otherEditContactDescriptor.getTags());
+ }
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/commands/EditEntryCommand.java b/src/main/java/seedu/ta/logic/commands/EditEntryCommand.java
new file mode 100644
index 00000000000..608e43ac5a9
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/commands/EditEntryCommand.java
@@ -0,0 +1,112 @@
+package seedu.ta.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_DATE_RANGE;
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_ENTRY_INDEX;
+import static seedu.ta.commons.core.Messages.MESSAGE_OVERLAPPING_ENTRY;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_END_DATE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_START_DATE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.ta.model.Model.PREDICATE_SHOW_ALL_ENTRIES;
+
+import java.util.List;
+import java.util.Set;
+
+import seedu.ta.commons.core.index.Index;
+import seedu.ta.logic.commands.exceptions.CommandException;
+import seedu.ta.model.Model;
+import seedu.ta.model.entry.Entry;
+import seedu.ta.model.entry.EntryDate;
+import seedu.ta.model.entry.EntryName;
+import seedu.ta.model.entry.TemporaryEntry;
+import seedu.ta.model.tag.Tag;
+
+/**
+ * Edits the details of an existing entry in Teaching Assistant.
+ */
+public class EditEntryCommand extends Command {
+
+ public static final String COMMAND_WORD = "eedit";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the entry identified "
+ + "by the entry index used in the displayed entry list. Index must be a positive integer."
+ + "Existing values will be overwritten by the input values.\n"
+ + "Parameters: INDEX "
+ + "[" + PREFIX_NAME + "NAME] "
+ + "[" + PREFIX_START_DATE + "START_DATE] "
+ + "[" + PREFIX_END_DATE + "END_DATE] "
+ + "[" + PREFIX_TAG + "TAG]...\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_START_DATE + "2021-06-07 13:00 "
+ + PREFIX_END_DATE + "2021-06-07 14:00";
+
+ public static final String MESSAGE_EDIT_ENTRY_SUCCESS = "Edited entry: %1$s";
+
+ private final Index targetIndex;
+
+ private final TemporaryEntry tempEntry;
+
+ /**
+ * Creates an EditEntryCommand to edit the contact corresponding to the specified {@code Index}
+ * with the details as specified by the {@code tempEntry}.
+ */
+ public EditEntryCommand(Index targetIndex, TemporaryEntry tempEntry) {
+ requireNonNull(targetIndex);
+ requireNonNull(tempEntry);
+
+ this.targetIndex = targetIndex;
+ this.tempEntry = tempEntry;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredEntryList();
+
+ Integer index = targetIndex.getOneBased();
+ if (index < 1 || index > lastShownList.size()) {
+ throw new CommandException(MESSAGE_INVALID_ENTRY_INDEX);
+ }
+
+ Entry targetEntry = lastShownList.get(index - 1);
+
+ EntryName updatedEntryName = tempEntry.getEntryName().orElse(targetEntry.getEntryName());
+ EntryDate updatedEntryStartDate = tempEntry.getStartDate().orElse(targetEntry.getOriginalStartDate());
+ EntryDate updatedEntryEndDate = tempEntry.getEndDate().orElse(targetEntry.getOriginalEndDate());
+ Set updatedTags = tempEntry.getTags().orElse(targetEntry.getTags());
+ Entry updatedEntry = new Entry(updatedEntryName, updatedEntryStartDate, updatedEntryEndDate, updatedTags);
+
+ if (!updatedEntryStartDate.isBefore(updatedEntryEndDate)) {
+ throw new CommandException(MESSAGE_INVALID_DATE_RANGE);
+ }
+
+ model.deleteEntry(targetEntry);
+ if (model.isOverlappingEntry(updatedEntry)) {
+ model.addEntry(targetEntry);
+ throw new CommandException(MESSAGE_OVERLAPPING_ENTRY);
+ }
+
+ model.addEntry(updatedEntry);
+ model.updateFilteredEntryList(PREDICATE_SHOW_ALL_ENTRIES);
+ return new CommandResult(String.format(MESSAGE_EDIT_ENTRY_SUCCESS, updatedEntry));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditEntryCommand)) {
+ return false;
+ }
+
+ // state check
+ EditEntryCommand otherEditEntryCommand = (EditEntryCommand) other;
+ return targetIndex.equals(otherEditEntryCommand.targetIndex)
+ && tempEntry.equals(otherEditEntryCommand.tempEntry);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/ta/logic/commands/ExitCommand.java
similarity index 84%
rename from src/main/java/seedu/address/logic/commands/ExitCommand.java
rename to src/main/java/seedu/ta/logic/commands/ExitCommand.java
index 3dd85a8ba90..b18a44ebdef 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/seedu/ta/logic/commands/ExitCommand.java
@@ -1,6 +1,6 @@
-package seedu.address.logic.commands;
+package seedu.ta.logic.commands;
-import seedu.address.model.Model;
+import seedu.ta.model.Model;
/**
* Terminates the program.
@@ -15,5 +15,4 @@ public class ExitCommand extends Command {
public CommandResult execute(Model model) {
return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
}
-
}
diff --git a/src/main/java/seedu/ta/logic/commands/FilterContactCommand.java b/src/main/java/seedu/ta/logic/commands/FilterContactCommand.java
new file mode 100644
index 00000000000..f847c15c645
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/commands/FilterContactCommand.java
@@ -0,0 +1,45 @@
+package seedu.ta.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.ta.commons.core.Messages;
+import seedu.ta.model.Model;
+import seedu.ta.model.contact.ContactTagsContainKeywordsPredicate;
+
+/**
+ * Filters and lists all contacts in Teaching Assistant whose tags contain all of the argument keywords.
+ * Keyword matching is case insensitive.
+ */
+public class FilterContactCommand extends Command {
+
+ public static final String COMMAND_WORD = "cfilter";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Filters all contacts that have the tags of "
+ + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
+ + "Example: " + COMMAND_WORD + " student english";
+
+ private final ContactTagsContainKeywordsPredicate predicate;
+
+ /**
+ * Creates a FilterContactCommand to filter the relevant contacts according to the specified {@code predicate}.
+ */
+ public FilterContactCommand(ContactTagsContainKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredContactList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_CONTACTS_LISTED_OVERVIEW, model.getFilteredContactList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof FilterContactCommand // instanceof handles nulls
+ && predicate.equals(((FilterContactCommand) other).predicate)); // state check
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/commands/FilterEntryCommand.java b/src/main/java/seedu/ta/logic/commands/FilterEntryCommand.java
new file mode 100644
index 00000000000..acdfdead19f
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/commands/FilterEntryCommand.java
@@ -0,0 +1,45 @@
+package seedu.ta.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.ta.commons.core.Messages;
+import seedu.ta.model.Model;
+import seedu.ta.model.entry.EntryTagsContainKeywordsPredicate;
+
+/**
+ * Filters and lists all entries in Teaching Assistant whose tags contain all of the argument keywords.
+ * Keyword matching is case insensitive.
+ */
+public class FilterEntryCommand extends Command {
+
+ public static final String COMMAND_WORD = "efilter";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Filters all entries that have the tags of "
+ + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
+ + "Example: " + COMMAND_WORD + " meeting";
+
+ private final EntryTagsContainKeywordsPredicate predicate;
+
+ /**
+ * Creates a FilterEntryCommand to filter the relevant entries according to the specified {@code predicate}.
+ */
+ public FilterEntryCommand(EntryTagsContainKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredEntryList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_ENTRIES_LISTED_OVERVIEW, model.getFilteredEntryList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof FilterEntryCommand // instanceof handles nulls
+ && predicate.equals(((FilterEntryCommand) other).predicate)); // state check
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/commands/FindContactCommand.java b/src/main/java/seedu/ta/logic/commands/FindContactCommand.java
new file mode 100644
index 00000000000..0a7935eb604
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/commands/FindContactCommand.java
@@ -0,0 +1,45 @@
+package seedu.ta.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.ta.commons.core.Messages;
+import seedu.ta.model.Model;
+import seedu.ta.model.contact.ContactNameContainsKeywordsPredicate;
+
+/**
+ * Finds and lists all contacts in Teaching Assistant whose name contains all of the argument keywords.
+ * Keyword matching is case insensitive.
+ */
+public class FindContactCommand extends Command {
+
+ public static final String COMMAND_WORD = "cfind";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all contacts whose names contain any of "
+ + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
+ + "Example: " + COMMAND_WORD + " Danny";
+
+ private final ContactNameContainsKeywordsPredicate predicate;
+
+ /**
+ * Creates a FindContactCommand to find the relevant contacts according to the specified {@code predicate}.
+ */
+ public FindContactCommand(ContactNameContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredContactList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_CONTACTS_LISTED_OVERVIEW, model.getFilteredContactList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof FindContactCommand // instanceof handles nulls
+ && predicate.equals(((FindContactCommand) other).predicate)); // state check
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/commands/FindEntryCommand.java b/src/main/java/seedu/ta/logic/commands/FindEntryCommand.java
new file mode 100644
index 00000000000..057424ebef8
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/commands/FindEntryCommand.java
@@ -0,0 +1,45 @@
+package seedu.ta.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.ta.commons.core.Messages;
+import seedu.ta.model.Model;
+import seedu.ta.model.entry.EntryNameContainsKeywordsPredicate;
+
+/**
+ * Finds and lists all entries in Teaching Assistant whose name contains all of the argument keywords.
+ * Keyword matching is case insensitive.
+ */
+public class FindEntryCommand extends Command {
+
+ public static final String COMMAND_WORD = "efind";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all entries whose name contain any of "
+ + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
+ + "Example: " + COMMAND_WORD + " consultation";
+
+ private final EntryNameContainsKeywordsPredicate predicate;
+
+ /**
+ * Creates a FindEntryCommand to find the relevant entries according to the specified {@code predicate}.
+ */
+ public FindEntryCommand(EntryNameContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredEntryList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_ENTRIES_LISTED_OVERVIEW, model.getFilteredEntryList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof FindEntryCommand // instanceof handles nulls
+ && predicate.equals(((FindEntryCommand) other).predicate)); // state check
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/commands/FreeCommand.java b/src/main/java/seedu/ta/logic/commands/FreeCommand.java
new file mode 100644
index 00000000000..6da43e3b940
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/commands/FreeCommand.java
@@ -0,0 +1,59 @@
+package seedu.ta.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_END_DATE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_START_DATE;
+
+import seedu.ta.logic.commands.exceptions.CommandException;
+import seedu.ta.model.Model;
+import seedu.ta.model.entry.ListOccupyingEntryPredicate;
+
+/**
+ * Checks all entries in Teaching Assistant to indicates if time interval provided as argument is free.
+ */
+public class FreeCommand extends Command {
+
+ public static final String COMMAND_WORD = "free";
+
+ public static final String MESSAGE_FREE = "You're free!";
+
+ public static final String MESSAGE_NOT_FREE = "Sorry, you're not free. Schedules occupying that time interval "
+ + "listed below!";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Indicates if an interval is free. "
+ + "If free, 'free' will be shown. If not, tasks occupying that interval will be shown in "
+ + "the entries listed below.\n"
+ + "Parameters: "
+ + PREFIX_START_DATE + "START_DATE "
+ + PREFIX_END_DATE + "END_DATE\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_START_DATE + " 2021-06-06 21:30 "
+ + PREFIX_END_DATE + " 2021-06-06 22:30 ";
+
+ private final ListOccupyingEntryPredicate predicate;
+
+ /**
+ * Creates a FreeCommand to search for the relevant entries according to the specified {@code predicate}.
+ */
+ public FreeCommand(ListOccupyingEntryPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ model.updateFilteredEntryList(predicate);
+ if (model.getFilteredEntryList().size() == 0) {
+ return new CommandResult(MESSAGE_FREE);
+ } else {
+ return new CommandResult(MESSAGE_NOT_FREE);
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof FreeCommand // instanceof handles nulls
+ && predicate.equals(((FreeCommand) other).predicate));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/ta/logic/commands/HelpCommand.java
similarity index 72%
rename from src/main/java/seedu/address/logic/commands/HelpCommand.java
rename to src/main/java/seedu/ta/logic/commands/HelpCommand.java
index bf824f91bd0..febfcddd01c 100644
--- a/src/main/java/seedu/address/logic/commands/HelpCommand.java
+++ b/src/main/java/seedu/ta/logic/commands/HelpCommand.java
@@ -1,9 +1,9 @@
-package seedu.address.logic.commands;
+package seedu.ta.logic.commands;
-import seedu.address.model.Model;
+import seedu.ta.model.Model;
/**
- * Format full help instructions for every command for display.
+ * Displays a message containing a link to the User Guide of Teaching Assistant where all command formats are stated.
*/
public class HelpCommand extends Command {
diff --git a/src/main/java/seedu/ta/logic/commands/ListContactCommand.java b/src/main/java/seedu/ta/logic/commands/ListContactCommand.java
new file mode 100644
index 00000000000..ae53d939aba
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/commands/ListContactCommand.java
@@ -0,0 +1,23 @@
+package seedu.ta.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.model.Model.PREDICATE_SHOW_ALL_CONTACTS;
+
+import seedu.ta.model.Model;
+
+/**
+ * Lists all contacts in Teaching Assistant to the user.
+ */
+public class ListContactCommand extends Command {
+
+ public static final String COMMAND_WORD = "clist";
+
+ public static final String MESSAGE_SUCCESS = "Listed all contacts";
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredContactList(PREDICATE_SHOW_ALL_CONTACTS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/commands/ListEntryCommand.java b/src/main/java/seedu/ta/logic/commands/ListEntryCommand.java
new file mode 100644
index 00000000000..ac5153fb1ea
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/commands/ListEntryCommand.java
@@ -0,0 +1,45 @@
+package seedu.ta.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.ta.commons.core.Messages;
+import seedu.ta.model.Model;
+import seedu.ta.model.entry.ListEntryFormatPredicate;
+
+/**
+ * Lists all entries in Teaching Assistant or lists entries based on day or week.
+ */
+public class ListEntryCommand extends Command {
+
+ public static final String COMMAND_WORD = "elist";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Lists all entries "
+ + "by displaying them as a list sorted by date. Entries can also be listed by day/week.\n"
+ + "Optional parameters: [FORMAT] \n"
+ + "The format is only restricted to two cases: day/week."
+ + "Example: " + COMMAND_WORD + " week";
+
+ final ListEntryFormatPredicate predicate;
+
+ /**
+ * Creates a ListEntryCommand in the relevant format according to the specified {@code predicate}.
+ */
+ public ListEntryCommand(ListEntryFormatPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredEntryList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_ENTRIES_LISTED_OVERVIEW, model.getFilteredEntryList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this
+ || (other instanceof ListEntryCommand
+ && predicate.equals(((ListEntryCommand) other).predicate));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java b/src/main/java/seedu/ta/logic/commands/exceptions/CommandException.java
similarity index 83%
rename from src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
rename to src/main/java/seedu/ta/logic/commands/exceptions/CommandException.java
index a16bd14f2cd..c033701bbaf 100644
--- a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
+++ b/src/main/java/seedu/ta/logic/commands/exceptions/CommandException.java
@@ -1,4 +1,6 @@
-package seedu.address.logic.commands.exceptions;
+package seedu.ta.logic.commands.exceptions;
+
+import seedu.ta.logic.commands.Command;
/**
* Represents an error which occurs during execution of a {@link Command}.
diff --git a/src/main/java/seedu/ta/logic/parser/AddContactCommandParser.java b/src/main/java/seedu/ta/logic/parser/AddContactCommandParser.java
new file mode 100644
index 00000000000..b8935c57aec
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/parser/AddContactCommandParser.java
@@ -0,0 +1,56 @@
+package seedu.ta.logic.parser;
+
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.Set;
+import java.util.stream.Stream;
+
+import seedu.ta.logic.commands.AddContactCommand;
+import seedu.ta.logic.parser.exceptions.ParseException;
+import seedu.ta.model.contact.Contact;
+import seedu.ta.model.contact.ContactEmail;
+import seedu.ta.model.contact.ContactName;
+import seedu.ta.model.contact.ContactPhone;
+import seedu.ta.model.tag.Tag;
+
+/**
+ * Parses input arguments and creates a new AddContactCommand object.
+ */
+public class AddContactCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddContactCommand
+ * and returns an AddContactCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public AddContactCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_TAG);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddContactCommand.MESSAGE_USAGE));
+ }
+
+ ContactName name = ParserUtil.parseContactName(argMultimap.getValue(PREFIX_NAME).get());
+ ContactPhone phone = ParserUtil.parseContactPhone(argMultimap.getValue(PREFIX_PHONE).get());
+ ContactEmail email = ParserUtil.parseContactEmail(argMultimap.getValue(PREFIX_EMAIL).get());
+ Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
+
+ Contact contact = new Contact(name, phone, email, tagList);
+ return new AddContactCommand(contact);
+ }
+
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+}
+
diff --git a/src/main/java/seedu/ta/logic/parser/AddEntryCommandParser.java b/src/main/java/seedu/ta/logic/parser/AddEntryCommandParser.java
new file mode 100644
index 00000000000..44f6888e6ed
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/parser/AddEntryCommandParser.java
@@ -0,0 +1,59 @@
+package seedu.ta.logic.parser;
+
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_DATE_RANGE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_END_DATE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_START_DATE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.Set;
+import java.util.stream.Stream;
+
+import seedu.ta.logic.commands.AddEntryCommand;
+import seedu.ta.logic.parser.exceptions.ParseException;
+import seedu.ta.model.entry.Entry;
+import seedu.ta.model.entry.EntryDate;
+import seedu.ta.model.entry.EntryName;
+import seedu.ta.model.tag.Tag;
+
+/**
+ * Parses input arguments and creates a new AddEntryCommand Object.
+ */
+public class AddEntryCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of AddEntryCommand
+ * and returns an AddEntryCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public AddEntryCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_START_DATE, PREFIX_END_DATE, PREFIX_TAG);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_START_DATE, PREFIX_END_DATE)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddEntryCommand.MESSAGE_USAGE));
+ }
+
+ EntryName entryName = ParserUtil.parseEntryName(argMultimap.getValue(PREFIX_NAME).get());
+ EntryDate startDate = ParserUtil.parseEntryDate(argMultimap.getValue(PREFIX_START_DATE).get());
+ EntryDate endDate = ParserUtil.parseEntryDate(argMultimap.getValue(PREFIX_END_DATE).get());
+ Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
+
+ if (!startDate.isBefore(endDate)) {
+ throw new ParseException(MESSAGE_INVALID_DATE_RANGE);
+ }
+
+ Entry entry = new Entry(entryName, startDate, endDate, tagList);
+ return new AddEntryCommand(entry);
+ }
+
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ private boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java b/src/main/java/seedu/ta/logic/parser/ArgumentMultimap.java
similarity index 90%
rename from src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
rename to src/main/java/seedu/ta/logic/parser/ArgumentMultimap.java
index 954c8e18f8e..19a649e9467 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
+++ b/src/main/java/seedu/ta/logic/parser/ArgumentMultimap.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package seedu.ta.logic.parser;
import java.util.ArrayList;
import java.util.HashMap;
@@ -15,15 +15,14 @@
*/
public class ArgumentMultimap {
- /** Prefixes mapped to their respective arguments**/
+ /** Prefixes mapped to their respective arguments. */
private final Map> argMultimap = new HashMap<>();
/**
* Associates the specified argument value with {@code prefix} key in this map.
* If the map previously contained a mapping for the key, the new value is appended to the list of existing values.
- *
- * @param prefix Prefix key with which the specified argument value is to be associated
- * @param argValue Argument value to be associated with the specified prefix key
+ * @param prefix Prefix key with which the specified argument value is to be associated.
+ * @param argValue Argument value to be associated with the specified prefix key.
*/
public void put(Prefix prefix, String argValue) {
List argValues = getAllValues(prefix);
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java b/src/main/java/seedu/ta/logic/parser/ArgumentTokenizer.java
similarity index 89%
rename from src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
rename to src/main/java/seedu/ta/logic/parser/ArgumentTokenizer.java
index 5c9aebfa488..d4adbbfe96a 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
+++ b/src/main/java/seedu/ta/logic/parser/ArgumentTokenizer.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package seedu.ta.logic.parser;
import java.util.ArrayList;
import java.util.Arrays;
@@ -18,10 +18,9 @@ public class ArgumentTokenizer {
/**
* Tokenizes an arguments string and returns an {@code ArgumentMultimap} object that maps prefixes to their
* respective argument values. Only the given prefixes will be recognized in the arguments string.
- *
- * @param argsString Arguments string of the form: {@code preamble value value ...}
- * @param prefixes Prefixes to tokenize the arguments string with
- * @return ArgumentMultimap object that maps prefixes to their arguments
+ * @param argsString Arguments string of the form: {@code preamble value value ...}.
+ * @param prefixes Prefixes to tokenize the arguments string with.
+ * @return ArgumentMultimap object that maps prefixes to their arguments.
*/
public static ArgumentMultimap tokenize(String argsString, Prefix... prefixes) {
List positions = findAllPrefixPositions(argsString, prefixes);
@@ -30,10 +29,9 @@ public static ArgumentMultimap tokenize(String argsString, Prefix... prefixes) {
/**
* Finds all zero-based prefix positions in the given arguments string.
- *
- * @param argsString Arguments string of the form: {@code preamble value value ...}
- * @param prefixes Prefixes to find in the arguments string
- * @return List of zero-based prefix positions in the given arguments string
+ * @param argsString Arguments string of the form: {@code preamble value value ...}.
+ * @param prefixes Prefixes to find in the arguments string.
+ * @return List of zero-based prefix positions in the given arguments string.
*/
private static List findAllPrefixPositions(String argsString, Prefix... prefixes) {
return Arrays.stream(prefixes)
@@ -79,10 +77,9 @@ private static int findPrefixPosition(String argsString, String prefix, int from
* Extracts prefixes and their argument values, and returns an {@code ArgumentMultimap} object that maps the
* extracted prefixes to their respective arguments. Prefixes are extracted based on their zero-based positions in
* {@code argsString}.
- *
- * @param argsString Arguments string of the form: {@code preamble value value ...}
- * @param prefixPositions Zero-based positions of all prefixes in {@code argsString}
- * @return ArgumentMultimap object that maps prefixes to their arguments
+ * @param argsString Arguments string of the form: {@code preamble value value ...}.
+ * @param prefixPositions Zero-based positions of all prefixes in {@code argsString}.
+ * @return ArgumentMultimap object that maps prefixes to their arguments.
*/
private static ArgumentMultimap extractArguments(String argsString, List prefixPositions) {
@@ -144,5 +141,4 @@ Prefix getPrefix() {
return prefix;
}
}
-
}
diff --git a/src/main/java/seedu/address/logic/parser/CliSyntax.java b/src/main/java/seedu/ta/logic/parser/CliSyntax.java
similarity index 65%
rename from src/main/java/seedu/address/logic/parser/CliSyntax.java
rename to src/main/java/seedu/ta/logic/parser/CliSyntax.java
index 75b1a9bf119..046d5b6e4d2 100644
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ b/src/main/java/seedu/ta/logic/parser/CliSyntax.java
@@ -1,15 +1,15 @@
-package seedu.address.logic.parser;
+package seedu.ta.logic.parser;
/**
* Contains Command Line Interface (CLI) syntax definitions common to multiple commands
*/
public class CliSyntax {
- /* Prefix definitions */
+ /** Prefix definitions */
public static final Prefix PREFIX_NAME = new Prefix("n/");
public static final Prefix PREFIX_PHONE = new Prefix("p/");
public static final Prefix PREFIX_EMAIL = new Prefix("e/");
- public static final Prefix PREFIX_ADDRESS = new Prefix("a/");
public static final Prefix PREFIX_TAG = new Prefix("t/");
-
+ public static final Prefix PREFIX_START_DATE = new Prefix("sd/");
+ public static final Prefix PREFIX_END_DATE = new Prefix("ed/");
}
diff --git a/src/main/java/seedu/ta/logic/parser/DeleteContactCommandParser.java b/src/main/java/seedu/ta/logic/parser/DeleteContactCommandParser.java
new file mode 100644
index 00000000000..08fb869bfc5
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/parser/DeleteContactCommandParser.java
@@ -0,0 +1,29 @@
+package seedu.ta.logic.parser;
+
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.ta.commons.core.index.Index;
+import seedu.ta.logic.commands.DeleteContactCommand;
+import seedu.ta.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new DeleteContactCommand object.
+ */
+public class DeleteContactCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteContactCommand
+ * and returns a DeleteContactCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public DeleteContactCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new DeleteContactCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteContactCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
+
diff --git a/src/main/java/seedu/ta/logic/parser/DeleteEntryCommandParser.java b/src/main/java/seedu/ta/logic/parser/DeleteEntryCommandParser.java
new file mode 100644
index 00000000000..4d9623ab9d9
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/parser/DeleteEntryCommandParser.java
@@ -0,0 +1,28 @@
+package seedu.ta.logic.parser;
+
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.ta.commons.core.index.Index;
+import seedu.ta.logic.commands.DeleteEntryCommand;
+import seedu.ta.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new DeleteEntryCommand object.
+ */
+public class DeleteEntryCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteEntryCommand
+ * and returns a DeleteEntryCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public DeleteEntryCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new DeleteEntryCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteEntryCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/parser/EditContactCommandParser.java b/src/main/java/seedu/ta/logic/parser/EditContactCommandParser.java
new file mode 100644
index 00000000000..0b23413dbdd
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/parser/EditContactCommandParser.java
@@ -0,0 +1,82 @@
+package seedu.ta.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.ta.commons.core.Messages.MESSAGE_NOT_EDITED;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.Set;
+
+import seedu.ta.commons.core.index.Index;
+import seedu.ta.logic.commands.EditContactCommand;
+import seedu.ta.logic.commands.EditContactCommand.EditContactDescriptor;
+import seedu.ta.logic.parser.exceptions.ParseException;
+import seedu.ta.model.tag.Tag;
+
+/**
+ * Parses input arguments and creates a new EditContactCommand object.
+ */
+public class EditContactCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the EditContactCommand
+ * and returns an EditContactCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public EditContactCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_TAG);
+
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String
+ .format(MESSAGE_INVALID_COMMAND_FORMAT, EditContactCommand.MESSAGE_USAGE), pe);
+ }
+
+ EditContactDescriptor editContactDescriptor = new EditContactDescriptor();
+
+ if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
+ editContactDescriptor.setName(ParserUtil.parseContactName(argMultimap.getValue(PREFIX_NAME).get()));
+ }
+ if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
+ editContactDescriptor.setPhone(ParserUtil.parseContactPhone(argMultimap.getValue(PREFIX_PHONE).get()));
+ }
+ if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
+ editContactDescriptor.setEmail(ParserUtil.parseContactEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
+ }
+ parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editContactDescriptor::setTags);
+
+ if (!editContactDescriptor.isAnyFieldEdited()) {
+ throw new ParseException(MESSAGE_NOT_EDITED);
+ }
+
+ return new EditContactCommand(index, editContactDescriptor);
+ }
+
+ /**
+ * Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty.
+ * If {@code tags} contain only one element which is an empty string, it will be parsed into a
+ * {@code Set} containing zero tags.
+ */
+ private Optional> parseTagsForEdit(Collection tags) throws ParseException {
+ assert tags != null;
+
+ if (tags.isEmpty()) {
+ return Optional.empty();
+ }
+
+ Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
+ return Optional.of(ParserUtil.parseTags(tagSet));
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/parser/EditEntryCommandParser.java b/src/main/java/seedu/ta/logic/parser/EditEntryCommandParser.java
new file mode 100644
index 00000000000..f8f1e5d3aab
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/parser/EditEntryCommandParser.java
@@ -0,0 +1,88 @@
+package seedu.ta.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.ta.commons.core.Messages.MESSAGE_NOT_EDITED;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_END_DATE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_START_DATE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.Set;
+
+import seedu.ta.commons.core.index.Index;
+import seedu.ta.logic.commands.EditEntryCommand;
+import seedu.ta.logic.parser.exceptions.ParseException;
+import seedu.ta.model.entry.TemporaryEntry;
+import seedu.ta.model.tag.Tag;
+
+/**
+ * Parses input arguments and creates a new EditEntryCommand object.
+ */
+public class EditEntryCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the EditEntryCommand
+ * and returns an EditEntryCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public EditEntryCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+
+ ArgumentMultimap argMultimap = ArgumentTokenizer
+ .tokenize(args, PREFIX_NAME, PREFIX_START_DATE, PREFIX_END_DATE, PREFIX_TAG);
+
+ Index targetIndex;
+
+ try {
+ targetIndex = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(String
+ .format(MESSAGE_INVALID_COMMAND_FORMAT, EditEntryCommand.MESSAGE_USAGE), pe);
+ }
+
+ TemporaryEntry tempEntry = new TemporaryEntry();
+
+ if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
+ tempEntry.setEntryName(ParserUtil.parseEntryName(argMultimap.getValue(PREFIX_NAME).get()));
+ }
+ if (argMultimap.getValue(PREFIX_START_DATE).isPresent()) {
+ tempEntry.setEntryStartDate(ParserUtil
+ .parseEntryDate(argMultimap.getValue(PREFIX_START_DATE).get()));
+ }
+ if (argMultimap.getValue(PREFIX_END_DATE).isPresent()) {
+ tempEntry.setEntryEndDate(ParserUtil
+ .parseEntryDate(argMultimap.getValue(PREFIX_END_DATE).get()));
+ }
+ parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(tempEntry::setTags);
+
+ if (!tempEntry.isUpdated()) {
+ throw new ParseException(MESSAGE_NOT_EDITED);
+ }
+
+ if (args.trim().length() == 0) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditEntryCommand.MESSAGE_USAGE));
+ }
+
+ return new EditEntryCommand(targetIndex, tempEntry);
+ }
+
+ /**
+ * Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty.
+ * If {@code tags} contain only one element which is an empty string, it will be parsed into a
+ * {@code Set} containing zero tags.
+ */
+ private Optional> parseTagsForEdit(Collection tags) throws ParseException {
+ assert tags != null;
+
+ if (tags.isEmpty()) {
+ return Optional.empty();
+ }
+
+ Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
+ return Optional.of(ParserUtil.parseTags(tagSet));
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/parser/FilterContactCommandParser.java b/src/main/java/seedu/ta/logic/parser/FilterContactCommandParser.java
new file mode 100644
index 00000000000..e7db4f0483d
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/parser/FilterContactCommandParser.java
@@ -0,0 +1,32 @@
+package seedu.ta.logic.parser;
+
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.Arrays;
+
+import seedu.ta.logic.commands.FilterContactCommand;
+import seedu.ta.logic.parser.exceptions.ParseException;
+import seedu.ta.model.contact.ContactTagsContainKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new FilterContactCommand object.
+ */
+public class FilterContactCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FilterContactCommand
+ * and returns a FilterContactCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public FilterContactCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterContactCommand.MESSAGE_USAGE));
+ }
+
+ String[] tagKeywords = trimmedArgs.split("\\s+");
+ return new FilterContactCommand(new ContactTagsContainKeywordsPredicate(Arrays.asList(tagKeywords)));
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/parser/FilterEntryCommandParser.java b/src/main/java/seedu/ta/logic/parser/FilterEntryCommandParser.java
new file mode 100644
index 00000000000..bae1ddc6ae0
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/parser/FilterEntryCommandParser.java
@@ -0,0 +1,32 @@
+package seedu.ta.logic.parser;
+
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.Arrays;
+
+import seedu.ta.logic.commands.FilterEntryCommand;
+import seedu.ta.logic.parser.exceptions.ParseException;
+import seedu.ta.model.entry.EntryTagsContainKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new FilterEntryCommand object.
+ */
+public class FilterEntryCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FilterEntryCommand
+ * and returns a FilterEntryCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public FilterEntryCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterEntryCommand.MESSAGE_USAGE));
+ }
+
+ String[] tagKeywords = trimmedArgs.split("\\s+");
+ return new FilterEntryCommand(new EntryTagsContainKeywordsPredicate(Arrays.asList(tagKeywords)));
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/parser/FindContactCommandParser.java b/src/main/java/seedu/ta/logic/parser/FindContactCommandParser.java
new file mode 100644
index 00000000000..87d3bb5fd00
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/parser/FindContactCommandParser.java
@@ -0,0 +1,32 @@
+package seedu.ta.logic.parser;
+
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.Arrays;
+
+import seedu.ta.logic.commands.FindContactCommand;
+import seedu.ta.logic.parser.exceptions.ParseException;
+import seedu.ta.model.contact.ContactNameContainsKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new FindContactCommand object.
+ */
+public class FindContactCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FindContactCommand
+ * and returns a FindContactCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public FindContactCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindContactCommand.MESSAGE_USAGE));
+ }
+
+ String[] nameKeywords = trimmedArgs.split("\\s+");
+ return new FindContactCommand(new ContactNameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/parser/FindEntryCommandParser.java b/src/main/java/seedu/ta/logic/parser/FindEntryCommandParser.java
new file mode 100644
index 00000000000..d9a97c5ce26
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/parser/FindEntryCommandParser.java
@@ -0,0 +1,32 @@
+package seedu.ta.logic.parser;
+
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.Arrays;
+
+import seedu.ta.logic.commands.FindEntryCommand;
+import seedu.ta.logic.parser.exceptions.ParseException;
+import seedu.ta.model.entry.EntryNameContainsKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new FindEntryCommand object.
+ */
+public class FindEntryCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FindEntryCommand
+ * and returns a FindEntryCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public FindEntryCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindEntryCommand.MESSAGE_USAGE));
+ }
+
+ String[] nameKeywords = trimmedArgs.split("\\s+");
+ return new FindEntryCommand(new EntryNameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/parser/FreeCommandParser.java b/src/main/java/seedu/ta/logic/parser/FreeCommandParser.java
new file mode 100644
index 00000000000..b25e5a323ea
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/parser/FreeCommandParser.java
@@ -0,0 +1,59 @@
+package seedu.ta.logic.parser;
+
+import static seedu.ta.commons.core.Messages.MESSAGE_ENTRY_START_DATE_IN_PAST;
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_DATE_RANGE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_END_DATE;
+import static seedu.ta.logic.parser.CliSyntax.PREFIX_START_DATE;
+
+import java.time.LocalDateTime;
+import java.util.stream.Stream;
+
+import seedu.ta.logic.commands.FreeCommand;
+import seedu.ta.logic.parser.exceptions.ParseException;
+import seedu.ta.model.entry.EntryDate;
+import seedu.ta.model.entry.ListOccupyingEntryPredicate;
+
+/**
+ * Parses input arguments and creates a new FreeCommand object.
+ */
+public class FreeCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FreeCommand
+ * and returns a FreeCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public FreeCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_START_DATE, PREFIX_END_DATE);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_START_DATE, PREFIX_END_DATE)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FreeCommand.MESSAGE_USAGE));
+ }
+
+ EntryDate startDateTime = ParserUtil.parseEntryDate(argMultimap.getValue(PREFIX_START_DATE).get());
+ EntryDate endDateTime = ParserUtil.parseEntryDate(argMultimap.getValue(PREFIX_END_DATE).get());
+
+ if (startDateTime.isAfter(endDateTime)) {
+ throw new ParseException(MESSAGE_INVALID_DATE_RANGE);
+ }
+
+ LocalDateTime now = LocalDateTime.now();
+
+ if (startDateTime.getDate().isBefore(now)) {
+ throw new ParseException(MESSAGE_ENTRY_START_DATE_IN_PAST);
+ }
+
+ return new FreeCommand(new ListOccupyingEntryPredicate(startDateTime, endDateTime));
+ }
+
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+}
diff --git a/src/main/java/seedu/ta/logic/parser/ListEntryCommandParser.java b/src/main/java/seedu/ta/logic/parser/ListEntryCommandParser.java
new file mode 100644
index 00000000000..a10bccca07b
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/parser/ListEntryCommandParser.java
@@ -0,0 +1,29 @@
+package seedu.ta.logic.parser;
+
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.ta.logic.commands.ListEntryCommand;
+import seedu.ta.logic.parser.exceptions.ParseException;
+import seedu.ta.model.entry.ListEntryFormatPredicate;
+
+/**
+ * Parses input arguments and creates a new ListEntryCommand object.
+ */
+public class ListEntryCommandParser implements Parser {
+
+ /**
+ * Parses the give {@code String} of arguments in the context of the ListEntryCommand
+ * and returns a ListEntryCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public ListEntryCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+
+ if (trimmedArgs.equals("day") || trimmedArgs.equals("week") || trimmedArgs.isEmpty()) {
+ return new ListEntryCommand(new ListEntryFormatPredicate(trimmedArgs));
+ } else {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, ListEntryCommand.MESSAGE_USAGE));
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/Parser.java b/src/main/java/seedu/ta/logic/parser/Parser.java
similarity index 67%
rename from src/main/java/seedu/address/logic/parser/Parser.java
rename to src/main/java/seedu/ta/logic/parser/Parser.java
index d6551ad8e3f..cdb39fc08ac 100644
--- a/src/main/java/seedu/address/logic/parser/Parser.java
+++ b/src/main/java/seedu/ta/logic/parser/Parser.java
@@ -1,7 +1,7 @@
-package seedu.address.logic.parser;
+package seedu.ta.logic.parser;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.ta.logic.commands.Command;
+import seedu.ta.logic.parser.exceptions.ParseException;
/**
* Represents a Parser that is able to parse user input into a {@code Command} of type {@code T}.
@@ -10,7 +10,7 @@ public interface Parser {
/**
* Parses {@code userInput} into a command and returns it.
- * @throws ParseException if {@code userInput} does not conform the expected format
+ * @throws ParseException if {@code userInput} does not conform the expected format.
*/
T parse(String userInput) throws ParseException;
}
diff --git a/src/main/java/seedu/ta/logic/parser/ParserUtil.java b/src/main/java/seedu/ta/logic/parser/ParserUtil.java
new file mode 100644
index 00000000000..56b131ac186
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/parser/ParserUtil.java
@@ -0,0 +1,165 @@
+package seedu.ta.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import seedu.ta.commons.core.index.Index;
+import seedu.ta.commons.util.StringUtil;
+import seedu.ta.logic.parser.exceptions.ParseException;
+import seedu.ta.model.contact.ContactEmail;
+import seedu.ta.model.contact.ContactName;
+import seedu.ta.model.contact.ContactPhone;
+import seedu.ta.model.entry.EntryDate;
+import seedu.ta.model.entry.EntryName;
+import seedu.ta.model.tag.Tag;
+
+/**
+ * Contains utility methods used for parsing strings in the various *Parser classes.
+ */
+public class ParserUtil {
+
+ public static final String MESSAGE_INVALID_INDEX = "Index is not a non-zero unsigned integer.";
+
+ // ======= Shared Utils =======
+
+ /**
+ * Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be
+ * trimmed.
+ * @throws ParseException if the specified index is invalid (not non-zero unsigned integer).
+ */
+ public static Index parseIndex(String oneBasedIndex) throws ParseException {
+ String trimmedIndex = oneBasedIndex.trim();
+
+ if (!StringUtil.isNonZeroUnsignedInteger(trimmedIndex)) {
+ throw new ParseException(String.format("Index given: %s\n%s", trimmedIndex, MESSAGE_INVALID_INDEX));
+ }
+
+ return Index.fromOneBased(Integer.parseInt(trimmedIndex));
+ }
+
+ /**
+ * Parses a {@code String tag} into a {@code Tag}.
+ * Leading and trailing whitespaces will be trimmed.
+ * @throws ParseException if the given {@code tag} is invalid.
+ */
+ public static Tag parseTag(String tag) throws ParseException {
+ requireNonNull(tag);
+
+ String trimmedTag = tag.trim();
+
+ if (!Tag.isValidTagName(trimmedTag)) {
+ throw new ParseException(String.format("Tag given: %s\n%s", trimmedTag, Tag.MESSAGE_CONSTRAINTS));
+ }
+
+ return new Tag(trimmedTag);
+ }
+
+ /**
+ * Parses {@code Collection tags} into a {@code Set}.
+ */
+ public static Set parseTags(Collection tags) throws ParseException {
+ requireNonNull(tags);
+
+ final Set tagSet = new HashSet<>();
+
+ for (String tagName : tags) {
+ tagSet.add(parseTag(tagName));
+ }
+
+ return tagSet;
+ }
+
+ // ======= Contact Utils =======
+
+ /**
+ * Parses a {@code String name} into a {@code ContactName}.
+ * Leading and trailing whitespaces will be trimmed.
+ * @throws ParseException if the given {@code name} is invalid.
+ */
+ public static ContactName parseContactName(String name) throws ParseException {
+ requireNonNull(name);
+
+ String trimmedName = name.trim();
+
+ if (!ContactName.isValidName(trimmedName)) {
+ throw new ParseException(String.format("Name given: %s\n%s", trimmedName, ContactName.MESSAGE_CONSTRAINTS));
+ }
+
+ return new ContactName(trimmedName);
+ }
+
+ /**
+ * Parses a {@code String phone} into a {@code ContactPhone}.
+ * Leading and trailing whitespaces will be trimmed.
+ * @throws ParseException if the given {@code phone} is invalid.
+ */
+ public static ContactPhone parseContactPhone(String phone) throws ParseException {
+ requireNonNull(phone);
+
+ String trimmedPhone = phone.trim();
+
+ if (!ContactPhone.isValidPhone(trimmedPhone)) {
+ throw new ParseException(String
+ .format("Phone number given: %s\n%s", trimmedPhone, ContactPhone.MESSAGE_CONSTRAINTS));
+ }
+
+ return new ContactPhone(trimmedPhone);
+ }
+
+ /**
+ * Parses a {@code String email} into an {@code ContactEmail}.
+ * Leading and trailing whitespaces will be trimmed.
+ * @throws ParseException if the given {@code email} is invalid.
+ */
+ public static ContactEmail parseContactEmail(String email) throws ParseException {
+ requireNonNull(email);
+
+ String trimmedEmail = email.trim();
+
+ if (!ContactEmail.isValidEmail(trimmedEmail)) {
+ throw new ParseException(String
+ .format("Email given: %s\n%s", trimmedEmail, ContactEmail.MESSAGE_CONSTRAINTS));
+ }
+
+ return new ContactEmail(trimmedEmail);
+ }
+
+ // ======= Entry Utils =======
+
+ /**
+ * Parses a {@code String entryName} into a {@code EntryName}.
+ * Leading and trailing whitespaces will be trimmed.
+ * @throws ParseException if the given {@code entryName} is invalid.
+ */
+ public static EntryName parseEntryName(String entryName) throws ParseException {
+ requireNonNull(entryName);
+
+ String trimmedEntryName = entryName.trim();
+
+ if (!EntryName.isValidName(trimmedEntryName)) {
+ throw new ParseException(String.format("Name given: %s\n%s", trimmedEntryName, EntryName.NAME_CONSTRAINTS));
+ }
+
+ return new EntryName(trimmedEntryName);
+ }
+
+ /**
+ * Parses a {@code String entryDate} into a {@code EntryDate}
+ * Leading and trailing whitespaces will be trimmed.
+ * @throws ParseException if the given {@code entryDate} is invalid.
+ */
+ public static EntryDate parseEntryDate(String entryDate) throws ParseException {
+ requireNonNull(entryDate);
+
+ String trimmedEntryDate = entryDate.trim();
+
+ if (!EntryDate.isValidDate(trimmedEntryDate)) {
+ throw new ParseException(String.format("Date given: %s\n%s", trimmedEntryDate, EntryDate.DATE_CONSTRAINTS));
+ }
+
+ return new EntryDate(trimmedEntryDate);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/Prefix.java b/src/main/java/seedu/ta/logic/parser/Prefix.java
similarity index 90%
rename from src/main/java/seedu/address/logic/parser/Prefix.java
rename to src/main/java/seedu/ta/logic/parser/Prefix.java
index c859d5fa5db..81c5c4c93aa 100644
--- a/src/main/java/seedu/address/logic/parser/Prefix.java
+++ b/src/main/java/seedu/ta/logic/parser/Prefix.java
@@ -1,10 +1,11 @@
-package seedu.address.logic.parser;
+package seedu.ta.logic.parser;
/**
* A prefix that marks the beginning of an argument in an arguments string.
- * E.g. 't/' in 'add James t/ friend'.
+ * E.g. 't/' in 'add James t/ friend'
*/
public class Prefix {
+
private final String prefix;
public Prefix(String prefix) {
diff --git a/src/main/java/seedu/ta/logic/parser/TeachingAssistantParser.java b/src/main/java/seedu/ta/logic/parser/TeachingAssistantParser.java
new file mode 100644
index 00000000000..ac088a1d5eb
--- /dev/null
+++ b/src/main/java/seedu/ta/logic/parser/TeachingAssistantParser.java
@@ -0,0 +1,112 @@
+package seedu.ta.logic.parser;
+
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.ta.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import seedu.ta.logic.commands.AddContactCommand;
+import seedu.ta.logic.commands.AddEntryCommand;
+import seedu.ta.logic.commands.ClearCommand;
+import seedu.ta.logic.commands.ClearOverdueEntryCommand;
+import seedu.ta.logic.commands.Command;
+import seedu.ta.logic.commands.DeleteContactCommand;
+import seedu.ta.logic.commands.DeleteEntryCommand;
+import seedu.ta.logic.commands.EditContactCommand;
+import seedu.ta.logic.commands.EditEntryCommand;
+import seedu.ta.logic.commands.ExitCommand;
+import seedu.ta.logic.commands.FilterContactCommand;
+import seedu.ta.logic.commands.FilterEntryCommand;
+import seedu.ta.logic.commands.FindContactCommand;
+import seedu.ta.logic.commands.FindEntryCommand;
+import seedu.ta.logic.commands.FreeCommand;
+import seedu.ta.logic.commands.HelpCommand;
+import seedu.ta.logic.commands.ListContactCommand;
+import seedu.ta.logic.commands.ListEntryCommand;
+import seedu.ta.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses user input.
+ */
+public class TeachingAssistantParser {
+
+ /**
+ * Used for initial separation of command word and args.
+ */
+ private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)");
+
+ /**
+ * Parses user input into command for execution.
+ * @param userInput full user input string.
+ * @return the command based on the user input.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public Command parseCommand(String userInput) throws ParseException {
+ final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
+
+ if (!matcher.matches()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
+ }
+
+ final String commandWord = matcher.group("commandWord");
+ final String arguments = matcher.group("arguments");
+
+ switch (commandWord) {
+
+ case AddContactCommand.COMMAND_WORD:
+ return new AddContactCommandParser().parse(arguments);
+
+ case AddEntryCommand.COMMAND_WORD:
+ return new AddEntryCommandParser().parse(arguments);
+
+ case ClearCommand.COMMAND_WORD:
+ return new ClearCommand();
+
+ case ClearOverdueEntryCommand.COMMAND_WORD:
+ return new ClearOverdueEntryCommand();
+
+ case DeleteContactCommand.COMMAND_WORD:
+ return new DeleteContactCommandParser().parse(arguments);
+
+ case DeleteEntryCommand.COMMAND_WORD:
+ return new DeleteEntryCommandParser().parse(arguments);
+
+ case EditContactCommand.COMMAND_WORD:
+ return new EditContactCommandParser().parse(arguments);
+
+ case EditEntryCommand.COMMAND_WORD:
+ return new EditEntryCommandParser().parse(arguments);
+
+ case ExitCommand.COMMAND_WORD:
+ return new ExitCommand();
+
+ case FilterContactCommand.COMMAND_WORD:
+ return new FilterContactCommandParser().parse(arguments);
+
+ case FilterEntryCommand.COMMAND_WORD:
+ return new FilterEntryCommandParser().parse(arguments);
+
+ case FindContactCommand.COMMAND_WORD:
+ return new FindContactCommandParser().parse(arguments);
+
+ case FindEntryCommand.COMMAND_WORD:
+ return new FindEntryCommandParser().parse(arguments);
+
+ case FreeCommand.COMMAND_WORD:
+ return new FreeCommandParser().parse(arguments);
+
+ case HelpCommand.COMMAND_WORD:
+ return new HelpCommand();
+
+ case ListContactCommand.COMMAND_WORD:
+ return new ListContactCommand();
+
+ case ListEntryCommand.COMMAND_WORD:
+ return new ListEntryCommandParser().parse(arguments);
+
+ default:
+ throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java b/src/main/java/seedu/ta/logic/parser/exceptions/ParseException.java
similarity index 73%
rename from src/main/java/seedu/address/logic/parser/exceptions/ParseException.java
rename to src/main/java/seedu/ta/logic/parser/exceptions/ParseException.java
index 158a1a54c1c..07198fd5532 100644
--- a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java
+++ b/src/main/java/seedu/ta/logic/parser/exceptions/ParseException.java
@@ -1,6 +1,6 @@
-package seedu.address.logic.parser.exceptions;
+package seedu.ta.logic.parser.exceptions;
-import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.ta.commons.exceptions.IllegalValueException;
/**
* Represents a parse error encountered by a parser.
diff --git a/src/main/java/seedu/ta/model/Model.java b/src/main/java/seedu/ta/model/Model.java
new file mode 100644
index 00000000000..53ed534ff14
--- /dev/null
+++ b/src/main/java/seedu/ta/model/Model.java
@@ -0,0 +1,141 @@
+package seedu.ta.model;
+
+import java.nio.file.Path;
+import java.util.function.Predicate;
+
+import javafx.collections.ObservableList;
+import seedu.ta.commons.core.GuiSettings;
+import seedu.ta.model.contact.Contact;
+import seedu.ta.model.entry.Entry;
+
+/**
+ * The API of the Model component.
+ */
+public interface Model {
+
+ /** {@code Predicate} that always evaluate to true */
+ Predicate PREDICATE_SHOW_ALL_ENTRIES = unused -> true;
+
+ /** {@code Predicate} that always evaluate to true */
+ Predicate PREDICATE_SHOW_ALL_CONTACTS = unused -> true;
+
+ /**
+ * Replaces user prefs data with the data in {@code userPrefs}.
+ */
+ void setUserPrefs(ReadOnlyUserPrefs userPrefs);
+
+ /**
+ * Returns the user prefs.
+ */
+ ReadOnlyUserPrefs getUserPrefs();
+
+ /**
+ * Returns the user prefs' GUI settings.
+ */
+ GuiSettings getGuiSettings();
+
+ /**
+ * Sets the user prefs' GUI settings.
+ */
+ void setGuiSettings(GuiSettings guiSettings);
+
+ /**
+ * Returns the user prefs' teaching assistant file path.
+ */
+ Path getTeachingAssistantFilePath();
+
+ /**
+ * Sets the user prefs' teaching assistant file path.
+ */
+ void setTeachingAssistantFilePath(Path teachingAssistantFilePath);
+
+ /**
+ * Replaces teaching assistant data with the data in {@code teachingAssistant}.
+ */
+ void setTeachingAssistant(ReadOnlyTeachingAssistant teachingAssistant);
+
+ /** Returns the TeachingAssistant */
+ ReadOnlyTeachingAssistant getTeachingAssistant();
+
+ // ====== Contact ======
+
+ /**
+ * Returns true if a contact with the same identity as {@code contact} exists in Teaching Assistant.
+ */
+ boolean hasContact(Contact contact);
+
+ /**
+ * Deletes the given contact.
+ * {@code target} must exist in Teaching Assistant.
+ */
+ void deleteContact(Contact target);
+
+ /**
+ * Adds the given contact.
+ * {@code contact} must not already exist in Teaching Assistant.
+ */
+ void addContact(Contact contact);
+
+ /**
+ * Replaces the given contact {@code target} with {@code editedContact}.
+ * {@code target} must exist in Teaching Assistant.
+ * The contact identity of {@code editedContact} must not be the same as another existing
+ * contact in Teaching Assistant.
+ */
+ void setContact(Contact target, Contact editedContact);
+
+ /** Returns an unmodifiable view of the filtered contact list */
+ ObservableList getFilteredContactList();
+
+ /**
+ * Updates the filter of the filtered contact list to filter by the given {@code predicate}.
+ * @throws NullPointerException if {@code predicate} is null.
+ */
+ void updateFilteredContactList(Predicate predicate);
+
+ // ====== Entry ======
+
+ /**
+ * Returns true if the entry exists in the list.
+ */
+ boolean hasEntry(Entry entry);
+
+ /**
+ * Deletes the given entry.
+ * {@code entry} must exist in the list.
+ */
+ void deleteEntry(Entry entry);
+
+ /**
+ * Adds the given entry.
+ * {@code entry} must not overlap with existing entries in the list.
+ */
+ void addEntry(Entry entry);
+
+ /**
+ * Replaces the given entry {@code target} with {@code editedEntry}.
+ * {@code target} must exist in the list.
+ * {@code editedEntry} must not overlap with existing entries in the list.
+ */
+ void setEntry(Entry target, Entry editedEntry);
+
+ /**
+ * Returns true if the given entry {@code toAdd} has dates overlapping with other entries in the list.
+ */
+ boolean isOverlappingEntry(Entry toAdd);
+
+ /**
+ * Removes all entries that are overdue.
+ */
+ void clearOverdueEntries();
+
+ /** Returns an unmodifiable view of the filtered entry list. */
+ ObservableList getFilteredEntryList();
+
+ /**
+ * Updates the filter of the filtered entry list to filter by the given {@code predicate}.
+ * @throws NullPointerException if {@code predicate} is null.
+ */
+ void updateFilteredEntryList(Predicate predicate);
+
+}
diff --git a/src/main/java/seedu/ta/model/ModelManager.java b/src/main/java/seedu/ta/model/ModelManager.java
new file mode 100644
index 00000000000..71e241e99dd
--- /dev/null
+++ b/src/main/java/seedu/ta/model/ModelManager.java
@@ -0,0 +1,211 @@
+package seedu.ta.model;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.nio.file.Path;
+import java.util.function.Predicate;
+import java.util.logging.Logger;
+
+import javafx.collections.ObservableList;
+import javafx.collections.transformation.FilteredList;
+import seedu.ta.commons.core.GuiSettings;
+import seedu.ta.commons.core.LogsCenter;
+import seedu.ta.model.contact.Contact;
+import seedu.ta.model.entry.Entry;
+
+/**
+ * Represents the in-memory model of the Teaching Assistant data.
+ */
+public class ModelManager implements Model {
+
+ private static final Logger logger = LogsCenter.getLogger(ModelManager.class);
+
+ private final TeachingAssistant teachingAssistant;
+ private final UserPrefs userPrefs;
+ private final FilteredList filteredContacts;
+ private final FilteredList filteredEntries;
+
+ /**
+ * Initializes a ModelManager with the given teachingAssistant and userPrefs.
+ */
+ public ModelManager(ReadOnlyTeachingAssistant teachingAssistant, ReadOnlyUserPrefs userPrefs) {
+ super();
+ requireAllNonNull(teachingAssistant, userPrefs);
+
+ logger.fine("Initializing with teaching assistant: " + teachingAssistant + " and user prefs " + userPrefs);
+
+ this.teachingAssistant = new TeachingAssistant(teachingAssistant);
+ this.userPrefs = new UserPrefs(userPrefs);
+ filteredContacts = new FilteredList<>(this.teachingAssistant.getContactList());
+ filteredEntries = new FilteredList<>(this.teachingAssistant.getEntryList());
+ }
+
+ public ModelManager() {
+ this(new TeachingAssistant(), new UserPrefs());
+ }
+
+ //=========== UserPrefs ==================================================================================
+
+ @Override
+ public void setUserPrefs(ReadOnlyUserPrefs userPrefs) {
+ requireNonNull(userPrefs);
+ this.userPrefs.resetData(userPrefs);
+ }
+
+ @Override
+ public ReadOnlyUserPrefs getUserPrefs() {
+ return userPrefs;
+ }
+
+ @Override
+ public GuiSettings getGuiSettings() {
+ return userPrefs.getGuiSettings();
+ }
+
+ @Override
+ public void setGuiSettings(GuiSettings guiSettings) {
+ requireNonNull(guiSettings);
+ userPrefs.setGuiSettings(guiSettings);
+ }
+
+ @Override
+ public Path getTeachingAssistantFilePath() {
+ return userPrefs.getTeachingAssistantFilePath();
+ }
+
+ @Override
+ public void setTeachingAssistantFilePath(Path teachingAssistantFilePath) {
+ requireNonNull(teachingAssistantFilePath);
+ userPrefs.setTeachingAssistantFilePath(teachingAssistantFilePath);
+ }
+
+ // ====== Teaching Assistant ======
+
+ @Override
+ public void setTeachingAssistant(ReadOnlyTeachingAssistant teachingAssistant) {
+ this.teachingAssistant.resetData(teachingAssistant);
+ }
+
+ @Override
+ public ReadOnlyTeachingAssistant getTeachingAssistant() {
+ return teachingAssistant;
+ }
+
+ // ====== Contact ======
+
+ @Override
+ public boolean hasContact(Contact contact) {
+ requireNonNull(contact);
+ return teachingAssistant.hasContact(contact);
+ }
+
+ @Override
+ public void deleteContact(Contact target) {
+ teachingAssistant.removeContact(target);
+ }
+
+ @Override
+ public void addContact(Contact contact) {
+ teachingAssistant.addContact(contact);
+ updateFilteredContactList(PREDICATE_SHOW_ALL_CONTACTS);
+ }
+
+ @Override
+ public void setContact(Contact target, Contact editedContact) {
+ requireAllNonNull(target, editedContact);
+
+ teachingAssistant.setContact(target, editedContact);
+ }
+
+ // ====== Entry ======
+
+ @Override
+ public boolean hasEntry(Entry entry) {
+ return teachingAssistant.hasEntry(entry);
+ }
+
+ @Override
+ public void addEntry(Entry entry) {
+ teachingAssistant.addEntry(entry);
+ updateFilteredEntryList(PREDICATE_SHOW_ALL_ENTRIES);
+ }
+
+ @Override
+ public void deleteEntry(Entry entry) {
+ teachingAssistant.removeEntry(entry);
+ }
+
+ @Override
+ public void setEntry(Entry target, Entry editedEntry) {
+ requireAllNonNull(target, editedEntry);
+ teachingAssistant.setEntry(target, editedEntry);
+ }
+
+ @Override
+ public boolean isOverlappingEntry(Entry toAdd) {
+ requireNonNull(toAdd);
+ return teachingAssistant.isOverlappingEntry(toAdd);
+ }
+
+ @Override
+ public void clearOverdueEntries() {
+ teachingAssistant.clearOverdueEntries();
+ }
+
+ //=========== Filtered Contact List Accessors =============================================================
+
+ /**
+ * Returns an unmodifiable view of the list of {@code Contact} backed by the internal list of
+ * {@code versionedTeachingAssistant}.
+ */
+ @Override
+ public ObservableList getFilteredContactList() {
+ return filteredContacts;
+ }
+
+ @Override
+ public void updateFilteredContactList(Predicate predicate) {
+ requireNonNull(predicate);
+ filteredContacts.setPredicate(predicate);
+ }
+
+ //=========== Filtered Entry List Accessors ==============================================================
+
+ /**
+ * Returns an unmodifiable view of the list of {@code Entry} backed by the internal list of
+ * {@code versionedTeachingAssistant}.
+ */
+ @Override
+ public ObservableList getFilteredEntryList() {
+ return filteredEntries;
+ }
+
+ @Override
+ public void updateFilteredEntryList(Predicate predicate) {
+ requireNonNull(predicate);
+ filteredEntries.setPredicate(predicate);
+ }
+
+ //=========== Misc ===============
+
+ @Override
+ public boolean equals(Object obj) {
+ // short circuit if same object
+ if (obj == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(obj instanceof ModelManager)) {
+ return false;
+ }
+
+ // state check
+ ModelManager other = (ModelManager) obj;
+ return teachingAssistant.equals(other.teachingAssistant)
+ && userPrefs.equals(other.userPrefs)
+ && filteredContacts.equals(other.filteredContacts)
+ && filteredEntries.equals(other.filteredEntries);
+ }
+}
diff --git a/src/main/java/seedu/ta/model/ReadOnlyTeachingAssistant.java b/src/main/java/seedu/ta/model/ReadOnlyTeachingAssistant.java
new file mode 100644
index 00000000000..8b5362872bb
--- /dev/null
+++ b/src/main/java/seedu/ta/model/ReadOnlyTeachingAssistant.java
@@ -0,0 +1,23 @@
+package seedu.ta.model;
+
+import javafx.collections.ObservableList;
+import seedu.ta.model.contact.Contact;
+import seedu.ta.model.entry.Entry;
+
+/**
+ * Unmodifiable view of Teaching Assistant.
+ */
+public interface ReadOnlyTeachingAssistant {
+
+ /**
+ * Returns an unmodifiable view of the contacts list.
+ * This list will not contain any duplicate contacts.
+ */
+ ObservableList getContactList();
+
+ /**
+ * Returns an unmodifiable view of the entries list.
+ * This list will not contain any overlapping entries.
+ */
+ ObservableList getEntryList();
+}
diff --git a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java b/src/main/java/seedu/ta/model/ReadOnlyUserPrefs.java
similarity index 57%
rename from src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
rename to src/main/java/seedu/ta/model/ReadOnlyUserPrefs.java
index befd58a4c73..02206650ef2 100644
--- a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
+++ b/src/main/java/seedu/ta/model/ReadOnlyUserPrefs.java
@@ -1,8 +1,8 @@
-package seedu.address.model;
+package seedu.ta.model;
import java.nio.file.Path;
-import seedu.address.commons.core.GuiSettings;
+import seedu.ta.commons.core.GuiSettings;
/**
* Unmodifiable view of user prefs.
@@ -11,6 +11,5 @@ public interface ReadOnlyUserPrefs {
GuiSettings getGuiSettings();
- Path getAddressBookFilePath();
-
+ Path getTeachingAssistantFilePath();
}
diff --git a/src/main/java/seedu/ta/model/TeachingAssistant.java b/src/main/java/seedu/ta/model/TeachingAssistant.java
new file mode 100644
index 00000000000..a5f3e98ebf8
--- /dev/null
+++ b/src/main/java/seedu/ta/model/TeachingAssistant.java
@@ -0,0 +1,190 @@
+package seedu.ta.model;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import javafx.collections.ObservableList;
+import seedu.ta.model.contact.Contact;
+import seedu.ta.model.contact.UniqueContactList;
+import seedu.ta.model.entry.Entry;
+import seedu.ta.model.entry.NonOverlappingEntryList;
+
+
+/**
+ * Wraps all data at the teaching-assistant level.
+ * Duplicates are not allowed (by .isSameContact comparison).
+ */
+public class TeachingAssistant implements ReadOnlyTeachingAssistant {
+
+ private final UniqueContactList contacts;
+ private final NonOverlappingEntryList entries;
+
+ /*
+ * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
+ * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
+ *
+ * Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication
+ * among constructors.
+ */
+ {
+ entries = new NonOverlappingEntryList();
+ contacts = new UniqueContactList();
+ }
+
+ public TeachingAssistant() {}
+
+ /**
+ * Creates an TeachingAssistant using the data in the {@code toBeCopied}.
+ */
+ public TeachingAssistant(ReadOnlyTeachingAssistant toBeCopied) {
+ this();
+ resetData(toBeCopied);
+ }
+
+ //// ===== List Operations =====
+
+ /**
+ * Replaces the contents of the contact list with {@code contacts}.
+ * {@code contacts} must not contain duplicate contacts.
+ */
+ public void setContacts(List contacts) {
+ this.contacts.setContacts(contacts);
+ }
+
+ /**
+ * Replaces the contents of the entry list with {@code entries}.
+ * {@code entries} must not contain overlapping entries.
+ */
+ public void setEntries(List entries) {
+ this.entries.setEntries(entries);
+ }
+
+ /**
+ * Resets the existing data of this {@code TeachingAssistant} with {@code newData}.
+ */
+ public void resetData(ReadOnlyTeachingAssistant newData) {
+ requireNonNull(newData);
+ setContacts(newData.getContactList());
+ setEntries(newData.getEntryList());
+ }
+
+ //// ===== Contact Operations =====
+
+ /**
+ * Returns true if a contact with the same identity as {@code contact} exists in Teaching Assistant.
+ */
+ public boolean hasContact(Contact contact) {
+ requireNonNull(contact);
+ return contacts.contains(contact);
+ }
+
+ /**
+ * Adds a contact to Teaching Assistant.
+ * The contact must not already exist in Teaching Assistant.
+ */
+ public void addContact(Contact contact) {
+ contacts.add(contact);
+ }
+
+ /**
+ * Replaces the given contact {@code target} in the list with {@code editedContact}.
+ * {@code target} must exist in Teaching Assistant.
+ * The contact identity of {@code editedContact} must not be the same as another existing
+ * contact in Teaching Assistant.
+ */
+ public void setContact(Contact target, Contact editedContact) {
+ requireNonNull(editedContact);
+ contacts.setContact(target, editedContact);
+ }
+
+ /**
+ * Removes {@code contact} from this {@code Teaching Assistant}.
+ * {@code contact} must exist in Teaching Assistant.
+ */
+ public void removeContact(Contact contact) {
+ contacts.remove(contact);
+ }
+
+ //// ===== Entry Operations =====
+
+ /**
+ * Returns true if an entry with the same identity as {@code entry} exists in Teaching Assistant.
+ */
+ public boolean hasEntry(Entry entry) {
+ requireNonNull(entry);
+ return entries.contains(entry);
+ }
+
+ /**
+ * Adds an entry to the list.
+ * The entry must not overlap with existing entries in the list.
+ */
+ public void addEntry(Entry entry) {
+ entries.add(entry);
+ }
+
+ /**
+ * Removes an entry {@code entry} from the list.
+ * {@code entry} must exist in the list.
+ */
+ public void removeEntry(Entry entry) {
+ requireNonNull(entry);
+ entries.remove(entry);
+ }
+
+ /**
+ * Replaces the given entry {@code target} in the list with {@code editedEntry}.
+ * {@code target} must exist in the list.
+ * {@code editedEntry} must not overlap with existing entries in the list.
+ */
+ public void setEntry(Entry target, Entry editedEntry) {
+ requireNonNull(editedEntry);
+ entries.setEntry(target, editedEntry);
+ }
+
+ /**
+ * Returns true if the give entry overlaps with existing entries in the list.
+ */
+ public boolean isOverlappingEntry(Entry entry) {
+ requireNonNull(entry);
+ return entries.overlapsWith(entry);
+ }
+
+ /**
+ * Clears all overdue entries in Teaching Assistant.
+ */
+ public void clearOverdueEntries() {
+ entries.clearOverdueEntries();
+ }
+
+ // ===== Util =====
+
+ @Override
+ public String toString() {
+ return contacts.asUnmodifiableObservableList().size() + " contacts";
+ // TODO: refine later
+ }
+
+ @Override
+ public ObservableList getContactList() {
+ return contacts.asUnmodifiableObservableList();
+ }
+
+ @Override
+ public ObservableList getEntryList() {
+ return entries.asUnmodifiableObservableList();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof TeachingAssistant // instanceof handles nulls
+ && contacts.equals(((TeachingAssistant) other).contacts));
+ }
+
+ @Override
+ public int hashCode() {
+ return contacts.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/ta/model/UserPrefs.java
similarity index 68%
rename from src/main/java/seedu/address/model/UserPrefs.java
rename to src/main/java/seedu/ta/model/UserPrefs.java
index 25a5fd6eab9..8ff047191b4 100644
--- a/src/main/java/seedu/address/model/UserPrefs.java
+++ b/src/main/java/seedu/ta/model/UserPrefs.java
@@ -1,4 +1,4 @@
-package seedu.address.model;
+package seedu.ta.model;
import static java.util.Objects.requireNonNull;
@@ -6,7 +6,7 @@
import java.nio.file.Paths;
import java.util.Objects;
-import seedu.address.commons.core.GuiSettings;
+import seedu.ta.commons.core.GuiSettings;
/**
* Represents User's preferences.
@@ -14,7 +14,7 @@
public class UserPrefs implements ReadOnlyUserPrefs {
private GuiSettings guiSettings = new GuiSettings();
- private Path addressBookFilePath = Paths.get("data" , "addressbook.json");
+ private Path teachingAssistantFilePath = Paths.get("data" , "teachingassistant.json");
/**
* Creates a {@code UserPrefs} with default values.
@@ -35,7 +35,7 @@ public UserPrefs(ReadOnlyUserPrefs userPrefs) {
public void resetData(ReadOnlyUserPrefs newUserPrefs) {
requireNonNull(newUserPrefs);
setGuiSettings(newUserPrefs.getGuiSettings());
- setAddressBookFilePath(newUserPrefs.getAddressBookFilePath());
+ setTeachingAssistantFilePath(newUserPrefs.getTeachingAssistantFilePath());
}
public GuiSettings getGuiSettings() {
@@ -47,13 +47,13 @@ public void setGuiSettings(GuiSettings guiSettings) {
this.guiSettings = guiSettings;
}
- public Path getAddressBookFilePath() {
- return addressBookFilePath;
+ public Path getTeachingAssistantFilePath() {
+ return teachingAssistantFilePath;
}
- public void setAddressBookFilePath(Path addressBookFilePath) {
- requireNonNull(addressBookFilePath);
- this.addressBookFilePath = addressBookFilePath;
+ public void setTeachingAssistantFilePath(Path teachingAssistantFilePath) {
+ requireNonNull(teachingAssistantFilePath);
+ this.teachingAssistantFilePath = teachingAssistantFilePath;
}
@Override
@@ -68,20 +68,19 @@ public boolean equals(Object other) {
UserPrefs o = (UserPrefs) other;
return guiSettings.equals(o.guiSettings)
- && addressBookFilePath.equals(o.addressBookFilePath);
+ && teachingAssistantFilePath.equals(o.teachingAssistantFilePath);
}
@Override
public int hashCode() {
- return Objects.hash(guiSettings, addressBookFilePath);
+ return Objects.hash(guiSettings, teachingAssistantFilePath);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Gui Settings : " + guiSettings);
- sb.append("\nLocal data file location : " + addressBookFilePath);
+ sb.append("\nLocal data file location : " + teachingAssistantFilePath);
return sb.toString();
}
-
}
diff --git a/src/main/java/seedu/ta/model/contact/Contact.java b/src/main/java/seedu/ta/model/contact/Contact.java
new file mode 100644
index 00000000000..1a397b736bd
--- /dev/null
+++ b/src/main/java/seedu/ta/model/contact/Contact.java
@@ -0,0 +1,103 @@
+package seedu.ta.model.contact;
+
+import static seedu.ta.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+import seedu.ta.model.tag.Tag;
+
+/**
+ * Represents a Contact in Teaching Assistant.
+ */
+public class Contact {
+
+ private final ContactName name;
+ private final ContactPhone phone;
+ private final ContactEmail email;
+ private final Set tags = new HashSet<>();
+
+ /**
+ * Creates a Contact where every field is present and not null.
+ */
+ public Contact(ContactName name, ContactPhone phone, ContactEmail email, Set tags) {
+ requireAllNonNull(name, phone, email, tags);
+ this.name = name;
+ this.phone = phone;
+ this.email = email;
+ this.tags.addAll(tags);
+ }
+
+ public ContactName getName() {
+ return name;
+ }
+
+ public ContactPhone getPhone() {
+ return phone;
+ }
+
+ public ContactEmail getEmail() {
+ return email;
+ }
+
+ /**
+ * Returns an immutable tag set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ */
+ public Set getTags() {
+ return Collections.unmodifiableSet(tags);
+ }
+
+ /**
+ * Returns true if both contacts have the same identity.
+ */
+ public boolean isSameContact(Contact otherContact) {
+ return equals(otherContact);
+ }
+
+ /**
+ * Returns true if both contacts have the same identity and data fields.
+ * This defines a stronger notion of equality between two contacts.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof Contact)) {
+ return false;
+ }
+
+ Contact otherContact = (Contact) other;
+ return otherContact.getName().equals(getName())
+ && otherContact.getPhone().equals(getPhone())
+ && otherContact.getEmail().equals(getEmail());
+ }
+
+ @Override
+ public int hashCode() {
+ // use this method for custom fields hashing instead of implementing your own
+ return Objects.hash(name, phone, email, tags);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(getName())
+ .append("; Phone: ")
+ .append(getPhone())
+ .append("; Email: ")
+ .append(getEmail());
+
+ Set tags = getTags();
+ if (!tags.isEmpty()) {
+ builder.append("; Tags: ");
+ tags.forEach(builder::append);
+ }
+ return builder.toString();
+ }
+}
+
diff --git a/src/main/java/seedu/ta/model/contact/ContactComparator.java b/src/main/java/seedu/ta/model/contact/ContactComparator.java
new file mode 100644
index 00000000000..47c99bd0b1d
--- /dev/null
+++ b/src/main/java/seedu/ta/model/contact/ContactComparator.java
@@ -0,0 +1,14 @@
+package seedu.ta.model.contact;
+
+import java.util.Comparator;
+
+/**
+ * Compares two contacts based on their names.
+ */
+public class ContactComparator implements Comparator {
+
+ @Override
+ public int compare(Contact contact, Contact otherContact) {
+ return contact.getName().fullName.compareTo(otherContact.getName().fullName);
+ }
+}
diff --git a/src/main/java/seedu/ta/model/contact/ContactEmail.java b/src/main/java/seedu/ta/model/contact/ContactEmail.java
new file mode 100644
index 00000000000..420c5da4888
--- /dev/null
+++ b/src/main/java/seedu/ta/model/contact/ContactEmail.java
@@ -0,0 +1,69 @@
+package seedu.ta.model.contact;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Contact's email.
+ */
+public class ContactEmail {
+
+ private static final String PRINTABLE_CHARACTERS = ".!#$%&'*+-/=?^_`{|}~";
+
+ public static final String MESSAGE_CONSTRAINTS = "Emails should be of the format local-part@domain "
+ + "and adhere to the following constraints:\n"
+ + "The local-part must:\n"
+ + "- be at least 2 characters long\n"
+ + "- start and end with alphanumeric characters\n"
+ + "- contain only alphanumeric characters and these special characters: " + PRINTABLE_CHARACTERS + "\n\n"
+ + "The domain name must:\n"
+ + "- be at least 2 characters long\n"
+ + "- start and end with alphanumeric characters\n"
+ + "- consist of alphanumeric characters, a period or a hyphen for the characters in between, if any.";
+
+ // local-part validation
+ private static final String LOCAL_PART_REGEX = "^\\w[\\w" + PRINTABLE_CHARACTERS + "]*\\w";
+
+ // domain validation
+ private static final String DOMAIN_FIRST_CHARACTER_REGEX = "\\w"; // alphanumeric characters except underscore
+ private static final String DOMAIN_MIDDLE_REGEX = "[\\w.-]*"; // alphanumeric, period and hyphen
+ private static final String DOMAIN_LAST_CHARACTER_REGEX = "\\w$";
+ public static final String VALIDATION_REGEX = LOCAL_PART_REGEX + "@"
+ + DOMAIN_FIRST_CHARACTER_REGEX + DOMAIN_MIDDLE_REGEX + DOMAIN_LAST_CHARACTER_REGEX;
+
+ public final String value;
+
+ /**
+ * Creates a ContactEmail with a valid email address.
+ */
+ public ContactEmail(String email) {
+ requireNonNull(email);
+ checkArgument(isValidEmail(email), MESSAGE_CONSTRAINTS);
+ value = email;
+ }
+
+ /**
+ * Returns true if a given string is a valid email.
+ */
+ public static boolean isValidEmail(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ContactEmail // instanceof handles nulls
+ && value.equalsIgnoreCase(((ContactEmail) other).value)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+}
+
diff --git a/src/main/java/seedu/ta/model/contact/ContactName.java b/src/main/java/seedu/ta/model/contact/ContactName.java
new file mode 100644
index 00000000000..37f1fd2827e
--- /dev/null
+++ b/src/main/java/seedu/ta/model/contact/ContactName.java
@@ -0,0 +1,57 @@
+package seedu.ta.model.contact;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Contact's name.
+ */
+public class ContactName {
+
+ public static final String MESSAGE_CONSTRAINTS = "The name must:\n"
+ + "- be at least 2 characters long\n"
+ + "- consist of only alphabets, spaces and hyphens\n"
+ + "- start and end with alphabets";
+
+ /**
+ * The first character of the name must not be a whitespace,
+ * otherwise " " (a blank string) becomes a valid input.
+ */
+ public static final String VALIDATION_REGEX = "^[A-Za-z][-A-Za-z ]*[A-Za-z]$";
+
+ public final String fullName;
+
+ /**
+ * Creates a ContactName with a vaild name.
+ */
+ public ContactName(String name) {
+ requireNonNull(name);
+ checkArgument(isValidName(name), MESSAGE_CONSTRAINTS);
+ fullName = name;
+ }
+
+ /**
+ * Returns true if a given string is a valid name.
+ */
+ public static boolean isValidName(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ @Override
+ public String toString() {
+ return fullName;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ContactName // instanceof handles nulls
+ && fullName.equalsIgnoreCase(((ContactName) other).fullName)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return fullName.hashCode();
+ }
+}
+
diff --git a/src/main/java/seedu/ta/model/contact/ContactNameContainsKeywordsPredicate.java b/src/main/java/seedu/ta/model/contact/ContactNameContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..306a2722fec
--- /dev/null
+++ b/src/main/java/seedu/ta/model/contact/ContactNameContainsKeywordsPredicate.java
@@ -0,0 +1,32 @@
+package seedu.ta.model.contact;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.ta.commons.util.StringUtil;
+
+/**
+ * Tests that a {@code Contact}'s {@code ContactName} matches all of the keywords given.
+ */
+public class ContactNameContainsKeywordsPredicate implements Predicate {
+
+ private final List keywords;
+
+ public ContactNameContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Contact contact) {
+ return keywords.stream()
+ .allMatch(keyword -> StringUtil.containsWordIgnoreCase(contact.getName().fullName, keyword));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ContactNameContainsKeywordsPredicate // instanceof handles nulls
+ && keywords.equals(((ContactNameContainsKeywordsPredicate) other).keywords)); // state check
+ }
+}
+
diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/seedu/ta/model/contact/ContactPhone.java
similarity index 52%
rename from src/main/java/seedu/address/model/person/Phone.java
rename to src/main/java/seedu/ta/model/contact/ContactPhone.java
index 872c76b382f..43248743579 100644
--- a/src/main/java/seedu/address/model/person/Phone.java
+++ b/src/main/java/seedu/ta/model/contact/ContactPhone.java
@@ -1,26 +1,24 @@
-package seedu.address.model.person;
+package seedu.ta.model.contact;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
+import static seedu.ta.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's phone number in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidPhone(String)}
+ * Represents a Contact's phone number.
*/
-public class Phone {
-
+public class ContactPhone {
public static final String MESSAGE_CONSTRAINTS =
- "Phone numbers should only contain numbers, and it should be at least 3 digits long";
- public static final String VALIDATION_REGEX = "\\d{3,}";
+ "Phone numbers are 8 digits long, must not start with a 0 and should not have symbols.";
+
+ public static final String VALIDATION_REGEX = "^[1-9]\\d{7}$";
+
public final String value;
/**
- * Constructs a {@code Phone}.
- *
- * @param phone A valid phone number.
+ * Creates a ContactPhone with a valid phone number.
*/
- public Phone(String phone) {
+ public ContactPhone(String phone) {
requireNonNull(phone);
checkArgument(isValidPhone(phone), MESSAGE_CONSTRAINTS);
value = phone;
@@ -41,13 +39,13 @@ public String toString() {
@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
- || (other instanceof Phone // instanceof handles nulls
- && value.equals(((Phone) other).value)); // state check
+ || (other instanceof ContactPhone // instanceof handles nulls
+ && value.equals(((ContactPhone) other).value)); // state check
}
@Override
public int hashCode() {
return value.hashCode();
}
-
}
+
diff --git a/src/main/java/seedu/ta/model/contact/ContactTagsContainKeywordsPredicate.java b/src/main/java/seedu/ta/model/contact/ContactTagsContainKeywordsPredicate.java
new file mode 100644
index 00000000000..2dd8f544bc7
--- /dev/null
+++ b/src/main/java/seedu/ta/model/contact/ContactTagsContainKeywordsPredicate.java
@@ -0,0 +1,32 @@
+package seedu.ta.model.contact;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.ta.commons.util.StringUtil;
+
+/**
+ * Tests that a {@code Contact}'s {@code Tags} matches all of the keywords given.
+ */
+public class ContactTagsContainKeywordsPredicate implements Predicate {
+
+ private final List keywords;
+
+ public ContactTagsContainKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Contact contact) {
+ return keywords.stream()
+ .allMatch(keyword -> contact.getTags().stream()
+ .anyMatch(tag -> StringUtil.containsWordIgnoreCase(tag.tagName, keyword)));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ContactTagsContainKeywordsPredicate // instanceof handles nulls
+ && keywords.equals(((ContactTagsContainKeywordsPredicate) other).keywords)); // state check
+ }
+}
diff --git a/src/main/java/seedu/ta/model/contact/UniqueContactList.java b/src/main/java/seedu/ta/model/contact/UniqueContactList.java
new file mode 100644
index 00000000000..6474ed8d91e
--- /dev/null
+++ b/src/main/java/seedu/ta/model/contact/UniqueContactList.java
@@ -0,0 +1,147 @@
+package seedu.ta.model.contact;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import seedu.ta.model.contact.exceptions.ContactNotFoundException;
+import seedu.ta.model.contact.exceptions.DuplicateContactException;
+
+
+/**
+ * A list of contacts that enforces uniqueness between its elements and does not allow nulls.
+ * A contact is considered unique by comparing using {@code Contact#isSameContact(Contact)}.
+ *
+ * As such, adding, deleting and updating of contacts uses Contact#isSameContact(Contact) for equality
+ * so as to ensure that the contact being added or updated is unique in terms of identity
+ * in the UniqueContactList.
+ *
+ * Supports a minimal set of list operations.
+ *
+ * @see Contact#isSameContact(Contact)
+ */
+public class UniqueContactList implements Iterable {
+
+ private final ObservableList internalList = FXCollections.observableArrayList();
+ private final ObservableList internalUnmodifiableList =
+ FXCollections.unmodifiableObservableList(internalList);
+
+ /**
+ * Returns true if the list contains an equivalent contact as the given argument.
+ */
+ public boolean contains(Contact toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::isSameContact);
+ }
+
+ /**
+ * Adds a contact to the list.
+ * The contact must not already exist in the list.
+ */
+ public void add(Contact toAdd) {
+ requireNonNull(toAdd);
+ if (contains(toAdd)) {
+ throw new DuplicateContactException();
+ }
+ internalList.add(toAdd);
+ FXCollections.sort(internalList, new ContactComparator());
+ }
+
+ /**
+ * Replaces the contact {@code target} in the list with {@code editedContact}.
+ * {@code target} must exist in the list.
+ * The contact identity of {@code editedContact} must not be the same as another
+ * existing contact in the list.
+ */
+ public void setContact(Contact target, Contact editedContact) {
+ requireAllNonNull(target, editedContact);
+
+ int index = internalList.indexOf(target);
+
+ if (index == -1) {
+ throw new ContactNotFoundException();
+ }
+
+ if (!target.equals(editedContact) && contains(editedContact)) {
+ throw new DuplicateContactException();
+ }
+
+ internalList.set(index, editedContact);
+ }
+
+ /**
+ * Removes the equivalent contact from the list.
+ * The contact must exist in the list.
+ */
+ public void remove(Contact toRemove) {
+ requireNonNull(toRemove);
+ if (!internalList.remove(toRemove)) {
+ throw new ContactNotFoundException();
+ }
+ }
+
+ /**
+ * Replaces the contents of this list with {@replacement}.
+ * All contacts in {@replacement} are unique.
+ */
+ public void setContacts(UniqueContactList replacement) {
+ requireNonNull(replacement);
+ internalList.setAll(replacement.internalList);
+ }
+
+ /**
+ * Replaces the contents of this list with {@code contacts}.
+ * {@code contacts} must not contain duplicate contacts.
+ */
+ public void setContacts(List contacts) {
+ requireAllNonNull(contacts);
+
+ if (!contactsAreUnique(contacts)) {
+ throw new DuplicateContactException();
+ }
+
+ internalList.setAll(contacts);
+ }
+
+ /**
+ * Returns the backing list as an unmodifiable {@code ObservableList}.
+ */
+ public ObservableList asUnmodifiableObservableList() {
+ return internalUnmodifiableList;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return internalList.iterator();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof UniqueContactList // instanceof handles nulls
+ && internalList.equals(((UniqueContactList) other).internalList));
+ }
+
+ @Override
+ public int hashCode() {
+ return internalList.hashCode();
+ }
+
+ /**
+ * Returns true if {@code contacts} contains only unique contacts.
+ */
+ private boolean contactsAreUnique(List contacts) {
+ for (int i = 0; i < contacts.size() - 1; i++) {
+ for (int j = i + 1; j < contacts.size(); j++) {
+ if (contacts.get(i).isSameContact(contacts.get(j))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/seedu/ta/model/contact/exceptions/ContactNotFoundException.java b/src/main/java/seedu/ta/model/contact/exceptions/ContactNotFoundException.java
new file mode 100644
index 00000000000..03884b738b1
--- /dev/null
+++ b/src/main/java/seedu/ta/model/contact/exceptions/ContactNotFoundException.java
@@ -0,0 +1,7 @@
+package seedu.ta.model.contact.exceptions;
+
+/**
+ * Represents an error that occurs because a specified contact referenced
+ * by an operation is unable to be found.
+ */
+public class ContactNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/ta/model/contact/exceptions/DuplicateContactException.java b/src/main/java/seedu/ta/model/contact/exceptions/DuplicateContactException.java
new file mode 100644
index 00000000000..4b248f2de39
--- /dev/null
+++ b/src/main/java/seedu/ta/model/contact/exceptions/DuplicateContactException.java
@@ -0,0 +1,11 @@
+package seedu.ta.model.contact.exceptions;
+
+/**
+ * Represents an error that occurs when an operation results in the creation of duplicate
+ * contacts (contacts are considered duplicates if they have the same identity).
+ */
+public class DuplicateContactException extends RuntimeException {
+ public DuplicateContactException() {
+ super("Operation would result in duplicate contacts");
+ }
+}
diff --git a/src/main/java/seedu/ta/model/entry/Entry.java b/src/main/java/seedu/ta/model/entry/Entry.java
new file mode 100644
index 00000000000..e0afa623be5
--- /dev/null
+++ b/src/main/java/seedu/ta/model/entry/Entry.java
@@ -0,0 +1,151 @@
+package seedu.ta.model.entry;
+
+import static seedu.ta.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import seedu.ta.model.tag.Tag;
+
+/**
+ * Represents an Entry in Teaching Assistant.
+ */
+public class Entry {
+
+ private final EntryName entryName;
+ private final EntryDate startDate;
+ private final EntryDate endDate;
+ private final Set tags = new HashSet<>();
+
+ /**
+ * Creates an Entry where every field is present and not null.
+ */
+ public Entry(EntryName entryName, EntryDate startDate,
+ EntryDate endDate, Set tags) {
+ requireAllNonNull(entryName, startDate, endDate, tags);
+ this.entryName = entryName;
+ this.startDate = startDate;
+ this.endDate = endDate;
+ this.tags.addAll(tags);
+ }
+
+ public EntryName getEntryName() {
+ return entryName;
+ }
+
+ public EntryDate getOriginalStartDate() {
+ return startDate;
+ }
+
+ public EntryDate getOriginalEndDate() {
+ return endDate;
+ }
+
+ public LocalDateTime getStartDate() {
+ return startDate.getDate();
+ }
+
+ public LocalDateTime getEndDate() {
+ return endDate.getDate();
+ }
+
+ /**
+ * Returns an immutable tag set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ */
+ public Set getTags() {
+ return Collections.unmodifiableSet(tags);
+ }
+
+ /**
+ * Returns true if both entries have the same fields.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof Entry)) {
+ return false;
+ }
+
+ Entry otherEntry = (Entry) other;
+ return otherEntry.getEntryName().equals(getEntryName())
+ && otherEntry.getOriginalStartDate().equals(getOriginalStartDate())
+ && otherEntry.getOriginalEndDate().equals(getOriginalEndDate())
+ && otherEntry.getTags().equals(getTags());
+ }
+
+ /**
+ * Returns true if both entries are the same objects.
+ */
+ public boolean isSameEntry(Entry otherEntry) {
+ return otherEntry == this;
+ }
+
+ /**
+ * Returns true if both entries have overlapping time intervals.
+ */
+ public boolean overlapsWith(Entry otherEntry) {
+ if (otherEntry == null) {
+ return true;
+ }
+
+ LocalDateTime firstStart = this.getStartDate();
+ LocalDateTime firstEnd = this.getEndDate();
+ LocalDateTime secondStart = otherEntry.getStartDate();
+ LocalDateTime secondEnd = otherEntry.getEndDate();
+
+ return (firstStart.isBefore(secondEnd) && secondStart.isBefore(firstEnd));
+ }
+
+ /**
+ * Returns true if the current date is after end date.
+ */
+ public boolean isOverdue() {
+ LocalDateTime currentDateTime = LocalDateTime.now();
+ return currentDateTime.isAfter(getEndDate());
+ }
+
+ /**
+ * Returns true if start date is different from end date.
+ */
+ public boolean haveDifferentDates() {
+ return !getStartDate().isEqual(getEndDate());
+ }
+
+ /**
+ * Returns the string representation of the start date and time
+ * formatted with the default formatter.
+ */
+ public String startTimestamp() {
+ return getStartDate().format(EntryDate.DEFAULT_FORMATTER);
+ }
+
+ /**
+ * Returns the string representation of the end date and time
+ * formatted with the default formatter.
+ */
+ public String endTimestamp() {
+ return getEndDate().format(EntryDate.DEFAULT_FORMATTER);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(getEntryName())
+ .append(haveDifferentDates() ? new StringBuilder("; Start Date: ").append(startTimestamp()) : "")
+ .append("; End Date: ")
+ .append(endTimestamp());
+
+ Set tags = getTags();
+ if (!tags.isEmpty()) {
+ builder.append("; Tags: ");
+ tags.forEach(builder::append);
+ }
+ return builder.toString();
+ }
+}
diff --git a/src/main/java/seedu/ta/model/entry/EntryComparator.java b/src/main/java/seedu/ta/model/entry/EntryComparator.java
new file mode 100644
index 00000000000..96cff7e1b22
--- /dev/null
+++ b/src/main/java/seedu/ta/model/entry/EntryComparator.java
@@ -0,0 +1,18 @@
+package seedu.ta.model.entry;
+
+import java.util.Comparator;
+
+/**
+ * Compares two entries based on their date times.
+ */
+public class EntryComparator implements Comparator {
+
+ @Override
+ public int compare(Entry entry, Entry otherEntry) {
+ if (entry.getStartDate().isBefore(otherEntry.getStartDate())) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+}
diff --git a/src/main/java/seedu/ta/model/entry/EntryDate.java b/src/main/java/seedu/ta/model/entry/EntryDate.java
new file mode 100644
index 00000000000..38cd68a9bd6
--- /dev/null
+++ b/src/main/java/seedu/ta/model/entry/EntryDate.java
@@ -0,0 +1,79 @@
+package seedu.ta.model.entry;
+
+import static java.time.format.ResolverStyle.STRICT;
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.commons.util.AppUtil.checkArgument;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+/**
+ * Represents a Entry's date and time.
+ */
+public class EntryDate {
+
+ public static final String DATE_CONSTRAINTS =
+ "Dates should be valid and in the format yyyy-mm-dd HH:MM. Time must be in the 24-hour clock notation.";
+
+ public static final DateTimeFormatter DEFAULT_FORMATTER =
+ DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm").withResolverStyle(STRICT);
+
+ public final LocalDateTime value;
+
+ /**
+ * Creates an EntryDate with valid date times.
+ */
+ public EntryDate(String date) {
+ requireNonNull(date);
+ checkArgument(isValidDate(date), DATE_CONSTRAINTS);
+ value = LocalDateTime.parse(date, DEFAULT_FORMATTER);
+ }
+
+ /**
+ * Returns true if a given string is a valid date.
+ */
+ public static boolean isValidDate(String dateStr) {
+ try {
+ DEFAULT_FORMATTER.parse(dateStr);
+ } catch (DateTimeParseException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if this entryDate is after the specified entryDate.
+ */
+ public boolean isAfter(EntryDate other) {
+ return value.isAfter(other.getDate());
+ }
+
+ /**
+ * Returns true if this entryDate is before the specified entryDate.
+ */
+ public boolean isBefore(EntryDate other) {
+ return value.isBefore(other.getDate());
+ }
+
+ public LocalDateTime getDate() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return getDate().format(DEFAULT_FORMATTER);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this
+ || (other instanceof EntryDate
+ && value.equals(((EntryDate) other).value));
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/ta/model/entry/EntryName.java b/src/main/java/seedu/ta/model/entry/EntryName.java
new file mode 100644
index 00000000000..ec6791fe8f2
--- /dev/null
+++ b/src/main/java/seedu/ta/model/entry/EntryName.java
@@ -0,0 +1,54 @@
+package seedu.ta.model.entry;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Entry's name.
+ */
+public class EntryName {
+
+ public static final String NAME_CONSTRAINTS =
+ "Names should only contain alphanumeric characters and spaces, and it should not be blank.";
+
+ /**
+ * The first character of the name must not be a whitespace,
+ * otherwise " " (a blank string) becomes a valid input.
+ */
+ public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
+
+ public final String name;
+
+ /**
+ * Creates an EntryName with a vaild name.
+ */
+ public EntryName(String name) {
+ requireNonNull(name);
+ checkArgument(isValidName(name), NAME_CONSTRAINTS);
+ this.name = name;
+ }
+
+ /**
+ * Returns true if a given string is a valid name.
+ */
+ public static boolean isValidName(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof EntryName // instanceof handles nulls
+ && name.equals(((EntryName) other).name)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/ta/model/entry/EntryNameContainsKeywordsPredicate.java b/src/main/java/seedu/ta/model/entry/EntryNameContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..b36715704fa
--- /dev/null
+++ b/src/main/java/seedu/ta/model/entry/EntryNameContainsKeywordsPredicate.java
@@ -0,0 +1,31 @@
+package seedu.ta.model.entry;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.ta.commons.util.StringUtil;
+
+/**
+ * Tests that an {@code Entry}'s {@code EntryName} matches all of the keywords given.
+ */
+public class EntryNameContainsKeywordsPredicate implements Predicate {
+
+ private final List keywords;
+
+ public EntryNameContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Entry entry) {
+ return keywords.stream()
+ .allMatch(keyword -> StringUtil.containsWordIgnoreCase(entry.getEntryName().name, keyword));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof EntryNameContainsKeywordsPredicate // instanceof handles nulls
+ && keywords.equals(((EntryNameContainsKeywordsPredicate) other).keywords)); // state check
+ }
+}
diff --git a/src/main/java/seedu/ta/model/entry/EntryTagsContainKeywordsPredicate.java b/src/main/java/seedu/ta/model/entry/EntryTagsContainKeywordsPredicate.java
new file mode 100644
index 00000000000..663a9dea608
--- /dev/null
+++ b/src/main/java/seedu/ta/model/entry/EntryTagsContainKeywordsPredicate.java
@@ -0,0 +1,31 @@
+package seedu.ta.model.entry;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.ta.commons.util.StringUtil;
+
+/**
+ * Tests that an {@code Entry}'s {@code Tags} matches all of the keywords given.
+ */
+public class EntryTagsContainKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public EntryTagsContainKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(Entry entry) {
+ return keywords.stream()
+ .allMatch(keyword -> entry.getTags().stream()
+ .anyMatch(tag -> StringUtil.containsWordIgnoreCase(tag.tagName, keyword)));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof EntryTagsContainKeywordsPredicate // instanceof handles nulls
+ && keywords.equals(((EntryTagsContainKeywordsPredicate) other).keywords)); // state check
+ }
+}
diff --git a/src/main/java/seedu/ta/model/entry/ListEntryFormatPredicate.java b/src/main/java/seedu/ta/model/entry/ListEntryFormatPredicate.java
new file mode 100644
index 00000000000..3017e2ecbd7
--- /dev/null
+++ b/src/main/java/seedu/ta/model/entry/ListEntryFormatPredicate.java
@@ -0,0 +1,50 @@
+package seedu.ta.model.entry;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.function.Predicate;
+
+/**
+ * Tests for the correct formatting needed based on the keyword given in order to display
+ * the {@code Entry} list.
+ */
+public class ListEntryFormatPredicate implements Predicate {
+
+ private final String keyword;
+
+ public ListEntryFormatPredicate(String keyword) {
+ this.keyword = keyword;
+ }
+
+ @Override
+ public boolean test(Entry entry) {
+
+ LocalDate today = LocalDate.from(LocalDateTime.now());
+ LocalDate yesterday = today.plusDays(-1);
+ LocalDate lastDay = today.plusDays(7);
+
+ LocalDate startDate = LocalDate.from(entry.getStartDate());
+ LocalDate endDate = LocalDate.from(entry.getEndDate());
+
+ if (keyword.equals("day")) {
+ return today.equals(startDate) || today.equals(endDate)
+ || startDate.isBefore(today) && endDate.isAfter(today);
+ } else if (keyword.equals("week")) {
+ return startDate.isAfter(yesterday) && startDate.isBefore(lastDay)
+ || endDate.isAfter(yesterday) && endDate.isBefore(lastDay)
+ || startDate.isBefore(yesterday) && endDate.isAfter(lastDay);
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ return (other instanceof ListEntryFormatPredicate)
+ && ((ListEntryFormatPredicate) other).keyword.equals(keyword);
+ }
+}
diff --git a/src/main/java/seedu/ta/model/entry/ListOccupyingEntryPredicate.java b/src/main/java/seedu/ta/model/entry/ListOccupyingEntryPredicate.java
new file mode 100644
index 00000000000..04ede87aac7
--- /dev/null
+++ b/src/main/java/seedu/ta/model/entry/ListOccupyingEntryPredicate.java
@@ -0,0 +1,29 @@
+package seedu.ta.model.entry;
+
+import java.time.LocalDateTime;
+import java.util.function.Predicate;
+
+/**
+ * Tests that an {@code Entry}'s start and end dates matches the target interval given.
+ */
+public class ListOccupyingEntryPredicate implements Predicate {
+
+ private final LocalDateTime targetStart;
+ private final LocalDateTime targetEnd;
+
+ /**
+ * Creates a ListOccupyingEntryPredicate with target interval.
+ */
+ public ListOccupyingEntryPredicate(EntryDate startDateTime, EntryDate endDateTime) {
+ this.targetStart = startDateTime.getDate();
+ this.targetEnd = endDateTime.getDate();
+ }
+
+ @Override
+ public boolean test(Entry entry) {
+ LocalDateTime entryStart = entry.getStartDate();
+ LocalDateTime entryEnd = entry.getEndDate();
+ return (targetStart.isBefore(entryEnd) && entryStart.isBefore(targetEnd));
+ }
+}
+
diff --git a/src/main/java/seedu/ta/model/entry/NonOverlappingEntryList.java b/src/main/java/seedu/ta/model/entry/NonOverlappingEntryList.java
new file mode 100644
index 00000000000..5dfb58928e4
--- /dev/null
+++ b/src/main/java/seedu/ta/model/entry/NonOverlappingEntryList.java
@@ -0,0 +1,157 @@
+package seedu.ta.model.entry;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.ta.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import seedu.ta.model.entry.exceptions.EntryNotFoundException;
+import seedu.ta.model.entry.exceptions.OverlappingEntryException;
+
+/**
+ * A list of entries that enforces that its elements do not overlap and are not nulls.
+ * An entry is considered overlapping by testing using {@code Entry#overlapsWith(Entry)}.
+ *
+ * Supports a minimal set of list operations.
+ *
+ * @see Entry#overlapsWith(Entry)
+ */
+public class NonOverlappingEntryList implements Iterable {
+
+ private final ObservableList internalList = FXCollections.observableArrayList();
+ private final ObservableList internalUnmodifiableList =
+ FXCollections.unmodifiableObservableList(internalList);
+
+ /**
+ * Returns true if the list contains the same entry as the given argument.
+ */
+ public boolean contains(Entry toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::isSameEntry);
+ }
+
+ /**
+ * Returns true if the list contains an overlapping entry as the given argument.
+ */
+ public boolean overlapsWith(Entry toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::overlapsWith);
+ }
+
+ /**
+ * Adds an entry to the list.
+ * The entry must not overlap with existing entries in the list.
+ */
+ public void add(Entry toAdd) {
+ requireNonNull(toAdd);
+
+ if (overlapsWith(toAdd)) {
+ throw new OverlappingEntryException();
+ }
+
+ internalList.add(toAdd);
+ FXCollections.sort(internalList, new EntryComparator());
+ }
+
+ /**
+ * Replaces the entry {@code target} in the list with {@code editedEntry}.
+ * {@code target} must exist in the list.
+ * {@code editedEntry} must not overlap with existing entries in the list.
+ */
+ public void setEntry(Entry target, Entry editedEntry) {
+ requireAllNonNull(target, editedEntry);
+
+ int index = internalList.indexOf(target);
+
+ if (index == -1) {
+ throw new EntryNotFoundException();
+ }
+
+ if (target.overlapsWith(editedEntry) || overlapsWith(editedEntry)) {
+ throw new OverlappingEntryException();
+ }
+
+ internalList.set(index, editedEntry);
+ }
+
+ /**
+ * Removes the equivalent entry from the list.
+ * The entry must exist in the list.
+ */
+ public void remove(Entry toRemove) {
+ requireNonNull(toRemove);
+ if (!internalList.remove(toRemove)) {
+ throw new EntryNotFoundException();
+ }
+ }
+
+ /**
+ * Replaces the contents of this list with {@replacement}.
+ * All entries in {@replacement} are non-overlapping.
+ */
+ public void setEntries(NonOverlappingEntryList replacement) {
+ requireNonNull(replacement);
+ internalList.setAll(replacement.internalList);
+ }
+
+ /**
+ * Replaces the contents of this list with {@code entries}.
+ * {@code entries} must not contain overlapping entries.
+ */
+ public void setEntries(List entries) {
+ requireAllNonNull(entries);
+ if (!entriesAreNotOverlapping(entries)) {
+ throw new OverlappingEntryException();
+ }
+
+ internalList.setAll(entries);
+ }
+
+ /**
+ * Removes all overdue entries in this list.
+ */
+ public void clearOverdueEntries() {
+ internalList.removeIf(Entry::isOverdue);
+ }
+
+ /**
+ * Returns the backing list as an unmodifiable {@code ObservableList}.
+ */
+ public ObservableList asUnmodifiableObservableList() {
+ return internalUnmodifiableList;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return internalList.iterator();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof NonOverlappingEntryList // instanceof handles nulls
+ && internalList.equals(((NonOverlappingEntryList) other).internalList));
+ }
+
+ @Override
+ public int hashCode() {
+ return internalList.hashCode();
+ }
+
+ /**
+ * Returns true if {@code entries} contains only non-overlapping entries.
+ */
+ private boolean entriesAreNotOverlapping(List entries) {
+ for (int i = 0; i < entries.size() - 1; i++) {
+ for (int j = i + 1; j < entries.size(); j++) {
+ if (entries.get(i).overlapsWith(entries.get(j))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/seedu/ta/model/entry/TemporaryEntry.java b/src/main/java/seedu/ta/model/entry/TemporaryEntry.java
new file mode 100644
index 00000000000..b0725556f94
--- /dev/null
+++ b/src/main/java/seedu/ta/model/entry/TemporaryEntry.java
@@ -0,0 +1,92 @@
+package seedu.ta.model.entry;
+
+import java.util.Optional;
+import java.util.Set;
+
+import seedu.ta.model.tag.Tag;
+
+/**
+ * Represents a TemporaryEntry.
+ */
+public class TemporaryEntry {
+
+ private boolean isAnyFieldEdited;
+ private Optional entryName;
+ private Optional startDate;
+ private Optional endDate;
+ private Optional> tags;
+
+ /**
+ * Creates a TemporaryEntry object which is a partial Entry object
+ * with optional fields.
+ */
+ public TemporaryEntry() {
+ isAnyFieldEdited = false;
+ entryName = Optional.empty();
+ startDate = Optional.empty();
+ endDate = Optional.empty();
+ tags = Optional.empty();
+ }
+
+ public boolean isUpdated() {
+ return isAnyFieldEdited;
+ }
+
+ public Optional getEntryName() {
+ return entryName;
+ }
+
+ public Optional getStartDate() {
+ return startDate;
+ }
+
+ public Optional getEndDate() {
+ return endDate;
+ }
+
+ public Optional> getTags() {
+ return tags;
+ }
+
+ public TemporaryEntry setEntryName(EntryName name) {
+ isAnyFieldEdited = true;
+ entryName = Optional.of(name);
+ return this;
+ }
+
+ public TemporaryEntry setEntryStartDate(EntryDate date) {
+ isAnyFieldEdited = true;
+ startDate = Optional.of(date);
+ return this;
+ }
+
+ public TemporaryEntry setEntryEndDate(EntryDate date) {
+ isAnyFieldEdited = true;
+ endDate = Optional.of(date);
+ return this;
+ }
+
+ public TemporaryEntry setTags(Set tags) {
+ isAnyFieldEdited = true;
+ this.tags = Optional.of(tags);
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof TemporaryEntry)) {
+ return false;
+ }
+
+ TemporaryEntry otherEntry = (TemporaryEntry) other;
+ return otherEntry.entryName.equals(entryName)
+ && otherEntry.startDate.equals(startDate)
+ && otherEntry.endDate.equals(endDate)
+ && otherEntry.tags.equals(tags)
+ && otherEntry.isAnyFieldEdited == isAnyFieldEdited;
+ }
+}
diff --git a/src/main/java/seedu/ta/model/entry/exceptions/EntryNotFoundException.java b/src/main/java/seedu/ta/model/entry/exceptions/EntryNotFoundException.java
new file mode 100644
index 00000000000..bcb50852fd6
--- /dev/null
+++ b/src/main/java/seedu/ta/model/entry/exceptions/EntryNotFoundException.java
@@ -0,0 +1,8 @@
+package seedu.ta.model.entry.exceptions;
+
+/**
+ * Represents an error that occurs because a specified entry referenced
+ * by an operation is unable to be found.
+ */
+public class EntryNotFoundException extends RuntimeException {
+}
diff --git a/src/main/java/seedu/ta/model/entry/exceptions/OverlappingEntryException.java b/src/main/java/seedu/ta/model/entry/exceptions/OverlappingEntryException.java
new file mode 100644
index 00000000000..1b0a59c63bc
--- /dev/null
+++ b/src/main/java/seedu/ta/model/entry/exceptions/OverlappingEntryException.java
@@ -0,0 +1,11 @@
+package seedu.ta.model.entry.exceptions;
+
+/**
+ * Represents an error that occurs when an operation results in the creation of overlapping
+ * entries (entries are considered overlapping if their dates clash).
+ */
+public class OverlappingEntryException extends RuntimeException {
+ public OverlappingEntryException() {
+ super("Operation would result in overlapping entries");
+ }
+}
diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/ta/model/tag/Tag.java
similarity index 72%
rename from src/main/java/seedu/address/model/tag/Tag.java
rename to src/main/java/seedu/ta/model/tag/Tag.java
index b0ea7e7dad7..a8ef5eb843e 100644
--- a/src/main/java/seedu/address/model/tag/Tag.java
+++ b/src/main/java/seedu/ta/model/tag/Tag.java
@@ -1,23 +1,21 @@
-package seedu.address.model.tag;
+package seedu.ta.model.tag;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
+import static seedu.ta.commons.util.AppUtil.checkArgument;
/**
- * Represents a Tag in the address book.
- * Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String)}
+ * Represents a Tag in Teaching Assistant.
*/
public class Tag {
- public static final String MESSAGE_CONSTRAINTS = "Tags names should be alphanumeric";
+ public static final String MESSAGE_CONSTRAINTS = "Tags names should be alphanumeric and a single word.";
+
public static final String VALIDATION_REGEX = "\\p{Alnum}+";
public final String tagName;
/**
- * Constructs a {@code Tag}.
- *
- * @param tagName A valid tag name.
+ * Creates a Tag with a valid name.
*/
public Tag(String tagName) {
requireNonNull(tagName);
@@ -26,7 +24,7 @@ public Tag(String tagName) {
}
/**
- * Returns true if a given string is a valid tag name.
+ * Returns true if a given string is a valid name.
*/
public static boolean isValidTagName(String test) {
return test.matches(VALIDATION_REGEX);
@@ -50,5 +48,4 @@ public int hashCode() {
public String toString() {
return '[' + tagName + ']';
}
-
}
diff --git a/src/main/java/seedu/ta/model/util/SampleDataUtil.java b/src/main/java/seedu/ta/model/util/SampleDataUtil.java
new file mode 100644
index 00000000000..d65977c9def
--- /dev/null
+++ b/src/main/java/seedu/ta/model/util/SampleDataUtil.java
@@ -0,0 +1,75 @@
+package seedu.ta.model.util;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import seedu.ta.model.ReadOnlyTeachingAssistant;
+import seedu.ta.model.TeachingAssistant;
+import seedu.ta.model.contact.Contact;
+import seedu.ta.model.contact.ContactEmail;
+import seedu.ta.model.contact.ContactName;
+import seedu.ta.model.contact.ContactPhone;
+import seedu.ta.model.entry.Entry;
+import seedu.ta.model.entry.EntryDate;
+import seedu.ta.model.entry.EntryName;
+import seedu.ta.model.tag.Tag;
+
+/**
+ * Contains utility methods for populating {@code TeachingAssistant} with sample data.
+ */
+public class SampleDataUtil {
+ public static Contact[] getSampleContacts() {
+ return new Contact[] {
+ new Contact(new ContactName("Alex Yeoh"), new ContactPhone("87438807"),
+ new ContactEmail("alexyeoh@example.com"), getTagSet("friends")),
+ new Contact(new ContactName("Bernice Yu"), new ContactPhone("99272758"),
+ new ContactEmail("berniceyu@example.com"), getTagSet("colleagues", "friends")),
+ new Contact(new ContactName("Charlotte Oliveiro"), new ContactPhone("93210283"),
+ new ContactEmail("charlotte@example.com"), getTagSet("neighbours")),
+ new Contact(new ContactName("David Li"), new ContactPhone("91031282"),
+ new ContactEmail("lidavid@example.com"), getTagSet("family")),
+ new Contact(new ContactName("Irfan Ibrahim"), new ContactPhone("92492021"),
+ new ContactEmail("irfan@example.com"), getTagSet("classmates")),
+ new Contact(new ContactName("Roy Balakrishnan"), new ContactPhone("92624417"),
+ new ContactEmail("royb@example.com"), getTagSet("colleagues"))
+ };
+ }
+
+ public static Entry[] getSampleEntries() {
+ return new Entry[] {
+ new Entry(new EntryName("Consultation with 2A"), new EntryDate("2021-05-04 13:00"),
+ new EntryDate("2021-05-04 15:00"), getTagSet("consultation")),
+ new Entry(new EntryName("Department meeting"), new EntryDate("2021-05-05 16:00"),
+ new EntryDate("2021-05-05 17:00"), getTagSet("meeting", "needprep")),
+ new Entry(new EntryName("CCA"), new EntryDate("2021-05-11 16:00"),
+ new EntryDate("2021-05-11 18:00"), getTagSet("cca")),
+ new Entry(new EntryName("Leadership Camp"), new EntryDate("2021-05-15 07:00"),
+ new EntryDate("2021-05-16 18:00"), getTagSet("event")),
+ new Entry(new EntryName("Sec 2 teachers meeting"), new EntryDate("2021-05-17 13:00"),
+ new EntryDate("2021-05-17 14:00"), getTagSet("meeting")),
+ new Entry(new EntryName("Consultation with 2B"), new EntryDate("2021-05-18 13:00"),
+ new EntryDate("2021-05-18 15:00"), getTagSet("consultation"))
+ };
+ }
+
+ public static ReadOnlyTeachingAssistant getSampleTeachingAssistant() {
+ TeachingAssistant sampleAb = new TeachingAssistant();
+ for (Contact sampleContact : getSampleContacts()) {
+ sampleAb.addContact(sampleContact);
+ }
+ for (Entry sampleEntry : getSampleEntries()) {
+ sampleAb.addEntry(sampleEntry);
+ }
+ return sampleAb;
+ }
+
+ /**
+ * Returns a tag set containing the list of strings given.
+ */
+ public static Set getTagSet(String... strings) {
+ return Arrays.stream(strings)
+ .map(Tag::new)
+ .collect(Collectors.toSet());
+ }
+}
diff --git a/src/main/java/seedu/ta/storage/JsonAdaptedContact.java b/src/main/java/seedu/ta/storage/JsonAdaptedContact.java
new file mode 100644
index 00000000000..12bd565c2cc
--- /dev/null
+++ b/src/main/java/seedu/ta/storage/JsonAdaptedContact.java
@@ -0,0 +1,100 @@
+package seedu.ta.storage;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import seedu.ta.commons.exceptions.IllegalValueException;
+import seedu.ta.model.contact.Contact;
+import seedu.ta.model.contact.ContactEmail;
+import seedu.ta.model.contact.ContactName;
+import seedu.ta.model.contact.ContactPhone;
+import seedu.ta.model.tag.Tag;
+
+/**
+ * Jackson-friendly version of {@link Contact}.
+ */
+class JsonAdaptedContact {
+
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Contact's %s field is missing!";
+
+ private final String name;
+ private final String phone;
+ private final String email;
+ private final List tagged = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonAdaptedContact} with the given contact details.
+ */
+ @JsonCreator
+ public JsonAdaptedContact(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
+ @JsonProperty("email") String email,
+ @JsonProperty("tagged") List tagged) {
+ this.name = name;
+ this.phone = phone;
+ this.email = email;
+ if (tagged != null) {
+ this.tagged.addAll(tagged);
+ }
+ }
+
+ /**
+ * Converts a given {@code Contact} into this class for Jackson use.
+ */
+ public JsonAdaptedContact(Contact source) {
+ name = source.getName().fullName;
+ phone = source.getPhone().value;
+ email = source.getEmail().value;
+ tagged.addAll(source.getTags().stream()
+ .map(JsonAdaptedTag::new)
+ .collect(Collectors.toList()));
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted contact object into the model's {@code Contact} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted contact.
+ */
+ public Contact toModelType() throws IllegalValueException {
+ final List contactTags = new ArrayList<>();
+ for (JsonAdaptedTag tag : tagged) {
+ contactTags.add(tag.toModelType());
+ }
+
+ if (name == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ ContactName.class.getSimpleName()));
+ }
+ if (!ContactName.isValidName(name)) {
+ throw new IllegalValueException(ContactName.MESSAGE_CONSTRAINTS);
+ }
+ final ContactName modelName = new ContactName(name);
+
+ if (phone == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ ContactPhone.class.getSimpleName()));
+ }
+ if (!ContactPhone.isValidPhone(phone)) {
+ throw new IllegalValueException(ContactPhone.MESSAGE_CONSTRAINTS);
+ }
+ final ContactPhone modelPhone = new ContactPhone(phone);
+
+ if (email == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ ContactEmail.class.getSimpleName()));
+ }
+ if (!ContactEmail.isValidEmail(email)) {
+ throw new IllegalValueException(ContactEmail.MESSAGE_CONSTRAINTS);
+ }
+ final ContactEmail modelEmail = new ContactEmail(email);
+
+ final Set modelTags = new HashSet<>(contactTags);
+ return new Contact(modelName, modelPhone, modelEmail, modelTags);
+ }
+
+}
diff --git a/src/main/java/seedu/ta/storage/JsonAdaptedEntry.java b/src/main/java/seedu/ta/storage/JsonAdaptedEntry.java
new file mode 100644
index 00000000000..861f1b4565a
--- /dev/null
+++ b/src/main/java/seedu/ta/storage/JsonAdaptedEntry.java
@@ -0,0 +1,101 @@
+package seedu.ta.storage;
+
+import static seedu.ta.commons.core.Messages.MESSAGE_INVALID_DATE_RANGE;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import seedu.ta.commons.exceptions.IllegalValueException;
+import seedu.ta.model.entry.Entry;
+import seedu.ta.model.entry.EntryDate;
+import seedu.ta.model.entry.EntryName;
+import seedu.ta.model.tag.Tag;
+
+public class JsonAdaptedEntry {
+
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Entry's %s field is missing!";
+
+ private final String entryName;
+ private final String startDate;
+ private final String endDate;
+ private final List tagged = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonAdaptedEntry} with the given entry details.
+ */
+ public JsonAdaptedEntry(@JsonProperty("entryName") String entryName,
+ @JsonProperty("startDate") String startDate,
+ @JsonProperty("endDate") String endDate,
+ @JsonProperty("tagged") List tagged) {
+ this.entryName = entryName;
+ this.startDate = startDate;
+ this.endDate = endDate;
+ if (tagged != null) {
+ this.tagged.addAll(tagged);
+ }
+ }
+
+ /**
+ * Converts a gievn {@code Entry} into this class for Jackson use.
+ */
+ public JsonAdaptedEntry(Entry source) {
+ entryName = source.getEntryName().name;
+ startDate = source.getOriginalStartDate().toString();
+ endDate = source.getOriginalEndDate().toString();
+ tagged.addAll(source.getTags().stream()
+ .map(JsonAdaptedTag::new)
+ .collect(Collectors.toList()));
+ }
+
+ /**
+ * Convert this Jackson-friendly adapted entry object into the model's {@code Entry} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted entry.
+ */
+ public Entry toModelType() throws IllegalValueException {
+ final List entryTags = new ArrayList<>();
+ for (JsonAdaptedTag tag : tagged) {
+ entryTags.add(tag.toModelType());
+ }
+
+ if (entryName == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ EntryName.class.getSimpleName()));
+ }
+ if (!EntryName.isValidName(entryName)) {
+ throw new IllegalValueException(EntryName.NAME_CONSTRAINTS);
+ }
+ final EntryName modelEntryName = new EntryName(entryName);
+
+ if (startDate == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ EntryDate.class.getSimpleName()));
+ }
+ if (!EntryDate.isValidDate(startDate)) {
+ throw new IllegalValueException(EntryDate.DATE_CONSTRAINTS);
+ }
+ final EntryDate modelStartDate = new EntryDate(startDate);
+
+ if (endDate == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ EntryDate.class.getSimpleName()));
+ }
+ if (!EntryDate.isValidDate(endDate)) {
+ throw new IllegalValueException(EntryDate.DATE_CONSTRAINTS);
+ }
+
+ final EntryDate modelEndDate = new EntryDate(endDate);
+
+ if (modelStartDate.isAfter(modelEndDate)) {
+ throw new IllegalValueException(MESSAGE_INVALID_DATE_RANGE);
+ }
+
+ final Set modelTags = new HashSet<>(entryTags);
+ return new Entry(modelEntryName, modelStartDate, modelEndDate, modelTags);
+ }
+}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTag.java b/src/main/java/seedu/ta/storage/JsonAdaptedTag.java
similarity index 89%
rename from src/main/java/seedu/address/storage/JsonAdaptedTag.java
rename to src/main/java/seedu/ta/storage/JsonAdaptedTag.java
index 0df22bdb754..0dd58a0e654 100644
--- a/src/main/java/seedu/address/storage/JsonAdaptedTag.java
+++ b/src/main/java/seedu/ta/storage/JsonAdaptedTag.java
@@ -1,10 +1,10 @@
-package seedu.address.storage;
+package seedu.ta.storage;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.tag.Tag;
+import seedu.ta.commons.exceptions.IllegalValueException;
+import seedu.ta.model.tag.Tag;
/**
* Jackson-friendly version of {@link Tag}.
diff --git a/src/main/java/seedu/ta/storage/JsonSerializableTeachingAssistant.java b/src/main/java/seedu/ta/storage/JsonSerializableTeachingAssistant.java
new file mode 100644
index 00000000000..ef3013fbc36
--- /dev/null
+++ b/src/main/java/seedu/ta/storage/JsonSerializableTeachingAssistant.java
@@ -0,0 +1,79 @@
+package seedu.ta.storage;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+
+import seedu.ta.commons.exceptions.IllegalValueException;
+import seedu.ta.model.ReadOnlyTeachingAssistant;
+import seedu.ta.model.TeachingAssistant;
+import seedu.ta.model.contact.Contact;
+import seedu.ta.model.entry.Entry;
+
+/**
+ * An Immutable TeachingAssistant that is serializable to JSON format.
+ */
+@JsonRootName(value = "teachingassistant")
+class JsonSerializableTeachingAssistant {
+
+ public static final String MESSAGE_DUPLICATE_CONTACT = "Contact list contains duplicate contacts(s).";
+ public static final String MESSAGE_DUPLICATE_ENTRY = "Entry List contains duplicate entry(s)";
+ public static final String MESSAGE_OVERLAPPING_ENTRY = "Entry List contains entries with overlapping dates";
+
+ private final List contacts = new ArrayList<>();
+ private final List entries = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonSerializableTeachingAssistant} with the given contacts.
+ */
+ @JsonCreator
+ public JsonSerializableTeachingAssistant(@JsonProperty("contacts") List contacts,
+ @JsonProperty("entries") List entries) {
+ this.contacts.addAll(contacts);
+ this.entries.addAll(entries);
+ }
+
+ /**
+ * Converts a given {@code ReadOnlyTeachingAssistant} into this class for Jackson use.
+ *
+ * @param source future changes to this will not affect the created {@code JsonSerializableTeachingAssistant}.
+ */
+ public JsonSerializableTeachingAssistant(ReadOnlyTeachingAssistant source) {
+ contacts.addAll(source.getContactList().stream().map(JsonAdaptedContact::new).collect(Collectors.toList()));
+ entries.addAll(source.getEntryList().stream().map(JsonAdaptedEntry::new).collect(Collectors.toList()));
+ }
+
+ /**
+ * Converts this teaching assistant into the model's {@code TeachingAssistant} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated.
+ */
+ public TeachingAssistant toModelType() throws IllegalValueException {
+ TeachingAssistant teachingAssistant = new TeachingAssistant();
+ for (JsonAdaptedContact jsonAdaptedContact : contacts) {
+ Contact contact = jsonAdaptedContact.toModelType();
+ if (teachingAssistant.hasContact(contact)) {
+ throw new IllegalValueException(MESSAGE_DUPLICATE_CONTACT);
+ }
+ teachingAssistant.addContact(contact);
+ }
+
+ for (JsonAdaptedEntry jsonAdaptedEntry : entries) {
+ Entry entry = jsonAdaptedEntry.toModelType();
+ if (teachingAssistant.hasEntry(entry)) {
+ throw new IllegalValueException(MESSAGE_DUPLICATE_ENTRY);
+ }
+
+ if (teachingAssistant.isOverlappingEntry(entry)) {
+ throw new IllegalValueException(MESSAGE_OVERLAPPING_ENTRY);
+ }
+ teachingAssistant.addEntry(entry);
+ }
+ return teachingAssistant;
+ }
+
+}
diff --git a/src/main/java/seedu/ta/storage/JsonTeachingAssistantStorage.java b/src/main/java/seedu/ta/storage/JsonTeachingAssistantStorage.java
new file mode 100644
index 00000000000..155bdc6b073
--- /dev/null
+++ b/src/main/java/seedu/ta/storage/JsonTeachingAssistantStorage.java
@@ -0,0 +1,80 @@
+package seedu.ta.storage;
+
+import static java.util.Objects.requireNonNull;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.logging.Logger;
+
+import seedu.ta.commons.core.LogsCenter;
+import seedu.ta.commons.exceptions.DataConversionException;
+import seedu.ta.commons.exceptions.IllegalValueException;
+import seedu.ta.commons.util.FileUtil;
+import seedu.ta.commons.util.JsonUtil;
+import seedu.ta.model.ReadOnlyTeachingAssistant;
+
+/**
+ * A class to access TeachingAssistant data stored as a json file on the hard disk.
+ */
+public class JsonTeachingAssistantStorage implements TeachingAssistantStorage {
+
+ private static final Logger logger = LogsCenter.getLogger(JsonTeachingAssistantStorage.class);
+
+ private Path filePath;
+
+ public JsonTeachingAssistantStorage(Path filePath) {
+ this.filePath = filePath;
+ }
+
+ public Path getTeachingAssistantFilePath() {
+ return filePath;
+ }
+
+ @Override
+ public Optional readTeachingAssistant() throws DataConversionException {
+ return readTeachingAssistant(filePath);
+ }
+
+ /**
+ * Similar to {@link #readTeachingAssistant()}.
+ *
+ * @param filePath location of the data. Cannot be null.
+ * @throws DataConversionException if the file is not in the correct format.
+ */
+ public Optional readTeachingAssistant(Path filePath) throws DataConversionException {
+ requireNonNull(filePath);
+
+ Optional jsonTeachingAssistant = JsonUtil.readJsonFile(
+ filePath, JsonSerializableTeachingAssistant.class);
+ if (!jsonTeachingAssistant.isPresent()) {
+ return Optional.empty();
+ }
+
+ try {
+ return Optional.of(jsonTeachingAssistant.get().toModelType());
+ } catch (IllegalValueException ive) {
+ logger.info("Illegal values found in " + filePath + ": " + ive.getMessage());
+ throw new DataConversionException(ive);
+ }
+ }
+
+ @Override
+ public void saveTeachingAssistant(ReadOnlyTeachingAssistant teachingAssistant) throws IOException {
+ saveTeachingAssistant(teachingAssistant, filePath);
+ }
+
+ /**
+ * Similar to {@link #saveTeachingAssistant(ReadOnlyTeachingAssistant)}.
+ *
+ * @param filePath location of the data. Cannot be null.
+ */
+ public void saveTeachingAssistant(ReadOnlyTeachingAssistant teachingAssistant, Path filePath) throws IOException {
+ requireNonNull(teachingAssistant);
+ requireNonNull(filePath);
+
+ FileUtil.createIfMissing(filePath);
+ JsonUtil.saveJsonFile(new JsonSerializableTeachingAssistant(teachingAssistant), filePath);
+ }
+
+}
diff --git a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java b/src/main/java/seedu/ta/storage/JsonUserPrefsStorage.java
similarity index 83%
rename from src/main/java/seedu/address/storage/JsonUserPrefsStorage.java
rename to src/main/java/seedu/ta/storage/JsonUserPrefsStorage.java
index bc2bbad84aa..1cb01649b11 100644
--- a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java
+++ b/src/main/java/seedu/ta/storage/JsonUserPrefsStorage.java
@@ -1,13 +1,13 @@
-package seedu.address.storage;
+package seedu.ta.storage;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.commons.util.JsonUtil;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
+import seedu.ta.commons.exceptions.DataConversionException;
+import seedu.ta.commons.util.JsonUtil;
+import seedu.ta.model.ReadOnlyUserPrefs;
+import seedu.ta.model.UserPrefs;
/**
* A class to access UserPrefs stored in the hard disk as a json file
diff --git a/src/main/java/seedu/ta/storage/Storage.java b/src/main/java/seedu/ta/storage/Storage.java
new file mode 100644
index 00000000000..6a7c72b613e
--- /dev/null
+++ b/src/main/java/seedu/ta/storage/Storage.java
@@ -0,0 +1,32 @@
+package seedu.ta.storage;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+
+import seedu.ta.commons.exceptions.DataConversionException;
+import seedu.ta.model.ReadOnlyTeachingAssistant;
+import seedu.ta.model.ReadOnlyUserPrefs;
+import seedu.ta.model.UserPrefs;
+
+/**
+ * API of the Storage component
+ */
+public interface Storage extends TeachingAssistantStorage, UserPrefsStorage {
+
+ @Override
+ Optional readUserPrefs() throws DataConversionException, IOException;
+
+ @Override
+ void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException;
+
+ @Override
+ Path getTeachingAssistantFilePath();
+
+ @Override
+ Optional readTeachingAssistant() throws DataConversionException, IOException;
+
+ @Override
+ void saveTeachingAssistant(ReadOnlyTeachingAssistant teachingAssistant) throws IOException;
+
+}
diff --git a/src/main/java/seedu/ta/storage/StorageManager.java b/src/main/java/seedu/ta/storage/StorageManager.java
new file mode 100644
index 00000000000..bbcca91d13e
--- /dev/null
+++ b/src/main/java/seedu/ta/storage/StorageManager.java
@@ -0,0 +1,80 @@
+package seedu.ta.storage;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.logging.Logger;
+
+import seedu.ta.commons.core.LogsCenter;
+import seedu.ta.commons.exceptions.DataConversionException;
+import seedu.ta.model.ReadOnlyTeachingAssistant;
+import seedu.ta.model.ReadOnlyUserPrefs;
+import seedu.ta.model.UserPrefs;
+
+/**
+ * Manages storage of TeachingAssistant data in local storage.
+ */
+public class StorageManager implements Storage {
+
+ private static final Logger logger = LogsCenter.getLogger(StorageManager.class);
+ private TeachingAssistantStorage teachingAssistantStorage;
+ private UserPrefsStorage userPrefsStorage;
+
+ /**
+ * Creates a {@code StorageManager} with the given {@code TeachingAssistantStorage} and {@code UserPrefStorage}.
+ */
+ public StorageManager(TeachingAssistantStorage teachingAssistantStorage, UserPrefsStorage userPrefsStorage) {
+ super();
+ this.teachingAssistantStorage = teachingAssistantStorage;
+ this.userPrefsStorage = userPrefsStorage;
+ }
+
+ // ================ UserPrefs methods ==============================
+
+ @Override
+ public Path getUserPrefsFilePath() {
+ return userPrefsStorage.getUserPrefsFilePath();
+ }
+
+ @Override
+ public Optional readUserPrefs() throws DataConversionException, IOException {
+ return userPrefsStorage.readUserPrefs();
+ }
+
+ @Override
+ public void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException {
+ userPrefsStorage.saveUserPrefs(userPrefs);
+ }
+
+
+ // ================ TeachingAssistant methods ==============================
+
+ @Override
+ public Path getTeachingAssistantFilePath() {
+ return teachingAssistantStorage.getTeachingAssistantFilePath();
+ }
+
+ @Override
+ public Optional readTeachingAssistant() throws DataConversionException, IOException {
+ return readTeachingAssistant(teachingAssistantStorage.getTeachingAssistantFilePath());
+ }
+
+ @Override
+ public Optional readTeachingAssistant(Path filePath)
+ throws DataConversionException, IOException {
+ logger.fine("Attempting to read data from file: " + filePath);
+ return teachingAssistantStorage.readTeachingAssistant(filePath);
+ }
+
+ @Override
+ public void saveTeachingAssistant(ReadOnlyTeachingAssistant teachingAssistant) throws IOException {
+ saveTeachingAssistant(teachingAssistant, teachingAssistantStorage.getTeachingAssistantFilePath());
+ }
+
+ @Override
+ public void saveTeachingAssistant(ReadOnlyTeachingAssistant teachingAssistant, Path filePath) throws IOException {
+ logger.fine("Attempting to write to data file: " + filePath);
+ teachingAssistantStorage.saveTeachingAssistant(teachingAssistant, filePath);
+ }
+
+}
diff --git a/src/main/java/seedu/ta/storage/TeachingAssistantStorage.java b/src/main/java/seedu/ta/storage/TeachingAssistantStorage.java
new file mode 100644
index 00000000000..492e53c3554
--- /dev/null
+++ b/src/main/java/seedu/ta/storage/TeachingAssistantStorage.java
@@ -0,0 +1,46 @@
+package seedu.ta.storage;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+
+import seedu.ta.commons.exceptions.DataConversionException;
+import seedu.ta.model.ReadOnlyTeachingAssistant;
+
+/**
+ * Represents a storage for {@link seedu.ta.model.TeachingAssistant}.
+ */
+public interface TeachingAssistantStorage {
+
+ /**
+ * Returns the file path of the data file.
+ */
+ Path getTeachingAssistantFilePath();
+
+ /**
+ * Returns TeachingAssistant data as a {@link ReadOnlyTeachingAssistant}.
+ * Returns {@code Optional.empty()} if storage file is not found.
+ * @throws DataConversionException if the data in storage is not in the expected format.
+ * @throws IOException if there was any problem when reading from the storage.
+ */
+ Optional readTeachingAssistant() throws DataConversionException, IOException;
+
+ /**
+ * @see #getTeachingAssistantFilePath()
+ */
+ Optional readTeachingAssistant(Path filePath)
+ throws DataConversionException, IOException;
+
+ /**
+ * Saves the given {@link ReadOnlyTeachingAssistant} to the storage.
+ * @param teachingAssistant cannot be null.
+ * @throws IOException if there was any problem writing to the file.
+ */
+ void saveTeachingAssistant(ReadOnlyTeachingAssistant teachingAssistant) throws IOException;
+
+ /**
+ * @see #saveTeachingAssistant(ReadOnlyTeachingAssistant)
+ */
+ void saveTeachingAssistant(ReadOnlyTeachingAssistant teachingAssistant, Path filePath) throws IOException;
+
+}
diff --git a/src/main/java/seedu/address/storage/UserPrefsStorage.java b/src/main/java/seedu/ta/storage/UserPrefsStorage.java
similarity index 71%
rename from src/main/java/seedu/address/storage/UserPrefsStorage.java
rename to src/main/java/seedu/ta/storage/UserPrefsStorage.java
index 29eef178dbc..62e6c0278de 100644
--- a/src/main/java/seedu/address/storage/UserPrefsStorage.java
+++ b/src/main/java/seedu/ta/storage/UserPrefsStorage.java
@@ -1,15 +1,15 @@
-package seedu.address.storage;
+package seedu.ta.storage;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
+import seedu.ta.commons.exceptions.DataConversionException;
+import seedu.ta.model.ReadOnlyUserPrefs;
+import seedu.ta.model.UserPrefs;
/**
- * Represents a storage for {@link seedu.address.model.UserPrefs}.
+ * Represents a storage for {@link seedu.ta.model.UserPrefs}.
*/
public interface UserPrefsStorage {
@@ -27,7 +27,7 @@ public interface UserPrefsStorage {
Optional readUserPrefs() throws DataConversionException, IOException;
/**
- * Saves the given {@link seedu.address.model.ReadOnlyUserPrefs} to the storage.
+ * Saves the given {@link seedu.ta.model.ReadOnlyUserPrefs} to the storage.
* @param userPrefs cannot be null.
* @throws IOException if there was any problem writing to the file.
*/
diff --git a/src/main/java/seedu/address/ui/CommandBox.java b/src/main/java/seedu/ta/ui/CommandBox.java
similarity index 89%
rename from src/main/java/seedu/address/ui/CommandBox.java
rename to src/main/java/seedu/ta/ui/CommandBox.java
index 9e75478664b..5d4c7e59e04 100644
--- a/src/main/java/seedu/address/ui/CommandBox.java
+++ b/src/main/java/seedu/ta/ui/CommandBox.java
@@ -1,12 +1,12 @@
-package seedu.address.ui;
+package seedu.ta.ui;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
import javafx.scene.layout.Region;
-import seedu.address.logic.commands.CommandResult;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.ta.logic.commands.CommandResult;
+import seedu.ta.logic.commands.exceptions.CommandException;
+import seedu.ta.logic.parser.exceptions.ParseException;
/**
* The UI component that is responsible for receiving user command inputs.
@@ -77,7 +77,7 @@ public interface CommandExecutor {
/**
* Executes the command and returns the result.
*
- * @see seedu.address.logic.Logic#execute(String)
+ * @see seedu.ta.logic.Logic#execute(String)
*/
CommandResult execute(String commandText) throws CommandException, ParseException;
}
diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/ta/ui/ContactCard.java
similarity index 61%
rename from src/main/java/seedu/address/ui/PersonCard.java
rename to src/main/java/seedu/ta/ui/ContactCard.java
index 7fc927bc5d9..2a03fa7a877 100644
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ b/src/main/java/seedu/ta/ui/ContactCard.java
@@ -1,4 +1,4 @@
-package seedu.address.ui;
+package seedu.ta.ui;
import java.util.Comparator;
@@ -7,14 +7,14 @@
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
-import seedu.address.model.person.Person;
+import seedu.ta.model.contact.Contact;
/**
- * An UI component that displays information of a {@code Person}.
+ * An UI component that displays information of a {@code Contact}.
*/
-public class PersonCard extends UiPart {
+public class ContactCard extends UiPart {
- private static final String FXML = "PersonListCard.fxml";
+ private static final String FXML = "ContactListCard.fxml";
/**
* Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
@@ -24,7 +24,7 @@ public class PersonCard extends UiPart {
* @see The issue on AddressBook level 4
*/
- public final Person person;
+ public final Contact contact;
@FXML
private HBox cardPane;
@@ -35,24 +35,21 @@ public class PersonCard extends UiPart {
@FXML
private Label phone;
@FXML
- private Label address;
- @FXML
private Label email;
@FXML
private FlowPane tags;
/**
- * Creates a {@code PersonCode} with the given {@code Person} and index to display.
+ * Creates a {@code ContactCode} with the given {@code Contact} and index to display.
*/
- public PersonCard(Person person, int displayedIndex) {
+ public ContactCard(Contact contact, int displayedIndex) {
super(FXML);
- this.person = person;
+ this.contact = contact;
id.setText(displayedIndex + ". ");
- name.setText(person.getName().fullName);
- phone.setText(person.getPhone().value);
- address.setText(person.getAddress().value);
- email.setText(person.getEmail().value);
- person.getTags().stream()
+ name.setText(contact.getName().fullName);
+ phone.setText(contact.getPhone().value);
+ email.setText(contact.getEmail().value);
+ contact.getTags().stream()
.sorted(Comparator.comparing(tag -> tag.tagName))
.forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
}
@@ -65,13 +62,13 @@ public boolean equals(Object other) {
}
// instanceof handles nulls
- if (!(other instanceof PersonCard)) {
+ if (!(other instanceof ContactCard)) {
return false;
}
// state check
- PersonCard card = (PersonCard) other;
+ ContactCard card = (ContactCard) other;
return id.getText().equals(card.id.getText())
- && person.equals(card.person);
+ && contact.equals(card.contact);
}
}
diff --git a/src/main/java/seedu/ta/ui/ContactListPanel.java b/src/main/java/seedu/ta/ui/ContactListPanel.java
new file mode 100644
index 00000000000..222780dc8af
--- /dev/null
+++ b/src/main/java/seedu/ta/ui/ContactListPanel.java
@@ -0,0 +1,49 @@
+package seedu.ta.ui;
+
+import java.util.logging.Logger;
+
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.layout.Region;
+import seedu.ta.commons.core.LogsCenter;
+import seedu.ta.model.contact.Contact;
+
+/**
+ * Panel containing the list of contacts.
+ */
+public class ContactListPanel extends UiPart {
+ private static final String FXML = "ContactListPanel.fxml";
+ private final Logger logger = LogsCenter.getLogger(ContactListPanel.class);
+
+ @FXML
+ private ListView contactListView;
+
+ /**
+ * Creates a {@code ContactListPanel} with the given {@code ObservableList}.
+ */
+ public ContactListPanel(ObservableList