diff --git a/.gitignore b/.gitignore
index 71c9194e8bd..884a338610a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,6 @@ src/test/data/sandbox/
# MacOS custom attributes files created by Finder
.DS_Store
docs/_site/
+
+# /bin folder
+/bin/
diff --git a/README.md b/README.md
index 13f5c77403f..30ae062ae1b 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,70 @@
-[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions)
-
-![Ui](docs/images/Ui.png)
-
-* This is **a sample project for Software Engineering (SE) students**.
- Example usages:
- * as a starting point of a course project (as opposed to writing everything from scratch)
- * as a case study
-* The project simulates an ongoing software project for a desktop application (called _AddressBook_) used for managing contact details.
- * It is **written in OOP fashion**. It provides a **reasonably well-written** code base **bigger** (around 6 KLoC) than what students usually write in beginner-level SE modules, without being overwhelmingly big.
- * It comes with a **reasonable level of user and developer documentation**.
-* It is named `AddressBook Level 3` (`AB3` for short) because it was initially created as a part of a series of `AddressBook` projects (`Level 1`, `Level 2`, `Level 3` ...).
-* For the detailed documentation of this project, see the **[Address Book Product Website](https://se-education.org/addressbook-level3)**.
-* This project is a **part of the se-education.org** initiative. If you would like to contribute code to this project, see [se-education.org](https://se-education.org#https://se-education.org/#contributing) for more info.
+[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/AY2223S2-CS2103T-T14-3/tp/actions)
+[![codecov](https://codecov.io/gh/AY2223S2-CS2103T-T14-3/tp/branch/master/graph/badge.svg)](https://codecov.io/gh/AY2223S2-CS2103T-T14-3/tp)
+
+![Logo](docs/images/internbuddy-logo.png)
+## About InternBuddy
+InternBuddy is a desktop application for Computing undergraduates to manage their internship applications.
+It is optimized for typing where it allows you to complete internship management tasks much more efficiently
+via the keyboard as compared to using traditional Graphical User Interface (GUI) applications.
+If you are a fast typist who is seeking a one-stop platform to systematically organise your internship
+applications, then InternBuddy is the perfect buddy to accompany you during your internship hunt.
+
+InternBuddy runs using Java 11, and is available on the Windows, macOS and Linux operating systems.
+
+
+## Core Features
+1. List all internships
+2. Add an internship
+3. Edit an internship
+4. View an internship
+5. Copy an internship to clipboard
+6. Find internships
+7. Get upcoming events and deadlines
+8. Delete internships by indices
+9. Delete internships by fields
+10. Clear all internships
+11. Get help
+12. Exit
+13. Navigating through past commands
+
+In InternBuddy, internship data is auto-saved whenever changes are made.
+
+## Getting Started
+1. Ensure you have Java 11 or above installed in your computer. Otherwise, you can download it
+ [here](https://www.oracle.com/java/technologies/downloads/#java11).
+2. Download the latest release of InternBuddy [here](https://github.com/AY2223S2-CS2103T-T14-3/tp/releases).
+3. Copy the file `internbuddy.jar` to the folder that you want to use as the home folder for InternBuddy.
+4. Double-click on the file internbuddy.jar to launch InternBuddy. A GUI similar to the diagram below should appear in
+ a few seconds. Note how the app contains some sample data.
+
+ ![Ui](docs/images/Ui.png)
+
+5. You can interact with InternBuddy by typing into the box with the text `Enter command here...`, then pressing `Enter`
+to execute your command. For example, typing `help` and pressing Enter will open the help window.
+6. Enjoy tracking your internships with InternBuddy!
+
+
+## Additional Information
+
+- If you are a user who is interested in learning more about what InternBuddy offers, do visit the
+[InternBuddy User Guide](https://ay2223s2-cs2103t-t14-3.github.io/tp/UserGuide.html).
+
+- Alternatively, if you are a developer who is curious about the implementation of InternBuddy, check
+out the [InternBuddy Developer Guide](https://ay2223s2-cs2103t-t14-3.github.io/tp/DeveloperGuide.html).
+
+
+## Acknowledgements
+
+* InternBuddy is written in **Java 11**.
+* It is adapted from the [AddressBook Level 3](https://github.com/se-edu/addressbook-level3) project created by
+ the [SE-EDU initiative](https://se-education.org).
+* Libraries and frameworks used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson),
+ [JUnit5](https://github.com/junit-team/junit5) and [TestFX](https://github.com/TestFX/TestFX).
+* GUI testing is implemented with references from [AddressBook Level 4](https://github.com/se-edu/addressbook-level4)
+ and [Please Hire Us](https://github.com/AY2223S1-CS2103T-W17-4/tp). We utilised code from these projects to set
+ up GUI testing and added our own test cases to test the UI components that we created.
+* The feature of Navigating Through Past Commands is primarily adapted from [HackNet](https://github.com/AY2122S2-CS2103T-W13-3/tp),
+ but we added code modifications and test cases.
+* The sections on explaining the formatting standards and GUI interface in the User and Developer Guides are
+ inspired by [Please Hire Us](https://github.com/AY2223S1-CS2103T-W17-4/tp).
+
diff --git a/build.gradle b/build.gradle
index 108397716bd..d77a1f038e2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,3 +1,5 @@
+import org.gradle.api.tasks.testing.logging.TestLogEvent
+
plugins {
id 'java'
id 'checkstyle'
@@ -6,7 +8,8 @@ plugins {
id 'jacoco'
}
-mainClassName = 'seedu.address.Main'
+
+mainClassName = 'seedu.internship.Main'
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
@@ -20,6 +23,10 @@ checkstyle {
toolVersion = '10.2'
}
+run {
+ enableAssertions = true
+}
+
test {
useJUnitPlatform()
finalizedBy jacocoTestReport
@@ -43,6 +50,7 @@ task coverage(type: JacocoReport) {
dependencies {
String jUnitVersion = '5.4.0'
String javaFxVersion = '11'
+ String testFxVersion = '4.0.15-alpha'
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win'
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac'
@@ -60,13 +68,81 @@ dependencies {
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.7.0'
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.7.4'
- testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: jUnitVersion
+ testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: jUnitVersion
testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: jUnitVersion
+
+ //@@author eugenetangkj-reused
+ //Reused from //Reused from https://github.com/se-edu/addressbook-level4/blob/master/build.gradle where it taught
+ //me how to include the dependencies for TestFx
+ testImplementation group: 'org.testfx', name: 'testfx-core', version: testFxVersion
+ testRuntimeOnly group: 'org.testfx', name: 'openjfx-monocle', version: 'jdk-12.0.1+2'
}
shadowJar {
- archiveFileName = 'addressbook.jar'
+ archiveFileName = 'internbuddy.jar'
+}
+
+//@@author eugenetangkj-reused
+//Reused from //Reused from https://github.com/se-edu/addressbook-level4/blob/master/build.gradle
+
+task(guiTests)
+task(nonGuiTests)
+
+// Run `test` task if `guiTests` or `nonGuiTests` is specified
+guiTests.dependsOn test
+nonGuiTests.dependsOn test
+
+task(allTests)
+
+// `allTests` implies both `guiTests` and `nonGuiTests`
+allTests.dependsOn guiTests
+allTests.dependsOn nonGuiTests
+
+test {
+ systemProperty 'testfx.setup.timeout', '60000'
+
+ testLogging {
+ events TestLogEvent.FAILED, TestLogEvent.SKIPPED
+
+ // Prints the currently running test's name in the CI's build log,
+ // so that we can check if tests are being silently skipped or
+ // stalling the build.
+ if (System.env.'CI') {
+ events << TestLogEvent.STARTED
+ }
+ }
+
+ jacoco {
+ destinationFile = new File("${buildDir}/jacoco/test.exec")
+ }
+
+ doFirst {
+ boolean runGuiTests = gradle.taskGraph.hasTask(guiTests)
+ boolean runNonGuiTests = gradle.taskGraph.hasTask(nonGuiTests)
+
+ if (!runGuiTests && !runNonGuiTests) {
+ runGuiTests = true
+ runNonGuiTests = true
+ }
+
+ if (runNonGuiTests) {
+ test.include 'seedu/internship/**'
+ }
+
+ if (runGuiTests) {
+ test.include 'systemtests/**'
+ test.include 'seedu/internship/ui/**'
+ }
+
+ if (!runGuiTests) {
+ test.exclude 'seedu/internship/ui/**'
+ }
+ }
+}
+
+tasks.withType(JavaExec) {
+ enableAssertions = true
}
defaultTasks 'clean', 'test'
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 1c9514e966a..bf4c712f597 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -2,58 +2,59 @@
layout: page
title: About Us
---
-
-We are a team based in the [School of Computing, National University of Singapore](http://www.comp.nus.edu.sg).
+# About InternBuddy
+We are team InternBuddy, and we are a team based in the [School of Computing, National University of Singapore](http://www.comp.nus.edu.sg).
You can reach us at the email `seer[at]comp.nus.edu.sg`
-## Project team
+## Project Team
-### John Doe
+### Christopher Tan Rui Yang
-
+
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/potty10)]
+[[portfolio](team/potty10.md)]
-* Role: Project Advisor
+* Role: Team Lead
+* Responsibilities: Testing
-### Jane Doe
+### Eugene Tang KangJie
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/eugenetangkj)]
+[[portfolio](team/eugenetangkj.md)]
-* Role: Team Lead
-* Responsibilities: UI
+* Role: Developer
+* Responsibilities: UI, Documentation
-### Johnny Doe
+### Koh Kai Xun
-
+
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](http://github.com/kohkaixun)]
+[[portfolio](team/kohkaixun.md)]
* Role: Developer
-* Responsibilities: Data
+* Responsibilities: Code Quality
-### Jean Doe
+### Lim Hai Leong Shawn
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/seadragon2000341)]
+[[portfolio](team/seadragon2000341.md)]
* Role: Developer
-* Responsibilities: Dev Ops + Threading
+* Responsibilities: Scheduling and Tracking, Deliverables and Deadlines
-### James Doe
+### Ou Chuhao
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/DerrickSaltFish)]
+[[portfolio](team/derricksaltfish.md)]
* Role: Developer
-* Responsibilities: UI
+* Responsibilities: Integration
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 46eae8ee565..f556bceb232 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -2,41 +2,140 @@
layout: page
title: Developer Guide
---
+## **Table of Contents**
* Table of Contents
{:toc}
---------------------------------------------------------------------------------------------------------------------
+
-## **Acknowledgements**
+## **Introducing InternBuddy**
-* {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+InternBuddy is a desktop application for [Computing undergraduates](#glossary) to manage their internship applications.
+It is optimized for typing where it allows you to complete internship management tasks much more efficiently
+via the keyboard as compared to using traditional [Graphical User Interface](#glossary) (GUI) applications.
+If you are a fast typist who is seeking a one-stop platform to systematically organise your internship applications,
+then InternBuddy is the perfect buddy to accompany you during your internship hunt.
---------------------------------------------------------------------------------------------------------------------
-## **Setting up, getting started**
+InternBuddy runs using Java 11, and is available on the Windows, macOS and Linux operating systems.
-Refer to the guide [_Setting up and getting started_](SettingUp.md).
+
+
+
+
---------------------------------------------------------------------------------------------------------------------
+
-## **Design**
+[//]: # (@@author eugenetangkj - reused with modifications)
+[//]: # (Adapted from https://ay2223s1-cs2103t-w17-4.github.io/tp/UserGuide.html#navigating-the-user-guide)
+
+
+## **About the Developer Guide**
+
+### Objectives of the Developer Guide
+This developer guide aims to provide developers with insights into the implementation of InternBuddy and to explain the
+design considerations behind its features. It utilises Unified Modeling Language (UML) diagrams created using
+[PlantUML](https://plantuml.com/) for a visual explanation of the implementation.
+
+Apart from shedding light on InternBuddy's internal details, this developer guide also provides
+information on how to conduct feature testing and showcases the user study component that we went through
+in the initial development phase for requirements gathering.
+
+Hopefully, this developer guide will enable you to easily set up the InternBuddy project and extend its
+functionality if you are interested in doing so.
+
+
+### Using the Developer Guide
+This developer guide uses a set of formatting standards and syntax to better communicate
+information.
+
+**Information Box**
-:bulb: **Tip:** The `.puml` files used to create diagrams in this document can be found in the [diagrams](https://github.com/se-edu/addressbook-level3/tree/master/docs/diagrams/) folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams.
+:information_source: **Info:** Provides useful information that supplements the main text
+
+
+**Tip Box**
+
+
+:bulb: **Tip:** Suggestions on how to enhance your experience
+
+
+**Warning Box**
+
+
+:warning: **Warning:** Warns of a dangerous action that you should be aware of and to consider
+carefully before committing
+
+
+**Syntax Highlighting**
+
+[Commands](#glossary), [fields](#glossary), file paths and class names are highlighted.
+
+`command`, `FIELD`, `filepath.json`, `ClassName`
+
+
+**Keyboard Actions**
+
+Keyboard keys are indicated using rounded buttons.
+
+
+
+
+
+## **Setting Up and Getting Started**
+
+Refer to the guide [_Setting up and getting started_](SettingUp.md) for instructions on how to
+set up the InternBuddy project in your personal computer. After launching InternBuddy, you would see a GUI.
+Figure 1 illustrates the main parts
+of InternBuddy's GUI and Table 1 explains their functions. We will be referencing
+these different parts throughout this developer guide.
+
+[//]: # (@@author eugenetangkj - reused with modifications)
+[//]: # (Adapted from https://ay2223s1-cs2103t-w17-4.github.io/tp/UserGuide.html#navigating-the-user-guide)
+
+
+
+
+
+
Figure 1: InternBuddy's GUI
+
+
+| Part | Usage |
+|----------------|----------------------------------------------------------------------------------------------|
+| Command Box | You can type in your commands here to interact with InternBuddy. |
+| Result Display | This is where the results of your command will be displayed. |
+| List Panel | Displays a list of internship entries. |
+| View Panel | Displays either the welcome message or detailed information of a specified internship entry. |
+| Status Bar | States where your InternBuddy data file is located on your computer. |
+
+
Table 1: Explanation of the different parts of InternBuddy's GUI
+
+
+
+
+## **Design**
+
+
+
+:bulb: **Tip:** The `.puml` files used to create diagrams in this developer guide can be found in the [diagrams](https://github.com/AY2223S2-CS2103T-T14-3/tp/tree/master/docs/diagrams) folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit these diagrams.
### Architecture
+The ***Architecture Diagram*** shown in Figure 2 explains the high-level design of the App.
+
+
+
-
+
Figure 2: InternBuddy's architecture diagram
-The ***Architecture Diagram*** given above explains the high-level design of the App.
-Given below is a quick overview of main components and how they interact with each other.
+Given below is a quick overview of the main components and how they interact with each other.
**Main components of the architecture**
-**`Main`** has two classes called [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java). It is responsible for,
+**`Main`** has two classes called [`Main`](https://github.com/AY2223S2-CS2103T-T14-3/tp/blob/master/src/main/java/seedu/internship/Main.java) and [`MainApp`](https://github.com/AY2223S2-CS2103T-T14-3/tp/blob/master/src/main/java/seedu/internship/MainApp.java). It is responsible for,
* At app launch: Initializes the components in the correct sequence, and connects them up with each other.
* At shut down: Shuts down the components and invokes cleanup methods where necessary.
@@ -44,7 +143,7 @@ Given below is a quick overview of main components and how they interact with ea
The rest of the App consists of four components.
-* [**`UI`**](#ui-component): The UI of the App.
+* [**`UI`**](#ui-component): The UI (User Interface) of the App.
* [**`Logic`**](#logic-component): The command executor.
* [**`Model`**](#model-component): Holds the data of the App in memory.
* [**`Storage`**](#storage-component): Reads data from, and writes data to, the hard disk.
@@ -52,196 +151,573 @@ The rest of the App consists of four components.
**How the architecture components interact with each other**
-The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues the command `delete 1`.
+Figure 3 is a *Sequence Diagram* that shows how the components interact with each other for the scenario where the user
+issues the command `delete-index 1`.
+
-
+
+
+
-Each of the four main components (also shown in the diagram above),
+
Figure 3: Sequence diagram that shows interactions between components
+
+
+
+
+Each of the four main components (also shown in the Figure 3),
* defines its *API* in an `interface` with the same name as the Component.
* implements its functionality using a concrete `{Component Name}Manager` class (which follows the corresponding API `interface` mentioned in the previous point.
-For example, the `Logic` component defines its API in the `Logic.java` interface and implements its functionality using the `LogicManager.java` class which follows the `Logic` interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
+For example, the `Logic` component defines its API in the `Logic.java` interface and implements its
+functionality using the `LogicManager.java` class which follows the `Logic` interface. Other components
+interact with a given component through its interface rather than the concrete class
+(reason: to prevent outside component's being coupled to the implementation of a component),
+as illustrated in the (partial) class diagram shown in Figure 4.
+
+
+
+
+
+
+
Figure 4: Partial class diagram for the logic, model and storage components
+
-
The sections below give more details of each component.
-### UI component
+
+
+### UI Component
-The **API** of this component is specified in [`Ui.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/Ui.java)
+The **API** of this component is specified in
+[`Ui.java`](https://github.com/AY2223S2-CS2103T-T14-3/tp/blob/master/src/main/java/seedu/internship/ui/Ui.java).
+The class diagram for the UI component is shown in Figure 5.
-![Structure of the UI Component](images/UiClassDiagram.png)
+
+
+
-The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI.
+
Figure 5: Class diagram for the UI component
+
-The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml)
+The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`,
+`InternshipListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`,
+inherit from the abstract `UiPart` class which captures the commonalities between classes that
+represent parts of the visible GUI.
+
+The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching
+`.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the
+[`MainWindow`](https://github.com/AY2223S2-CS2103T-T14-3/tp/blob/master/src/main/java/seedu/internship/ui/MainWindow.java)
+is specified in [`MainWindow.fxml`](https://github.com/AY2223S2-CS2103T-T14-3/tp/blob/master/src/main/resources/view/MainWindow.fxml)
The `UI` component,
* executes user commands using the `Logic` component.
* listens for changes to `Model` data so that the UI can be updated with the modified data.
* keeps a reference to the `Logic` component, because the `UI` relies on the `Logic` to execute commands.
-* depends on some classes in the `Model` component, as it displays `Person` object residing in the `Model`.
+* depends on some classes in the `Model` component, as it displays `Internship` object residing in the `Model`.
+
+
-### Logic component
+### Logic Component
-**API** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java)
+**API** : [`Logic.java`](https://github.com/AY2223S2-CS2103T-T14-3/tp/blob/master/src/main/java/seedu/internship/logic/Logic.java)
+
+Figure 6 illustrates a (partial) class diagram of the `Logic` component:
+
+
+
+
+
+
Figure 6: Partial class diagram for the logic component
+
-Here's a (partial) class diagram of the `Logic` component:
-
How the `Logic` component works:
-1. When `Logic` is called upon to execute a command, it uses the `AddressBookParser` class to parse the user command.
-1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `AddCommand`) which is executed by the `LogicManager`.
-1. The command can communicate with the `Model` when it is executed (e.g. to add a person).
-1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`.
+1. When `Logic` is called upon to execute a command, it uses the `InternBuddyParser` class to parse the user command.
+2. This results in a `Command` object (more precisely, an object of one of its subclasses such as `AddCommand`) which is executed by the `LogicManager`.
+3. The command can communicate with the `Model` when it is executed (e.g. to add an internship).
+4. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`.
+
+
+Figure 7 below illustrates the interactions within the `Logic` component for the `execute("delete-index 1 2")` API call.
+
+![Interactions Inside the Logic Component for the `delete-index 1 2` Command](images/DeleteIndexSequenceDiagram.png)
+
+
+
Figure 7: Sequence diagram for the delete-index command
+
-The Sequence Diagram below illustrates the interactions within the `Logic` component for the `execute("delete 1")` API call.
-![Interactions Inside the Logic Component for the `delete 1` Command](images/DeleteSequenceDiagram.png)
-
:information_source: **Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+
+
+
:information_source: **Info:** The lifeline for
+`DeleteIndexCommandParser` and `DeleteIndexCommand` should end at the destroy marker (X) but due to a
+limitation of PlantUML, the lifeline reaches the end of diagram.
-Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command:
-
+
+Figure 8 shows the other classes in `Logic` (omitted from Figure 6) that are used for parsing a user command:
+
+
+
+
+
+
Figure 8: Class diagram for parser classes in the logic component
+
How the parsing works:
-* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object.
-* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing.
+* When called upon to parse a user command, the `InternBuddyParser` class creates an `XYZCommandParser`
+(`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes
+shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the
+`InternBuddyParser` returns back as a `Command` object.
+* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `FindCommandParser`, ...) inherit from
+the `Parser` interface so that they can be treated similarly where possible e.g, during testing.
+
+
+
+### Model Component
+**API** : [`Model.java`](https://github.com/AY2223S2-CS2103T-T14-3/tp/blob/master/src/main/java/seedu/internship/model/Model.java)
-### Model component
-**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java)
+Figure 9 is a class diagram for the `Model` component.
-
+
+
+
+
Figure 9: Class diagram for the model component
+
The `Model` component,
-* stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object).
-* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.
+* stores the internsip data i.e., all `Internship` objects (which are contained in a `UniqueInternshipList` object).
+* stores the currently 'selected' `Internship` objects (e.g., results of a search query) as a separate _filtered_ list
+which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed'
+(e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.).
* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects.
* does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components)
-
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
+
-
+
:information_source: **Info:** An alternative (arguably, a more OOP)
+model is shown in Figure 10. It has a `Tag` list in the `InternBuddy`, which `Internship` references. This allows `InternBuddy`
+to only require one `Tag` object per unique tag, instead of each `Internship` needing their own `Tag` objects.
+
+
+
-### Storage component
+
Figure 10: Alternative model that is more OOP
+
-**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java)
-
+
+
+### Storage Component
+
+**API** : [`Storage.java`](https://github.com/AY2223S2-CS2103T-T14-3/tp/blob/master/src/main/java/seedu/internship/storage/Storage.java)
+
+
+Figure 11 is a class diagram for the `Storage` component.
+
+
+
+
+
Figure 11: Class diagram for the storage component
+
+
The `Storage` component,
-* can save both address book data and user preference data in json format, and read them back into corresponding objects.
-* inherits from both `AddressBookStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed).
+* can save both internship data and user preference data in json format, and read them back into corresponding objects.
+* inherits from both `InternBuddyStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed).
* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`)
-### Common classes
+### Common Classes
-Classes used by multiple components are in the `seedu.addressbook.commons` package.
+Classes used by multiple components are in the [`seedu.internship.commons`](https://github.com/AY2223S2-CS2103T-T14-3/tp/tree/master/src/main/java/seedu/internship/commons) package.
---------------------------------------------------------------------------------------------------------------------
+
## **Implementation**
This section describes some noteworthy details on how certain features are implemented.
-### \[Proposed\] Undo/redo feature
+
:information_source: **Info:** Due to a limitation of PlantUML, the lifeline
+for objects in sequence diagrams would always reach the end of the diagrams. However, it is worthy to note that objects
+with destroy markers (X) would have been destroyed at the markers.
-#### Proposed Implementation
+
-The proposed undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo history, stored internally as an `addressBookStateList` and `currentStatePointer`. Additionally, it implements the following operations:
+[//]: # (@@author eugenetangkj)
+### Add an Internship - `add`
-* `VersionedAddressBook#commit()` — Saves the current address book state in its history.
-* `VersionedAddressBook#undo()` — Restores the previous address book state from its history.
-* `VersionedAddressBook#redo()` — Restores a previously undone address book state from its history.
+#### Implementation
-These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively.
+Figure 12 shows how the `add` command works.
-Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
+![AddSequenceDiagram](images/AddSequenceDiagram.png)
-Step 1. The user launches the application for the first time. The `VersionedAddressBook` will be initialized with the initial address book state, and the `currentStatePointer` pointing to that single address book state.
+
Figure 12: Sequence diagram for the add command
+
-![UndoRedoState0](images/UndoRedoState0.png)
-Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book state.
-![UndoRedoState1](images/UndoRedoState1.png)
+The following gives a more detailed explanation of the `add` command.
-Step 3. The user executes `add n/David …` to add a new person. The `add` command also calls `Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`.
-![UndoRedoState2](images/UndoRedoState2.png)
+1. When the user enters an `add` command, the `AddCommandParser` parses the user's input.
+2. It checks for the following:
+ - `n/` followed by the company's name [Compulsory]
+ - `r/` followed by the role applied [Compulsory]
+ - `s/` followed by the status of the internship application [Compulsory]
+ - `d/` followed by the date associated with the entry [Compulsory]
+ - `c/` followed by the comment for the entry [Optional]
+ - `t/` followed by tags for the entry [Optional]
+3. If any of the compulsory fields is missing or any of the fields entered by the user
+ does not meet the field requirements, a `ParseException` will be thrown.
+4. An `Internship` will be created from the parsed user's input if Step 3 passes.
+5. A check is done to see if the `Model` component, which stores all the `Internship` entries,
+ contains the `Internship` created in Step 4.
+6. If a duplicate `Internship` is found, a `CommandException` will be thrown.
+7. Else if there is no duplicate `Internship`, the `Internship` created will be added into
+ the `Model` component.
+8. The currently selected `Internship` in the `Model` component will be updated to become
+ this new `Internship` such that the [View Panel](#setting-up-and-getting-started) displays the information for
+ this new `Internship`.
-
: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`.
+
-
+#### Design Considerations
-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.
+- Whether to make all fields in the `add` command compulsory
-![UndoRedoState3](images/UndoRedoState3.png)
+1. **Alternative 1 (chosen): Make only essential fields compulsory**
+ * Pros: More user-centric as not all users want to enter the optional information,
+ which is not exactly critical in tracking internships.
+ * Cons: More work needs to be done in code implementation. For example, the absence of optional
+ fields should not cause a `ParseException`, and there is a need to include a
+ default value of `NA` for input without any `Comment`.
-
: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.
+2. **Alternative 2: Make all fields compulsory**
+ * Pros: Easier to implement as there is no need to differentiate between compulsory
+ and optional fields during command parsing, and it is easier to compare between
+ different `Internship` since we just require an exact match of all fields.
+ * Cons: Less user-centric where users who do not want to include `Comment` and `Tag`
+ are forced to input something for the `Add` command to work.
-
+
-The following sequence diagram shows how the undo operation works:
+- Whether to update the [View Panel](#setting-up-and-getting-started) according to the `add` command
-![UndoSequenceDiagram](images/UndoSequenceDiagram.png)
+1. **Alternative 1 (chosen): Update the [View Panel](#setting-up-and-getting-started) whenever a new** `Internship` **is added**
+ * Pros: Better visual indication that the `add` command has been successfully executed.
+ If the user has a lot of `Internship` entries, when a new `Internship` is added,
+ the new entry will be placed at the bottom of the [List Panel](#setting-up-and-getting-started),
+ which is not visible if the user's scroll position is at the top of the
+ [List Panel](#setting-up-and-getting-started). Therefore, updating
+ the [View Panel](#setting-up-and-getting-started) enhances visual indication to the user
+ that the `Internship` has been successfully added.
+ * Cons: An additional line of code is required in the `execute` method of `AddCommand`
+ to update the selected `Internship` in the `Model` component in order to update
+ the [View Panel](#setting-up-and-getting-started).
-
: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.
+2. **Alternative 2: Do not update the [View Panel](#setting-up-and-getting-started) when a new** `Internship` **is added**
+ * Pros: No additional code is required in the `execute` method of `AddCommand`.
+ * Cons: When the user has a lot of `Internship` entries, the added entry in the
+ [List Panel](#setting-up-and-getting-started) may not be visible since it is added to the bottom.
+ Without scrolling, users have to rely on the [Result Display](#setting-up-and-getting-started) to
+ determine if the `AddCommand` is successful.
-
-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.
-
: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.
+
-
+[//]: # (@@author seadragon2000341)
+### Edit an Internship - `edit`
+
+#### Implementation
+
+
+Figure 13 shows how the `edit` command works.
+
+![EditSequenceDiagram](images/EditSequenceDiagram.png)
+
Figure 13: Sequence diagram for the edit command
+
+
+
+The following gives a more detailed explanation of the `edit` command.
+
+1. When the user enters an `edit` command, the `EditCommandParser` parses the user's input.
+2. If the internship index specified is invalid, a `ParseException` will be thrown and the specified `Internship` will not be edited.
+3. If the company name, role, status, date, tag or comment fields are missing (at least one must be present) or invalid, a `ParseException` will be thrown and the specified `Internship` will not be edited.
+4. After the successful parsing of user input into `EditCommandParser`, the `EditCommand` object is created with a new updated `Internship` object (to maintain immutability).
+5. Following which, `EditCommand#execute(Model model)` method is called which eventually calls the `Model#setInternship(Internship toEdit, Internship edited)` method, replacing the old `Internship` object with the newly updated one.
+
+
+
+#### Design considerations
+
+- How `edit` executes
+
+1. **Alternative 1 (chosen): Edit command will create a new** `Internship` **to replace the existing** `Internship` **object.**
+ * Pros:
+ * Maintains immutability of `Internship` class.
+ * Cons:
+ * May be less efficient than Alternative 2.
+
+2. **Alternative 2: Edit command will directly edit the** `Internship` **by modifying its attributes**.
+ * Pros:
+ * Will use less memory (no new `Internship` object will be created).
+ * Saves time since there is no need to create the new object.
+ * Cons:
+ * Reduces the defensiveness of the code and the class.
+
+
+
+[//]: # (@@author eugenetangkj)
+### View an Internship - `view`
+
+#### Implementation
+Figure 14 shows how the `view` command works.
+
+![ViewSequenceDiagram](images/ViewSequenceDiagram.png)
+
+
Figure 14: Sequence diagram for the view command
+
+
+The following gives a more detailed explanation of the `view` command.
+
+
+1. When the user enters a `view` command, the `ViewCommandParser` parses the user's input.
+2. It checks for the following:
+ - The `INDEX` entered by the user must be able to be converted into a numeric index.
+3. If the user entered a value of `INDEX` that cannot be converted, a `ParseException` will
+ be thrown.
+4. An `Index` will be created from the user's input if Step 2 passes.
+5. A check is done to see if the `Index` created in Step 4 is a valid index given the number
+ of `Internship` entries in the filtered `Internship` list of the `Model` component.
+6. If the `Index` is invalid, a `CommandException` will be thrown.
+7. Else if the `Index` is valid, the `Internship` which belongs to that `Index` will be
+ retrieved by accessing the filtered `Internship` list.
+8. The currently selected `Internship` in the `Model` component will be updated to become
+ the `Internship` obtained from Step 7 such that the [View Panel](#setting-up-and-getting-started) displays the
+ information for this selected `Internship`.
+
+
+#### Design Considerations
+
+- Whether to separate the checking of valid user input into 2 classes
+
+1. **Alternative 1: Allow** `ViewCommand` **to handle the checking of whether user input can be
+ parsed into an index, and whether it is a valid index**
+ * Pros: No need for a separate `ViewCommandParser` class and any problems with checking of
+ user input can be isolated to the `ViewCommand` class.
+ * Cons: Breaks the abstraction where parsing of user input should be done by a `Parser`
+ class instead of a `Command` class.
+
+2. **Alternative 2 (chosen): Allow** `ViewCommandParser` **to handle checking of whether user input
+ can be parsed into an index, and `ViewCommand` to handle checking of whether it
+ is a valid index**
+ * Pros: Maintains the abstraction between the `Parser` and `Command` classes. Also, it
+ makes it more maintainable for future extensions in the event that further checks
+ to the user input are required.
+ * Cons: Have to maintain code in 2 separate classes and in the event that there
+ is an issue in processing user input for the `ViewCommand`, there is a need to
+ identify and isolate which of the 2 checks does the problem originate from.
+
+
+
+[//]: # (@@author DerrickSaltFish)
+### Copy an Internship to Clipboard - `copy`
+#### Implementation
+Figure 15 shows how the `copy` command works.
+
+![CopySequenceDiagram](images/CopySequenceDiagram.png)
+
+
Figure 15: Sequence diagram for the copy command
+
+
+
+The following gives a more detailed explanation of the `copy` command.
+
+1. When the user enters a `copy` command, the `CopyCommandParser` parses the user's input.
+2. It checks for the following:
+ - The `INDEX` entered by the user must be able to be converted into a numeric index.
+3. If the user entered a value of `INDEX` that cannot be converted, a `ParseException` will
+ be thrown.
+4. An `Index` will be created from the user's input if Step 2 passes.
+5. A check is done to see if the `Index` created in Step 4 is a valid index given the number
+ of `Internship` entries in the filtered `Internship` list of the `Model` component.
+6. If the `Index` is invalid, a `CommandException` will be thrown.
+7. Else if the `Index` is valid, the `Internship` which belongs to that `Index` will be
+ retrieved by accessing the filtered `Internship` list.
+8. Following which, `CopyCommand#execute(Model model)` method is called which eventually calls the `Model#copyInternship(Internship target)` method. This copies the `toString()` representation of the `Internship` object onto the clipboard.
+
+#### Design Considerations
+
+- How to run the clipboard operation
+
+1. **Alternative 1: Run the clipboard code directly.**
+ * Will work if the testing framework is already running on the event dispatch thread (such as JUnit Swing or FEST-Swing). However, this is
+ not the case for this project.
+
+2. **Alternative 2: (chosen): Use the** `SwingUtilities.invokeLater()` **method to wrap the clipboard code in a Runnable object**
+ * Ensures that the clipboard operation is safe to run from a test or a non-GUI context.
+
+
+
+
+[//]: # (@@author kohkaixun)
+### Find Internships - `find`
+#### Implementation
+
+Figure 16 shows how the `find` command works.
+
+![FindSequenceDiagram](images/FindSequenceDiagram.png)
+
+
Figure 16: Sequence diagram for the find command
+
+
+
+
+
+The following gives a more detailed explanation of the `find` command.
+
+1. If the name, role, status, date and tag fields are all missing or one of their values are invalid, a `ParseException` will be thrown and the `FindCommand` will not be executed.
+2. After the successful parsing of user input into `FindCommandParser`, an `InternshipContainsKeywordPredicate` object, containing the lists of keywords specified in the user input, is created, which in turn is used to create a `FindCommand` object.
+3. Following which, the `FindCommand#execute(Model model)` method is called which eventually calls the `updateFilteredInternshipList(Predicate predicate)` method with the `InternshipContainsKeywordPredicate` object, previously created by `FindCommandParser`, as its argument and updates the `FilteredList` stored inside the `Model`.
+
+
+
+#### Design Considerations
+
+- How `find` command uses user input
-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.
+1. **Alternative 1 (chosen): Find an internship by exact match of user input and the** `Internship` **object's corresponding attributes.**
+ * Pros:
+ * Instructions on how to use the find command will be clear and easily communicated to user.
+ * Cons:
+ * Restrictive for the user (e.g. An internship with the company name `Google Ltd` will not turn up for the command `find n/Google`).
-![UndoRedoState4](images/UndoRedoState4.png)
+2. **Alternative 2: Find an internship by match of user input and the substrings in the** `Internship` **object's attributes**.
+ * Pros:
+ * Command is much more flexible (e.g. An internship with the company name `Google` will turn up for the find command `find n/goo`).
+ * Cons:
+ * May be confusing for the user (e.g. The user assumes that the `find` command works for matching substrings of individual words. He inputs `find n/goo inc` for an `Internship` with company name `Google Incorporated`).
-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.
+3. **Alternative 3: Find an internship by match of any word of user input and any word of the** `Internship` **object's corresponding attributes.**
+ * Pros:
+ * Command is much more flexible.
+ * Cons:
+ * Command becomes too flexible (e.g. A `find` command like `find n/google ltd` will return `Internship` objects that have either the word `google` or `ltd` in their company names. Internships with company names such as `Apple ltd` and `Meta Ltd` will be returned.
-![UndoRedoState5](images/UndoRedoState5.png)
-The following activity diagram summarizes what happens when a user executes a new command:
-
+
-#### Design considerations:
+[//]: # (@@author seadragon2000341)
+### Get Upcoming Events and Deadlines - `upcoming`
-**Aspect: How undo & redo executes:**
+#### Implementation
+Figure 17 shows how the `upcoming` command works.
-* **Alternative 1 (current choice):** Saves the entire address book.
- * Pros: Easy to implement.
- * Cons: May have performance issues in terms of memory usage.
+![UpcomingSequenceDiagram](images/UpcomingSequenceDiagram.png)
+
Figure 17: Sequence diagram for the upcoming command
+
-* **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.
+The following gives a more detailed explanation of the `upcoming` command.
+1. When the user enters an `upcoming` command, an `UpcomingCommand` object is created.
+2. Following which, `FilteredList` stored inside the model will be updated by checking each internship entry against a predicate.
+3. The predicate checks whether both of the following conditions are met:
+- The `STATUS` of the internship must be one of the following:
+ - `NEW`
+ - `ASSESSMENT`
+ - `INTERVIEW`
+ - `OFFERED`
+- The `DATE` must be within the upcoming week.
-_{more aspects and alternatives to be added}_
+
-### \[Proposed\] Data archiving
+#### Design Considerations
-_{Explain here how the data archiving feature will be implemented}_
+- Whether to include all possible statuses of an internship
+1. **Alternative 1 (chosen): The predicate for the** `upcoming` **command should be limited to internships that have the status** `NEW/ASSESSMENT/INTERVIEW/OFFERED`.
+ * Pros: Makes more practical sense as these statuses have dates that are tied to an event or deadline:
+ * `NEW` - Deadline of Application
+ * `ASSESSMENT` - Date of Assessment
+ * `INTERVIEW` - Date of Interview
+ * `Offered` - Deadline of Offer Acceptance
+ * Cons: If the instructions for using the command are not clearly explained in the user guide, users may have difficulty understanding the output that is generated.
+
+2. **Alternative 2: Internships with any status would be accepted, even with statuses that are not tied to an upcoming event or deadline.**
+ * Pros: May be more intuitive for users to understand.
+ * Cons: This may cause users to forget the intended use case of the command, leading to confusion or misuse.
---------------------------------------------------------------------------------------------------------------------
+
-## **Documentation, logging, testing, configuration, dev-ops**
+[//]: # (@@author potty10)
+### Delete Internship Entries by Fields - `delete-field`
+#### Implementation
+Figure 18 shows how the `delete-field` command works.
+
+![DeleteFieldSequenceDiagram](images/DeleteFieldSequenceDiagram.png)
+
Figure 18: Sequence diagram for the delete-field command
+
+
+The following gives a more detailed explanation of the `delete-field` command.
+
+1. When the user enters a `delete-field` command, the `DeleteFieldCommandParser` parses the user's input. It attempts to parse the arguments as a set of prefixed
+fields (`[n/COMPANY_NAME] [r/ROLE] [s/STATUS] [d/DATE] [t/TAG]`).
+2. A new `InternshipContainsKeywordPredicate` object is created. A `DeleteFieldCommand` object is then created.
+3. When the `DeleteFieldCommand` object executes, a list of `Internship` objects is obtained with `model.getFilteredInternshipList()`.
+4. For each `Internship` object in the list that matches with **at least one** value for
+ **every** field type that is specified, it will be deleted using `model.deleteInternship(internshipToDelete)`
+
+
+
+#### Design Considerations
+
+- **Whether to use an AND relationship or an OR relationship between different fields**
+ * For example, should `delete-field n\Google r\Software Engineer` delete internships that have company name of Google AND role as Software Engineer, or delete internships that have company name of Google OR role of Software Engineer?
+
+1. **Alternative 1 (chosen): Use an AND relationship**
+ * Pros: More user-centric as users will be able to have more fine-grained control over what internships they want to delete. For example, they may want to delete all internship entries related to a certain company AND role.
+ * Cons: If users want to delete internships based on an OR relationships, they need to call `delete-field` multiple times.
+
+2. **Alternative 2: Use an OR relationship**
+ * Pros: Much easier for the user to reason about which internships will be deleted.
+ * Cons: Less fine-grained control over `delete`. For example, there is no way to delete internships that have company name of Google AND role of Software Engineer
+
+
+
+- **Whether to add this enhancement to the** `clear` **or** `delete` **command, or to create a new command entirely**
+
+1. **Alternative 1 (chosen):** Split the `delete` command into `delete-index` and `delete-field`. `delete-index` will delete only indices, while `delete-field` will only delete by fields.
+ * Pros: Both commands now share the same prefix `delete`, so it is easier to remember.
+ * Cons: Delete now has 2 formats, and this may be a source of confusion.
+2. **Alternative 2: Enhance the** `delete` **command only. For example,** `delete 1 2 n/Google` **will delete any of the first 2 entries if they have a company name of** `Google`.
+ * Pros: Combining all delete features into one command makes it easier to remember.
+ * Cons:
+ * Very difficult to justify usage. It is unlikely for a user to require such absolute fine-grained control. A more likely use case is to mass delete internships that are no longer required.
+ * Difficult to define a suitable interpretation of the fields. For example, in the command `delete 1 2 n/Google`,
+ the command should delete internships with (Index 1 OR 2) AND have a company name `Google`. Maintaining both AND and OR relationships can be confusing for the user.
+
+3. **Alternative 3: Enhance the** `clear` **command**.
+ * Pros: The current `clear` command takes in no arguments, so it is much easier to implement.
+ * Cons: May be confusing to the user, since there will be no clear distinction between `delete` and `clear`.
+
+
+
+
+
+## **Documentation, Logging, Testing, Configuration, Dev-ops**
* [Documentation guide](Documentation.md)
* [Testing guide](Testing.md)
@@ -249,129 +725,1022 @@ _{Explain here how the data archiving feature will be implemented}_
* [Configuration guide](Configuration.md)
* [DevOps guide](DevOps.md)
---------------------------------------------------------------------------------------------------------------------
-## **Appendix: Requirements**
+
+
+## **Appendix A: Requirements**
-### Product scope
+### Product Scope
-**Target user profile**:
+**Target user profile:**
+[Computing Undergraduates](#glossary)
-* 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
+**Characteristics of user profile:**
+* Has a need to manage many internship applications
-**Value proposition**: manage contacts faster than a typical mouse/GUI driven app
+Internships form an integral part of the undergraduate curriculum for Computing Undergraduates.
+In a technical field like Computing, it is especially important for undergraduates to practice what they have learnt in classrooms.
+However, given the tight competition in the market, many undergraduates source for numerous internship opportunities
+before being accepted for one. Therefore, many Computing undergraduates face the need to track many applications
+where each could be in a different phase of the application process.
+* Prefers typing to mouse interactions, with good typing speed
+
+Computing undergraduates have great exposure to computer usage where coding assignments and projects in school require
+extensive typing. This justifies a sufficiently good level of proficiency with regard to typing. In fact, with the
+existence of keyboard shortcuts, many programmers prefer typing over using the mouse because of the efficiency gains.
+
+
+* Reasonably comfortable in using [Command Line Interface](#glossary) (CLI) apps
+
+CLI provides a simple way to interact with computers to run programs and manage files.
+Computing undergraduates are taught how to use the CLI in their curriculums, and are often required to use it
+to run system tasks that cannot be done over the GUI. Hence, this would imply a reasonable level of comfort in using
+the CLI interface.
+
+
+* Prefers desktop applications over other types
+
+**Value proposition**:
+
+InternBuddy aims to provide a 1-stop platform for a computing undergraduate to view and
+manage his internship applications. Consolidating internship information, the application provides organisational
+capabilities for easy tracking and follow-ups while eliminating the need to handle data across multiple platforms.
+
+
+
+### User Stories
+Table 2 documents the user stories for InternBuddy.
-### User stories
Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
-| 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 |
-*{More to be added}*
+| Priority | As a … | I want to … | So that I can… |
+|----------|------------------------------------------------------------------------------------------|------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------|
+| `* * *` | Computing undergraduate with many internship applications | list out all the entries | browse through my list of applications. |
+| `* * *` | Computing undergraduate applying for many internships | add a new entry | manage new applications using InternBuddy. |
+| `* * *` | Computing undergraduate managing many concurrent internship applications | add a status to each entry | track the status of each application. |
+| `* * *` | Computing undergraduate who is planning to track internship applications in the long run | delete entries | remove outdated or irrelevant entries from InternBuddy. |
+| `* * *` | Computing undergraduate who is planning to track internship applications in the long run | store data | resume from where I left off in my previous run of InternBuddy. |
+| `* * *` | Computing undergraduate who is a new user of InternBuddy | view the list of supported commands | refer to it when I am unsure about the usage of InternBuddy. |
+| `* *` | meticulous Computing undergraduate | be notified that InternBuddy is exiting | be rest assured that InternBuddy has successfully terminated when I exit it. |
+| `* *` | careless Computing undergraduate | modify the details of an entry | correct my typos without having to create a new entry from scratch. |
+| `* *` | careless Computing undergraduate | be prompted with a confirmation message before I delete an entry | avoid accidental deletes. |
+| `* *` | forgetful Computing undergraduate | rely on auto-saving of data | avoid the problem of forgetting to save my entries when I make changes to them. |
+| `* *` | Computing undergraduate applying for technical roles | tag each entry with its associated [tech stack](#glossary) | identify the technical requirements associated with each application. |
+| `* *` | Computing undergraduate applying for technical roles | filter internship entries by tags | narrow down the search to internship applications with the tech stack that I would like to work on. |
+| `* *` | Computing undergraduate managing many concurrent internship applications | filter internship entries by date | identify the upcoming tasks or deadlines. |
+| `* *` | Computing undergraduate with many internship applications | search an entry by name | easily and swiftly locate the desired entry. |
+| `* *` | Computing undergraduate who is not extremely proficient with the command line interface | have intuitive and simple-to-pick-up commands | use InternBuddy without much technical difficulties. |
+| `* *` | detail-oriented Computing undergraduate | add custom remarks to each entry | have the flexibility of documenting miscellaneous but relevant information. |
+| `* *` | Computing undergraduate managing many concurrent internship applications | obtain reminders | avoid forgetting about upcoming tasks or deadlines. |
+| `* *` | Computing undergraduate using multiple devices | export my internship data into a file | view the same data when I am not using the device with InternBuddy installed. |
+| `* *` | Computing undergraduate who wants to share my internship details with others | copy the details of an internship | send the details to other people. |
+| `*` | Computing undergraduate who is slow in learning | go through a step-by-step in-app tutorial | learn how to use InternBuddy in a guided and self-paced environment. |
+| `*` | analytical Computing undergraduate | have a summary overview of all the entries | analyse the composition of the entries, such as what percentage of applications were successful. |
+| `*` | Computing undergraduate who is new to internships | receive tips | use the tips to improve my experience during the internship application process. |
+| `*` | Computing undergraduate who is planning to track internship applications in the long run | archive old entries | delete them from InternBuddy while maintaining a backup copy of the outdated data. |
+| `*` | Computing undergraduate who is experienced in using InternBuddy | have shortcuts to existing commands | carry out tasks in InternBuddy even more efficiently than previously. |
+
+
Table 2: List of user stories
+
+
+
+### Use Cases
-### Use cases
+(For all use cases below, the **System** is `InternBuddy` and the **Actor** is the `user`, unless specified otherwise)
-(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
+**Use case: List all internships**
-**Use case: Delete a person**
+**Main Success Scenario**
-**MSS**
+1. User requests for the list of all internship applications in InternBuddy.
+2. InternBuddy displays a list of all the internship entries.
-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
+ Use case ends.
+
+
+
+**Use case: Add an internship**
+
+**Main Success Scenario**
+
+1. User enters internship entry.
+2. InternBuddy adds an internship entry, updates the View Panel, and displays a success message.
Use case ends.
**Extensions**
-* 2a. The list is empty.
+* 1a. InternBuddy detects that one or more compulsory fields are missing.
+ * 1a1. InternBuddy prompts the user for an `add` command of the correct format.
- Use case ends.
+ Use case resumes from Step 1.
-* 3a. The given index is invalid.
+* 1b. InternBuddy detects one or more fields are invalid.
+ * 1b1. InternBuddy prompts the user for an `add` command of the correct format.
- * 3a1. AddressBook shows an error message.
+ Use case resumes from Step 1.
- Use case resumes at step 2.
+
-*{More to be added}*
+**Use Case: Edit an internship**
-### Non-Functional Requirements
+**Main Success Story**
+
+1. User edits an internship entry.
+2. InternBuddy updates that particular internship entry, updates the View Panel, and displays a success message.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. InternBuddy detects that no fields are provided.
+ * 1a1. InternBuddy prompts the user for an `edit` command of the correct format.
+
+ Use case resumes from Step 1.
+
+* 1b. InternBuddy detects one or more fields are invalid.
+ * 1b1. InternBuddy prompts the user for an `edit` command of the correct format.
+
+ Use case resumes from Step 1.
+
+
+
+**Use Case: View an internship**
+
+**Main Success Scenario**
+
+1. User views an internship entry.
+2. InternBuddy updates the View Panel with the details of the internship that is being viewed,
+ and displays a success message.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. InternBuddy detects that the required internship index is missing.
+ * 1a1. InternBuddy prompts the user for an `view` command of the correct format.
+
+ Use case resumes from Step 1.
+
+* 1b. InternBuddy detects that the internship index entered is invalid.
+ * 1b1. InternBuddy prompts the user for a `view` command of the correct format.
+
+ Use case resumes from Step 1.
+
+* 1c. InternBuddy detects that the index is out of range.
+ * 1c1. InternBuddy informs the user that the index is out of range.
+
+ Use case resumes from Step 1.
+
+
+
+**Use Case: Copy an internship to clipboard**
+
+**Main Success Scenario**
+
+1. User copies an internship entry to clipboard.
+2. InternBuddy displays a success message.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. InternBuddy detects that the required internship index is missing.
+ * 1a1. InternBuddy prompts the user for a `copy` command of the correct format.
+
+ Use case resumes from Step 1.
+
+* 1b. InternBuddy detects that the internship index entered is invalid.
+ * 1b1. InternBuddy prompts the user for a `view` command of the correct format.
+
+ Use case resumes from Step 1.
+
+* 1c. InternBuddy detects that the index is out of range.
+ * 1c1. InternBuddy informs the user that the index is out of range.
+
+ Use case resumes from Step 1.
+
+
+
+
+
+**Use Case: Find internships**
+
+**Main Success Scenario**
+
+1. User finds internship entries based on the fields given.
+2. InternBuddy lists the internships that match the given fields and displays a success message indicating
+ how many internships were found.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. InternBuddy detects that no fields are provided.
+ * 1a1. InternBuddy prompts the user for a `find` command of the correct format.
+
+ Use case resumes from Step 1.
+
+* 1b. InternBuddy detects that one or more fields given are invalid.
+ * 1b1. InternBuddy prompts the user for a `find` command of the correct format.
+
+ Use case resumes from Step 1.
+
+
+
+
+**Use Case: Get internships with upcoming events or deadlines**
+
+**Main Success Scenario**
+
+1. User requests for internship entries with upcoming events or deadlines.
+2. InternBuddy displays a list of internship entries with events or deadlines within the week.
+
+ Use case ends.
+
+
+
+**Use Case: Delete internships by indices**
+
+**Main Success Scenario**
+
+1. User deletes internship entries based on specified indices.
+2. InternBuddy displays a success message that indicates how many internships were deleted.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. InternBuddy detects that no index is given.
+ * 1a1. InternBuddy prompts the user for a `delete-index` command of the correct format.
+
+ Use case resumes from Step 1.
+
+* 1b. InternBuddy detects that one or more fields given are invalid.
+ * 1b1. InternBuddy prompts the user for a `delete-index` command of the correct format.
+
+ Use case resumes from Step 1.
+
+* 1c. InternBuddy detects that one or more of the given indices are out of range.
+ * 1c1. InternBuddy informs the user that the index is out of range.
+
+ Use case resumes from Step 1.
+
+* 2a. InternBuddy detects that the internship whose details are currently displayed in the
+ [View Panel](#setting-up-and-getting-started) has been deleted by this `delete-index` command.
+ * 2a1. InternBuddy resets the [View Panel](#setting-up-and-getting-started) to display the
+ welcome message.
+
+ Use case resumes from Step 2.
+
+
+
+
+
+**Use Case: Delete internships by fields**
+
+**Main Success Scenario**
+
+1. User deletes internship entries based on specified fields.
+2. InternBuddy displays a success message that indicates how many internships were deleted.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. InternBuddy detects that no field is given.
+ * 1a1. InternBuddy prompts the user for a `delete-field` command of the correct format.
+
+ Use case resumes from Step 1.
+
+* 1b. InternBuddy detects that one or more fields given are invalid.
+ * 1b1. InternBuddy prompts the user for a `delete-field` command of the correct format.
-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.
+ Use case resumes from Step 1.
-*{More to be added}*
+* 2a. InternBuddy detects that the internship whose details are currently displayed in the
+ [View Panel](#setting-up-and-getting-started) has been deleted by this `delete-field` command.
+ * 2a1. InternBuddy resets the [View Panel](#setting-up-and-getting-started) to display the
+ welcome message.
-### Glossary
+ Use case resumes from Step 2.
-* **Mainstream OS**: Windows, Linux, Unix, OS-X
-* **Private contact detail**: A contact detail that is not meant to be shared with others
+
---------------------------------------------------------------------------------------------------------------------
-## **Appendix: Instructions for manual testing**
+**Use Case: Clear all internships**
-Given below are instructions to test the app manually.
+**Main Success Scenario**
-
:information_source: **Note:** These instructions only provide a starting point for testers to work on;
-testers are expected to do more *exploratory* testing.
+1. User requests to clear all internship entries stored in InternBuddy.
+2. InternBuddy deletes all internship entries. It resets the [View Panel](#setting-up-and-getting-started) to display the welcome
+ message and shows a success message.
+
+ Use case ends.
+
+
+
+
+
+**Use Case: Get Help**
+
+**Main Success Scenario**
+
+1. User requests for help in using InternBuddy.
+2. InternBuddy opens up a new window that displays the list of commands supported by InternBuddy and provides
+ the link to InternBuddy's user guide.
+
+ Use case ends.
+
+
+
+
+**Use case: Exit InternBuddy**
+
+**Main Success Scenario**
+
+1. User requests to exit InternBuddy.
+2. InternBuddy closes.
+
+ Use case ends.
+
+
+### Non-Functional Requirements
+
+1. InternBuddy should work on any [mainstream operating systems](#glossary) as long as it has Java `11` or above installed.
+2. InternBuddy should be able to hold up to 500 internship entries without a noticeable sluggishness in performance for typical usage.
+3. InternBuddy should be able to respond to user input within 6 seconds.
+4. A Computing undergraduate 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.
+5. Computing undergraduates who have never used command line applications to track internships before should be able to easily pick up InternBuddy.
+6. InternBuddy is not required to handle concurrent users.
+7. InternBuddy is not required to make data available online.
+
+
+
+
+## **Appendix B: Instructions for Manual Testing**
+
+Given below are instructions and test cases to test InternBuddy manually.
+
+
:information_source: **Note:** These instructions only provide a starting point for testers to work on.
+Testers are expected to do more *exploratory* testing. Also, each test case is independent of the other test cases.
-### Launch and shutdown
+### Launch and Shutdown
+
+1. **Initial launch**
+
+ 1. Download the [InternBuddy jar file](https://github.com/AY2223S2-CS2103T-T14-3/tp/releases) and copy into an empty folder.
+
+ 2. Double-click the jar file.
+
+ **Expected**: Shows the GUI with a set of sample internships. The window size may not be optimal.
+
+
+2. **Saving window preferences**
+
+ 1. Resize the window to an optimum size. Move the window to a different location. Close the window.
+
+ 2. Re-launch the app by double-clicking the jar file.
+
+ **Expected**: The most recent window size and location are retained.
+
+### List all Internships
+
+1. `list`
+
+ **Expected**: All internship entries are listed out and displayed in the List Panel.
+
+
+2. `list hello`
+
+ **Expected**: All internship entries are listed out and displayed in the List Panel.
+
+
+3. `list edit 1 n/Apples`
+
+ **Expected**: All internship entries are listed out and displayed in the List Panel.
+
+### Add an Internship
+
+1. `add n/Visa r/Software Engineer s/New d/2023-03-01 c/Considering to apply t/Payment`
+
+ **Expected**: A new internship entry is successfully added. The new internship entry will have company name
+ `Visa`, role `Software Engineer`, status `New`, deadline of application `2023-03-01`, comment `Considering to apply`,
+ and tag `Payment`. The View Panel displays the information for this new internship entry, and a success
+ message is displayed in the Result Display.
+
+2. `add n/Mastercard r/Software Engineer s/New d/2023-03-01`
+
+ **Expected**: A new internship entry is successfully added. The new internship entry will have company name
+ `Mastercard`, role `Software Engineer`, status `New`, deadline of application `2023-03-01`. The View Panel displays the information for this new internship entry, where the comment is shown as `NA`. A success message
+ is displayed in the Result Display.
+
+3. `add n/Visa s/New d/2023-03-01`
+
+ **Expected**: No new internship is added. An error message is displayed in the Result Display.
+ This is because the compulsory field for role is missing.
+
+4. `add n/Visa r/Software Engineer s/Applying d/2023-03-01`
+
+ **Expected**: No new internship is added. An error message is displayed in the Result Display.
+ This is because `Applying` is not a valid value for the `STATUS` field.
+
+5. `add n/Visa r/Software Engineer s/Applied d/1st March 2023`
+
+ **Expected**: No new internship is added. An error message is displayed in the Result Display.
+ This is because the field for `DATE` must be in the format of `YYYY-MM-DD`.
+
+6. `add n/Visa r/Software Engineer s/Applied d/2023-02-32`
+
+ **Expected**: No new internship is added. An error message is displayed in the Result Display.
+ This is because `2023-02-32` is not a valid date (i.e. March does not have 32 days).
+
+7. `add n/Visa r/Software Engineer s/Applied d/2023-02-15 c/`
+
+ **Expected**: No new internship is added. An error message is displayed in the Result Display.
+ This is because the `COMMENT` field cannot be left blank.
+
+
+
+### Edit an Internship
+Assumptions: The sample data provided by InternBuddy is used, where there is a total of 7 internship entries.
+
+
+1. `edit 2 n/Amazon Technologies`
+
+ **Expected**: The company name of the second internship entry is updated to `Amazon Technologies`.
+ The View Panel displays the updated details of the second internship entry.
+
+2. `edit 2 n/Amazon Technologies s/Applied`
+
+ **Expected**: The company name and status of the second internship entry are updated to
+ `Amazon Technologies` and `Applied` respectively. The View Panel displays the updated details
+ of the second internship entry.
+
+3. `edit 2 t/front-end`
+
+ **Expected**: All previous tags for the second internship entry are removed, and a new tag
+ `front-end` is added. The View Panel displays the updated details of the second internship
+ entry.
+
+4. `edit 2 c/`
+
+ **Expected**: The comment of the second internship entry is updated to `NA`. The View Panel
+ displays the updated details of the second internship entry.
+
+5. Successful editing through the filtered internship list
+ 1. `find n/Apple n/Google`
+ 2. `edit 2 n/Google Technologies`
+
+ **Expected**: The company name of the internship entry whose original company name is `Google` is updated
+ to become `Google Technologies`. The View Panel displays the updated details for this internship entry.
+
+6. Unsuccessful editing through the filtered internship list
+ 1. `find n/Apple n/Google`
+ 2. `edit 3 n/Google Technologies`
+
+ **Expected**: An error message is displayed in the Result Display. This is because in the filtered
+ internship list, there are only 2 internship entries, implying that`3` is not a valid value for the
+ `INDEX` field.
+
+7. `edit 2 n/Amazon Technologies s/Applying`
+
+ **Expected**: No internship is edited. An error message is displayed in the Result Display.
+ This is because `Applying` is an invalid status.
+
+8. `edit`
+
+ **Expected**: An error message is displayed in the Result Display. This is because a minimum of 1
+ optional field must be specified.
+
+9. `edit -2 n/Amazon Technologies`
+
+ **Expected**: An error message is displayed in the Result Display. This is because the `INDEX`
+ field must be a positive integer greater than or equal to 1.
+
+10. `edit 12 n/Amazon Technologies`
+
+ **Expected**: An error message is displayed in the Result Display. This is because there are only
+ 7 internship entries in the sample data. Index 12 is out of range.
+
+
+
+### View an Internship
+Assumptions: The sample data provided by InternBuddy is used, where there is a total of 7 internship entries.
+1. `view 2`
+
+ **Expected**: The View Panel displays the details for the second internship entry.
+
+2. Successful viewing through the filtered internship list
+
+ 1. `find n/Apple n/Google`
+ 2. `view 2`
+
+ **Expected**: The View Panel displays the details for the second internship entry in the
+ filtered internship list. In this case, it displays the details for the entry whose company
+ name is `Google`.
+
+3. Unsuccessful viewing through the filtered internship list
+ 1. `find n/Apple n/Google`
+ 2. `view 3`
+
+ **Expected**: An error message is displayed in the Result Display. This is because in the filtered
+ internship list, there are only 2 internship entries, implying that `3` is not a valid value for the
+ `INDEX` field.
+
+4. `view -1`
+
+ **Expected**: An error message is displayed in the Result Display. This is because the `INDEX`
+ field must be a positive integer greater than or equal to 1.
+
+5. `view 1 2`
+
+ **Expected**: An error message is displayed in the Result Display. This is because the `view`
+ command does not support viewing of more than 1 internship entry simultaneously.
+
+6. `view 12`
+
+ **Expected**: An error message is displayed in the Result Display. This is because there are only
+ 7 internship entries in the sample data. Index 12 is out of range.
+
+7. `view`
+
+ **Expected**: An error message is displayed in the Result Display. This is because the compulsory
+ `INDEX` field is missing.
+
+
+
+### Copy an Internship to Clipboard
+Assumptions: The sample data provided by InternBuddy is used, where there is a total of 7 internship entries.
+1. `copy 2`
+
+ **Expected**: The details of the second internship entry are copied to the clipboard.
+
+2. Successful copying through the filtered internship list
+
+ 1. `find n/Apple n/Google`
+ 2. `copy 2`
+
+ **Expected**: The details of the second internship shown in the List Panel will be copied to the
+ clipboard. In this case, it copies the details for the entry whose company
+ name is `Google`.
+
+3. Unsuccessful copying through the filtered internship list
+ 1. `find n/Apple n/Google`
+ 2. `copy 3`
+
+ **Expected**: An error message is displayed in the Result Display. This is because in the filtered
+ internship list, there are only 2 internship entries, implying that `3` is not a valid value for the
+ `INDEX` field.
+
+4. `copy -1`
+
+ **Expected**: An error message is displayed in the Result Display. This is because the `INDEX`
+ field must be a positive integer greater than or equal to 1.
+
+5. `copy 1 2`
+
+ **Expected**: An error message is displayed in the Result Display. This is because the `copy`
+ command does not support copying of more than 1 internship entry simultaneously.
+
+6. `copy 12`
+
+ **Expected**: An error message is displayed in the Result Display. This is because there are only
+ 7 internship entries in the sample data. Index 12 is out of range.
+
+7. `copy`
+
+ **Expected**: An error message is displayed in the Result Display. This is because the compulsory
+ `INDEX` field is missing.
+
+
+
+### Find Internships
+Assumptions: The sample data provided by InternBuddy is used, where there is a total of 7 internship entries.
+1. `find n/Amazon`
+
+ **Expected**: The List Panel shows the internship entry whose company name matches with
+ `Amazon`. A success message is displayed in the Result Display.
+
+2. `find n/Amazon n/Google`
+
+ **Expected**: The List Panel shows the internship entries whose company name matches with
+ `Amazon` or `Google`. A success message is displayed in the Result Display.
+
+3. Finding through the filtered internship list
+ 1. `find n/Apple n/Google`
+ 2. `find n/Amazon`
+
+ **Expected**: The List Panel shows the internship entry whose company name matches with
+ `Amazon`. This means that for the `find` command, the search is always done in the **unfiltered list**
+ even if the List Panel was showing a filtered list.
+
+4. `find`
+
+ **Expected**: An error message is displayed in the Result Display. This is because a minimum of 1
+ optional field must be specified.
+
+5. `find s/Applied s/Interviewing`
+
+ **Expected**: An error message is displayed in the Result Display. This is because `Interviewing`
+ is not a valid value for the `STATUS` field.
-1. Initial launch
+6. `find n/Google n/Samsung s/Applied s/Assessment`
- 1. Download the jar file and copy into an empty folder
+ **Expected**: Only the internship entry with company name `Google` and status `Assessment` is
+ filtered out. This is because all other internship entries do not have a matching value with both
+ `CompanyName` and `Status`.
- 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
+7. `find s/Assessment s/Interview t/Golang`
-1. Saving window preferences
+ **Expected**: Only the internship entry with status `Assessment` and tag `Golang` is filtered out.
+ This is because all other internship entries do not have a matching value with both `Status` and
+ `Tag`.
- 1. Resize the window to an optimum size. Move the window to a different location. Close the window.
+
- 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained.
+### Get Upcoming Events and Deadlines
-1. _{ more test cases … }_
+1. `upcoming`
-### Deleting a person
+ **Expected**: All internship entries with events or deadlines in the upcoming week are
+ listed out and displayed in the List Panel.
-1. Deleting a person while all persons are being shown
- 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
+2. `upcoming hello`
- 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.
+ **Expected**: All internship entries with events or deadlines in the upcoming week are
+ listed out and displayed in the List Panel.
- 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.
- 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous.
+3. `upcoming edit 1 n/Apples`
-1. _{ more test cases … }_
+ **Expected**: All internship entries with events or deadlines in the upcoming week are
+ listed out and displayed in the List Panel.
-### Saving data
-1. Dealing with missing/corrupted data files
+### Delete Internships by Indices
+Prerequisites: List all internships using the `list` command. Multiple internships are present in the list.
- 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
+1. `delete-index 1`
+
+ **Expected**: The first internship entry in the List Panel is deleted. If the View Panel was displaying
+ the details of the deleted internship entry, it defaults to displaying the welcome message.
+
+2. `delete-index 1 2`
+
+ **Expected**: The first and second internship entry in the List Panel are deleted. If the View
+ Panel was displaying the details of either of the deleted internship entries, it defaults to displaying
+ the welcome message.
+
+3. `delete-index 3 1 3 3 1`
+
+ **Expected**: The first and third internship entries in the List Panel are deleted. If the View Panel was
+ displaying the details of either of the deleted internship entries, it defaults to displaying the
+ welcome message.
+
+4. `delete-index`
+
+ **Expected**: An error message is displayed in the Result Display. This is because a minimum of 1
+ index must be specified.
+
+
+### Delete Internships by Fields
+Assumptions: The sample data provided by InternBuddy is used, where there is a total of 7 internship entries.
+1. `delete-field n/Amazon`
+
+ **Expected**: The internship entry whose company name matches with `Amazon` is deleted.
+ A success message is displayed in the Result Display.
+
+2. `delete-field n/Amazon n/Google`
+
+ **Expected**: The internship entries whose company name is either `Amazon` or `Google` are deleted.
+ A success message is displayed in the Result Display.
+
+3. Deleting through the filtered internship list
+ 1. `find n/Apple n/Google`
+ 2. `delete-field n/Amazon`
+
+ **Expected**: No internship is deleted. This is because in the List Panel, there is no internship
+ with company name `Amazon`. This shows that `delete-field` searches through the **filtered list**.
+
+4. `delete-field`
+
+ **Expected**: An error message is displayed in the Result Display. This is because a minimum of 1
+ optional field must be specified.
+
+5. `delete-field s/Applied s/Interviewing`
+
+ **Expected**: An error message is displayed in the Result Display. This is because `Interviewing`
+ is not a valid value for the `STATUS` field.
+
+6. `delete-field n/Google n/Samsung s/Assessment s/Applied`
+
+ **Expected**: Only the internship with company name `Google` and status `Assessment` is deleted,
+ because all the other internships do not have a matching field for both `CompanyName` and `Status`.
+
+7. `delete-field s/Assessment s/Interview t/Android`
+
+ **Expected**: Only the internship with status `Interview` and tag `Android` is deleted, because
+ all the other internships do not have a matching field for both `Status` and `Tag`.
+
+
+
+### Clear all Internships
+
+1. `clear`
+
+ **Expected**: All internship entries are deleted. The View Panel displays the welcome message.
+
+
+2. `clear hello`
+
+ **Expected**: All internship entries are deleted. The View Panel displays the welcome message.
+
+
+3. `clear edit 1 n/Apples`
+
+ **Expected**: All internship entries are deleted. The View Panel displays the welcome message.
+
+
+### Get Help
+
+1. `help`
+
+ **Expected**: The help window opens.
+
+
+2. `help hello`
+
+ **Expected**: The help window opens.
+
+
+3. `help edit 1 n/Apples`
+
+ **Expected**: The help window opens.
+
+
+
+### Exit InternBuddy
+
+1. `exit`
+
+ **Expected**: InternBuddy closes.
+
+
+2. `exit hello`
+
+ **Expected**: InternBuddy closes.
+
+
+3. `exit edit 1 n/Apples`
+
+ **Expected**: InternBuddy closes.
+
+
+### Save Data
+
+1. Missing Data File
+
+ Prerequisite: There is no file called `internbuddy.json` in the `data` subfolder of the folder
+ where InternBuddy is located.
+
+ 1. If you have an existing `internbuddy.json` file, delete the file.
+ 2. Double-click InternBuddy's jar file.
+
+ **Expected**: InternBuddy launches with the sample internship data shown in the List Panel. There
+ is a total of 7 internship entries.
+
+2. Corrupted Data File
+
+ Prerequisite: There is a file called `internbuddy.json` in the `data` subfolder where InternBuddy is located.
+
+ 1. Ensure that InternBuddy is not running. If it is running, close it.
+ 2. Open the file `internbuddy.json`.
+ 3. In `internbuddy.json`, locate any line that contains the word `CompanyName`.
+ 4. Highlight the line located and delete the entire line.
+ 5. Save the `internbuddy.json` file and close it.
+ 6. Launch InternBuddy.
+
+ **Expected**: No entry is shown in the List Panel. InternBuddy starts afresh with 0 internship entry.
+
+
+
+## **Appendix C: Planned Enhancements**
+While we strive to make InternBuddy a perfect product for you, there are nevertheless areas of improvement.
+Hence, we are constantly striving to make InternBuddy better. This appendix documents some of the areas
+that our team is currently working on, and we would release them in the future once their functionalities
+have been finalised.
+
+### Make Prefixes Case-Insensitive
+#### Problem
+Prefixes are case-sensitive, hence command arguments such as `T/` will be interpreted as plain text. In InternBuddy, command prefixes are lowercase. For example, `add n/Visa r/Software Engineer s/New d/2023-03-01 t/javascript T/react` will add an internship entry with company name
+`Visa`, role `Software Engineer`, status `New`, deadline of application `2023-03-01`,
+and tag `javascript T/react` (refer to Figure 19).
+Therefore, it is possible to add substrings such as `T/`, `C/` or `R/` to any of the fields, even though the user could have intended to enter `t/`, `c/` or `r/`.
+
+
+
+
+
+
Figure 19: Adding the tag 'javascript T/react'
+
+
+
+We originally intended for this design to allow maximum flexibility for the user. If the user had entered something wrongly, it is possible to just use the command `edit`. However, this design could have an unintentional side-effect.
+
+To illustrate this side effect, we use an example of the `find` command. `find t/javascript t/react` tries to find entries with either the tag `javascript` or `react` (refer to Figure 20). Tag matching is case-insensitive, so it also tries to find `Javascript` or `React` (refer to Figure 21). Similarly, `delete-field t/javascript t/react` tries to delete entries with either the tag `javascript` or `react` or `Javascript` or `React`.
+
+
+
+
+
+
Figure 20: Find the tags "javascript" and "react"
+
+
+
+
+
+
Figure 21: Result of the find command in figure 20
+
+There could be another conflicting meaning of the command. In this case, instead of trying to find entries with either the tag `javascript` or `react`, the user could have intended to find the tag `javascript T/react`. This could lead to some confusion.
+
+#### Proposed Design Tweak
+Make prefixes for all commands with prefixes (`add`, `edit`, `find`, `delete-field`) case-insensitive. For example, `add n/Visa r/Software Engineer s/New d/2023-03-01 t/javascript t/react` should have the same result as `add n/Visa r/Software Engineer s/New d/2023-03-01 t/javascript T/react`, where `t/` and `T/` both refer to the tag field. The new internship entry will have company name `Visa`, role `Software Engineer`, status `New`, deadline of application `2023-03-01`, and the tags `javascript` and `react`. The View Panel displays the information for this new internship entry, and a success
+message is displayed in the Result Display. Do refer to Figures 22 and 23 for an illustrated example.
+
+
+
+
+
+
+
Figure 22: Adding a new entry with case-insensitive prefix
+
+
+
+
+
+
+
+
Figure 23: Result of the add command in figure 22
+
+
+A possible implementation is to change the `findPrefixPosition()` method in `seedu.internship.logic.parser.ArgumentTokenizer` as shown in Figure 24. Instead of finding the first exact match of the prefix, the method tries to find the first case-insensitive match of the prefix.
+
+
+
+
+
+
+
+
+
Figure 24: The parser checks for both lowercase prefix and uppercase prefix
+
+This would address the above problem. For example, `find t/javascript t/react` should have the same result as `find T/javascript T/react`. This would remove the confusion as substrings such as `T/` cannot be entered in any of the fields.
+
+
+
+
+
+### Inaccurate Error Message for Integer Overflow
+#### Problem
+There are currently 4 types of commands that require internship indices: `edit`, `view` `copy` and `delete-index`.
+However, the current implementation of the parsing of these indices does not take into account integer overflows, which is when the integer is too large or too small for InternBuddy to compute.
+
+When trying to parse these integers, it recognises that they are either too large or too small and treats them as not an integer.
+As a result, InternBuddy is unable to differentiate between internship index inputs that are not integers and are integer overflows.
+
+Thus, an invalid command format error message is displayed when these integer overflows are inputted (refer to Figure 25), instead of an index out of range error message when the integer is too large or an invalid index error message when the integer is too small.
+
+
+
+
+
+
Figure 25: Invalid command format error message is returned even though internship index is an integer
+
+
+
+#### Proposed Design Tweak
+We plan to display the invalid index and out of range index error messages even when there is a negative and positive integer overflow respectively.
+
+* When InternBuddy recognises an input as not an integer, we can check if the input begins with the negative sign and is followed by only digits or contains only digits (refer to Figure 26).
+ * If the latter is true, there is a negative integer overflow and InternBuddy can be configured to display an invalid index error message (refer to Figure 27).
+ * If the former is true, there is a positive integer overflow and InternBuddy can be configured to display an index out of range error message (refer to Figure 28).
+
+
+
+
+
+
Figure 26: Checking of input added when InternBuddy recognises that it isn't an integer
+
+
+
+
+
+
+
+
Figure 27: Invalid index error message displayed when there is negative integer overflow
+
+
+
+
+
+
+
+
Figure 28: Out of range index error message displayed when there is positive integer overflow
+
+
+
+
+
+## **Appendix D: Effort**
+InternBuddy is a brownfield project adapted from
+[AddressBook Level 3](https://github.com/se-edu/addressbook-level3). Our team morphed it from a contact
+management application to an internship tracker that is designed for Computing undergraduates. Development
+took place over 4 sprints which spanned a period of 2-3 months.
+
+### Difficulty Level
+For most of our team members, InternBuddy is the first brownfield project that we have undertaken. Dealing
+with a large code base is no simple feat. Therefore, our team went with a more conservative approach of
+focusing our efforts on refactoring and enhancing existing features to suit our product. This enabled us
+to create a functional product at the end of our sprints, with a lower likelihood of encountering bugs.
+
+### Challenges
+There are several challenges that we faced during the development phase.
+1. **Understanding and Refactoring the Code Base**
+
+ * [AddressBook Level 3](https://github.com/se-edu/addressbook-level3) is a project with around 6k lines of
+code. Much effort was required in understanding how the different components (e.g. `Model` and `Logic`)
+interact with one another. As our team decided to morph the project, we had to refactor a significant
+amount of code.
+ * For example, `Person` had to be refactored into `Internship`, and classes like `Phone`
+and `Email` were no longer relevant, and we had to transform them into classes like `Role` and `Status`.
+
+2. **Matching of Multiple Fields**
+ * The original `find` command in [AddressBook Level 3](https://github.com/se-edu/addressbook-level3)
+ does matching by only one field, `Name`.
+ * We wanted to extend the functionality of the `find` command to enable matching by multiple fields.
+ * There were many possible options on how to implement it, and we struggled to find an implementation
+ that is both simple-to-understand and intuitive to use.
+ * We eventually decided on using exact matching and a mix of both OR and AND relationships, as explained
+ in the implementation for the [`find`](#find-internships---find) command.
+3. **Responsive User Interface**
+ * It was challenging to set up the [View Panel](#setting-up-and-getting-started) to make it respond
+ to both the `view` command and the user interactions with the [List Panel](#setting-up-and-getting-started),
+ as programming the GUI is something new to many of us.
+ * Furthermore, we had to ensure that the text wraps smoothly when the interface is resized. In other
+ words, the wrapping width had to scale with screen size. It took us time to learn how to do it in code,
+ and how to adjust our JavaFX components accordingly.
+
+### Achievements
+Our team is proud to have successfully morphed the project from a contact management application
+to an internship tracker. InternBuddy offers a total of 13 different features.
+- 3 features that are unmodified from [AddressBook Level 3](https://github.com/se-edu/addressbook-level3) (`list`, `clear`, `exit`).
+- 6 features that are modified from [AddressBook Level 3](https://github.com/se-edu/addressbook-level3) (`add`, `edit`, `find`, `delete-index`, `delete-field`, `help`).
+- 1 feature that is adapted from [HackNet](https://github.com/AY2122S2-CS2103T-W13-3/tp) (Navigating through Past Commands).
+- 3 new features implemented by our team (`view`, `copy`, `upcoming`)
+
+In the area of testing, our team has managed to increase code coverage to [79.55%](https://app.codecov.io/gh/AY2223S2-CS2103T-T14-3/tp).
+This is made possible with GUI testing, where we received help from [AddressBook Level 4](https://github.com/se-edu/addressbook-level4)
+and [Please Hire Us](https://github.com/AY2223S1-CS2103T-W17-4/tp).
+
+
+
+## **Glossary**
+
+Table 3 provides the glossary for the terms used in this developer guide.
+
+| Term | Definition |
+|--------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Command | An instruction for InternBuddy to perform an action. |
+| Command Line Interface (CLI) | A CLI is the text-based interface that you can use to provide instructions to your computer. Examples of instructions include opening files and running programs. |
+| Computing undergraduate | A university undergraduate pursuing a Computing degree. |
+| Graphical User Interface (GUI) | A GUI is the visual interface that you see when an application launches, allowing you to interact with it by clicking on its various buttons and components. |
+| Mainstream Operating Systems | Include Windows, macOS, Linux and Unix. |
+| Field | A part of the command where you have to supply a value for the command to be valid. |
+| Prefix | A short form for the name of a field. It indicates which field does a value belongs to. For example, in `n/Apple`, the value `Apple` is supplied to the field `COMPANY_NAME` since the `n/` prefix is used. |
+| Tech Stack | A set of technologies that an individual or company uses to create and/or maintain a software system or product. |
+
+
Table 3: Glossary for Developer Guide
+
+
+
+## **Acknowledgements**
-1. _{ more test cases … }_
+* InternBuddy is written in **Java 11**.
+* It is adapted from the [AddressBook Level 3](https://github.com/se-edu/addressbook-level3) project created by
+ the [SE-EDU initiative](https://se-education.org).
+* Libraries and frameworks used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson),
+ [JUnit5](https://github.com/junit-team/junit5) and [TestFX](https://github.com/TestFX/TestFX).
+* GUI testing was implemented with references from [AddressBook Level 4](https://github.com/se-edu/addressbook-level4)
+ and [Please Hire Us](https://github.com/AY2223S1-CS2103T-W17-4/tp). We utilised code from these projects to set
+ up GUI testing, then added our own test cases to test the UI components that we created ourselves.
+* The feature of Navigating Through Past Commands was primarily adapted from [HackNet](https://github.com/AY2122S2-CS2103T-W13-3/tp),
+ but we added code modifications and test coverage.
+* The sections on explaining the formatting standards and GUI interface in the User and Developer Guides are
+ inspired by [Please Hire Us](https://github.com/AY2223S1-CS2103T-W17-4/tp).
diff --git a/docs/SettingUp.md b/docs/SettingUp.md
index 275445bd551..a016d944437 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.internship.Main` and try a few commands.
1. [Run the tests](Testing.md) to ensure they all pass.
--------------------------------------------------------------------------------------------------------------------
diff --git a/docs/Testing.md b/docs/Testing.md
index 8a99e82438a..a20d89462ab 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.internship.commons.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`
+ e.g. `seedu.internship.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.internship.logic.LogicManagerTest`
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index e7df68b01ea..004636c53ee 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -2,192 +2,932 @@
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.
-
+## **Table of Contents**
* Table of Contents
{:toc}
---------------------------------------------------------------------------------------------------------------------
+
+
+
+## **Introducing InternBuddy**
+
+InternBuddy is a desktop application for university undergraduates to manage their internship applications.
+It is optimized for typing where it allows you to complete internship management tasks much more efficiently via
+the keyboard as compared to using traditional [Graphical User Interface](#glossary) (GUI) applications. If you are a fast typist
+who is seeking a one-stop platform to systematically organise your internship applications,
+then InternBuddy is the perfect buddy to accompany you during your internship hunt.
+
+InternBuddy runs using Java 11 and is available on the Windows, macOS, and Linux operating systems.
+
+
+
+
+
+
+
+
+## **About the User Guide**
+
+### Objectives of the User Guide
+This user guide aims to provide comprehensive instructions for learning how to use InternBuddy,
+including details on the installation process and features. For more advanced users,
+this guide will also help customize your experience.
+
+[//]: # (@@author eugenetangkj - reused with modifications)
+[//]: # (Adapted from https://ay2223s1-cs2103t-w17-4.github.io/tp/UserGuide.html#navigating-the-user-guide)
+
+### Using the User Guide
+This uses guide uses a set of formatting standards and visuals to better communicate information.
+
+**Information Box**
+
+
+:information_source: **Info:** Provides useful information that supplements the main text
+
+
+**Tip Box**
+
+
+:bulb: **Tip:** Suggestions on how to enhance your experience
+
+
+**Warning Box**
+
+
+:warning: **Warning:** Warns of a dangerous action that you should be aware of and to consider
+carefully before committing
+
+
+**Syntax Highlighting**
+
+[Commands](#glossary), [fields](#glossary), file paths and class names are highlighted.
-## Quick start
+`command`, `FIELD`, `filepath.json`, `ClassName`
-1. Ensure you have Java `11` or above installed in your Computer.
-1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases).
+**Keyboard Actions**
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+Keyboard keys are indicated using rounded buttons.
-1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar addressbook.jar` command to run the application.
- A GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
- ![Ui](images/Ui.png)
+
-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.
- Some example commands you can try:
+
- * `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.
+## **Quick Start**
- * `delete 3` : Deletes the 3rd contact shown in the current list.
+1. Ensure you have Java `11` or above installed in your computer.
+
+
+ :information_source: **Info:** If you are unsure of whether you have Java 11 installed, or need help installing
+ it, you can refer to Appendix A.
+
- * `clear` : Deletes all contacts.
+2. Download the latest `internbuddy.jar` from [here](https://github.com/AY2223S2-CS2103T-T14-3/tp/releases).
+
+3. Copy the file `internbuddy.jar` to the folder you want to use as the _home folder_ for InternBuddy.
+
+
+ :information_source: **Info:** The home folder is the folder that you will navigate to when you want to launch
+ InternBuddy. It will contain a subfolder where your InternBuddy data will be stored.
+
+
+
+4. Double-click on the file `internbuddy.jar` to launch InternBuddy. A GUI similar to Figure 1 should
+ appear in a few seconds. Note how the app contains some sample data.
+
+
+
+
+
Figure 1: InternBuddy's GUI
+
+
+5. You can interact with InternBuddy by typing into the box with the text `Enter command here...`, then pressing
+ to execute your command. For example, typing `help` and pressing will open
+ the help window.
+
+
+6. Here are some other example commands you can try:
+
+ - `list`: Lists all internships stored in InternBuddy
+ - `add n/Food Panda r/Web Developer s/Applied d/2023-04-01`: Adds a new internship into InternBuddy.
+ - `delete-index 3` : Deletes the 3rd internship of the current list displayed in InternBuddy.
+ - `exit` : Exits InternBuddy.
+
+
+Do refer to [Features](#features) below for a comprehensive list of supported features and their associated details.
+
+
+
+[//]: # (@@author eugenetangkj - reused with modifications)
+[//]: # (Adapted from https://ay2223s1-cs2103t-w17-4.github.io/tp/UserGuide.html#navigating-the-user-guide)
+
+## **Exploring the Graphical User Interface**
+Figure 2 provides a visual representation of the different parts of InternBuddy's GUI, while
+Table 1 explains what each part is used for.
+
+
+
+
+
+
Figure 2: Different parts of InternBuddy's GUI
+
+
+| Part | Usage |
+|----------------|----------------------------------------------------------------------------------------------|
+| Command Box | You can type in your commands here to interact with InternBuddy. |
+| Result Display | This is where the results of your command will be displayed. |
+| List Panel | Displays a list of internship entries. |
+| View Panel | Displays either the welcome message or detailed information of a specified internship entry. |
+| Status Bar | States where your InternBuddy data file is located on your computer. |
+
+
Table 1: Explanation of the different parts of InternBuddy's GUI
+
+
+
+
+:bulb: **Tip:** The GUI is resizeable. You can resize it according to your preferences.
+
+
+
+
+
+:bulb: **Tip:** You can left-click on any of the entries displayed in the List Panel to view more information
+about an entry. Your selected entry will be highlighted blue. You can also use
+and to change your selected entry.
+
+
- * `exit` : Exits the app.
+
-1. Refer to the [Features](#features) below for details of each command.
+:information_source: **Info:** Commands in InternBuddy will not change your selected entry in the
+List Panel. To change your selected entry, you will have to manually change it either via
+left-clicking and/or using and
+
---------------------------------------------------------------------------------------------------------------------
+
-## Features
-
+## **Command Information**
-**:information_source: Notes about the command format:**
+[//]: # (@@author potty10)
+### Command Format
-* 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`.
+* Words in `UPPER_CASE` are the fields that are to be supplied by you.
+ e.g. If the command format is `add n/COMPANY_NAME`, you may input the command as `add n/Apple` where you supply the
+ value `Apple` to the field `COMPANY_NAME`.
* 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`.
+ e.g. If the command format is `edit INDEX [n/COMPANY_NAME] [c/COMMENT]`, you may input the command as `edit 2 n/Apple` where
+ you omit the value for the field `COMMENT`.
* 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.
+ e.g. `[t/TAG]…` can be used as ` ` (i.e. 0 times), `t/Java`, `t/Java t/Python` etc.
+
+* Fields can be in any order.
+ e.g. If the command format is `n/COMPANY_NAME r/ROLE`, both `n/Apple r/Software Engineer` and `r/Software Engineer n/Apple`
+ are acceptable.
+
+* If a field is expected only once in the command, but you specified it multiple times, only the last occurrence of
+ the field will be taken.
+ e.g. If the command format is `r/ROLE`, typing in `r/Front-end Developer r/Back-end Developer` will cause your
+ input to be interpreted as `r/Back-end Developer`.
+
+* Extraneous values for commands that do not take in fields (such as `help`, `list`, and `exit`) will be
+ ignored.
+ e.g. If the command format is `help`, typing in `help 123` will cause your input to be interpreted as `help`.
+
+* Command names are case-sensitive. For example, `help` will work, but `HELP` or `Help` will not.
+
+
+
+[//]: # (@@author eugenetangkj)
+### Prefixes and Constraints for Fields
+In InternBuddy's commands, we refer to a range of fields that you can replace with values to input information that
+is customised to your internship applications.
+
+There are 3 important things that you should note:
+1. Most fields have associated [**prefixes**](#glossary).
+ * Prefixes are short character combinations that you can use to identify the field to which a value belongs.
+ They are a convenient shorthand that allows you to refer a field without having to type out its
+ entire name, saving precious time.
+ * For example, in `add n/Apple`, the value `Apple` is associated with the
+ field `COMPANY_NAME` since the `n/` prefix is used.
+ * Prefixes are **case-sensitive**. `n/` will work but `N/` will not.
+
+2. When entering a command, do remember to use **spaces** to separate different fields of information. If you enter multiple fields without using space(s) to separate them, InternBuddy will interpret them as a single field.
+ * For example, `edit 1 n/Visa r/Software Engineer` associates `Visa` with the field `COMPANY_NAME` and `Software Engineer` with the field `ROLE`.
+ * Conversely, `edit 1 n/Visar/Software Engineer` associates `Visar/Software Engineer` with the field `COMPANY_NAME`.
+
+3. There are **constraints** that you must adhere to when replacing fields with values.
+ * Constraints differ based on the fields.
+ * If you do not adhere to these constraints and enter invalid values, an error message will be
+ displayed in the [Result Display](#exploring-the-graphical-user-interface) when you
+ press . The message will alert you to the invalid input and provide information
+ on how to correct the command.
+
+Table 2 provides a summary of the fields with their descriptions, prefixes and constraints.
+
+| Field | Description | Prefix | Constraints |
+|----------------|--------------------------------------------------------------------------------------------------------------------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `COMPANY_NAME` | The name of the company | `n/` | Cannot be blank and must be at most 50 characters. |
+| `ROLE` | The role that you applied for | `r/` | Cannot be blank and must be at most 50 characters. |
+| `STATUS` | The status of the internship application | `s/` | Must be one of the following: `New`, `Applied`, `Assessment`, `Interview`, `Offered`, `Accepted`, `Rejected`. Note that this is **not** case-sensitive. |
+| `DATE` | The date associated with the internship application | `d/` | Must be a valid date in the format of `YYYY-MM-DD`. |
+| `COMMENT` | A comment that you can make on an internship application | `c/` | Cannot be blank (except when used in the `edit` command). |
+| `TAG` | A label that you can give to an internship application | `t/` | Cannot be blank (except when used in the `edit` command) and must be at most 30 characters. |
+| `INDEX` | The index number of the internship entry as displayed in the [List Panel](#exploring-the-graphical-user-interface) | - | A positive integer that is smaller than or equal to the largest index number shown in the [List Panel](#exploring-the-graphical-user-interface). Note that 0 is not a positive integer. |
+
+
Table 2: Fields with their descriptions, prefixes and constraints
+
+### Details on `STATUS` and `DATE`
+The field `STATUS` represents the current status of an internship application. It can only take on one
+of the following values: `New`, `Applied`, `Assessment`, `Interview`, `Offered`, `Accepted` and `Rejected`.
+Note that this is **not case-sensitive**. Table 3 explains the meaning of each status.
+
+
+| `STATUS` | Description |
+|--------------|-----------------------------------------------------------------------------------------------------------------------------------|
+| `New` | You have recently saw this internship opportunity and would like to record it in InternBuddy. Also, you have yet to apply for it. |
+| `Applied` | You have applied for this internship opportunity and you are currently waiting for the company's response. |
+| `Assessment` | You are currently in the technical assessment stage of the application process. |
+| `Interview` | You are currently in the behavioral interview stage of the application process. |
+| `Offered` | You have been offered the internship opportunity. |
+| `Accepted` | You have accepted the internship opportunity. |
+| `Rejected` | You have either been rejected by the company, or that you have rejected the internship offer. |
+
+
Table 3: Description of statuses
+
+Depending on the status of the internship application, the `DATE` field will be interpreted differently. Table 4
+documents the meaning of `DATE` with respect to each `STATUS` value.
+
+| `STATUS` | Interpretation of `DATE` |
+|--------------|------------------------------|
+| `New` | Deadline of Application |
+| `Applied` | Date Applied |
+| `Assessment` | Date of Technical Assessment |
+| `Interview` | Date of Behavioral Interview |
+| `Offered` | Deadline of Offer Acceptance |
+| `Accepted` | Date of Acceptance |
+| `Rejected` | Date of Rejection |
+
+
Table 4: Description of dates
+
+[//]: # (@@author seadragon2000341)
+### Duplicate Internships
+InternBuddy does not allow for the storage of duplicate internships. Should you enter a command that attempts to store
+a duplicate internship, InternBuddy will remind you that the internship already exists.
+
+2 internships are considered to be duplicates if they have matching `COMPANY_NAME`, `STATUS`, `ROLE` **and**
+`DATE`. The comparison is **case-insensitive**.
+
+In Table 5, internships A and B are considered as duplicate internships, because they have the same
+`COMPANY_NAME`, `ROLE`, `STATUS` and `DATE`. Note how the capitalisation differences in `COMPANY_NAME`
+and `ROLE` do not affect the comparison.
-* 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.
-* 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.
+| `Field` | Internship A | Internship B |
+|----------------|-------------------|-------------------|
+| `COMPANY_NAME` | Google | google |
+| `ROLE` | Frontend Engineer | frontend engineer |
+| `STATUS` | New | New |
+| `DATE` | 2023-02-02 | 2023-02-02 |
+| `COMMENT` | NA | NA |
+| `TAGS` | C++ | Java |
-* 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`.
+
Table 5: Duplicate internships
+
+Meanwhile, in Table 6, internships C and D are not considered as duplicate
+internships, because they have different values for `COMPANY_NAME`.
+
+
+| `Field` | Internship C | Internship D |
+|----------------|-------------------|-------------------|
+| `COMPANY_NAME` | Apple | Apple Inc |
+| `ROLE` | Frontend Engineer | frontend engineer |
+| `STATUS` | New | New |
+| `DATE` | 2023-02-02 | 2023-02-02 |
+| `COMMENT` | NA | NA |
+| `TAGS` | Java | Java |
+
+
Table 6: Non-duplicate internships
+
+
+
+[//]: # (@@author potty10)
+### Duplicate Tags
+If you attempt to store duplicate tags within the same internship entry, InternBuddy would only store one of them. A duplicate tag refers to a tag that is identical to another tag in every way, including the spelling and capitalisation (tags are **case-sensitive**). In other words, a duplicate tag is a tag that is an exact copy of another tag.
+
+
+
+## **Features**
+InternBuddy offers a variety of features that can empower you to systematically track your internships.
+
+[//]: # (@@author eugenetangkj)
+### Listing all Internships : `list`
+Shows the list of all internship entries that you have stored in InternBuddy.
+
+
+
+:information_source: **Info:** `list` will always reset the
+[View Panel](#exploring-the-graphical-user-interface) to display the welcome message.
-### Viewing help : `help`
-Shows a message explaning how to access the help page.
+Format: `list`
-![help message](images/helpMessage.png)
+[//]: # (@@author eugenetangkj)
+### Adding an Internship : `add`
-Format: `help`
+Do you have a new internship to track? Add it to InternBuddy using the `add` command.
+Format: `add n/COMPANY_NAME r/ROLE s/STATUS d/DATE [c/COMMENT] [t/TAG]...`
-### Adding a person: `add`
+* The optional `COMMENT` field has a default value of `NA`. This means that if you do not specify any value for it,
+ the comment for the newly added internship will be `NA`.
+* The optional `TAG` field will be empty by default. This means that if you do not specify any value for it, there
+ will be no tags associated with the newly added internship.
-Adds a person to the address book.
+
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
+:information_source: **Info:** You will not be able to add [duplicate internships](#duplicate-internships) into InternBuddy (an error message will be shown). If you attempt to add [duplicate tags](#duplicate-tags) into the same internship entry, InternBuddy will only store one of the tags.
-
:bulb: **Tip:**
-A person can have any number of tags (including 0)
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`
+* `add n/Food Panda r/Web Developer s/New d/2023-02-01 c/I love Food Panda! t/React t/Front-end` Adds a new internship entry
+ with company name `Food Panda`, role `Web Developer`, status `New`, deadline of application `2023-02-01`,
+ comment `I love Food Panda!` and tags `React` and `Front-End`. This example is illustrated in Figure 3.
+* `add n/Deliveroo r/Software Engineer s/Assessment d/2023-02-01` Adds a new internship entry with
+ company name `Deliveroo`, role `Software Engineer`, status `Assessment` and date of technical assessment
+ `2023-02-01`.
+* `add n/Food Panda s/New d/2023-02-01` Displays an error because the `ROLE` field is missing.
+* `add n/Apple r/App Developer s/New d/2023-02-01 t/Java t/Java` Adds a new internship entry
+ with company name `Apple`, role `App Developer`, status `New`, deadline of application `2023-02-01`,
+ and tag `Java` (only one tag is stored since the two tags provided are duplicates).
-### Listing all persons : `list`
-Shows a list of all persons in the address book.
+![Add Command](images/ug-add-example.png)
+
Figure 3: Example of the add command in action
-Format: `list`
+
+
+[//]: # (@@author seadragon2000341)
+### Editing an Internship : `edit`
+
+Made a mistake, or wish to update your internship entry? The `edit` command allows you to make modifications.
-### Editing a person : `edit`
+Format: `edit INDEX [n/COMPANY_NAME] [r/ROLE] [s/STATUS] [d/DATE] [c/COMMENT] [t/TAG]...`
-Edits an existing person in the address book.
+* Edits the internship whose index number is `INDEX`.
+* You have to provide at least one of the optional fields.
+* You can reset the comment of an internship to the default value of `NA` by typing `c/` without specifying any comments
+ after it.
+* You can remove all of an internship’s tags by typing `t/` without specifying any other tags after it.
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [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, …
-* 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.
+:warning: **Warning:** When editing tags, the existing tags of the internship will be removed. For example, if the
+internship with index 1 currently has the tags `iOS` and `Swift`, editing the internship via `edit 1 t/macOS` will lead
+to the internship only having the tag `macOS`. To have all 3 tags, you need to type `edit 1 t/iOS t/Swift t/macOS`.
+
+
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.
-### Locating persons by name: `find`
+Suppose you have at least 2 internships displayed in the [List Panel](#exploring-the-graphical-user-interface).
+
+* `edit 2 s/Assessment r/Software Developer` Sets the status and role of the second internship entry as `Assessment` and
+ `Software Developer` respectively. This example is illustrated in Figure 4.
+* `edit 2` Displays an error because the command does not satisfy the criteria of having at least one optional field.
+* `edit 2 t/Java t/Go` Sets the tags of the second internship entry as Java and Go (existing tags will be removed).
+* `edit 2 c/` Sets the comment of the second internship entry to be `NA`.
+* `edit 2 t/` Removes all the tags of the second internship entry.
-Finds persons whose names contain any of the given keywords.
+![Edit Command](images/ug-edit-example.png)
+
Figure 4: Example of the edit command in action
-Format: `find KEYWORD [MORE_KEYWORDS]`
+
-* 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`
+
+
+[//]: # (@@author eugenetangkj)
+### Viewing an Internship : `view`
+Want to view the details of a specific internship entry? You can do so using the `view` command.
+
+Format: `view INDEX`
+* Views the details of the internship entry with index number `INDEX` as indicated in
+ the [List Panel](#exploring-the-graphical-user-interface).
+* The details will be shown in the [View Panel](#exploring-the-graphical-user-interface).
+* Apart from the internship details, a custom tips box is also included in the
+ [View Panel](#exploring-the-graphical-user-interface). The tips provide you with suggestions on how to improve your internship experience,
+ where their content change according to the status of the internship entry.
Examples:
-* `find John` returns `john` and `John Doe`
-* `find alex david` returns `Alex Yeoh`, `David Li`
- ![result for 'find alex david'](images/findAlexDavidResult.png)
+* `view 3` Assuming that you have at least 3 internships displayed in the
+[List Panel](#exploring-the-graphical-user-interface), this displays the details of the third internship in the
+[View Panel](#exploring-the-graphical-user-interface).
+* `view -1` Displays an error because `INDEX` must be a positive integer.
+* `view 8` Assuming that you have 7 internships displayed in the
+ [List Panel](#exploring-the-graphical-user-interface), this displays an error because `INDEX` cannot be greater
+ than the maximum index shown in the [List Panel](#exploring-the-graphical-user-interface), which is 7 in this case.
+
-### Deleting a person : `delete`
+
-Deletes the specified person from the address book.
+[//]: # (@@author DerrickSaltFish)
+### Copying an Internship to Clipboard : `copy`
+Need to quickly export the details of an internship? Use `copy` to copy the details of an internship to
+your clipboard.
-Format: `delete INDEX`
+Format: `copy INDEX`
-* 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, …
+* Copies the details of the internship entry with index number `INDEX` as indicated in
+ the [List Panel](#exploring-the-graphical-user-interface).
+* The copied text will be in the format of
+ `Company Name: COMPANY_NAME; Role: ROLE; Status: STATUS; Date: DATE; Comment: [COMMENT]; Tags: [TAG]`.
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.
+* Suppose the first internship displayed in the [List Panel](#exploring-the-graphical-user-interface)
+ has company name `Amazon`, role `Cloud Architect`, status `New`, date `2023-03-28`, comment `I love Amazon!`,
+ and tags `AWS` and `Cloud Services`. Then, `copy 1` copies `Company Name: Amazon; Role: Cloud Architect; Status: New; Date: 2023-03-28; Comment: [I love Amazon!]; Tags: [Cloud Services][AWS]` to your clipboard.
+
+* `copy -1` Displays an error because `INDEX` must be a positive integer.
+* `copy 8` Assuming that you have 7 internships displayed in the
+ [List Panel](#exploring-the-graphical-user-interface), this displays an error because `INDEX` cannot be greater
+ than the maximum index shown in the [List Panel](#exploring-the-graphical-user-interface), which is 7 in this case.
+
+
+
+[//]: # (@@author kohkaixun)
+### Finding Internships : `find`
+Want to locate selected internship entries? Use the `find` command to filter through
+your entries and narrow down your search.
+
+
+Format: `find [n/COMPANY_NAME]... [r/ROLE]... [s/STATUS]... [d/DATE]... [t/TAG]...`
+
+* You have to provide at least one of the optional fields.
+* The `find` command is **case-insensitive**, and it returns **exact matches only**. For example,
+ `find n/Google Ltd` will not return an entry with company name `Google` because `Google`
+ does not exactly match with `Google Ltd`. On the other hand, `find t/Java` will return
+ an entry with tag `java` because the search is case-insensitive.
+
+There are 2 possible ways for you to use the `find` command.
+
+**Method 1: Use a single field type**
+
+e.g. `find s/Applied`, `find s/Applied s/New`, `find n/Google n/Apple n/Meta`
+
+* The `find` command returns all internship entries that match with **any** of the values that you provide.
+
+More examples:
+* `find s/Applied s/New` returns all internship entries that have a status of **either**
+ `Applied` **or** `New`.
+
+
+
+**Method 2: Use 2 or more different field types**
-### Clearing all entries : `clear`
+e.g. `find n/Google n/Apple s/New`, `find n/Google n/Apple s/Applied s/New`, `find n/Google r/Engineer t/Python t/Java`
-Clears all entries from the address book.
+* The `find` command returns all internship entries that match with **at least one** value for
+ **every** field type that is specified.
+
+Detailed example:
+* Figure 5 below shows InternBuddy starting with 5 internship entries. After entering `find n/Google n/Apple t/python t/java`,
+ the internships in green boxes were returned while those in red boxes were not.
+
+
+
+
+
+
+
Figure 5: Example of the find command in action
+
+
+
+
+
+* Table 7 explains the reasoning behind Figure 5.
+
+
+| Index of Internship | Returned? | Explanation |
+|---------------------|-----------|-----------------------------------------------------------------------------------|
+| 1 | Yes | It contains at least one company name `Google` and both tags `python` and `java`. |
+| 2 | Yes | It contains at least one company name `Google` and at least one tag `python`. |
+| 3 | Yes | It contains at least one company name `Apple` and at least one tag `java`. |
+| 4 | No | It lacks both of the searched tags, `python` and `java`. |
+| 5 | No | It lacks both of the searched company names, `Google` and `Apple`. |
+
+
Table 7: Explanation of Figure 5
+
+
+
+
+
+More examples:
+* `find n/Google n/Apple s/Interview` returns internship entries that have a status `Interview` **and** have
+ a company name of `Google` **or** `Apple`.
+* `find n/Google n/Apple s/Applied s/Interview` returns internship entries that have company names
+ of `Google` **or** `Apple` **and** roles of `Applied` **or** `Interview`.
+
+
+
+
+
+:information_source: **Info:** The `find` command always searches through all of your internship entries
+that are stored in InternBuddy. This means that it will also search through entries that are not currently displayed
+in the [List Panel](#exploring-the-graphical-user-interface).
+
+
+
+
+[//]: # (@@author seadragon2000341)
+### Getting Upcoming Events and Deadlines : `upcoming`
+Want to view your upcoming events and deadlines? You can do so using the `upcoming` command.
+
+Format: `upcoming`
+* The `upcoming` command provides the list of internships that have events (interviews/assessments) or deadlines (application deadline/offer acceptance deadline) within the upcoming week.
+* In other words, it gives you the list of internships that have a `STATUS` of `New/Offered/Assessment/Interview` and a `DATE` that falls within the upcoming week.
+* Upcoming week is defined as the current day and the 6 days that follow it.
+
+
+
+Examples:
+* `upcoming` If today's date is 5 January 2023, it will list all internships that have a `STATUS` of `New/Offered/Assessment/Interview` and a `DATE` that is from 5 January 2023 to 11 January 2023 inclusive.
+
+
+[//]: # (@@author potty10)
+### Deleting Internships by Indices : `delete-index`
+Need to keep your screen neat and tidy? `delete-index` can help you achieve this by deleting multiple internships using their indices.
+
+Format: `delete-index INDEX [INDEX]...`
+
+* Deletes the internship whose index number is `INDEX`.
+* If multiple `INDEX` are provided, multiple internships can be deleted.
+* At least 1 `INDEX` must be provided.
+* `INDEX` does not need to be unique. If 2 or more of `INDEX` have the same value, only the first one will be taken.
+
+
+Examples:
+* If you run `delete-index 1` after `find`, it will delete the first entry as displayed by `find` in the [List Panel](#exploring-the-graphical-user-interface).
+* If you run `delete-index 1` after `list`, it will delete the first entry as displayed by `list` in the [List Panel](#exploring-the-graphical-user-interface).
+* `delete-index 1 3` Deletes the first and third
+ internships in the [List Panel](#exploring-the-graphical-user-interface).
+* `delete-index 3 1 3 3 1` Deletes the first and third
+ internships in the [List Panel](#exploring-the-graphical-user-interface).
+* `delete-index` Displays an error because at least one `INDEX` must be specified.
+
+[//]: # (@@author potty10)
+### Deleting Internships by Fields : `delete-field`
+Wish that you can delete internships using fields instead of indices? You can
+certainly do so using `delete-field`.
+
+Format: `delete-field [n/COMPANY_NAME]... [r/ROLE]... [s/STATUS]... [d/DATE]... [t/TAG]...`
+
+* You have to provide at least one of the optional fields.
+* The `delete-field` command is **case-insensitive**. For example, `delete-field n/Google` deletes all internships with company names `google`, `Google` or `gOOgle`.
+ Also, `delete-field t/java` deletes all internships with tags `Java`, `java` or `JaVa`.
+* `delete-field` deletes entries with **exact matches only**. For example, `delete-field n/Google Ltd` will not delete an entry with company name `Google` because
+ `Google` does not exactly match with `Google Ltd`.
+
+There are 2 possible ways for you to use the `delete-field` command.
+
+**Method 1: Use a single field type**
+
+e.g. `delete-field s/Applied`, `delete-field s/Applied s/New`,
+`delete-field n/Google n/Apple n/Meta`
+
+* The `delete-field` command deletes all internship entries that match with **any** of the values that you provide.
+
+More Examples:
+* `delete-field s/Applied s/New` deletes all internship entries that have a status of **either**
+ `Applied` **or** `New`.
+
+
+**Method 2: Use 2 or more different field types**
+
+e.g. `delete-field n/Google n/Apple s/New`, `delete-field n/Google n/Apple s/Applied s/New`,
+`delete-field n/Google r/Engineer t/Python t/Java`
+
+* The `delete-field` command deletes all internship entries that matches with **at least one** value for
+ **every** field type that is specified.
+
+More Examples:
+* `delete-field n/Google n/Apple s/Interview` Deletes internship entries that have a status `Interview` **and** have
+ a company name of `Google` **or** `Apple`.
+* `delete-field n/Google n/Apple s/New s/Interview` Deletes internship entries that have company names
+ of `Google` **or** `Apple` **and** roles of `New` **or** `Interview`.
+
+
+
+
+:information_source: **Info:** The `delete-field` command only searches through the internship entries
+that are displayed in the [List Panel](#exploring-the-graphical-user-interface). This means that it
+will never delete entries that are not currently displayed in the
+[List Panel](#exploring-the-graphical-user-interface).
+
+
+
+
+
+:warning: **Warning:** If you use an unknown prefix or a prefix not specific to this command, it will be interpreted as
+part of your input value. For example, `delete-field r/Engineer c/Good company` will try to delete internships with a role
+of `Engineer c/Good company`.
+
+
+[//]: # (@@author potty10)
+### Clearing all Internships : `clear`
+The `clear` command permanently deletes all entries from InternBuddy.
Format: `clear`
-### Exiting the program : `exit`
+
-Exits the program.
+:warning: **Warning:** It will be good to think twice before running this command because
+once you run this command, all your internship data will be deleted. In the event that you
+accidentally ran `clear`, you can refer to [Appendix C](#appendix-c-populating-internbuddy-with-sample-data)
+to repopulate InternBuddy with sample data.
+
+
+
+
+
+[//]: # (@@author eugenetangkj)
+### Getting Help : `help`
+Forgot the commands for InternBuddy? Fret not! You can easily view the list of supported commands and their formats
+using the `help` command.
+
+Format: `help`
+* Opens a new window which displays the list of supported commands in InternBuddy, and provides a link to InternBuddy's
+ user guide where you can view more detailed information about each command. Figure 6 shows how the Help Window looks like.
+* You can click on the button to copy the link to your clipboard.
+
+
+
+
+
+
Figure 6: Help Window
+
+
+
+
+
+:information_source: **Info:** Clicking on the hyperlink in the help window may not work on some Linux
+devices as the functionality is dependent on Gnome libraries. If you are using a Linux device and
+the hyperlink does not work, you can click on the button instead.
+
+
+
+
+### Exiting InternBuddy : `exit`
+
+Done with tracking your internships for the day? Exit InternBuddy using the `exit` command.
Format: `exit`
-### 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.
+[//]: # (@@author kohkaixun)
+### Navigating through Past Commands
-### Editing the data file
+Want to reuse a command you entered just now but too lazy to type it all out again? InternBuddy has got your back!
+After clicking on the [Command Box](#exploring-the-graphical-user-interface), pressing and will fill the [Command Box](#exploring-the-graphical-user-interface) with commands that you have recently entered.
+This allows you to effortlessly access and use past commands without having to go through the tedious process of typing them all over again.
-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.
+
-
: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.
+:information_source: **Info:** InternBuddy only tracks your past commands from the current run of
+InternBuddy. This means that if you restart InternBuddy, you can no longer navigate to the commands that
+you entered during the previous run.
-### Archiving data files `[coming in v2.0]`
+
-_Details coming soon ..._
+:information_source: **Info:** Once you have navigated to the first command that you have ever entered into
+InternBuddy, pressing will not lead to any further change. Similarly, once you have
+navigated to the current state of waiting for new input, pressing will not
+change anything.
+
-## FAQ
+:bulb: **Tip:** InternBuddy keeps track of all past commands entered, regardless of whether they were
+valid or not. Hence, if you accidentally entered an invalid command, you can easily navigate to it and
+make amendments accordingly without having to type out the entire command again.
+
+
+Example:
+- Figure 7 illustrates how you can navigate through past commands where the inputs
+ `list`, `clear` and `upcoming` are entered in this particular order. The and
+ keys are used to navigate between the different inputs.
+
+
+
+
+
+
+
Figure 7: Navigating between commands
+
+
+
+[//]: # (@@author DerrickSaltFish)
+### Saving your Internship Data
+
+Your internship data for InternBuddy are saved automatically after any command that changes the data. The data are saved
+in a file `internbuddy.json` which is located in a subfolder `data` in the [home folder](#quick-start)
+where you placed `internbuddy.json`. There is no need to save manually.
+
+
+
+:information_source: **Info:** The file location of `internbuddy.json` is stated in the
+Status Bar of the GUI.
+
-**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.
---------------------------------------------------------------------------------------------------------------------
+### Loading the Data
-## Command summary
+InternBuddy data is loaded from `internbuddy.json` automatically at the beginning of each run. There is no need to load
+manually.
+* If `internbuddy.json` is missing, InternBuddy will start with a new data file containing the sample internship
+ entries.
+* If the content in `internbuddy.json` was altered and as a result has an invalid format, InternBuddy will start with an
+ empty data file.
+
+
+
+
+
+:warning: **Warning:** Starting with an empty data file means that all internship entries previously stored in
+InternBuddy will no longer be present. This is equivalent to a data wipeout. Therefore, we advise against tampering
+with the content in `internbuddy.json` unless you are confident in doing so. If you are interested, you can refer to
+ [Appendix B](#appendix-b-customising-the-data-file) for instructions on how to do so.
+
+
+
+
+## **FAQ**
+
+**Q**: How do I transfer my data to another Computer?
+**A**: Install InternBuddy in the other computer and overwrite the file `internbuddy.json` that it creates with the
+file `internbuddy.json` that is stored on your existing computer.
+
+**Q**: Does InternBuddy support undoing of commands? For example, can I undo a `delete-index` action?
+**A**: Unfortunately, the current version of InternBuddy does not support the `undo` command. However, it is a feature
+that we are exploring and hope to implement in the future!
+
+
+
+[//]: # (@@author potty10)
+## **Command Summary**
+Table 8 provides an overview of the commands supported in InternBuddy.
+
+| Action | Format, Examples |
+|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------|
+| List all Internships | `list` |
+| Add an Internship | `add n/COMPANY_NAME r/ROLE s/STATUS d/DATE [c/COMMENT] [t/TAG]...` e.g. `add n/Apple r/Software Engineer s/New d/2023-03-01` |
+| Edit an Internship | `edit INDEX [n/COMPANY_NAME] [r/ROLE] [s/STATUS] [d/DATE] [c/COMMENT] [t/TAG]...` e.g.`edit 2 s/Assessment r/Software Developer` |
+| View an Internship | `view INDEX` e.g. `view 1` |
+| Copy an Internship to Clipboard | `copy INDEX` e.g. `copy 1` |
+| Find Internships | `find [n/COMPANY_NAME]... [r/ROLE]... [s/STATUS]... [d/DATE]... [t/TAG]...` e.g. `find n/Apple n/Google` |
+| Get Upcoming Events/Deadlines | `upcoming` |
+| Delete Internships by Indices | `delete-index INDEX [INDEX]...` e.g. `delete-index 1 3` |
+| Delete Internships by Fields | `delete-field [n/COMPANY_NAME]... [r/ROLE]... [s/STATUS]... [d/DATE]... [t/TAG]...` e.g. `delete-field n/Apple n/Google s/New s/Applied` |
+| Clear all Internships | `clear` |
+| Get Help | `help` |
+| Exit InternBuddy | `exit` |
+
+
+
Table 8: Commands in InternBuddy
+
+
+## **Appendix A: Installing Java 11**
+Follow the following steps to set up Java 11 on your computer.
+1. Open up a terminal on your computer.
+ - If you are using Windows, click on the `Windows` icon at the bottom left of your computer. Then, type in `terminal` in
+ the search bar and double-click the application called `Terminal`.
+ - If you are using macOS, click on the `Spotlight` search icon at the top right of your computer. Then, type in `terminal`
+ in the search bar and double-click the application called `Terminal`.
+ - If you are using Linux, press + + to launch the terminal.
+2. In the terminal, type in `java -version` and press . The terminal will display the version of
+ Java that you have installed on your computer.
+3. If you do not have any versions of Java installed, or you have a version older than Java 11, download [Java 11](https://www.oracle.com/java/technologies/downloads/#java11) here.
+ You may then return to Step 1 to check whether you have the correct version of Java installed.
+
+
+
+
+
+
+## **Appendix B: Customising the Data File**
+If you are an advanced user of InternBuddy, you can directly edit the contents of your data through the `internbuddy.json`
+file without using the GUI. The `internbuddy.json` file is found in the `data` subfolder of your InternBuddy
+[home folder](#quick-start).
+
+
+:warning: **Warning:** If you are new to InternBuddy or are not confident in reading JSON files, we will advise you against
+directly editing the `internbuddy.json` file. This is because if you accidentally make a mistake that leads to the JSON
+file not having the correct format, InternBuddy would restart with the sample data file, wiping out any data that you had
+previously.
+
+
-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`
-**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`
+The following steps outline how you can properly edit the `internbuddy.json` file:
+1. Open the `internbuddy.json` file by double-clicking on it. If you are prompted to select an application to open
+ the file, you can choose any text editor such as `Notepad`.
+2. Once opened, you will see the JSON data file in a format as shown in Figure 8. Referring to Figure 8,
+ each box contains the data for one specific internship entry.
+3. Within each box, you can see that there are pairings where each pair is made up of a `FIELD` and `VALUE`.
+
+
+
+
Figure 8: Sample JSON data file
+
+
+
+4. To manually change the value of a field, simply replace the text for `VALUE`. Figure 9 illustrates an example
+ where we change the value of `STATUS` from `assessment` to `interview` for the internship entry with company name
+ `Google`. Once your changes have been made, you can save the file by pressing + .
+
+
+ :warning: **Warning:** Make sure that you follow the constraints
+ when substituting in your own values. If the constraints are not satisfied, InternBuddy will not be able to
+ read your data in the `internbuddy.json` file and will restart with all your internship data cleared.
+
+
+
+
+ ![Editing the JSON File](images/ug-appendix-b-json-change.png)
+
Figure 9: Editing the JSON file
+
+
+5. Launch InternBuddy and you will see that your data have been updated accordingly.
+
+
+
+
+## **Appendix C: Populating InternBuddy with Sample Data**
+Follow the following steps to populate InternBuddy with sample data.
+1. Visit this [link](https://github.com/AY2223S2-CS2103T-T14-3/tp/blob/master/internbuddy.json).
+2. Left-click the button labelled `Raw`. Figure 10 shows where the `Raw` button is.
+
+ ![InternBuddy Sample Data](images/github-raw.png)
+
Figure 10: Raw button on the GitHub interface
+
+
+
+
+3. Your screen will look like Figure 11. Right click, then click on `Save As`.
+
+
+
+
+
Figure 11: InternBuddy Sample Data
+
+4. You will be prompted to choose a folder to save the file in. Choose the `data` subfolder that is found in the [home folder](#quick-start) that
+ you have chosen for InternBuddy.
+5. Click `Save`.
+
+
+ :warning: **Warning:** If you already have an internbuddy.json file in the subfolder, you will be prompted to
+ confirm whether you want to overwrite it when attempting to populate InternBuddy with sample data.
+ It is important to only choose to overwrite the existing file if you are absolutely certain that you
+ do not need your old InternBuddy data anymore. If you are unsure, you can always make a backup copy
+ of the file before overwriting.
+
+6. You are done! InternBuddy will be populated with the sample data the next time you launch it.
+
+
+
+
+## **Glossary**
+Table 9 provides a glossary for the technical terms used in this user guide.
+
+| Term | Definition |
+|--------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Command | An instruction for InternBuddy to perform an action. |
+| Command Line Interface (CLI) | A CLI is the text-based interface that you can use to provide instructions to your computer. Examples of instructions include opening files and running programs. |
+| Graphical User Interface (GUI) | A GUI is the visual interface that you see when an application launches, allowing you to interact with it by clicking on its various buttons and components. |
+| Mainstream Operating Systems | Include Windows, macOS, Linux and Unix. |
+| Field | A part of the command where you have to supply a value for the command to be valid. |
+| Prefix | A short form for the name of a field. It indicates which field does a value belongs to. For example, in `n/Apple`, the value `Apple` is supplied to the field `COMPANY_NAME` since the `n/` prefix is used. |
+
+
Table 9: Glossary for InternBuddy's User Guide
+
+
+
+## **Acknowledgements**
+
+* InternBuddy is written in **Java 11**.
+* It is adapted from the [AddressBook Level 3](https://github.com/se-edu/addressbook-level3) project created by
+ the [SE-EDU initiative](https://se-education.org).
+* Libraries and frameworks used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson),
+ [JUnit5](https://github.com/junit-team/junit5) and [TestFX](https://github.com/TestFX/TestFX).
+* GUI testing is implemented with references from [AddressBook Level 4](https://github.com/se-edu/addressbook-level4)
+ and [Please Hire Us](https://github.com/AY2223S1-CS2103T-W17-4/tp). We utilised code from these projects to set
+ up GUI testing and added our own test cases to test the UI components that we created.
+* The feature of Navigating Through Past Commands is primarily adapted from [HackNet](https://github.com/AY2122S2-CS2103T-W13-3/tp),
+ but we added code modifications and test cases.
+* The sections on explaining the formatting standards and GUI interface in the User and Developer Guides are
+ inspired by [Please Hire Us](https://github.com/AY2223S1-CS2103T-W17-4/tp).
diff --git a/docs/_config.yml b/docs/_config.yml
index 6bd245d8f4e..e9c15ecc606 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,4 +1,4 @@
-title: "AB-3"
+title: "InternBuddy"
theme: minima
header_pages:
@@ -8,7 +8,7 @@ header_pages:
markdown: kramdown
-repository: "se-edu/addressbook-level3"
+repository: "AY2223S2-CS2103T-T14-3/tp"
github_icon: "images/github-icon.png"
plugins:
diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss
index 0d3f6e80ced..f5be31f58ae 100644
--- a/docs/_sass/minima/_base.scss
+++ b/docs/_sass/minima/_base.scss
@@ -288,7 +288,7 @@ table {
text-align: center;
}
.site-header:before {
- content: "AB-3";
+ content: "InternBuddy";
font-size: 32px;
}
}
diff --git a/docs/diagrams/AddSequenceDiagram.puml b/docs/diagrams/AddSequenceDiagram.puml
new file mode 100644
index 00000000000..fbed503353b
--- /dev/null
+++ b/docs/diagrams/AddSequenceDiagram.puml
@@ -0,0 +1,78 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternBuddyParser" as InternBuddyParser LOGIC_COLOR
+participant ":AddCommandParser" as AddCommandParser LOGIC_COLOR
+participant "a:AddCommand" as AddCommand LOGIC_COLOR
+participant "cr:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+
+end box
+[-> LogicManager : execute("add n/Google r/Engineer s/Applied d/2023-02-01")
+activate LogicManager
+
+LogicManager -> InternBuddyParser : parseCommand("add n/Google r/Engineer s/Applied d/2023-02-01")
+activate InternBuddyParser
+
+create AddCommandParser
+InternBuddyParser -> AddCommandParser
+activate AddCommandParser
+
+AddCommandParser --> InternBuddyParser
+deactivate AddCommandParser
+
+
+
+InternBuddyParser -> AddCommandParser : parse("n/Google r/Engineer s/Applied d/2023-02-01")
+activate AddCommandParser
+
+create AddCommand
+AddCommandParser -> AddCommand : AddCommand(toAdd)
+activate AddCommand
+
+AddCommand --> AddCommandParser
+deactivate AddCommand
+
+AddCommandParser --> InternBuddyParser : a
+deactivate AddCommandParser
+
+
+InternBuddyParser --> LogicManager : a
+destroy AddCommandParser
+deactivate InternBuddyParser
+
+LogicManager -> AddCommand : execute()
+activate AddCommand
+
+AddCommand -> Model : addInternship(toAdd)
+activate Model
+
+Model --> AddCommand
+deactivate Model
+
+AddCommand -> Model : updateSelectedInternship(toAdd)
+activate Model
+
+Model --> AddCommand
+deactivate Model
+
+create CommandResult
+AddCommand -> CommandResult
+activate CommandResult
+CommandResult --> AddCommand
+deactivate CommandResult
+
+
+AddCommand --> LogicManager : cr
+deactivate AddCommand
+AddCommand -[hidden]-> LogicManager : result
+destroy AddCommand
+
+[<--LogicManager : cr
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml
index ef81d18c337..64fc110e5e3 100644
--- a/docs/diagrams/ArchitectureSequenceDiagram.puml
+++ b/docs/diagrams/ArchitectureSequenceDiagram.puml
@@ -7,19 +7,19 @@ 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 : "delete-index 1"
activate ui UI_COLOR
-ui -[UI_COLOR]> logic : execute("delete 1")
+ui -[UI_COLOR]> logic : execute("delete-index 1")
activate logic LOGIC_COLOR
-logic -[LOGIC_COLOR]> model : deletePerson(p)
+logic -[LOGIC_COLOR]> model : deleteInternship(i)
activate model MODEL_COLOR
model -[MODEL_COLOR]-> logic
deactivate model
-logic -[LOGIC_COLOR]> storage : saveAddressBook(addressBook)
+logic -[LOGIC_COLOR]> storage : saveInternBuddy(internBuddy)
activate storage STORAGE_COLOR
storage -[STORAGE_COLOR]> storage : Save to file
diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml
index 598474a5c82..85784a164f2 100644
--- a/docs/diagrams/BetterModelClassDiagram.puml
+++ b/docs/diagrams/BetterModelClassDiagram.puml
@@ -4,18 +4,19 @@ skinparam arrowThickness 1.1
skinparam arrowColor MODEL_COLOR
skinparam classBackgroundColor MODEL_COLOR
-AddressBook *-right-> "1" UniquePersonList
-AddressBook *-right-> "1" UniqueTagList
-UniqueTagList -[hidden]down- UniquePersonList
-UniqueTagList -[hidden]down- UniquePersonList
+InternBuddy *-right-> "1" UniqueInternshipList
+InternBuddy *-right-> "1" UniqueTagList
+UniqueTagList -[hidden]down- UniqueInternshipList
+UniqueTagList -[hidden]down- UniqueInternshipList
UniqueTagList -right-> "*" Tag
-UniquePersonList -right-> Person
+UniqueInternshipList -right-> Internship
-Person -up-> "*" Tag
+Internship -up-> "*" Tag
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
+Internship *--> CompanyName
+Internship *--> Role
+Internship *--> Status
+Internship *--> Date
+Internship *--> Comment
@enduml
diff --git a/docs/diagrams/ClearSequenceDiagram.puml b/docs/diagrams/ClearSequenceDiagram.puml
new file mode 100644
index 00000000000..5c725025c5d
--- /dev/null
+++ b/docs/diagrams/ClearSequenceDiagram.puml
@@ -0,0 +1,81 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternBuddyParser" as InternBuddyParser LOGIC_COLOR
+participant ":ClearCommandParser" as ClearCommandParser LOGIC_COLOR
+participant "p:InternshipContainsKeywordPredicate" as InternshipContainsKeywordPredicate LOGIC_COLOR
+participant "c:ClearCommand" as ClearCommand LOGIC_COLOR
+participant "cr:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("clear n/google")
+activate LogicManager
+
+LogicManager -> InternBuddyParser : parseCommand("clear n/google")
+activate InternBuddyParser
+
+create ClearCommandParser
+InternBuddyParser -> ClearCommandParser
+activate ClearCommandParser
+
+ClearCommandParser --> InternBuddyParser
+deactivate ClearCommandParser
+
+InternBuddyParser -> ClearCommandParser : parse("n/google")
+activate ClearCommandParser
+
+create InternshipContainsKeywordPredicate
+ClearCommandParser -> InternshipContainsKeywordPredicate : InternshipContainsKeywordPredicate()
+activate InternshipContainsKeywordPredicate
+
+InternshipContainsKeywordPredicate --> ClearCommandParser : p
+deactivate InternshipContainsKeywordPredicate
+
+create ClearCommand
+ClearCommandParser -> ClearCommand : ClearCommand(p)
+activate ClearCommand
+
+ClearCommand --> ClearCommandParser : c
+deactivate ClearCommand
+
+ClearCommandParser --> InternBuddyParser : c
+deactivate ClearCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+ClearCommandParser -[hidden]-> InternBuddyParser
+destroy ClearCommandParser
+
+InternBuddyParser --> LogicManager : c
+deactivate InternBuddyParser
+
+LogicManager -> ClearCommand : execute()
+activate ClearCommand
+
+ClearCommand -> Model : deleteInternshipByPredicate(p)
+activate Model
+
+Model --> ClearCommand
+deactivate Model
+
+create CommandResult
+ClearCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> ClearCommand : cr
+deactivate CommandResult
+
+ClearCommand --> LogicManager : cr
+deactivate ClearCommand
+ClearCommand -[hidden]-> LogicManager
+destroy ClearCommand
+
+destroy InternshipContainsKeywordPredicate
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/CommitActivityDiagram.puml b/docs/diagrams/CommitActivityDiagram.puml
index 6a6b23a006f..e71780ccd56 100644
--- a/docs/diagrams/CommitActivityDiagram.puml
+++ b/docs/diagrams/CommitActivityDiagram.puml
@@ -5,10 +5,10 @@ start
'Since the beta syntax does not support placing the condition outside the
'diamond we place it as the true branch instead.
-if () then ([command commits AddressBook])
+if () then ([command commits InternBuddy])
:Purge redundant states;
- :Save AddressBook to
- addressBookStateList;
+ :Save InternBuddy to
+ internBuddyStateList;
else ([else])
endif
stop
diff --git a/docs/diagrams/CopyActivityDiagram.puml b/docs/diagrams/CopyActivityDiagram.puml
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/docs/diagrams/CopySequenceDiagram.puml b/docs/diagrams/CopySequenceDiagram.puml
new file mode 100644
index 00000000000..a4836f574fd
--- /dev/null
+++ b/docs/diagrams/CopySequenceDiagram.puml
@@ -0,0 +1,75 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternBuddyParser" as InternBuddyParser LOGIC_COLOR
+participant ":CopyCommandParser" as CopyCommandParser LOGIC_COLOR
+participant "c:CopyCommand" as CopyCommand LOGIC_COLOR
+participant "<>\nParserUtil" as ParserUtil LOGIC_COLOR
+participant "cr:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+[-> LogicManager : execute("copy 1")
+activate LogicManager
+
+LogicManager -> InternBuddyParser : parseCommand("copy 1")
+activate InternBuddyParser
+
+create CopyCommandParser
+InternBuddyParser -> CopyCommandParser
+activate CopyCommandParser
+
+CopyCommandParser --> InternBuddyParser
+deactivate CopyCommandParser
+
+InternBuddyParser -> CopyCommandParser : parse("1")
+activate CopyCommandParser
+
+CopyCommandParser -> ParserUtil : parseIndex("1")
+activate ParserUtil
+
+ParserUtil --> CopyCommandParser : indexObject
+deactivate ParserUtil
+
+create CopyCommand
+CopyCommandParser -> CopyCommand : CopyCommand(indexObject)
+activate CopyCommand
+
+CopyCommand --> CopyCommandParser
+deactivate CopyCommand
+
+CopyCommandParser --> InternBuddyParser : c
+deactivate CopyCommandParser
+
+InternBuddyParser --> LogicManager : c
+destroy CopyCommandParser
+deactivate InternBuddyParser
+
+LogicManager -> CopyCommand : execute()
+activate CopyCommand
+
+CopyCommand -> Model : copyInternship(internshipToCopy)
+activate Model
+
+Model --> CopyCommand
+deactivate Model
+
+create CommandResult
+CopyCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> CopyCommand
+deactivate CommandResult
+
+CopyCommand --> LogicManager : cr
+deactivate CopyCommand
+
+[<--LogicManager : cr
+destroy CopyCommand
+deactivate LogicManager
+
+@enduml
diff --git a/docs/diagrams/DeleteFieldSequenceDiagram.puml b/docs/diagrams/DeleteFieldSequenceDiagram.puml
new file mode 100644
index 00000000000..a076ffe5d99
--- /dev/null
+++ b/docs/diagrams/DeleteFieldSequenceDiagram.puml
@@ -0,0 +1,100 @@
+'(@@author potty10)
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternBuddyParser" as InternBuddyParser LOGIC_COLOR
+participant ":DeleteFieldCommandParser" as DeleteFieldCommandParser LOGIC_COLOR
+participant "p:InternshipContainsKeywordPredicate\n" as InternshipContainsKeywordPredicate LOGIC_COLOR
+participant "c:DeleteFieldCommand" as DeleteFieldCommand LOGIC_COLOR
+participant "cr:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("delete-field n/google")
+activate LogicManager
+
+LogicManager -> InternBuddyParser : parseCommand("delete-field n/google")
+activate InternBuddyParser
+
+create DeleteFieldCommandParser
+InternBuddyParser -> DeleteFieldCommandParser
+activate DeleteFieldCommandParser
+
+DeleteFieldCommandParser --> InternBuddyParser
+deactivate DeleteFieldCommandParser
+
+InternBuddyParser -> DeleteFieldCommandParser : parse("n/google")
+activate DeleteFieldCommandParser
+
+create InternshipContainsKeywordPredicate
+DeleteFieldCommandParser -> InternshipContainsKeywordPredicate : InternshipContainsKeywordPredicate(nameList,\n roleList, statusList, dateList, tagList)
+activate InternshipContainsKeywordPredicate
+
+InternshipContainsKeywordPredicate --> DeleteFieldCommandParser
+deactivate InternshipContainsKeywordPredicate
+
+create DeleteFieldCommand
+DeleteFieldCommandParser -> DeleteFieldCommand : DeleteFieldCommand(p)
+activate DeleteFieldCommand
+
+DeleteFieldCommand --> DeleteFieldCommandParser
+deactivate DeleteFieldCommand
+
+DeleteFieldCommandParser --> InternBuddyParser : c
+deactivate DeleteFieldCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+DeleteFieldCommandParser -[hidden]-> InternBuddyParser
+destroy DeleteFieldCommandParser
+
+InternBuddyParser --> LogicManager : c
+deactivate InternBuddyParser
+
+LogicManager -> DeleteFieldCommand : execute()
+activate DeleteFieldCommand
+
+DeleteFieldCommand -> Model : getFilteredInternshipList()
+activate Model
+
+Model --> DeleteFieldCommand
+deactivate Model
+
+
+
+loop internship in internshipsToDelete
+ DeleteFieldCommand -> Model: deleteInternship(internship)
+ activate Model
+ Model --> DeleteFieldCommand
+ deactivate Model
+
+opt internship is selected
+ DeleteFieldCommand -> Model: updateSelectedInternship(null)
+ activate Model
+ Model --> DeleteFieldCommand
+ deactivate Model
+end
+end
+
+deactivate Model
+
+create CommandResult
+DeleteFieldCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> DeleteFieldCommand : cr
+deactivate CommandResult
+
+DeleteFieldCommand --> LogicManager : cr
+deactivate DeleteFieldCommand
+DeleteFieldCommand -[hidden]-> LogicManager
+destroy DeleteFieldCommand
+destroy InternshipContainsKeywordPredicate
+
+
+[<--LogicManager : cr
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/DeleteIndexSequenceDiagram.puml b/docs/diagrams/DeleteIndexSequenceDiagram.puml
new file mode 100644
index 00000000000..bba36929714
--- /dev/null
+++ b/docs/diagrams/DeleteIndexSequenceDiagram.puml
@@ -0,0 +1,85 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternBuddyParser" as InternBuddyParser LOGIC_COLOR
+participant ":DeleteIndexCommandParser" as DeleteIndexCommandParser LOGIC_COLOR
+participant "c:DeleteIndexCommand" as DeleteIndexCommand LOGIC_COLOR
+participant "cr:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("delete-index 1 2")
+activate LogicManager
+
+LogicManager -> InternBuddyParser : parseCommand("delete-index 1 2")
+activate InternBuddyParser
+
+create DeleteIndexCommandParser
+InternBuddyParser -> DeleteIndexCommandParser
+activate DeleteIndexCommandParser
+
+DeleteIndexCommandParser --> InternBuddyParser
+deactivate DeleteIndexCommandParser
+
+InternBuddyParser -> DeleteIndexCommandParser : parse("1 2")
+activate DeleteIndexCommandParser
+
+create DeleteIndexCommand
+DeleteIndexCommandParser -> DeleteIndexCommand : DeleteIndexCommand(indexes)
+activate DeleteIndexCommand
+
+DeleteIndexCommand --> DeleteIndexCommandParser
+deactivate DeleteIndexCommand
+
+DeleteIndexCommandParser --> InternBuddyParser : c
+deactivate DeleteIndexCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+DeleteIndexCommandParser -[hidden]-> InternBuddyParser
+destroy DeleteIndexCommandParser
+
+InternBuddyParser --> LogicManager : c
+deactivate InternBuddyParser
+
+LogicManager -> DeleteIndexCommand : execute()
+activate DeleteIndexCommand
+
+DeleteIndexCommand -> Model : getFilteredInternshipList()
+activate Model
+
+Model --> DeleteIndexCommand
+deactivate Model
+
+loop internship in internshipsToDelete
+ DeleteIndexCommand -> Model: deleteInternship(internship)
+ activate Model
+ Model --> DeleteIndexCommand
+ deactivate Model
+opt internship is selected
+ DeleteIndexCommand -> Model: updateSelectedInternship(null)
+ activate Model
+ Model --> DeleteIndexCommand
+ deactivate Model
+end
+end
+
+create CommandResult
+DeleteIndexCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> DeleteIndexCommand : cr
+deactivate CommandResult
+
+DeleteIndexCommand --> LogicManager : cr
+deactivate DeleteIndexCommand
+DeleteIndexCommand -[hidden]-> LogicManager
+destroy DeleteIndexCommand
+
+
+[<--LogicManager : cr
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml
index 1dc2311b245..528c1f10efd 100644
--- a/docs/diagrams/DeleteSequenceDiagram.puml
+++ b/docs/diagrams/DeleteSequenceDiagram.puml
@@ -3,66 +3,83 @@
box Logic LOGIC_COLOR_T1
participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":InternBuddyParser" as InternBuddyParser LOGIC_COLOR
participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR
-participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR
-participant ":CommandResult" as CommandResult LOGIC_COLOR
+participant "p:InternshipContainsKeywordPredicate" as InternshipContainsKeywordPredicate LOGIC_COLOR
+participant "c:DeleteCommand" as DeleteCommand LOGIC_COLOR
+participant "cr:CommandResult" as CommandResult LOGIC_COLOR
end box
box Model MODEL_COLOR_T1
participant ":Model" as Model MODEL_COLOR
end box
-[-> LogicManager : execute("delete 1")
+[-> LogicManager : execute("delete n/google")
activate LogicManager
-LogicManager -> AddressBookParser : parseCommand("delete 1")
-activate AddressBookParser
+LogicManager -> InternBuddyParser : parseCommand("delete n/google")
+activate InternBuddyParser
create DeleteCommandParser
-AddressBookParser -> DeleteCommandParser
+InternBuddyParser -> DeleteCommandParser
activate DeleteCommandParser
-DeleteCommandParser --> AddressBookParser
+DeleteCommandParser --> InternBuddyParser
deactivate DeleteCommandParser
-AddressBookParser -> DeleteCommandParser : parse("1")
+InternBuddyParser -> DeleteCommandParser : parse("n/google")
activate DeleteCommandParser
+create InternshipContainsKeywordPredicate
+DeleteCommandParser -> InternshipContainsKeywordPredicate : InternshipContainsKeywordPredicate()
+activate InternshipContainsKeywordPredicate
+
+InternshipContainsKeywordPredicate --> DeleteCommandParser : p
+deactivate InternshipContainsKeywordPredicate
+
create DeleteCommand
-DeleteCommandParser -> DeleteCommand
+DeleteCommandParser -> DeleteCommand : DeleteCommand(p)
activate DeleteCommand
-DeleteCommand --> DeleteCommandParser : d
+DeleteCommand --> DeleteCommandParser : c
deactivate DeleteCommand
-DeleteCommandParser --> AddressBookParser : d
+DeleteCommandParser --> InternBuddyParser : c
deactivate DeleteCommandParser
'Hidden arrow to position the destroy marker below the end of the activation bar.
-DeleteCommandParser -[hidden]-> AddressBookParser
+DeleteCommandParser -[hidden]-> InternBuddyParser
destroy DeleteCommandParser
-AddressBookParser --> LogicManager : d
-deactivate AddressBookParser
+InternBuddyParser --> LogicManager : c
+deactivate InternBuddyParser
LogicManager -> DeleteCommand : execute()
activate DeleteCommand
-DeleteCommand -> Model : deletePerson(1)
+DeleteCommand -> Model : getFilteredInternshipList()
activate Model
Model --> DeleteCommand
+
+loop internship in internshipsToDelete
+ DeleteCommand -> Model: deleteInternship(internship)
+end
+
deactivate Model
create CommandResult
DeleteCommand -> CommandResult
activate CommandResult
-CommandResult --> DeleteCommand
+CommandResult --> DeleteCommand : cr
deactivate CommandResult
-DeleteCommand --> LogicManager : result
+DeleteCommand --> LogicManager : cr
deactivate DeleteCommand
+DeleteCommand -[hidden]-> LogicManager
+destroy DeleteCommand
+
+destroy InternshipContainsKeywordPredicate
[<--LogicManager
deactivate LogicManager
diff --git a/docs/diagrams/EditActivityDiagram.puml b/docs/diagrams/EditActivityDiagram.puml
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/docs/diagrams/EditSequenceDiagram.puml b/docs/diagrams/EditSequenceDiagram.puml
new file mode 100644
index 00000000000..e2184153a55
--- /dev/null
+++ b/docs/diagrams/EditSequenceDiagram.puml
@@ -0,0 +1,91 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternBuddyParser" as InternBuddyParser LOGIC_COLOR
+participant ":EditCommandParser" as EditCommandParser LOGIC_COLOR
+participant "e:EditCommand" as EditCommand LOGIC_COLOR
+participant "cr:CommandResult" as CommandResult LOGIC_COLOR
+participant ":EditInternshipDescriptor" as Descriptor LOGIC_COLOR
+participant "<> \n EditCommand" as ClassEditCommand LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("edit 2 n/Google")
+activate LogicManager
+
+LogicManager -> InternBuddyParser : parseCommand("edit 2 n/Google")
+activate InternBuddyParser
+
+create EditCommandParser
+InternBuddyParser -> EditCommandParser
+activate EditCommandParser
+
+EditCommandParser --> InternBuddyParser
+deactivate EditCommandParser
+
+InternBuddyParser -> EditCommandParser : parse("2 n/Google")
+activate EditCommandParser
+
+create EditCommand
+EditCommandParser -> EditCommand
+activate EditCommand
+create Descriptor
+EditCommand -> Descriptor
+activate Descriptor
+Descriptor --> EditCommand :
+deactivate Descriptor
+EditCommand --> EditCommandParser : e
+deactivate EditCommand
+
+EditCommandParser --> InternBuddyParser : e
+deactivate EditCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+EditCommandParser -[hidden]-> InternBuddyParser
+destroy EditCommandParser
+
+InternBuddyParser --> LogicManager : e
+deactivate InternBuddyParser
+
+LogicManager -> EditCommand : execute()
+activate EditCommand
+EditCommand -> ClassEditCommand : createEditedInternship(toEdit, editInternshipDescriptor)
+activate ClassEditCommand
+ClassEditCommand -->EditCommand :edited
+deactivate ClassEditCommand
+'EditCommand -> Descriptor
+'activate Descriptor
+'Descriptor --> EditCommand : edited
+'deactivate Descriptor
+'Descriptor -[hidden]-> EditCommand
+'destroy Descriptor
+EditCommand -> Model : setInternship(toEdit, edited)
+activate Model
+
+Model --> EditCommand
+deactivate Model
+EditCommand -> Model : updateSelectedInternship(edited)
+activate Model
+
+Model --> EditCommand
+deactivate Model
+
+create CommandResult
+EditCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> EditCommand
+deactivate CommandResult
+
+EditCommand --> LogicManager : cr
+deactivate EditCommand
+
+[<--LogicManager : cr
+destroy EditCommand
+destroy Descriptor
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/FindSequenceDiagram.puml b/docs/diagrams/FindSequenceDiagram.puml
new file mode 100644
index 00000000000..f117de3256f
--- /dev/null
+++ b/docs/diagrams/FindSequenceDiagram.puml
@@ -0,0 +1,82 @@
+'(@@author kohkaixun)
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternBuddyParser" as InternBuddyParser LOGIC_COLOR
+participant ":FindCommandParser" as FindCommandParser LOGIC_COLOR
+participant "p:InternshipContainsKeywordPredicate" as InternshipContainsKeywordPredicate LOGIC_COLOR
+participant "f:FindCommand" as FindCommand 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("find n/Google")
+activate LogicManager
+
+LogicManager -> InternBuddyParser : parseCommand("find n/Google")
+activate InternBuddyParser
+
+create FindCommandParser
+InternBuddyParser -> FindCommandParser
+activate FindCommandParser
+
+FindCommandParser --> InternBuddyParser
+deactivate FindCommandParser
+
+InternBuddyParser -> FindCommandParser : parse("n/ Google")
+activate FindCommandParser
+
+create InternshipContainsKeywordPredicate
+FindCommandParser -> InternshipContainsKeywordPredicate
+activate InternshipContainsKeywordPredicate
+
+InternshipContainsKeywordPredicate --> FindCommandParser : p
+deactivate InternshipContainsKeywordPredicate
+
+create FindCommand
+FindCommandParser -> FindCommand : FindCommand(p)
+activate FindCommand
+
+FindCommand --> FindCommandParser : f
+deactivate FindCommand
+
+FindCommandParser --> InternBuddyParser : f
+deactivate FindCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+FindCommandParser -[hidden]-> InternBuddyParser
+destroy FindCommandParser
+
+InternBuddyParser --> LogicManager : f
+deactivate InternBuddyParser
+
+LogicManager -> FindCommand : execute()
+activate FindCommand
+
+FindCommand -> Model : updateFilteredInternshipList(p)
+activate Model
+
+Model --> FindCommand
+deactivate Model
+
+create CommandResult
+FindCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> FindCommand
+deactivate CommandResult
+
+FindCommand --> LogicManager : result
+deactivate FindCommand
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+FindCommand -[hidden]-> LogicManager
+destroy FindCommand
+destroy InternshipContainsKeywordPredicate
+
+[<--LogicManager : result
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml
index d4193173e18..1f196f63cd2 100644
--- a/docs/diagrams/LogicClassDiagram.puml
+++ b/docs/diagrams/LogicClassDiagram.puml
@@ -6,13 +6,13 @@ skinparam classBackgroundColor LOGIC_COLOR
package Logic {
-Class AddressBookParser
+Class InternBuddyParser
Class XYZCommand
Class CommandResult
Class "{abstract}\nCommand" as Command
-Class "<>\nLogic" as Logic
+Class "<>\nLogic" as LogicInterface
Class LogicManager
}
@@ -24,11 +24,11 @@ package Storage{
}
Class HiddenOutside #FFFFFF
-HiddenOutside ..> Logic
+HiddenOutside ..> LogicInterface
-LogicManager .right.|> Logic
-LogicManager -right->"1" AddressBookParser
-AddressBookParser ..> XYZCommand : creates >
+LogicManager .right.|> LogicInterface
+LogicManager -right->"1" InternBuddyParser
+InternBuddyParser ..> XYZCommand : creates >
XYZCommand -up-|> Command
LogicManager .left.> Command : executes >
@@ -40,7 +40,7 @@ Command .[hidden]up.> Storage
Command .right.> Model
note right of XYZCommand: XYZCommand = AddCommand, \nFindCommand, etc
-Logic ..> CommandResult
+LogicInterface ..> CommandResult
LogicManager .down.> CommandResult
Command .up.> CommandResult : produces >
@enduml
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 4439108973a..4b47be8810f 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -5,46 +5,48 @@ skinparam arrowColor MODEL_COLOR
skinparam classBackgroundColor MODEL_COLOR
Package Model <>{
-Class "<>\nReadOnlyAddressBook" as ReadOnlyAddressBook
+Class "<>\nReadOnlyInternBuddy" as ReadOnlyInternBuddy
Class "<>\nReadOnlyUserPrefs" as ReadOnlyUserPrefs
-Class "<>\nModel" as Model
-Class AddressBook
+Class "<>\nModel" as ModelInterface
+Class InternBuddy
Class ModelManager
Class UserPrefs
-Class UniquePersonList
-Class Person
-Class Address
-Class Email
-Class Name
-Class Phone
+Class UniqueInternshipList
+Class Internship
+Class Status
+Class Date
+Class CompanyName
+Class Role
+class Comment
Class Tag
}
Class HiddenOutside #FFFFFF
-HiddenOutside ..> Model
+HiddenOutside ..> ModelInterface
-AddressBook .up.|> ReadOnlyAddressBook
+InternBuddy .up.|> ReadOnlyInternBuddy
-ModelManager .up.|> Model
-Model .right.> ReadOnlyUserPrefs
-Model .left.> ReadOnlyAddressBook
-ModelManager -left-> "1" AddressBook
+ModelManager .up.|> ModelInterface
+ModelInterface .right.> ReadOnlyUserPrefs
+ModelInterface .left.> ReadOnlyInternBuddy
+ModelManager -left-> "1" InternBuddy
ModelManager -right-> "1" UserPrefs
UserPrefs .up.|> ReadOnlyUserPrefs
-AddressBook *--> "1" UniquePersonList
-UniquePersonList --> "~* all" Person
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
-Person *--> "*" Tag
+InternBuddy *--> "1" UniqueInternshipList
+UniqueInternshipList --> "~* all" Internship
+Internship *--> CompanyName
+Internship *--> Role
+Internship *--> Date
+Internship *--> Status
+Internship *--> Comment
+Internship *--> "*" Tag
-Name -[hidden]right-> Phone
-Phone -[hidden]right-> Address
-Address -[hidden]right-> Email
+CompanyName -[hidden]right-> Role
+Role -[hidden]right-> Status
+Status -[hidden]right-> Date
-ModelManager -->"~* filtered" Person
+ModelManager -->"~* filtered" Internship
@enduml
diff --git a/docs/diagrams/ParserClasses.puml b/docs/diagrams/ParserClasses.puml
index 0c7424de6e0..f9137798737 100644
--- a/docs/diagrams/ParserClasses.puml
+++ b/docs/diagrams/ParserClasses.puml
@@ -9,7 +9,7 @@ Class XYZCommand
package "Parser classes"{
Class "<>\nParser" as Parser
-Class AddressBookParser
+Class InternBuddyParser
Class XYZCommandParser
Class CliSyntax
Class ParserUtil
@@ -19,12 +19,12 @@ Class Prefix
}
Class HiddenOutside #FFFFFF
-HiddenOutside ..> AddressBookParser
+HiddenOutside ..> InternBuddyParser
-AddressBookParser .down.> XYZCommandParser: creates >
+InternBuddyParser .down.> XYZCommandParser: creates >
XYZCommandParser ..> XYZCommand : creates >
-AddressBookParser ..> Command : returns >
+InternBuddyParser ..> Command : returns >
XYZCommandParser .up.|> Parser
XYZCommandParser ..> ArgumentMultimap
XYZCommandParser ..> ArgumentTokenizer
diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml
index 760305e0e58..12c83691b7f 100644
--- a/docs/diagrams/StorageClassDiagram.puml
+++ b/docs/diagrams/StorageClassDiagram.puml
@@ -11,33 +11,33 @@ Class "<>\nUserPrefsStorage" as UserPrefsStorage
Class JsonUserPrefsStorage
}
-Class "<>\nStorage" as Storage
+Class "<>\nStorage" as StorageInterface
Class StorageManager
-package "AddressBook Storage" #F4F6F6{
-Class "<>\nAddressBookStorage" as AddressBookStorage
-Class JsonAddressBookStorage
-Class JsonSerializableAddressBook
-Class JsonAdaptedPerson
+package "InternBuddy Storage" #F4F6F6{
+Class "<>\nInternBuddyStorage" as InternBuddyStorage
+Class JsonInternBuddyStorage
+Class JsonSerializableInternBuddy
+Class JsonAdaptedInternship
Class JsonAdaptedTag
}
}
Class HiddenOutside #FFFFFF
-HiddenOutside ..> Storage
+HiddenOutside ..> StorageInterface
-StorageManager .up.|> Storage
+StorageManager .up.|> StorageInterface
StorageManager -up-> "1" UserPrefsStorage
-StorageManager -up-> "1" AddressBookStorage
+StorageManager -up-> "1" InternBuddyStorage
-Storage -left-|> UserPrefsStorage
-Storage -right-|> AddressBookStorage
+StorageInterface -left-|> UserPrefsStorage
+StorageInterface -right-|> InternBuddyStorage
JsonUserPrefsStorage .up.|> UserPrefsStorage
-JsonAddressBookStorage .up.|> AddressBookStorage
-JsonAddressBookStorage ..> JsonSerializableAddressBook
-JsonSerializableAddressBook --> "*" JsonAdaptedPerson
-JsonAdaptedPerson --> "*" JsonAdaptedTag
+JsonInternBuddyStorage .up.|> InternBuddyStorage
+JsonInternBuddyStorage ..> JsonSerializableInternBuddy
+JsonSerializableInternBuddy --> "*" JsonAdaptedInternship
+JsonAdaptedInternship --> "*" JsonAdaptedTag
@enduml
diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml
index 95473d5aa19..6e63338b1b0 100644
--- a/docs/diagrams/UiClassDiagram.puml
+++ b/docs/diagrams/UiClassDiagram.puml
@@ -11,10 +11,11 @@ Class UiManager
Class MainWindow
Class HelpWindow
Class ResultDisplay
-Class PersonListPanel
-Class PersonCard
+Class InternshipListPanel
+Class InternshipCard
Class StatusBarFooter
Class CommandBox
+Class InternshipDetailsCard
}
package Model <> {
@@ -32,26 +33,30 @@ UiManager .left.|> Ui
UiManager -down-> "1" MainWindow
MainWindow *-down-> "1" CommandBox
MainWindow *-down-> "1" ResultDisplay
-MainWindow *-down-> "1" PersonListPanel
+MainWindow *-down-> "1" InternshipListPanel
MainWindow *-down-> "1" StatusBarFooter
MainWindow --> "0..1" HelpWindow
+MainWindow *-down-> "0..1" InternshipDetailsCard
-PersonListPanel -down-> "*" PersonCard
+InternshipListPanel -down-> "*" InternshipCard
MainWindow -left-|> UiPart
ResultDisplay --|> UiPart
CommandBox --|> UiPart
-PersonListPanel --|> UiPart
-PersonCard --|> UiPart
+InternshipListPanel --|> UiPart
+InternshipCard --|> UiPart
+InternshipDetailsCard --|> UiPart
StatusBarFooter --|> UiPart
HelpWindow --|> UiPart
-PersonCard ..> Model
+InternshipDetailsCard ...> Model
+InternshipCard ...> Model
+
UiManager -right-> Logic
MainWindow -left-> Logic
-PersonListPanel -[hidden]left- HelpWindow
+InternshipListPanel -[hidden]left- HelpWindow
HelpWindow -[hidden]left- CommandBox
CommandBox -[hidden]left- ResultDisplay
ResultDisplay -[hidden]left- StatusBarFooter
diff --git a/docs/diagrams/UndoRedoState0.puml b/docs/diagrams/UndoRedoState0.puml
index 96e30744d24..b761e07e08c 100644
--- a/docs/diagrams/UndoRedoState0.puml
+++ b/docs/diagrams/UndoRedoState0.puml
@@ -6,15 +6,15 @@ skinparam ClassBorderColor #000000
title Initial state
package States {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab2:AddressBook__"
+ class State1 as "ib0:InternBuddy"
+ class State2 as "ib1:InternBuddy"
+ class State3 as "ib2:InternBuddy"
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
hide State2
hide State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFFFFF
Pointer -up-> State1
@end
diff --git a/docs/diagrams/UndoRedoState1.puml b/docs/diagrams/UndoRedoState1.puml
index 01fcb9b2b96..aac6165d778 100644
--- a/docs/diagrams/UndoRedoState1.puml
+++ b/docs/diagrams/UndoRedoState1.puml
@@ -6,9 +6,9 @@ skinparam ClassBorderColor #000000
title After command "delete 5"
package States <> {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab2:AddressBook__"
+ class State1 as "ib0:InternBuddy"
+ class State2 as "ib1:InternBuddy"
+ class State3 as "ib2:InternBuddy"
}
State1 -[hidden]right-> State2
@@ -16,7 +16,7 @@ State2 -[hidden]right-> State3
hide State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFFFFF
Pointer -up-> State2
@end
diff --git a/docs/diagrams/UndoRedoState2.puml b/docs/diagrams/UndoRedoState2.puml
index bccc230a5d1..8708d39a475 100644
--- a/docs/diagrams/UndoRedoState2.puml
+++ b/docs/diagrams/UndoRedoState2.puml
@@ -3,18 +3,18 @@
skinparam ClassFontColor #000000
skinparam ClassBorderColor #000000
-title After command "add n/David"
+title After command "add n/Tesla"
package States <> {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab2:AddressBook__"
+ class State1 as "ib0:InternBuddy"
+ class State2 as "ib1:InternBuddy"
+ class State3 as "ib2:InternBuddy"
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFFFFF
Pointer -up-> State3
@end
diff --git a/docs/diagrams/UndoRedoState3.puml b/docs/diagrams/UndoRedoState3.puml
index ea29c9483e4..f75f199d98f 100644
--- a/docs/diagrams/UndoRedoState3.puml
+++ b/docs/diagrams/UndoRedoState3.puml
@@ -6,15 +6,15 @@ skinparam ClassBorderColor #000000
title After command "undo"
package States <> {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab2:AddressBook__"
+ class State1 as "ib0:InternBuddy"
+ class State2 as "ib1:InternBuddy"
+ class State3 as "ib2:InternBuddy"
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFFFFF
Pointer -up-> State2
@end
diff --git a/docs/diagrams/UndoRedoState4.puml b/docs/diagrams/UndoRedoState4.puml
index 1b784cece80..73ff37ca27a 100644
--- a/docs/diagrams/UndoRedoState4.puml
+++ b/docs/diagrams/UndoRedoState4.puml
@@ -6,15 +6,15 @@ skinparam ClassBorderColor #000000
title After command "list"
package States <> {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab2:AddressBook__"
+ class State1 as "ib0:InternBuddy"
+ class State2 as "ib1:InternBuddy"
+ class State3 as "ib2:InternBuddy"
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFFFFF
Pointer -up-> State2
@end
diff --git a/docs/diagrams/UndoRedoState5.puml b/docs/diagrams/UndoRedoState5.puml
index 88927be32bc..a1b95f0898c 100644
--- a/docs/diagrams/UndoRedoState5.puml
+++ b/docs/diagrams/UndoRedoState5.puml
@@ -6,16 +6,16 @@ skinparam ClassBorderColor #000000
title After command "clear"
package States <> {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab3:AddressBook__"
+ class State1 as "ib0:InternBuddy"
+ class State2 as "ib1:InternBuddy"
+ class State3 as "ib3:InternBuddy"
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFFFFF
Pointer -up-> State3
-note right on link: State ab2 deleted.
+note right on link: State ib2 deleted.
@end
diff --git a/docs/diagrams/UndoSequenceDiagram.puml b/docs/diagrams/UndoSequenceDiagram.puml
index 410aab4e412..9fbc8cce56e 100644
--- a/docs/diagrams/UndoSequenceDiagram.puml
+++ b/docs/diagrams/UndoSequenceDiagram.puml
@@ -3,42 +3,42 @@
box Logic LOGIC_COLOR_T1
participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":InternBuddyParser" as InternBuddyParser LOGIC_COLOR
participant "u:UndoCommand" as UndoCommand LOGIC_COLOR
end box
box Model MODEL_COLOR_T1
participant ":Model" as Model MODEL_COLOR
-participant ":VersionedAddressBook" as VersionedAddressBook MODEL_COLOR
+participant ":VersionedInternBuddy" as VersionedInternBuddy MODEL_COLOR
end box
[-> LogicManager : execute(undo)
activate LogicManager
-LogicManager -> AddressBookParser : parseCommand(undo)
-activate AddressBookParser
+LogicManager -> InternBuddyParser : parseCommand(undo)
+activate InternBuddyParser
create UndoCommand
-AddressBookParser -> UndoCommand
+InternBuddyParser -> UndoCommand
activate UndoCommand
-UndoCommand --> AddressBookParser
+UndoCommand --> InternBuddyParser
deactivate UndoCommand
-AddressBookParser --> LogicManager : u
-deactivate AddressBookParser
+InternBuddyParser --> LogicManager : u
+deactivate InternBuddyParser
LogicManager -> UndoCommand : execute()
activate UndoCommand
-UndoCommand -> Model : undoAddressBook()
+UndoCommand -> Model : undoInternBuddy()
activate Model
-Model -> VersionedAddressBook : undo()
-activate VersionedAddressBook
+Model -> VersionedInternBuddy : undo()
+activate VersionedInternBuddy
-VersionedAddressBook -> VersionedAddressBook :resetData(ReadOnlyAddressBook)
-VersionedAddressBook --> Model :
-deactivate VersionedAddressBook
+VersionedInternBuddy -> VersionedInternBuddy :resetData(ReadOnlyInternBuddy)
+VersionedInternBuddy --> Model :
+deactivate VersionedInternBuddy
Model --> UndoCommand
deactivate Model
diff --git a/docs/diagrams/UpcomingSequenceDiagram.puml b/docs/diagrams/UpcomingSequenceDiagram.puml
new file mode 100644
index 00000000000..cde144a6979
--- /dev/null
+++ b/docs/diagrams/UpcomingSequenceDiagram.puml
@@ -0,0 +1,54 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternBuddyParser" as InternBuddyParser LOGIC_COLOR
+participant "u:UpcomingCommand" as UpcomingCommand LOGIC_COLOR
+participant "cr:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+[-> LogicManager : execute("upcoming")
+activate LogicManager
+
+LogicManager -> InternBuddyParser : parseCommand("upcoming")
+activate InternBuddyParser
+
+create UpcomingCommand
+InternBuddyParser -> UpcomingCommand
+activate UpcomingCommand
+
+UpcomingCommand -->InternBuddyParser : u
+deactivate UpcomingCommand
+
+InternBuddyParser --> LogicManager : u
+
+deactivate InternBuddyParser
+
+LogicManager -> UpcomingCommand : execute()
+activate UpcomingCommand
+
+UpcomingCommand -> Model : updateFilteredInternshipList(predicate)
+activate Model
+
+Model --> UpcomingCommand
+deactivate Model
+
+create CommandResult
+UpcomingCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> UpcomingCommand
+deactivate CommandResult
+
+UpcomingCommand --> LogicManager : cr
+deactivate UpcomingCommand
+
+[<--LogicManager : cr
+destroy UpcomingCommand
+deactivate LogicManager
+
+@enduml
diff --git a/docs/diagrams/ViewActivityDiagram.puml b/docs/diagrams/ViewActivityDiagram.puml
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/docs/diagrams/ViewSequenceDiagram.puml b/docs/diagrams/ViewSequenceDiagram.puml
new file mode 100644
index 00000000000..f0105836b1c
--- /dev/null
+++ b/docs/diagrams/ViewSequenceDiagram.puml
@@ -0,0 +1,81 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InternBuddyParser" as InternBuddyParser LOGIC_COLOR
+participant ":ViewCommandParser" as ViewCommandParser LOGIC_COLOR
+participant "v:ViewCommand" as ViewCommand LOGIC_COLOR
+participant "<>\nParserUtil" as ParserUtil LOGIC_COLOR
+participant "cr:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+[-> LogicManager : execute("view 1")
+activate LogicManager
+
+LogicManager -> InternBuddyParser : parseCommand("view 1")
+activate InternBuddyParser
+
+create ViewCommandParser
+InternBuddyParser -> ViewCommandParser
+activate ViewCommandParser
+
+ViewCommandParser --> InternBuddyParser
+deactivate ViewCommandParser
+
+InternBuddyParser -> ViewCommandParser : parse("1")
+activate ViewCommandParser
+
+ViewCommandParser -> ParserUtil : parseIndex("1")
+activate ParserUtil
+
+ParserUtil --> ViewCommandParser : indexObject
+deactivate ParserUtil
+
+create ViewCommand
+ViewCommandParser -> ViewCommand : ViewCommand(indexObject)
+activate ViewCommand
+
+ViewCommand --> ViewCommandParser
+deactivate ViewCommand
+
+ViewCommandParser --> InternBuddyParser : v
+deactivate ViewCommandParser
+
+InternBuddyParser --> LogicManager : v
+destroy ViewCommandParser
+deactivate InternBuddyParser
+
+LogicManager -> ViewCommand : execute()
+activate ViewCommand
+
+ViewCommand -> Model : getFilteredInternshipList()
+activate Model
+
+Model --> ViewCommand : filteredInternshipList
+deactivate Model
+
+ViewCommand -> Model : updateSelectedInternship(retrievedInternship)
+activate Model
+
+Model --> ViewCommand
+deactivate Model
+
+create CommandResult
+ViewCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> ViewCommand
+deactivate CommandResult
+
+ViewCommand --> LogicManager : cr
+deactivate ViewCommand
+
+[<--LogicManager : cr
+destroy ViewCommand
+deactivate LogicManager
+
+@enduml
diff --git a/docs/images/AddSequenceDiagram.png b/docs/images/AddSequenceDiagram.png
new file mode 100644
index 00000000000..a631e385440
Binary files /dev/null and b/docs/images/AddSequenceDiagram.png differ
diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png
index 2f1346869d0..02a29078513 100644
Binary files a/docs/images/ArchitectureSequenceDiagram.png and b/docs/images/ArchitectureSequenceDiagram.png differ
diff --git a/docs/images/BetterModelClassDiagram.png b/docs/images/BetterModelClassDiagram.png
index 94440f0ac4a..7ad7ea85fc5 100644
Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ
diff --git a/docs/images/Clear-entries-warning-message.png b/docs/images/Clear-entries-warning-message.png
new file mode 100644
index 00000000000..d51cd78c10c
Binary files /dev/null and b/docs/images/Clear-entries-warning-message.png differ
diff --git a/docs/images/CommitActivityDiagram.png b/docs/images/CommitActivityDiagram.png
index c08c13f5c8b..0bf974108c8 100644
Binary files a/docs/images/CommitActivityDiagram.png and b/docs/images/CommitActivityDiagram.png differ
diff --git a/docs/images/CopySequenceDiagram.png b/docs/images/CopySequenceDiagram.png
new file mode 100644
index 00000000000..f6967f0388b
Binary files /dev/null and b/docs/images/CopySequenceDiagram.png differ
diff --git a/docs/images/DeleteFieldSequenceDiagram.png b/docs/images/DeleteFieldSequenceDiagram.png
new file mode 100644
index 00000000000..732eb079266
Binary files /dev/null and b/docs/images/DeleteFieldSequenceDiagram.png differ
diff --git a/docs/images/DeleteIndexSequenceDiagram.png b/docs/images/DeleteIndexSequenceDiagram.png
new file mode 100644
index 00000000000..7dfdec79f56
Binary files /dev/null and b/docs/images/DeleteIndexSequenceDiagram.png differ
diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png
index fa327b39618..888f97d6f50 100644
Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ
diff --git a/docs/images/EditSequenceDiagram.png b/docs/images/EditSequenceDiagram.png
new file mode 100644
index 00000000000..f639d077453
Binary files /dev/null and b/docs/images/EditSequenceDiagram.png differ
diff --git a/docs/images/Edit_data_warning_message.png b/docs/images/Edit_data_warning_message.png
new file mode 100644
index 00000000000..dce1664c904
Binary files /dev/null and b/docs/images/Edit_data_warning_message.png differ
diff --git a/docs/images/FindSequenceDiagram.png b/docs/images/FindSequenceDiagram.png
new file mode 100644
index 00000000000..809c9482680
Binary files /dev/null and b/docs/images/FindSequenceDiagram.png differ
diff --git a/docs/images/InternBuddy GUI Markup.pptx b/docs/images/InternBuddy GUI Markup.pptx
new file mode 100644
index 00000000000..8f730640519
Binary files /dev/null and b/docs/images/InternBuddy GUI Markup.pptx differ
diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png
index 9e9ba9f79e5..35138ee640d 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 04070af60d8..a8d8f85c68d 100644
Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ
diff --git a/docs/images/ParserClasses.png b/docs/images/ParserClasses.png
index e7b4c8880cd..1122156e804 100644
Binary files a/docs/images/ParserClasses.png and b/docs/images/ParserClasses.png differ
diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png
index 2533a5c1af0..8d104730243 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..b9c9b4ad935 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 785e04dbab4..cea4068044b 100644
Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ
diff --git a/docs/images/UndoRedoState0.png b/docs/images/UndoRedoState0.png
index 8f7538cd884..7812a55d57d 100644
Binary files a/docs/images/UndoRedoState0.png and b/docs/images/UndoRedoState0.png differ
diff --git a/docs/images/UndoRedoState1.png b/docs/images/UndoRedoState1.png
index df9908d0948..e214456808d 100644
Binary files a/docs/images/UndoRedoState1.png and b/docs/images/UndoRedoState1.png differ
diff --git a/docs/images/UndoRedoState2.png b/docs/images/UndoRedoState2.png
index 36519c1015b..8485ecb2d6c 100644
Binary files a/docs/images/UndoRedoState2.png and b/docs/images/UndoRedoState2.png differ
diff --git a/docs/images/UndoRedoState3.png b/docs/images/UndoRedoState3.png
index 19959d01712..94f1763743b 100644
Binary files a/docs/images/UndoRedoState3.png and b/docs/images/UndoRedoState3.png differ
diff --git a/docs/images/UndoRedoState4.png b/docs/images/UndoRedoState4.png
index 4c623e4f2c5..be74bf157b6 100644
Binary files a/docs/images/UndoRedoState4.png and b/docs/images/UndoRedoState4.png differ
diff --git a/docs/images/UndoRedoState5.png b/docs/images/UndoRedoState5.png
index 84ad2afa6bd..0977b7cf5e2 100644
Binary files a/docs/images/UndoRedoState5.png and b/docs/images/UndoRedoState5.png differ
diff --git a/docs/images/UndoSequenceDiagram.png b/docs/images/UndoSequenceDiagram.png
index 6addcd3a8d9..7eb6ca91857 100644
Binary files a/docs/images/UndoSequenceDiagram.png and b/docs/images/UndoSequenceDiagram.png differ
diff --git a/docs/images/UpcomingSequenceDiagram.png b/docs/images/UpcomingSequenceDiagram.png
new file mode 100644
index 00000000000..04d9ea7cf8d
Binary files /dev/null and b/docs/images/UpcomingSequenceDiagram.png differ
diff --git a/docs/images/ViewSequenceDiagram.png b/docs/images/ViewSequenceDiagram.png
new file mode 100644
index 00000000000..d269dfe09cd
Binary files /dev/null and b/docs/images/ViewSequenceDiagram.png differ
diff --git a/docs/images/derricksaltfish.png b/docs/images/derricksaltfish.png
new file mode 100644
index 00000000000..39d00073762
Binary files /dev/null and b/docs/images/derricksaltfish.png differ
diff --git a/docs/images/dg-case-insensitive-add-after.png b/docs/images/dg-case-insensitive-add-after.png
new file mode 100644
index 00000000000..da5dc0b56e9
Binary files /dev/null and b/docs/images/dg-case-insensitive-add-after.png differ
diff --git a/docs/images/dg-case-insensitive-add-before.png b/docs/images/dg-case-insensitive-add-before.png
new file mode 100644
index 00000000000..7d18bc6af0f
Binary files /dev/null and b/docs/images/dg-case-insensitive-add-before.png differ
diff --git a/docs/images/dg-case-insensitive-prefix-fix.png b/docs/images/dg-case-insensitive-prefix-fix.png
new file mode 100644
index 00000000000..f98afdab898
Binary files /dev/null and b/docs/images/dg-case-insensitive-prefix-fix.png differ
diff --git a/docs/images/dg-case-sensitive-find-after.png b/docs/images/dg-case-sensitive-find-after.png
new file mode 100644
index 00000000000..ec1cffc2ab5
Binary files /dev/null and b/docs/images/dg-case-sensitive-find-after.png differ
diff --git a/docs/images/dg-case-sensitive-find-before.png b/docs/images/dg-case-sensitive-find-before.png
new file mode 100644
index 00000000000..3a7ecbb2fd3
Binary files /dev/null and b/docs/images/dg-case-sensitive-find-before.png differ
diff --git a/docs/images/dg-case-sensitive-prefix-add-example.png b/docs/images/dg-case-sensitive-prefix-add-example.png
new file mode 100644
index 00000000000..4464a99bc8c
Binary files /dev/null and b/docs/images/dg-case-sensitive-prefix-add-example.png differ
diff --git a/docs/images/dg-int-overflow-problem.png b/docs/images/dg-int-overflow-problem.png
new file mode 100644
index 00000000000..8a54a125d98
Binary files /dev/null and b/docs/images/dg-int-overflow-problem.png differ
diff --git a/docs/images/dg-int-overflow-solution.png b/docs/images/dg-int-overflow-solution.png
new file mode 100644
index 00000000000..cf9f8e87a58
Binary files /dev/null and b/docs/images/dg-int-overflow-solution.png differ
diff --git a/docs/images/dg-negative-int-overflow-solved.png b/docs/images/dg-negative-int-overflow-solved.png
new file mode 100644
index 00000000000..7b3a430603a
Binary files /dev/null and b/docs/images/dg-negative-int-overflow-solved.png differ
diff --git a/docs/images/dg-positive-int-overflow-solved.png b/docs/images/dg-positive-int-overflow-solved.png
new file mode 100644
index 00000000000..95a382ebbe4
Binary files /dev/null and b/docs/images/dg-positive-int-overflow-solved.png differ
diff --git a/docs/images/eugenetangkj.png b/docs/images/eugenetangkj.png
new file mode 100644
index 00000000000..b5c4177c0c9
Binary files /dev/null and b/docs/images/eugenetangkj.png differ
diff --git a/docs/images/github-raw.png b/docs/images/github-raw.png
new file mode 100644
index 00000000000..9dbac9423cc
Binary files /dev/null and b/docs/images/github-raw.png differ
diff --git a/docs/images/gui-markup.png b/docs/images/gui-markup.png
new file mode 100644
index 00000000000..23ae6fcc5fb
Binary files /dev/null and b/docs/images/gui-markup.png differ
diff --git a/docs/images/help-window-changes.png b/docs/images/help-window-changes.png
new file mode 100644
index 00000000000..0bd4c172262
Binary files /dev/null and b/docs/images/help-window-changes.png differ
diff --git a/docs/images/internbuddy-computer.png b/docs/images/internbuddy-computer.png
new file mode 100644
index 00000000000..e1724bc0a1e
Binary files /dev/null and b/docs/images/internbuddy-computer.png differ
diff --git a/docs/images/internbuddy-help.png b/docs/images/internbuddy-help.png
new file mode 100644
index 00000000000..507a3b94b23
Binary files /dev/null and b/docs/images/internbuddy-help.png differ
diff --git a/docs/images/internbuddy-hero.png b/docs/images/internbuddy-hero.png
new file mode 100644
index 00000000000..c178020de00
Binary files /dev/null and b/docs/images/internbuddy-hero.png differ
diff --git a/docs/images/internbuddy-json-sample.png b/docs/images/internbuddy-json-sample.png
new file mode 100644
index 00000000000..a64e66a65f8
Binary files /dev/null and b/docs/images/internbuddy-json-sample.png differ
diff --git a/docs/images/internbuddy-logo.png b/docs/images/internbuddy-logo.png
new file mode 100644
index 00000000000..fff09590835
Binary files /dev/null and b/docs/images/internbuddy-logo.png differ
diff --git a/docs/images/kohkaixun.png b/docs/images/kohkaixun.png
new file mode 100644
index 00000000000..961179aec90
Binary files /dev/null and b/docs/images/kohkaixun.png differ
diff --git a/docs/images/potty10.png b/docs/images/potty10.png
new file mode 100644
index 00000000000..14d133f9e39
Binary files /dev/null and b/docs/images/potty10.png differ
diff --git a/docs/images/seadragon2000341.png b/docs/images/seadragon2000341.png
new file mode 100644
index 00000000000..f9be5af883f
Binary files /dev/null and b/docs/images/seadragon2000341.png differ
diff --git a/docs/images/team-mascots/InternBuddyArtist.png b/docs/images/team-mascots/InternBuddyArtist.png
new file mode 100644
index 00000000000..13f64e2db6f
Binary files /dev/null and b/docs/images/team-mascots/InternBuddyArtist.png differ
diff --git a/docs/images/ug-add-example.png b/docs/images/ug-add-example.png
new file mode 100644
index 00000000000..d27e55180cf
Binary files /dev/null and b/docs/images/ug-add-example.png differ
diff --git a/docs/images/ug-appendix-b-json-change.png b/docs/images/ug-appendix-b-json-change.png
new file mode 100644
index 00000000000..604bd3ccd07
Binary files /dev/null and b/docs/images/ug-appendix-b-json-change.png differ
diff --git a/docs/images/ug-appendix-b-json-example.png b/docs/images/ug-appendix-b-json-example.png
new file mode 100644
index 00000000000..917979e87dc
Binary files /dev/null and b/docs/images/ug-appendix-b-json-example.png differ
diff --git a/docs/images/ug-clear-example.png b/docs/images/ug-clear-example.png
new file mode 100644
index 00000000000..6272aa6defd
Binary files /dev/null and b/docs/images/ug-clear-example.png differ
diff --git a/docs/images/ug-delete-example.png b/docs/images/ug-delete-example.png
new file mode 100644
index 00000000000..5c21cf1c456
Binary files /dev/null and b/docs/images/ug-delete-example.png differ
diff --git a/docs/images/ug-edit-example.png b/docs/images/ug-edit-example.png
new file mode 100644
index 00000000000..19076f27e4b
Binary files /dev/null and b/docs/images/ug-edit-example.png differ
diff --git a/docs/images/ug-find-example.png b/docs/images/ug-find-example.png
new file mode 100644
index 00000000000..f9207a01fca
Binary files /dev/null and b/docs/images/ug-find-example.png differ
diff --git a/docs/images/ug-help-window.png b/docs/images/ug-help-window.png
new file mode 100644
index 00000000000..430e491d683
Binary files /dev/null and b/docs/images/ug-help-window.png differ
diff --git a/docs/images/ug-navigate-commands.png b/docs/images/ug-navigate-commands.png
new file mode 100644
index 00000000000..963f9861c86
Binary files /dev/null and b/docs/images/ug-navigate-commands.png differ
diff --git a/docs/images/ug-view-example.png b/docs/images/ug-view-example.png
new file mode 100644
index 00000000000..fc6c40d409f
Binary files /dev/null and b/docs/images/ug-view-example.png differ
diff --git a/docs/images/ui-changes.png b/docs/images/ui-changes.png
new file mode 100644
index 00000000000..ee8c041acdd
Binary files /dev/null and b/docs/images/ui-changes.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..9e553003285 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,19 +1,38 @@
---
layout: page
-title: AddressBook Level-3
+title: InternBuddy
---
+[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/AY2223S2-CS2103T-T14-3/tp/actions)
+[![codecov](https://codecov.io/gh/AY2223S2-CS2103T-T14-3/tp/branch/master/graph/badge.svg)](https://codecov.io/gh/AY2223S2-CS2103T-T14-3/tp)
+
-[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions)
-[![codecov](https://codecov.io/gh/se-edu/addressbook-level3/branch/master/graph/badge.svg)](https://codecov.io/gh/se-edu/addressbook-level3)
![Ui](images/Ui.png)
-**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).
+InternBuddy is a desktop application for Computing undergraduates to manage their internship applications.
+It is optimized for typing where it allows you to complete internship management tasks much more efficiently
+via the keyboard as compared to using traditional Graphical User Interface (GUI) applications.
+If you are a fast typist who is seeking a one-stop platform to systematically organise your internship
+applications, then InternBuddy is the perfect buddy to accompany you during your internship hunt.
+
+InternBuddy runs using Java 11, and is available on the Windows, macOS and Linux operating systems.
+
-* 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.
+* If you are interested in using InternBuddy, head over to the [_Quick Start_ section of the **User Guide**](https://ay2223s2-cs2103t-t14-3.github.io/tp/UserGuide.html#quick-start).
+* If you are interested about developing InternBuddy, the [**Developer Guide**](https://ay2223s2-cs2103t-t14-3.github.io/tp/DeveloperGuide.html) is a good place to start.
-**Acknowledgements**
+## Acknowledgements
-* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5)
+* InternBuddy is written in **Java 11**.
+* It is adapted from the [AddressBook Level 3](https://github.com/se-edu/addressbook-level3) project created by
+ the [SE-EDU initiative](https://se-education.org).
+* Libraries and frameworks used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson),
+ [JUnit5](https://github.com/junit-team/junit5) and [TestFX](https://github.com/TestFX/TestFX).
+* GUI testing is implemented with references from [AddressBook Level 4](https://github.com/se-edu/addressbook-level4)
+ and [Please Hire Us](https://github.com/AY2223S1-CS2103T-W17-4/tp). We utilised code from these projects to set
+ up GUI testing and added our own test cases to test the UI components that we created.
+* The feature of Navigating Through Past Commands is primarily adapted from [HackNet](https://github.com/AY2122S2-CS2103T-W13-3/tp),
+ but we added code modifications and test cases.
+* The sections on explaining the formatting standards and GUI interface in the User and Developer Guides are
+ inspired by [Please Hire Us](https://github.com/AY2223S1-CS2103T-W17-4/tp).
diff --git a/docs/team/derricksaltfish.md b/docs/team/derricksaltfish.md
new file mode 100644
index 00000000000..6a5cccad5d4
--- /dev/null
+++ b/docs/team/derricksaltfish.md
@@ -0,0 +1,51 @@
+---
+layout: page
+title: Ou Chuhao's Project Portfolio Page
+---
+
+### Project: InternBuddy
+
+InternBuddy provides a 1-stop platform for Computing undergraduates to manage and track their internship applications. It is optimized for typing which Computing undergraduates are comfortable and proficient in, allowing them to fully and efficiently exploit the application’s organisational capabilities.
+The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
+
+Given below are my contributions to the project.
+
+* **Code contributed**:
+My code contributions can be found on:
+[RepoSense link](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=derricksaltfish&breakdown=true)
+
+
+## Feature and Enhancements
+
+* **New Feature**: Added `copy` command [#130](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/130)
+ * What it does: Allows users to copy the information of an internship entry onto the clipboard of the computer.
+ * Justification:
+ * Uses `SwingUtilities.invokeLater()` to wrap the clipboard code in a `Runnable` object, ensures the clipboard operation to be safe to run from a test or other non-GUI context.
+
+* **Enhancements to existing features**:
+ * Update help information for the help box opened by command `help` and click on the Help button [#59](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/59)
+ * Update Load Data feature to fit for InternBuddy [#59](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/59)
+
+**Project Management**
+* Reviewed and approved pull requests for merging.
+* Testing of InternBuddy releases after each version evolution.
+
+## Documentation
+
+**Documentation**
+* Side-Wide settings:
+ * Update site-wide settings in `[JAR file location]\docs\_config.yml` and `[JAR file location]\docs\index.md` [#19](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/19)
+* User Guide:
+ * Initial update of command `exit`, Save data and Load data contents [#28](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/28)
+ * Update descriptions for Load data [#51](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/51)
+ * Update descriptions for Edit data [#51](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/51)
+ * Update descriptions for Clearing all Internship entries [#51](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/51)
+* Developer Guide:
+ * Update content in common classes and AddressBook related content to InternBuddy [#99](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/99)
+ * Update of `copy` command with inclusion of UML sequence diagrams [#205](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/205)
+ * Update appendix A content [#104](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/104)
+
+## Others
+
+**Community**
+* PRs reviewed (with non-trivial review comments): [#33](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/33) [#204](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/204)
diff --git a/docs/team/eugenetangkj.md b/docs/team/eugenetangkj.md
new file mode 100644
index 00000000000..93b848a48ba
--- /dev/null
+++ b/docs/team/eugenetangkj.md
@@ -0,0 +1,101 @@
+---
+layout: page
+title: Eugene Tang's Project Portfolio Page
+---
+
+## About InternBuddy
+InternBuddy is a desktop application for Computing undergraduates to manage their internship applications.
+It is optimized for typing where it allows you to complete internship management tasks much more efficiently
+via the keyboard as compared to using traditional Graphical User Interface (GUI) applications.
+
+## Project Contributions
+My code contributions can be found on
+[RepoSense](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=eugenetangkj&breakdown=true&sort=groupTitle&sortWithin=title&since=2023-02-17&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other).
+
+### Features and Enhancement
+- **Refactored code to adapt the content of AB3 to the context of InternBuddy**
+ [\#37](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/37)
+ * Renamed classes and packages, such as from `Person` to `Internship`.
+ * Renamed variables.
+ * Redefined test cases to suit the context of internships instead of persons.
+
+- **Redesigned the GUI of InternBuddy**
+ [\#52](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/52),
+ [\#78](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/78),
+ [\#191](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/191)
+ * Created a new look for the List Panel.
+ * Implemented a new responsive View Panel for the viewing of internship information.
+
+- **Implemented feature to add optional field,** `COMMENT`
+ [\#79](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/79)
+ * Users can now add an optional comment to an internship entry via the `add` command.
+ * Editing of comments is made possible via the `edit` command.
+ * If the user did not include a value for the comment, the comment will have a default value of `NA`.
+ * Added test cases accordingly, such as in the class `CommentTest`.
+
+
+
+- **Implemented the** `view` **command**
+ [\#78](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/78)
+ * Users can now view the detailed information of a selected internship entry.
+ * Details are displayed in the View Panel.
+ * Apart from showing the internship information, I added a tips box that will appear
+ below the internship information. The contents of the tips box will change depending
+ on the status of the internship entry.
+ * Added test cases accordingly, such as in the class `InternshipDetailsCardTest`.
+
+- **Redesigned the Help Window**
+ [\#81](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/81)
+ [\#132](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/132)
+ * Inserted the command summary and hyperlink to InternBuddy's user guide in the Help Window.
+ * Created a new look for the Help Window.
+
+- **Co-implemented GUI testing for InternBuddy**
+ [\#52](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/52)
+ * With code references from [AddressBook Level 4](https://github.com/se-edu/addressbook-level4)
+ and [Please Hire Us](https://github.com/AY2223S1-CS2103T-W17-4/tp), I managed to implement
+ test cases for UI components such as in the class `InternshipCardTest`.
+ * Worked with my teammate, Christopher, to implement this.
+ * GUI testing improved code coverage for InternBuddy.
+
+### Documentation
+
+- **Contributed to User Guide**
+ [\#21](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/21),
+ [\#34](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/34),
+ [\#102](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/102),
+ [\#109](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/109),
+ [\#204](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/204)
+ * Documented the explanation for the different parts in InternBuddy's GUI.
+ * Wrote up the command information, explaining the format and constraints of commands and
+ fields in InternBuddy.
+ * Responsible for the write-up of the `list`, `add`, `view`, `help` and `exit` commands.
+ * Created the appendices to explain to users how to install Java 11, manually edit the `internbuddy.json` file
+ and populate InternBuddy with sample data.
+- **Contributed to Developer Guide**
+ [\#23](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/23),
+ [\#82](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/82),
+ [\#84](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/84),
+ [\#86](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/86),
+ [\#119](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/119)
+ * Explained implementation and design considerations for `add` and `view` commands, supplementing the explanations with sequence diagrams.
+ * Defined product scope by identifying InternBuddy's target audience and value proposition, as well as drafted user stories.
+ * Added test cases for instructions on manual testing, such as for the `add` and `view` commands.
+
+### Others
+- Provided non-trivial PR reviews for
+ [\#47](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/47),
+ [\#80](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/80),
+ [\#100](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/100),
+ [\#201](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/201).
+- Designed the logo for InternBuddy.
+- Contributed to CS2103T forum discussions for
+ [\#45](https://github.com/nus-cs2103-AY2223S2/forum/issues/45),
+ [\#99](https://github.com/nus-cs2103-AY2223S2/forum/issues/99),
+ [\#177](https://github.com/nus-cs2103-AY2223S2/forum/issues/177),
+ [\#252](https://github.com/nus-cs2103-AY2223S2/forum/issues/252),
+ [\#254](https://github.com/nus-cs2103-AY2223S2/forum/issues/254),
+ [\#266](https://github.com/nus-cs2103-AY2223S2/forum/issues/266),
+ [\#319](https://github.com/nus-cs2103-AY2223S2/forum/issues/319),
+ [\#322](https://github.com/nus-cs2103-AY2223S2/forum/issues/322).
+
diff --git a/docs/team/kohkaixun.md b/docs/team/kohkaixun.md
new file mode 100644
index 00000000000..3b3e629e7d4
--- /dev/null
+++ b/docs/team/kohkaixun.md
@@ -0,0 +1,54 @@
+---
+layout: page
+title: Kai Xun's Project Portfolio Page
+---
+
+### Project: InternBuddy
+
+InternBuddy provides a 1-stop platform for Computing undergraduates to manage and track their internship applications. It is optimized for typing which Computing undergraduates are comfortable and proficient in, allowing them to fully and efficiently exploit the application’s organisational capabilities.
+The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
+
+My code contributions can be found [here](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=kohkaixun&breakdown=true&sort=groupTitle%20dsc&sortWithin=title&since=2023-02-17&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other) on RepoSense.
+
+#### Features and Enhancements
+
+* **New Feature**: Implemented multiple iterations of the `find` command [#50](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/50) [#58](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/58) [#89](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/89)
+ * What it does:
+ * The first iteration of the `find` command [#50](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/50) would look for all internship with the matching `COMPANY NAME`, `STATUS` and `TAG` fields. Other than the `TAG` field, fields with multiple instances in the input only had the last instance considered.
+ * The second iteration [#58](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/58) took into account the `ROLE` field as well when searching for internships. InternBuddy also now took into consideration multiple instances for every field.
+ * The third iteration [#89](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/89) could now take into account the `DATE` field as well. Matching of user input to internship field was also changed to an exact but case-insensitive match.
+ * Justification
+ * In the first iteration [#50](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/50), if InternBuddy has a long list of internship entries, the user can quickly look for the desired entry using the `find` command instead of manually going through the entire list.
+ * In the second iteration [#58](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/58), the user can just enter one `find` command to search for entries with different information in the same field and compare them all on the same screen, instead of entering multiple `find` commands and being unable to view all these entries altogether at once.
+ * In the third iteration [#89](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/89), exact matching between inputs and internship fields will streamline search results, instead of keyword matching where entries could be filtered out due to a matching with a non-essential keyword within the input.
+
+* **New Feature**: Save past user input [#144](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/144)
+ * What it does: Keeps a record of all user input in the current run of InternBuddy and allows user to navigate through them using the up and down arrow keys.
+ * Justification:
+ * If the user is trying to enter multiple similar commands, after entering the first command, he or she can simply use the up arrow key to retrieve the last inputted command and make a quick edit instead of typing the whole command again.
+ * Suppose there was a past input that was of the wrong format, the user would be able to navigate to it and make edits before entering instead of typing everything out again
+
+* **Enhancements to existing features**:
+ * Made displayed indexing error messages more specific. [#131](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/131) [#133](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/133) [#216](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/216)
+ * Addressed integer overflow bug in displayed error messages, but enhancement was not merged after discovering it violated feature freeze. [#194](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/194)
+
+**Project Management**
+* Set up certain issues.
+* Reviewed and approved pull requests for merging.
+* Testing of InternBuddy releases on MacOS environment.
+
+**Documentation**
+* User Guide:
+ * Initial update of `list` and `delete` commands [#32](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/32)
+ * Update of `find` command according to new implementation [#123](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/123)
+ * Add and update of navigating through command history section [#149](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/149) [#202](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/202)
+* Developer Guide:
+ * Wrote use cases for `list` command [#30](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/30)
+ * Wrote use cases for `edit` command [#30](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/30)
+ * Update of `find` command with inclusion of UML sequence diagrams [#88](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/88) [#90](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/90) [#95](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/95) [#123](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/123) [#203](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/203)
+ * Update set up and get started section [#107](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/107)
+ * Wrote design tweaks addressing bugs found in PE dry run [#202](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/202/files#diff-b50feaf9240709b6b02fb9584696b012c2a69feeba89e409952cc2f401f373fb)
+
+**Community**
+* PRs reviewed (with non-trivial review comments): [#79](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/79), [#80](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/80)
+* Contributed to forum discussions (example: [1](https://github.com/nus-cs2103-AY2223S2/forum/issues/340))
diff --git a/docs/team/potty10.md b/docs/team/potty10.md
new file mode 100644
index 00000000000..bc8e3bff4c6
--- /dev/null
+++ b/docs/team/potty10.md
@@ -0,0 +1,77 @@
+---
+layout: page
+title: Christopher's Project Portfolio Page
+---
+
+### Project: InternBuddy
+
+InternBuddy provides a 1-stop platform for Computing undergraduates to manage and track their internship applications. It is optimized for typing which Computing undergraduates are comfortable and proficient in, allowing them to fully and efficiently exploit the application’s organisational capabilities.
+The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
+
+## Project Contributions
+My code contributions can be found on
+[RepoSense](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=potty10&breakdown=true)
+
+
+### Features and Enhancement
+
+* **New Feature**: Refactored `delete` as `delete-index` command [#100](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/100)
+ * What it does: Allows users to delete multiple internships by their indexes.
+ * Justification: This feature allows the user to clear delete multiple internships from the list at once, instead of entering `delete` multiple times. Users can then
+ keep their internship list nice and tidy.
+* **New Feature**: Added `delete-field` command [#100](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/100)
+ * What it does: Allows users to delete multiple internships by their fields.
+ * Justification: Users may want to mass delete internships from the list when internship application season is over, but still want to archive some for future reference. It is an improvement over `clear`, which deletes all internship entries.
+
+* **Co-implemented GUI testing for InternBuddy**
+ [\#198](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/198),
+ [\#57](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/57)
+ * With code references from [AB4](https://github.com/se-edu/addressbook-level4)
+ and [Please Hire Us](https://github.com/AY2223S1-CS2103T-W17-4/tp), I managed to implement
+ test cases for UI components such as in the class `InternshipCardTest` and `CommandBoxTest`.
+ * Worked with my teammate, Eugene, to implement this.
+ * GUI testing improved code coverage for InternBuddy.
+
+
+
+* **Enhancements to existing features**:
+ * Added date labels to UI, so that users understand what the dates mean. [\#57](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/57), [\#138](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/138)
+ * Added a feature where clicking on an internship entry updates the right panel with the selected internship. [\#150](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/150)
+ * Refactored Status as a set of final constant strings, mitigating misuse of Status strings. [\#57](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/57)
+ * Fixed a bug where the right panel does not reset after clear. [\##128](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/128)
+
+### Documentation
+
+* **About Us page**
+ [\#18](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/18)
+ * Collected my team photos and drafted the About Us page.
+
+* **Project management**:
+ * Managed release v1.3.2 on GitHub.
+ * PRs reviewed (with non-trivial review comments):
+ [\#118](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/118),
+ [\#58](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/58),
+ [\#32](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/32),
+ [\#30](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/30),
+ [\#20](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/20)
+
+* **Documentation**:
+ * User Guide:
+ * Contributed to Introduction, Quick Start, Notes about Features, FAQ [\#26](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/26)
+ * Contributed to implementation of `delete-index` command [\#121](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/121)
+ * Contributed to implementation of `delete-field` command [\#121](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/121)
+ * Fixed UG bugs from PE-D [#195](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/195)
+ * Developer Guide:
+ * Contributed to Acknowledgements, Non functional requirements and Glossary [\#31](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/31)
+ * Contributed to Introduction and About Developer Guide [\#106](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/106)
+ * Added implementation for `delete-field` command [#122](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/122)
+ * Updated UML sequence diagram for `delete-field` command [#94](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/94)
+ * Wrote design tweaks addressing bugs found in PE dry run [#201](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/201)
+
+* **Community**:
+ * Contributed to forum discussions for
+ [\#297](https://github.com/nus-cs2103-AY2223S2/forum/issues/297),
+ [\#287](https://github.com/nus-cs2103-AY2223S2/forum/issues/287),
+ [\#190](https://github.com/nus-cs2103-AY2223S2/forum/issues/190)
+
+
diff --git a/docs/team/seadragon2000341.md b/docs/team/seadragon2000341.md
new file mode 100644
index 00000000000..c60eee4e0b3
--- /dev/null
+++ b/docs/team/seadragon2000341.md
@@ -0,0 +1,59 @@
+---
+layout: page
+title: Shawn's Project Portfolio Page
+---
+
+### Project: InternBuddy
+
+InternBuddy provides a 1-stop platform for Computing undergraduates to manage and track their internship applications. It is optimized for typing which Computing undergraduates are comfortable and proficient in, allowing them to fully and efficiently exploit the application’s organisational capabilities.
+The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
+
+Given below are my contributions to the project.
+
+* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2223s2.github.io/tp-dashboard/?search=seadragon2000341&breakdown=true)
+
+* **New Feature**: Added `upcoming` command [#93](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/93)
+ * What it does: Allows users to find internships that have upcoming events (interviews/assessments) or deadlines (application/acceptance deadline).
+ * Justification: This feature improves the product because it provides a busy user with a convenient way to check his internship application schedule for the week.
+
+
+* **Enhancements to existing features**:
+ * Updated constraints for `COMPANY_NAME` and `ROLE` fields [#126](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/126)
+ * Fixed inconsistencies with internship shown using the `LIST`command [#125](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/125)
+ * Changed equality/duplicate notion that was inherited from Address Book to suit InternBuddy [#124](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/124)
+ * Created a new `STATUS` field `ACCPETED` to complement existing statuses [#87](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/87)
+ * Updated `DATE` labels for `OFFERED` and `NEW` statuses [#87](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/87)
+ * Updated `TAG` validation to be at most 30 characters and cannot be an empty string [#47](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/47)
+ * Updated `STATUS` field inputs to be non case-sensitive [#39](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/39)
+ * Enhanced `DATE` validation to make sure the date is of the correct format and a valid date [#38](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/38)
+
+
+* **Project management**:
+ * Created team's organisation and repository
+ * Set up the project's Continuous Integration and website
+ * Enable assertion [#76](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/76)
+ * Reviewed and approved PRs for merging
+ * Updated config.yml [#16](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/16)
+ * Set up certain milestones and issues
+
+
+* **Documentation**:
+ * User Guide:
+ * Added implementation for `upcoming` command [#120](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/120)
+ * Updated implementation for `edit` command [#120](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/120), [#22](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/22)
+ * Updated implementation for `help` command [#22](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/22)
+ * Fixed UG bugs from PE-D [#187](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/187)
+ * Developer Guide:
+ * Added implementation for `upcoming` command [#122](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/122)
+ * Updated UML sequence diagram for `edit` command [#94](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/94)
+ * Updated implementation for `edit` command [#80](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/80)
+ * Wrote use cases for `add` command [#24](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/24/)
+ * Wrote use cases for `exit` command [#24](https://github.com/AY2223S2-CS2103T-T14-3/tp/pull/24/)
+
+
+
+* **Community**:
+
+ * Contributed to forum discussions (examples: [1](https://github.com/nus-cs2103-AY2223S2/forum/issues/223), [2](https://github.com/nus-cs2103-AY2223S2/forum/issues/180), [3](https://github.com/nus-cs2103-AY2223S2/forum/issues/176), [4](https://github.com/nus-cs2103-AY2223S2/forum/issues/163), [5](https://github.com/nus-cs2103-AY2223S2/forum/issues/137), [6](https://github.com/nus-cs2103-AY2223S2/forum/issues/136), [7](https://github.com/nus-cs2103-AY2223S2/forum/issues/83), [8](https://github.com/nus-cs2103-AY2223S2/forum/issues/67), [9](https://github.com/nus-cs2103-AY2223S2/forum/issues/64), [10](https://github.com/nus-cs2103-AY2223S2/forum/issues/60), [11](https://github.com/nus-cs2103-AY2223S2/forum/issues/49), [12](https://github.com/nus-cs2103-AY2223S2/forum/issues/42). [13](https://github.com/nus-cs2103-AY2223S2/forum/issues/4))
+
+
diff --git a/docs/tutorials/AddRemark.md b/docs/tutorials/AddRemark.md
index 880c701042f..95518e07f8c 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.internship.logic.commands;
-import seedu.address.model.Model;
+import seedu.internship.model.Model;
/**
* Changes the remark of an existing person in the address book.
@@ -91,7 +91,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.internship.commons.util.CollectionUtil.requireAllNonNull;
//...
public class RemarkCommand extends Command {
//...
@@ -142,7 +142,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.internship.logic.parser` package. The class must extend the `Parser` interface.
![The relationship between Parser and RemarkCommandParser](../images/add-remark/ParserInterface.png)
@@ -229,7 +229,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.internship.model.internship`. 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-41bb13c581e280c686198251ad6cc337cd5e27032772f06ed9bf7f1440995ece). Note how `Remark` has no constrains and thus does not require input
validation.
@@ -242,7 +242,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-639834f1e05afe2276a86372adf0fe5f69314642c2d93cfa543d614ce5a76688).
+Simply add the following to [`seedu.internship.ui.PersonCard`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-639834f1e05afe2276a86372adf0fe5f69314642c2d93cfa543d614ce5a76688).
**`PersonCard.java`:**
diff --git a/docs/tutorials/RemovingFields.md b/docs/tutorials/RemovingFields.md
index f29169bc924..8d1755a4047 100644
--- a/docs/tutorials/RemovingFields.md
+++ b/docs/tutorials/RemovingFields.md
@@ -28,7 +28,7 @@ IntelliJ IDEA provides a refactoring tool that can identify *most* parts of a re
### 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.internship.model.internship.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.
* :bulb: To make things simpler, you can unselect the options `Search in comments and strings` and `Search for text occurrences`
![Usages detected](../images/remove/UnsafeDelete.png)
diff --git a/docs/tutorials/TracingCode.md b/docs/tutorials/TracingCode.md
index 4fb62a83ef6..fdc11df5169 100644
--- a/docs/tutorials/TracingCode.md
+++ b/docs/tutorials/TracingCode.md
@@ -39,7 +39,7 @@ In our case, we would want to begin the tracing at the very point where the App
-According to the sequence diagram you saw earlier (and repeated above for reference), the `UI` component yields control to the `Logic` component through a method named `execute`. Searching through the code base for an `execute()` method that belongs to the `Logic` component yields a promising candidate in `seedu.address.logic.Logic`.
+According to the sequence diagram you saw earlier (and repeated above for reference), the `UI` component yields control to the `Logic` component through a method named `execute`. Searching through the code base for an `execute()` method that belongs to the `Logic` component yields a promising candidate in `seedu.internship.logic.Logic`.
@@ -48,7 +48,7 @@ According to the sequence diagram you saw earlier (and repeated above for refere
:bulb: **Intellij Tip:** The ['**Search Everywhere**' feature](https://www.jetbrains.com/help/idea/searching-everywhere.html) can be used here. In particular, the '**Find Symbol**' ('Symbol' here refers to methods, variables, classes etc.) variant of that feature is quite useful here as we are looking for a _method_ named `execute`, not simply the text `execute`.
-A quick look at the `seedu.address.logic.Logic` (an extract given below) confirms that this indeed might be what we’re looking for.
+A quick look at the `seedu.internship.logic.Logic` (an extract given below) confirms that this indeed might be what we’re looking for.
```java
public interface Logic {
diff --git a/internbuddy.json b/internbuddy.json
new file mode 100644
index 00000000000..fa6309a797f
--- /dev/null
+++ b/internbuddy.json
@@ -0,0 +1,52 @@
+{
+ "internships" : [ {
+ "companyName" : "Apple",
+ "role" : "iOS Developer",
+ "status" : "applied",
+ "date" : "2023-03-20",
+ "comment" : "Yay! My dream company!",
+ "tagged" : [ "iOS" ]
+ }, {
+ "companyName" : "Amazon",
+ "role" : "Cloud Architect",
+ "status" : "new",
+ "date" : "2023-03-28",
+ "comment" : "Need to research more on cloud services.",
+ "tagged" : [ "Cloud Services", "AWS" ]
+ }, {
+ "companyName" : "Google",
+ "role" : "Software Engineer",
+ "status" : "assessment",
+ "date" : "2023-04-02",
+ "comment" : "Good company culture and environment.",
+ "tagged" : [ "Golang", "Back-end" ]
+ }, {
+ "companyName" : "Samsung",
+ "role" : "Android Developer",
+ "status" : "interview",
+ "date" : "2023-04-10",
+ "comment" : "To compare with Apple's offer again.",
+ "tagged" : [ "Mobile", "Android" ]
+ }, {
+ "companyName" : "Grab",
+ "role" : "Frontend Designer",
+ "status" : "offered",
+ "date" : "2023-03-27",
+ "comment" : "Good benefits. Can consider.",
+ "tagged" : [ "CSS", "React" ]
+ }, {
+ "companyName" : "Paypal",
+ "role" : "Product Designer",
+ "status" : "accepted",
+ "date" : "2023-03-26",
+ "comment" : "Starting work on 1 May. Excited!",
+ "tagged" : [ "UX", "UI" ]
+ }, {
+ "companyName" : "Facebook",
+ "role" : "Backend Developer",
+ "status" : "rejected",
+ "date" : "2023-03-15",
+ "comment" : "Rejected since I lack proficiency in SQL.",
+ "tagged" : [ "SQL" ]
+ } ]
+}
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/commons/util/StringUtil.java b/src/main/java/seedu/address/commons/util/StringUtil.java
deleted file mode 100644
index 61cc8c9a1cb..00000000000
--- a/src/main/java/seedu/address/commons/util/StringUtil.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package seedu.address.commons.util;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.Arrays;
-
-/**
- * Helper functions for handling strings.
- */
-public class StringUtil {
-
- /**
- * Returns true if the {@code sentence} contains the {@code word}.
- * Ignores case, but a full word match is required.
- * examples:
- * containsWordIgnoreCase("ABc def", "abc") == true
- * containsWordIgnoreCase("ABc def", "DEF") == true
- * containsWordIgnoreCase("ABc def", "AB") == false //not a full word match
- *
- * @param sentence cannot be null
- * @param word cannot be null, cannot be empty, must be a single word
- */
- public static boolean containsWordIgnoreCase(String sentence, String word) {
- requireNonNull(sentence);
- requireNonNull(word);
-
- String preppedWord = word.trim();
- checkArgument(!preppedWord.isEmpty(), "Word parameter cannot be empty");
- checkArgument(preppedWord.split("\\s+").length == 1, "Word parameter should be a single word");
-
- String preppedSentence = sentence;
- String[] wordsInPreppedSentence = preppedSentence.split("\\s+");
-
- return Arrays.stream(wordsInPreppedSentence)
- .anyMatch(preppedWord::equalsIgnoreCase);
- }
-
- /**
- * Returns a detailed message of the t, including the stack trace.
- */
- public static String getDetails(Throwable t) {
- requireNonNull(t);
- StringWriter sw = new StringWriter();
- t.printStackTrace(new PrintWriter(sw));
- return t.getMessage() + "\n" + sw.toString();
- }
-
- /**
- * Returns true if {@code s} represents a non-zero unsigned integer
- * e.g. 1, 2, 3, ..., {@code Integer.MAX_VALUE}
- * Will return false for any other non-null string input
- * e.g. empty string, "-1", "0", "+1", and " 2 " (untrimmed), "3 0" (contains whitespace), "1 a" (contains letters)
- * @throws NullPointerException if {@code s} is null.
- */
- public static boolean isNonZeroUnsignedInteger(String s) {
- requireNonNull(s);
-
- try {
- int value = Integer.parseInt(s);
- return value > 0 && !s.startsWith("+"); // "+1" is successfully parsed by Integer#parseInt(String)
- } catch (NumberFormatException nfe) {
- return false;
- }
- }
-}
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/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java
deleted file mode 100644
index 9c86b1fa6e4..00000000000
--- a/src/main/java/seedu/address/logic/commands/ClearCommand.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
-
-/**
- * Clears the address book.
- */
-public class ClearCommand extends Command {
-
- public static final String COMMAND_WORD = "clear";
- public static final String MESSAGE_SUCCESS = "Address book has been cleared!";
-
-
- @Override
- public CommandResult execute(Model model) {
- requireNonNull(model);
- model.setAddressBook(new AddressBook());
- return new CommandResult(MESSAGE_SUCCESS);
- }
-}
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/CliSyntax.java b/src/main/java/seedu/address/logic/parser/CliSyntax.java
deleted file mode 100644
index 75b1a9bf119..00000000000
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package seedu.address.logic.parser;
-
-/**
- * Contains Command Line Interface (CLI) syntax definitions common to multiple commands
- */
-public class CliSyntax {
-
- /* 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/");
-
-}
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 86c1df298d7..00000000000
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ /dev/null
@@ -1,150 +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) {
- 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 f866e7133de..00000000000
--- a/src/main/java/seedu/address/model/person/Email.java
+++ /dev/null
@@ -1,71 +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 + "). The local-part may not start or end with any special "
- + "characters.\n"
- + "2. This is followed by a '@' and then a domain name. The domain name is made up of domain labels "
- + "separated by periods.\n"
- + "The domain name must:\n"
- + " - end with a domain label at least 2 characters long\n"
- + " - have each domain label start and end with alphanumeric characters\n"
- + " - have each domain label consist of alphanumeric characters, separated only by hyphens, if any.";
- // alphanumeric and special characters
- private static final String ALPHANUMERIC_NO_UNDERSCORE = "[^\\W_]+"; // alphanumeric characters except underscore
- private static final String LOCAL_PART_REGEX = "^" + ALPHANUMERIC_NO_UNDERSCORE + "([" + SPECIAL_CHARACTERS + "]"
- + ALPHANUMERIC_NO_UNDERSCORE + ")*";
- private static final String DOMAIN_PART_REGEX = ALPHANUMERIC_NO_UNDERSCORE
- + "(-" + ALPHANUMERIC_NO_UNDERSCORE + ")*";
- private static final String DOMAIN_LAST_PART_REGEX = "(" + DOMAIN_PART_REGEX + "){2,}$"; // At least two chars
- private static final String DOMAIN_REGEX = "(" + DOMAIN_PART_REGEX + "\\.)*" + DOMAIN_LAST_PART_REGEX;
- public static final String VALIDATION_REGEX = LOCAL_PART_REGEX + "@" + DOMAIN_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/Phone.java b/src/main/java/seedu/address/model/person/Phone.java
deleted file mode 100644
index 872c76b382f..00000000000
--- a/src/main/java/seedu/address/model/person/Phone.java
+++ /dev/null
@@ -1,53 +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 phone number in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidPhone(String)}
- */
-public class Phone {
-
-
- 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,}";
- public final String value;
-
- /**
- * Constructs a {@code Phone}.
- *
- * @param phone A valid phone number.
- */
- public Phone(String phone) {
- requireNonNull(phone);
- checkArgument(isValidPhone(phone), MESSAGE_CONSTRAINTS);
- value = phone;
- }
-
- /**
- * Returns true if a given string is a valid phone number.
- */
- public static boolean isValidPhone(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 Phone // instanceof handles nulls
- && value.equals(((Phone) other).value)); // state check
- }
-
- @Override
- public int hashCode() {
- return value.hashCode();
- }
-
-}
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/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java
deleted file mode 100644
index 7fc927bc5d9..00000000000
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package seedu.address.ui;
-
-import java.util.Comparator;
-
-import javafx.fxml.FXML;
-import javafx.scene.control.Label;
-import javafx.scene.layout.FlowPane;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.Region;
-import seedu.address.model.person.Person;
-
-/**
- * An UI component that displays information of a {@code Person}.
- */
-public class PersonCard extends UiPart {
-
- private static final String FXML = "PersonListCard.fxml";
-
- /**
- * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
- * As a consequence, UI elements' variable names cannot be set to such keywords
- * or an exception will be thrown by JavaFX during runtime.
- *
- * @see The issue on AddressBook level 4
- */
-
- public final Person person;
-
- @FXML
- private HBox cardPane;
- @FXML
- private Label name;
- @FXML
- private Label id;
- @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.
- */
- public PersonCard(Person person, int displayedIndex) {
- super(FXML);
- this.person = person;
- 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()
- .sorted(Comparator.comparing(tag -> tag.tagName))
- .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
- }
-
- @Override
- public boolean equals(Object other) {
- // short circuit if same object
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof PersonCard)) {
- return false;
- }
-
- // state check
- PersonCard card = (PersonCard) other;
- return id.getText().equals(card.id.getText())
- && person.equals(card.person);
- }
-}
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/internship/AppParameters.java
similarity index 93%
rename from src/main/java/seedu/address/AppParameters.java
rename to src/main/java/seedu/internship/AppParameters.java
index ab552c398f3..a42c1334095 100644
--- a/src/main/java/seedu/address/AppParameters.java
+++ b/src/main/java/seedu/internship/AppParameters.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.internship;
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.internship.commons.core.LogsCenter;
+import seedu.internship.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/internship/Main.java
similarity index 97%
rename from src/main/java/seedu/address/Main.java
rename to src/main/java/seedu/internship/Main.java
index 052a5068631..9607b3f3827 100644
--- a/src/main/java/seedu/address/Main.java
+++ b/src/main/java/seedu/internship/Main.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.internship;
import javafx.application.Application;
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/internship/MainApp.java
similarity index 66%
rename from src/main/java/seedu/address/MainApp.java
rename to src/main/java/seedu/internship/MainApp.java
index 4133aaa0151..5887949852d 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/seedu/internship/MainApp.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.internship;
import java.io.IOException;
import java.nio.file.Path;
@@ -7,36 +7,36 @@
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.internship.commons.core.Config;
+import seedu.internship.commons.core.LogsCenter;
+import seedu.internship.commons.core.Version;
+import seedu.internship.commons.exceptions.DataConversionException;
+import seedu.internship.commons.util.ConfigUtil;
+import seedu.internship.commons.util.StringUtil;
+import seedu.internship.logic.Logic;
+import seedu.internship.logic.LogicManager;
+import seedu.internship.model.InternBuddy;
+import seedu.internship.model.Model;
+import seedu.internship.model.ModelManager;
+import seedu.internship.model.ReadOnlyInternBuddy;
+import seedu.internship.model.ReadOnlyUserPrefs;
+import seedu.internship.model.UserPrefs;
+import seedu.internship.model.util.SampleDataUtil;
+import seedu.internship.storage.InternBuddyStorage;
+import seedu.internship.storage.JsonInternBuddyStorage;
+import seedu.internship.storage.JsonUserPrefsStorage;
+import seedu.internship.storage.Storage;
+import seedu.internship.storage.StorageManager;
+import seedu.internship.storage.UserPrefsStorage;
+import seedu.internship.ui.Ui;
+import seedu.internship.ui.UiManager;
/**
* Runs the application.
*/
public class MainApp extends Application {
- public static final Version VERSION = new Version(0, 2, 0, true);
+ public static final Version VERSION = new Version(1, 4, 1, true);
private static final Logger logger = LogsCenter.getLogger(MainApp.class);
@@ -48,7 +48,7 @@ public class MainApp extends Application {
@Override
public void init() throws Exception {
- logger.info("=============================[ Initializing AddressBook ]===========================");
+ logger.info("=============================[ Initializing InternBuddy ]===========================");
super.init();
AppParameters appParameters = AppParameters.parse(getParameters());
@@ -56,8 +56,8 @@ 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);
+ InternBuddyStorage internBuddyStorage = new JsonInternBuddyStorage(userPrefs.getInternBuddyFilePath());
+ storage = new StorageManager(internBuddyStorage, userPrefsStorage);
initLogging(config);
@@ -69,25 +69,25 @@ 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 InternBuddy and {@code userPrefs}.
+ * The data from the sample InternBuddy will be used instead if {@code storage}'s InternBuddy is not found,
+ * or an empty InternBuddy will be used instead if errors occur when reading {@code storage}'s InternBuddy.
*/
private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
- Optional addressBookOptional;
- ReadOnlyAddressBook initialData;
+ Optional internBuddyOptional;
+ ReadOnlyInternBuddy initialData;
try {
- addressBookOptional = storage.readAddressBook();
- if (!addressBookOptional.isPresent()) {
- logger.info("Data file not found. Will be starting with a sample AddressBook");
+ internBuddyOptional = storage.readInternBuddy();
+ if (!internBuddyOptional.isPresent()) {
+ logger.info("Data file not found. Will be starting with a sample InternBuddy");
}
- initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook);
+ initialData = internBuddyOptional.orElseGet(SampleDataUtil::getSampleInternBuddy);
} 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 InternBuddy");
+ initialData = new InternBuddy();
} 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 InternBuddy");
+ initialData = new InternBuddy();
}
return new ModelManager(initialData, userPrefs);
@@ -151,7 +151,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 InternBuddy");
initializedPrefs = new UserPrefs();
}
@@ -167,13 +167,13 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
@Override
public void start(Stage primaryStage) {
- logger.info("Starting AddressBook " + MainApp.VERSION);
+ logger.info("Starting InternBuddy " + MainApp.VERSION);
ui.start(primaryStage);
}
@Override
public void stop() {
- logger.info("============================ [ Stopping Address Book ] =============================");
+ logger.info("============================ [ Stopping InternBuddy ] =============================");
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/internship/commons/core/Config.java
similarity index 97%
rename from src/main/java/seedu/address/commons/core/Config.java
rename to src/main/java/seedu/internship/commons/core/Config.java
index 91145745521..768ab25ca89 100644
--- a/src/main/java/seedu/address/commons/core/Config.java
+++ b/src/main/java/seedu/internship/commons/core/Config.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.internship.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/internship/commons/core/GuiSettings.java
similarity index 98%
rename from src/main/java/seedu/address/commons/core/GuiSettings.java
rename to src/main/java/seedu/internship/commons/core/GuiSettings.java
index ba33653be67..7b903b3cf3a 100644
--- a/src/main/java/seedu/address/commons/core/GuiSettings.java
+++ b/src/main/java/seedu/internship/commons/core/GuiSettings.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.internship.commons.core;
import java.awt.Point;
import java.io.Serializable;
diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/seedu/internship/commons/core/LogsCenter.java
similarity index 97%
rename from src/main/java/seedu/address/commons/core/LogsCenter.java
rename to src/main/java/seedu/internship/commons/core/LogsCenter.java
index 431e7185e76..f5fe14b25b5 100644
--- a/src/main/java/seedu/address/commons/core/LogsCenter.java
+++ b/src/main/java/seedu/internship/commons/core/LogsCenter.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.internship.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 = "InternBuddy.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/internship/commons/core/Messages.java b/src/main/java/seedu/internship/commons/core/Messages.java
new file mode 100644
index 00000000000..b7917b5e730
--- /dev/null
+++ b/src/main/java/seedu/internship/commons/core/Messages.java
@@ -0,0 +1,16 @@
+package seedu.internship.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_INTERNSHIP_DISPLAYED_INDEX = "The internship index provided is invalid";
+ public static final String MESSAGE_OUT_OF_RANGE_INTERNSHIP_DISPLAYED_INDEX = "The internship index provided is "
+ + "out of range";
+ public static final String MESSAGE_INTERNSHIP_LISTED_OVERVIEW = "%1$d internship/s listed!";
+ public static final String MESSAGE_MISSING_ARGUMENTS = "This command requires at least 1 argument!\n%1$s";
+
+}
diff --git a/src/main/java/seedu/address/commons/core/Version.java b/src/main/java/seedu/internship/commons/core/Version.java
similarity index 98%
rename from src/main/java/seedu/address/commons/core/Version.java
rename to src/main/java/seedu/internship/commons/core/Version.java
index 12142ec1e32..aad8760aa9c 100644
--- a/src/main/java/seedu/address/commons/core/Version.java
+++ b/src/main/java/seedu/internship/commons/core/Version.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.internship.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/internship/commons/core/index/Index.java
similarity index 78%
rename from src/main/java/seedu/address/commons/core/index/Index.java
rename to src/main/java/seedu/internship/commons/core/index/Index.java
index 19536439c09..adafe1fc8af 100644
--- a/src/main/java/seedu/address/commons/core/index/Index.java
+++ b/src/main/java/seedu/internship/commons/core/index/Index.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core.index;
+package seedu.internship.commons.core.index;
/**
* Represents a zero-based or one-based index.
@@ -8,7 +8,7 @@
* base the other component is using for its index. However, after receiving the {@code Index}, that component can
* convert it back to an int if the index will not be passed to a different component again.
*/
-public class Index {
+public class Index implements Comparable {
private int zeroBasedIndex;
/**
@@ -51,4 +51,20 @@ public boolean equals(Object other) {
|| (other instanceof Index // instanceof handles nulls
&& zeroBasedIndex == ((Index) other).zeroBasedIndex); // state check
}
+
+ @Override
+ public int compareTo(Index other) {
+ if (this.zeroBasedIndex == other.getZeroBased()) {
+ return 0;
+ }
+ if (this.zeroBasedIndex < other.getZeroBased()) {
+ return -1;
+ }
+ return 1;
+ }
+ @Override
+ public int hashCode() {
+ return this.zeroBasedIndex;
+ }
+
}
diff --git a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java b/src/main/java/seedu/internship/commons/exceptions/DataConversionException.java
similarity index 83%
rename from src/main/java/seedu/address/commons/exceptions/DataConversionException.java
rename to src/main/java/seedu/internship/commons/exceptions/DataConversionException.java
index 1f689bd8e3f..8e253f780a6 100644
--- a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java
+++ b/src/main/java/seedu/internship/commons/exceptions/DataConversionException.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.exceptions;
+package seedu.internship.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/internship/commons/exceptions/IllegalValueException.java
similarity index 92%
rename from src/main/java/seedu/address/commons/exceptions/IllegalValueException.java
rename to src/main/java/seedu/internship/commons/exceptions/IllegalValueException.java
index 19124db485c..db2a91efab8 100644
--- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java
+++ b/src/main/java/seedu/internship/commons/exceptions/IllegalValueException.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.exceptions;
+package seedu.internship.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/internship/commons/util/AppUtil.java
similarity index 94%
rename from src/main/java/seedu/address/commons/util/AppUtil.java
rename to src/main/java/seedu/internship/commons/util/AppUtil.java
index 87aa89c0326..5f4c78b483f 100644
--- a/src/main/java/seedu/address/commons/util/AppUtil.java
+++ b/src/main/java/seedu/internship/commons/util/AppUtil.java
@@ -1,9 +1,9 @@
-package seedu.address.commons.util;
+package seedu.internship.commons.util;
import static java.util.Objects.requireNonNull;
import javafx.scene.image.Image;
-import seedu.address.MainApp;
+import seedu.internship.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/internship/commons/util/CollectionUtil.java
similarity index 96%
rename from src/main/java/seedu/address/commons/util/CollectionUtil.java
rename to src/main/java/seedu/internship/commons/util/CollectionUtil.java
index eafe4dfd681..717376b67d1 100644
--- a/src/main/java/seedu/address/commons/util/CollectionUtil.java
+++ b/src/main/java/seedu/internship/commons/util/CollectionUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.internship.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/internship/commons/util/ConfigUtil.java
similarity index 76%
rename from src/main/java/seedu/address/commons/util/ConfigUtil.java
rename to src/main/java/seedu/internship/commons/util/ConfigUtil.java
index f7f8a2bd44c..0225425de60 100644
--- a/src/main/java/seedu/address/commons/util/ConfigUtil.java
+++ b/src/main/java/seedu/internship/commons/util/ConfigUtil.java
@@ -1,11 +1,11 @@
-package seedu.address.commons.util;
+package seedu.internship.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.internship.commons.core.Config;
+import seedu.internship.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/internship/commons/util/FileUtil.java
similarity index 98%
rename from src/main/java/seedu/address/commons/util/FileUtil.java
rename to src/main/java/seedu/internship/commons/util/FileUtil.java
index b1e2767cdd9..670ee2a8be2 100644
--- a/src/main/java/seedu/address/commons/util/FileUtil.java
+++ b/src/main/java/seedu/internship/commons/util/FileUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.internship.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/internship/commons/util/JsonUtil.java
similarity index 97%
rename from src/main/java/seedu/address/commons/util/JsonUtil.java
rename to src/main/java/seedu/internship/commons/util/JsonUtil.java
index 8ef609f055d..ee76bc61355 100644
--- a/src/main/java/seedu/address/commons/util/JsonUtil.java
+++ b/src/main/java/seedu/internship/commons/util/JsonUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.internship.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.internship.commons.core.LogsCenter;
+import seedu.internship.commons.exceptions.DataConversionException;
/**
* Converts a Java object instance to JSON and vice versa
diff --git a/src/main/java/seedu/internship/commons/util/StringUtil.java b/src/main/java/seedu/internship/commons/util/StringUtil.java
new file mode 100644
index 00000000000..add8f423e40
--- /dev/null
+++ b/src/main/java/seedu/internship/commons/util/StringUtil.java
@@ -0,0 +1,105 @@
+package seedu.internship.commons.util;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.commons.util.AppUtil.checkArgument;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+
+import seedu.internship.logic.parser.ParserUtil;
+import seedu.internship.logic.parser.exceptions.ParseException;
+
+/**
+ * Helper functions for handling strings.
+ */
+public class StringUtil {
+
+ /**
+ * Returns true if the {@code sentence} contains the {@code word}.
+ * Ignores case, but a full word match is required.
+ * examples:
+ * containsWordIgnoreCase("ABc def", "abc") == true
+ * containsWordIgnoreCase("ABc def", "DEF") == true
+ * containsWordIgnoreCase("ABc def", "AB") == false //not a full word match
+ *
+ * @param sentence cannot be null
+ * @param word cannot be null, cannot be empty, must be a single word
+ */
+ public static boolean containsWordIgnoreCase(String sentence, String word) {
+ requireNonNull(sentence);
+ requireNonNull(word);
+
+ String preppedWord = word.trim();
+ checkArgument(!preppedWord.isEmpty(), "Word parameter cannot be empty");
+ checkArgument(preppedWord.split("\\s+").length == 1, "Word parameter should be a single word");
+
+ String preppedSentence = sentence;
+ String[] wordsInPreppedSentence = preppedSentence.split("\\s+");
+
+ return Arrays.stream(wordsInPreppedSentence)
+ .anyMatch(preppedWord::equalsIgnoreCase);
+ }
+
+ /**
+ * Returns true if the {@code input} equals the {@code target}.
+ * Ignores case but both strings must match.
+ * examples:
+ * matchingStringIgnoreCase("abc def", "abc def") == true
+ * matchingStringIgnoreCase("ABc dEf", "abc DEF") == true
+ * matchingStringIgnoreCase("ABc def", "AB") == false //not a full string match
+ *
+ * @param input cannot be null
+ * @param target cannot be null, cannot be empty
+ */
+ public static boolean matchingStringIgnoreCase(String input, String target) {
+ requireNonNull(input);
+ requireNonNull(target);
+
+ checkArgument(!target.isEmpty(), "Target cannot be empty!");
+ assert(!target.isEmpty());
+
+ return target.equalsIgnoreCase(input);
+ }
+
+ /**
+ * Returns a detailed message of the t, including the stack trace.
+ */
+ public static String getDetails(Throwable t) {
+ requireNonNull(t);
+ StringWriter sw = new StringWriter();
+ t.printStackTrace(new PrintWriter(sw));
+ return t.getMessage() + "\n" + sw.toString();
+ }
+
+ /**
+ * Throws ParseException objects with error message {@code Messages.MESSAGE_INVALID_COMMAND_FORMAT} if {@code s}
+ * does not represent an integer or represents a positive integer with the plus sign "+" in front and
+ * {@code Messages.MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX} if {@code s} represents a negative integer. Else,
+ * does nothing.
+ * @param s String input
+ * @throws ParseException with error message {@code Messages.MESSAGE_INVALID_COMMAND_FORMAT} if {@code s}
+ * does not represent an integer or represents a positive integer with the plus sign "+" in front and
+ * {@code Messages.MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX} if {@code s} represents a negative integer.
+ */
+ public static void nonZeroUnsignedIntegerCheck(String s) throws ParseException {
+ requireNonNull(s);
+
+ int value;
+
+ try {
+ value = Integer.parseInt(s);
+ } catch (NumberFormatException nfe) {
+ throw new ParseException(ParserUtil.MESSAGE_INVALID_INDEX_FORMAT);
+ }
+
+ if (s.startsWith("+")) {
+ throw new ParseException(ParserUtil.MESSAGE_INVALID_POSITIVE_SIGNED_INDEX);
+ }
+
+ if (value <= 0) {
+ throw new ParseException(ParserUtil.MESSAGE_INVALID_INDEX);
+ }
+
+ }
+}
diff --git a/src/main/java/seedu/internship/logic/Logic.java b/src/main/java/seedu/internship/logic/Logic.java
new file mode 100644
index 00000000000..bd310f46698
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/Logic.java
@@ -0,0 +1,65 @@
+package seedu.internship.logic;
+
+import java.nio.file.Path;
+
+import javafx.collections.ObservableList;
+import seedu.internship.commons.core.GuiSettings;
+import seedu.internship.logic.commands.CommandResult;
+import seedu.internship.logic.commands.exceptions.CommandException;
+import seedu.internship.logic.parser.exceptions.ParseException;
+import seedu.internship.model.Model;
+import seedu.internship.model.ReadOnlyInternBuddy;
+import seedu.internship.model.internship.Internship;
+
+/**
+ * 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 InternBuddy.
+ *
+ * @see seedu.internship.model.Model#getInternBuddy()
+ */
+ ReadOnlyInternBuddy getInternBuddy();
+
+ /** Returns an unmodifiable view of the filtered list of internships */
+ ObservableList getFilteredInternshipList();
+
+ /**
+ * Returns the user prefs' InternBuddy file path.
+ */
+ Path getInternBuddyFilePath();
+
+ /**
+ * Returns the user prefs' GUI settings.
+ */
+ GuiSettings getGuiSettings();
+
+ /**
+ * Set the user prefs' GUI settings.
+ */
+ void setGuiSettings(GuiSettings guiSettings);
+
+ /**
+ * Gets the selected internship.
+ *
+ * @return the currently selected Internship
+ */
+ Internship getSelectedInternship();
+
+ /**
+ * Gets the model associated with the logic object.
+ * @return the model in the logic object.
+ */
+ Model getModel();
+
+}
diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/internship/logic/LogicManager.java
similarity index 51%
rename from src/main/java/seedu/address/logic/LogicManager.java
rename to src/main/java/seedu/internship/logic/LogicManager.java
index 9d9c6d15bdc..060a03f3145 100644
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ b/src/main/java/seedu/internship/logic/LogicManager.java
@@ -1,21 +1,21 @@
-package seedu.address.logic;
+package seedu.internship.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.internship.commons.core.GuiSettings;
+import seedu.internship.commons.core.LogsCenter;
+import seedu.internship.logic.commands.Command;
+import seedu.internship.logic.commands.CommandResult;
+import seedu.internship.logic.commands.exceptions.CommandException;
+import seedu.internship.logic.parser.InternBuddyParser;
+import seedu.internship.logic.parser.exceptions.ParseException;
+import seedu.internship.model.Model;
+import seedu.internship.model.ReadOnlyInternBuddy;
+import seedu.internship.model.internship.Internship;
+import seedu.internship.storage.Storage;
/**
* The main LogicManager of the app.
@@ -26,7 +26,7 @@ public class LogicManager implements Logic {
private final Model model;
private final Storage storage;
- private final AddressBookParser addressBookParser;
+ private final InternBuddyParser internBuddyParser;
/**
* Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}.
@@ -34,7 +34,7 @@ public class LogicManager implements Logic {
public LogicManager(Model model, Storage storage) {
this.model = model;
this.storage = storage;
- addressBookParser = new AddressBookParser();
+ internBuddyParser = new InternBuddyParser();
}
@Override
@@ -42,11 +42,11 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
logger.info("----------------[USER COMMAND][" + commandText + "]");
CommandResult commandResult;
- Command command = addressBookParser.parseCommand(commandText);
+ Command command = internBuddyParser.parseCommand(commandText);
commandResult = command.execute(model);
try {
- storage.saveAddressBook(model.getAddressBook());
+ storage.saveInternBuddy(model.getInternBuddy());
} catch (IOException ioe) {
throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe);
}
@@ -55,18 +55,18 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
}
@Override
- public ReadOnlyAddressBook getAddressBook() {
- return model.getAddressBook();
+ public ReadOnlyInternBuddy getInternBuddy() {
+ return model.getInternBuddy();
}
@Override
- public ObservableList getFilteredPersonList() {
- return model.getFilteredPersonList();
+ public ObservableList getFilteredInternshipList() {
+ return model.getFilteredInternshipList();
}
@Override
- public Path getAddressBookFilePath() {
- return model.getAddressBookFilePath();
+ public Path getInternBuddyFilePath() {
+ return model.getInternBuddyFilePath();
}
@Override
@@ -78,4 +78,14 @@ public GuiSettings getGuiSettings() {
public void setGuiSettings(GuiSettings guiSettings) {
model.setGuiSettings(guiSettings);
}
+
+ @Override
+ public Internship getSelectedInternship() {
+ return model.getSelectedInternship();
+
+ }
+ @Override
+ public Model getModel() {
+ return this.model;
+ };
}
diff --git a/src/main/java/seedu/internship/logic/commands/AddCommand.java b/src/main/java/seedu/internship/logic/commands/AddCommand.java
new file mode 100644
index 00000000000..0a7024fe1fd
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/commands/AddCommand.java
@@ -0,0 +1,74 @@
+package seedu.internship.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_COMMENT;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_ROLE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_STATUS;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_TAG;
+
+import seedu.internship.logic.commands.exceptions.CommandException;
+import seedu.internship.model.Model;
+import seedu.internship.model.internship.Internship;
+
+/**
+ * Adds an internship to InternBuddy.
+ */
+public class AddCommand extends Command {
+
+ public static final String COMMAND_WORD = "add";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds an internship to InternBuddy. "
+ + "Fields: "
+ + PREFIX_COMPANY_NAME + "COMPANY_NAME "
+ + PREFIX_ROLE + "ROLE "
+ + PREFIX_STATUS + "STATUS "
+ + PREFIX_DATE + "DATE "
+ + "[" + PREFIX_COMMENT + "COMMENT] "
+ + "[" + PREFIX_TAG + "TAG]...\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_COMPANY_NAME + "Google "
+ + PREFIX_ROLE + "Software Engineer "
+ + PREFIX_STATUS + "Applied "
+ + PREFIX_DATE + "2023-02-01 "
+ + PREFIX_COMMENT + "I like the company culture! "
+ + PREFIX_TAG + "Go "
+ + PREFIX_TAG + "Java";
+
+ public static final String MESSAGE_SUCCESS = "New internship added: %1$s";
+ public static final String MESSAGE_DUPLICATE_INTERNSHIP = "This internship already exists in InternBuddy";
+
+ private final Internship toAdd;
+
+ /**
+ * Creates an AddCommand to add the specified {@code Internship}
+ */
+ public AddCommand(Internship internship) {
+ requireNonNull(internship);
+ toAdd = internship;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (model.hasInternship(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_INTERNSHIP);
+ }
+
+ //Add internship
+ model.addInternship(toAdd);
+ //Update right panel
+ model.updateSelectedInternship(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/internship/logic/commands/ClearCommand.java b/src/main/java/seedu/internship/logic/commands/ClearCommand.java
new file mode 100644
index 00000000000..c05862a890b
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/commands/ClearCommand.java
@@ -0,0 +1,24 @@
+package seedu.internship.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.internship.model.InternBuddy;
+import seedu.internship.model.Model;
+
+/**
+ * Clears the data in InternBuddy.
+ */
+public class ClearCommand extends Command {
+
+ public static final String COMMAND_WORD = "clear";
+ public static final String MESSAGE_SUCCESS = "InternBuddy data has been cleared!";
+
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.setInternBuddy(new InternBuddy());
+ model.updateSelectedInternship(null);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/seedu/internship/logic/commands/Command.java
similarity index 77%
rename from src/main/java/seedu/address/logic/commands/Command.java
rename to src/main/java/seedu/internship/logic/commands/Command.java
index 64f18992160..1876f4e2b64 100644
--- a/src/main/java/seedu/address/logic/commands/Command.java
+++ b/src/main/java/seedu/internship/logic/commands/Command.java
@@ -1,7 +1,7 @@
-package seedu.address.logic.commands;
+package seedu.internship.logic.commands;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
+import seedu.internship.logic.commands.exceptions.CommandException;
+import seedu.internship.model.Model;
/**
* Represents a command with hidden internal logic and the ability to be executed.
diff --git a/src/main/java/seedu/address/logic/commands/CommandResult.java b/src/main/java/seedu/internship/logic/commands/CommandResult.java
similarity index 97%
rename from src/main/java/seedu/address/logic/commands/CommandResult.java
rename to src/main/java/seedu/internship/logic/commands/CommandResult.java
index 92f900b7916..eb132ba2eef 100644
--- a/src/main/java/seedu/address/logic/commands/CommandResult.java
+++ b/src/main/java/seedu/internship/logic/commands/CommandResult.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.commands;
+package seedu.internship.logic.commands;
import static java.util.Objects.requireNonNull;
diff --git a/src/main/java/seedu/internship/logic/commands/CopyCommand.java b/src/main/java/seedu/internship/logic/commands/CopyCommand.java
new file mode 100644
index 00000000000..ee7b70e01af
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/commands/CopyCommand.java
@@ -0,0 +1,59 @@
+package seedu.internship.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import seedu.internship.commons.core.Messages;
+import seedu.internship.commons.core.index.Index;
+import seedu.internship.logic.commands.exceptions.CommandException;
+import seedu.internship.model.Model;
+import seedu.internship.model.internship.Internship;
+
+/**
+ * Copies the internship information identified using it's displayed index from InternBuddy.
+ */
+public class CopyCommand extends Command {
+
+ public static final String COMMAND_WORD = "copy";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Copies the details of the internship identified by the index"
+ + " number used in the displayed internship list.\n"
+ + "Fields: INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ public static final String MESSAGE_COPY_INTERNSHIP_SUCCESS = "Copied Internship: %1$s";
+
+ private final Index targetIndex;
+
+ public CopyCommand(Index targetIndex) {
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredInternshipList();
+
+ //Checks for a valid index
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_OUT_OF_RANGE_INTERNSHIP_DISPLAYED_INDEX);
+ }
+
+ //Gets the internship to copy
+ Internship internshipToCopy = lastShownList.get(targetIndex.getZeroBased());
+
+ //Functionality of the copy internship command
+ model.copyInternship(internshipToCopy);
+
+ return new CommandResult(String.format(MESSAGE_COPY_INTERNSHIP_SUCCESS, internshipToCopy));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof CopyCommand // instanceof handles nulls
+ && targetIndex.equals(((CopyCommand) other).targetIndex)); // state check
+ }
+}
diff --git a/src/main/java/seedu/internship/logic/commands/DeleteFieldCommand.java b/src/main/java/seedu/internship/logic/commands/DeleteFieldCommand.java
new file mode 100644
index 00000000000..98cbe01c9d9
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/commands/DeleteFieldCommand.java
@@ -0,0 +1,91 @@
+package seedu.internship.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_ROLE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_STATUS;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+import seedu.internship.MainApp;
+import seedu.internship.commons.core.LogsCenter;
+import seedu.internship.logic.commands.exceptions.CommandException;
+import seedu.internship.model.Model;
+import seedu.internship.model.internship.Internship;
+import seedu.internship.model.internship.InternshipContainsKeywordsPredicate;
+
+
+
+
+
+/**
+ * Deletes an internship identified using it's displayed index from InternBuddy.
+ */
+public class DeleteFieldCommand extends Command {
+
+ public static final String COMMAND_WORD = "delete-field";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes all internships containing at least one of the inputs for every different field "
+ + "(COMPANY_NAME, ROLE, STATUS, DATE or TAG) that you have provided.\n"
+ + "Fields: [" + PREFIX_COMPANY_NAME + "COMPANY_NAME]... "
+ + "[" + PREFIX_ROLE + "ROLE]... "
+ + "[" + PREFIX_DATE + "DATE]... "
+ + "[" + PREFIX_STATUS + "STATUS]... "
+ + "[" + PREFIX_TAG + "TAG]...\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_COMPANY_NAME + "Apple "
+ + PREFIX_COMPANY_NAME + "Google ";
+
+ public static final String MESSAGE_DELETE_INTERNSHIP_SUCCESS = "%1$d internship/s have been deleted!";
+ private static final Logger logger = LogsCenter.getLogger(MainApp.class);
+ private final InternshipContainsKeywordsPredicate predicate;
+ /**
+ * Create a DeleteFieldCommand object from the list of user supplied indexes and a predicate
+ * @param predicate A user supplied predicate to filter internships.
+ */
+ public DeleteFieldCommand(InternshipContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredInternshipList();
+
+ int previousSize = lastShownList.size();
+
+ if (!this.predicate.isEmpty()) {
+ lastShownList = lastShownList.stream()
+ .filter(this.predicate)
+ .collect(Collectors.toList());
+ }
+
+ logger.info(String.format("Deleting internships: %s", Arrays.toString(lastShownList.toArray())));
+
+ for (Internship internshipToDelete: lastShownList) {
+ //Delete internship
+ model.deleteInternship(internshipToDelete);
+ //Update right panel
+ if (internshipToDelete.equals(model.getSelectedInternship())) {
+ model.updateSelectedInternship(null);
+ }
+ }
+
+ int newSize = model.getFilteredInternshipList().size();
+
+ return new CommandResult(String.format(MESSAGE_DELETE_INTERNSHIP_SUCCESS, previousSize - newSize));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof DeleteFieldCommand // instanceof handles nulls
+ && predicate.equals(((DeleteFieldCommand) other).predicate));
+ }
+}
diff --git a/src/main/java/seedu/internship/logic/commands/DeleteIndexCommand.java b/src/main/java/seedu/internship/logic/commands/DeleteIndexCommand.java
new file mode 100644
index 00000000000..dd93f075d40
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/commands/DeleteIndexCommand.java
@@ -0,0 +1,94 @@
+package seedu.internship.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+import seedu.internship.MainApp;
+import seedu.internship.commons.core.LogsCenter;
+import seedu.internship.commons.core.Messages;
+import seedu.internship.commons.core.index.Index;
+import seedu.internship.logic.commands.exceptions.CommandException;
+import seedu.internship.model.Model;
+import seedu.internship.model.internship.Internship;
+
+/**
+ * Deletes an internship identified using it's displayed index from InternBuddy.
+ */
+public class DeleteIndexCommand extends Command {
+
+ public static final String COMMAND_WORD = "delete-index";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes all internships identified by the index numbers used in the displayed internship list.\n"
+ + "Fields: INDEX [INDEX]... (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1 2";
+
+ public static final String MESSAGE_DELETE_INTERNSHIP_SUCCESS = "%1$d internships have been deleted!";
+ private static final Logger logger = LogsCenter.getLogger(MainApp.class);
+
+ private final List targetIndexes;
+ /**
+ * Create a DeleteIndexCommand object from the list of user supplied indexes and a predicate
+ * @param targetIndexes A list of {@code Index} that refers to the index of internship entries in list.
+ */
+ public DeleteIndexCommand(List targetIndexes) {
+ this.targetIndexes = targetIndexes;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredInternshipList();
+
+ int previousSize = lastShownList.size();
+
+ // Remove duplicates
+ List uniqueTargetIndexes = new ArrayList<>(new HashSet<>(this.targetIndexes));
+
+
+ // Sort list
+ Collections.sort(uniqueTargetIndexes);
+
+ if (uniqueTargetIndexes.size() > 0 && uniqueTargetIndexes.get(uniqueTargetIndexes.size() - 1)
+ .getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_OUT_OF_RANGE_INTERNSHIP_DISPLAYED_INDEX);
+ }
+
+ List internshipsToDelete = new ArrayList<>(lastShownList);
+
+ if (uniqueTargetIndexes.size() > 0) {
+ internshipsToDelete = uniqueTargetIndexes.stream()
+ .map(index -> lastShownList.get(index.getZeroBased()))
+ .collect(Collectors.toList());
+ }
+
+ logger.info(String.format("Deleting internships: %s", Arrays.toString(internshipsToDelete.toArray())));
+
+ for (Internship internshipToDelete: internshipsToDelete) {
+ //Delete internship
+ model.deleteInternship(internshipToDelete);
+ //Update right panel
+ if (internshipToDelete.equals(model.getSelectedInternship())) {
+ model.updateSelectedInternship(null);
+ }
+ }
+
+ int newSize = model.getFilteredInternshipList().size();
+
+ return new CommandResult(String.format(MESSAGE_DELETE_INTERNSHIP_SUCCESS, previousSize - newSize));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof DeleteIndexCommand // instanceof handles nulls
+ && new HashSet<>(this.targetIndexes).equals(new HashSet<>(((DeleteIndexCommand) other).targetIndexes)));
+ }
+}
diff --git a/src/main/java/seedu/internship/logic/commands/EditCommand.java b/src/main/java/seedu/internship/logic/commands/EditCommand.java
new file mode 100644
index 00000000000..c163158fa4f
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/commands/EditCommand.java
@@ -0,0 +1,247 @@
+package seedu.internship.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_COMMENT;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_ROLE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_STATUS;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.internship.model.Model.PREDICATE_SHOW_ALL_INTERNSHIPS;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import seedu.internship.commons.core.Messages;
+import seedu.internship.commons.core.index.Index;
+import seedu.internship.commons.util.CollectionUtil;
+import seedu.internship.logic.commands.exceptions.CommandException;
+import seedu.internship.model.Model;
+import seedu.internship.model.internship.Comment;
+import seedu.internship.model.internship.CompanyName;
+import seedu.internship.model.internship.Date;
+import seedu.internship.model.internship.Internship;
+import seedu.internship.model.internship.Role;
+import seedu.internship.model.internship.Status;
+import seedu.internship.model.tag.Tag;
+
+/**
+ * Edits the details of an existing internship in InternBuddy.
+ */
+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 internship identified "
+ + "by the index number used in the displayed internship list. "
+ + "Existing values will be overwritten by the input values.\n"
+ + "Fields: INDEX (must be a positive integer) "
+ + "[" + PREFIX_COMPANY_NAME + "COMPANY_NAME] "
+ + "[" + PREFIX_ROLE + "ROLE] "
+ + "[" + PREFIX_STATUS + "STATUS] "
+ + "[" + PREFIX_DATE + "DATE] "
+ + "[" + PREFIX_COMMENT + "COMMENT] "
+ + "[" + PREFIX_TAG + "TAG]...\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_ROLE + "Backend Engineer "
+ + PREFIX_STATUS + "Interview";
+
+ public static final String MESSAGE_EDIT_INTERNSHIP_SUCCESS = "Edited Internship: %1$s";
+ public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
+ public static final String MESSAGE_DUPLICATE_INTERNSHIP = "This internship already exists in InternBuddy.";
+
+ private final Index index;
+ private final EditInternshipDescriptor editInternshipDescriptor;
+
+ /**
+ * @param index of the internship in the filtered internship list to edit
+ * @param editInternshipDescriptor details to edit the internship with
+ */
+ public EditCommand(Index index, EditInternshipDescriptor editInternshipDescriptor) {
+ requireNonNull(index);
+ requireNonNull(editInternshipDescriptor);
+
+ this.index = index;
+ this.editInternshipDescriptor = new EditInternshipDescriptor(editInternshipDescriptor);
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredInternshipList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_OUT_OF_RANGE_INTERNSHIP_DISPLAYED_INDEX);
+ }
+
+ Internship internshipToEdit = lastShownList.get(index.getZeroBased());
+ Internship editedInternship = createEditedInternship(internshipToEdit, editInternshipDescriptor);
+
+ if (!internshipToEdit.isSameInternship(editedInternship) && model.hasInternship(editedInternship)) {
+ throw new CommandException(MESSAGE_DUPLICATE_INTERNSHIP);
+ }
+
+ //Edit functionality
+ model.setInternship(internshipToEdit, editedInternship);
+ model.updateFilteredInternshipList(PREDICATE_SHOW_ALL_INTERNSHIPS);
+ model.updateSelectedInternship(editedInternship);
+ return new CommandResult(String.format(MESSAGE_EDIT_INTERNSHIP_SUCCESS, editedInternship));
+ }
+
+ /**
+ * Creates and returns a {@code Internship} with the details of {@code internshipToEdit}
+ * edited with {@code editInternshipDescriptor}.
+ */
+ private static Internship createEditedInternship(Internship internshipToEdit,
+ EditInternshipDescriptor editInternshipDescriptor) {
+
+ assert internshipToEdit != null;
+ CompanyName updatedCompanyName = editInternshipDescriptor.getCompanyName()
+ .orElse(internshipToEdit.getCompanyName());
+ Role updatedRole = editInternshipDescriptor.getRole().orElse(internshipToEdit.getRole());
+ Status updatedStatus = editInternshipDescriptor.getStatus().orElse(internshipToEdit.getStatus());
+ Date updatedDate = editInternshipDescriptor.getDate().orElse(internshipToEdit.getDate());
+ Comment updatedComment = editInternshipDescriptor.getComment().orElse(internshipToEdit.getComment());
+ Set updatedTags = editInternshipDescriptor.getTags().orElse(internshipToEdit.getTags());
+
+ return new Internship(updatedCompanyName, updatedRole, updatedStatus, updatedDate, updatedComment,
+ 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)
+ && editInternshipDescriptor.equals(e.editInternshipDescriptor);
+ }
+
+ /**
+ * Stores the details to edit the internship with. Each non-empty field value will replace the
+ * corresponding field value of the internship.
+ */
+ public static class EditInternshipDescriptor {
+ private CompanyName companyName;
+ private Role role;
+ private Status status;
+ private Date date;
+ private Comment comment;
+ private Set tags;
+
+ public EditInternshipDescriptor() {}
+
+ /**
+ * Copy constructor.
+ * A defensive copy of {@code tags} is used internally.
+ */
+ public EditInternshipDescriptor(EditInternshipDescriptor toCopy) {
+ setCompanyName(toCopy.companyName);
+ setRole(toCopy.role);
+ setStatus(toCopy.status);
+ setDate(toCopy.date);
+ setComment(toCopy.comment);
+ setTags(toCopy.tags);
+ }
+
+ /**
+ * Returns true if at least one field is edited.
+ */
+ public boolean isAnyFieldEdited() {
+ return CollectionUtil.isAnyNonNull(companyName, role, status, date, comment, tags);
+ }
+
+ public void setCompanyName(CompanyName companyName) {
+ this.companyName = companyName;
+ }
+
+ public Optional getCompanyName() {
+ return Optional.ofNullable(companyName);
+ }
+
+ public void setRole(Role role) {
+ this.role = role;
+ }
+
+ public Optional getRole() {
+ return Optional.ofNullable(role);
+ }
+
+
+ public void setStatus(Status status) {
+ this.status = status;
+ }
+
+ public Optional getStatus() {
+ return Optional.ofNullable(status);
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public Optional getDate() {
+ return Optional.ofNullable(date);
+ }
+
+ public void setComment(Comment comment) {
+ this.comment = comment;
+ }
+
+ public Optional getComment() {
+ return Optional.ofNullable(comment);
+ }
+
+ /**
+ * 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 EditInternshipDescriptor)) {
+ return false;
+ }
+
+ // state check
+ EditInternshipDescriptor e = (EditInternshipDescriptor) other;
+
+ return getCompanyName().equals(e.getCompanyName())
+ && getRole().equals(e.getRole())
+ && getStatus().equals(e.getStatus())
+ && getDate().equals(e.getDate())
+ && getComment().equals(e.getComment())
+ && getTags().equals(e.getTags());
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/internship/logic/commands/ExitCommand.java
similarity index 75%
rename from src/main/java/seedu/address/logic/commands/ExitCommand.java
rename to src/main/java/seedu/internship/logic/commands/ExitCommand.java
index 3dd85a8ba90..fa965bb9418 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/seedu/internship/logic/commands/ExitCommand.java
@@ -1,6 +1,6 @@
-package seedu.address.logic.commands;
+package seedu.internship.logic.commands;
-import seedu.address.model.Model;
+import seedu.internship.model.Model;
/**
* Terminates the program.
@@ -9,7 +9,7 @@ public class ExitCommand extends Command {
public static final String COMMAND_WORD = "exit";
- public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ...";
+ public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting InternBuddy as requested ...";
@Override
public CommandResult execute(Model model) {
diff --git a/src/main/java/seedu/internship/logic/commands/FindCommand.java b/src/main/java/seedu/internship/logic/commands/FindCommand.java
new file mode 100644
index 00000000000..209b168eb7f
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/commands/FindCommand.java
@@ -0,0 +1,62 @@
+package seedu.internship.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_ROLE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_STATUS;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_TAG;
+
+import seedu.internship.commons.core.Messages;
+import seedu.internship.model.Model;
+import seedu.internship.model.internship.InternshipContainsKeywordsPredicate;
+
+/**
+ * Finds and lists all internships in InternBuddy which match with the given search terms
+ * 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 internships containing at least one of the "
+ + "inputs for every different field (COMPANY_NAME, ROLE, STATUS, DATE or TAG) that you have provided.\n"
+ + "Fields: "
+ + "[" + PREFIX_COMPANY_NAME + "COMPANY_NAME]... "
+ + "[" + PREFIX_ROLE + "ROLE]... "
+ + "[" + PREFIX_STATUS + "STATUS]... "
+ + "[" + PREFIX_DATE + "DATE]... "
+ + "[" + PREFIX_TAG + "TAG]...\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_COMPANY_NAME + "Apple "
+ + PREFIX_COMPANY_NAME + "Google "
+ + PREFIX_ROLE + "Software Developer "
+ + PREFIX_ROLE + "App Developer "
+ + PREFIX_STATUS + "Applied "
+ + PREFIX_STATUS + "Offered "
+ + PREFIX_DATE + "2023-01-01 "
+ + PREFIX_DATE + "2023-02-02 "
+ + PREFIX_TAG + "Python "
+ + PREFIX_TAG + "Java";
+
+ private final InternshipContainsKeywordsPredicate predicate;
+
+ public FindCommand(InternshipContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredInternshipList(predicate);
+ return new CommandResult(
+ String.format(Messages.MESSAGE_INTERNSHIP_LISTED_OVERVIEW, model.getFilteredInternshipList().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/HelpCommand.java b/src/main/java/seedu/internship/logic/commands/HelpCommand.java
similarity index 87%
rename from src/main/java/seedu/address/logic/commands/HelpCommand.java
rename to src/main/java/seedu/internship/logic/commands/HelpCommand.java
index bf824f91bd0..d6278a3ad0b 100644
--- a/src/main/java/seedu/address/logic/commands/HelpCommand.java
+++ b/src/main/java/seedu/internship/logic/commands/HelpCommand.java
@@ -1,6 +1,6 @@
-package seedu.address.logic.commands;
+package seedu.internship.logic.commands;
-import seedu.address.model.Model;
+import seedu.internship.model.Model;
/**
* Format full help instructions for every command for display.
diff --git a/src/main/java/seedu/internship/logic/commands/ListCommand.java b/src/main/java/seedu/internship/logic/commands/ListCommand.java
new file mode 100644
index 00000000000..ee049430373
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/commands/ListCommand.java
@@ -0,0 +1,25 @@
+package seedu.internship.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.model.Model.PREDICATE_SHOW_ALL_INTERNSHIPS;
+
+import seedu.internship.model.Model;
+
+/**
+ * Lists all internships in InternBuddy to the user.
+ */
+public class ListCommand extends Command {
+
+ public static final String COMMAND_WORD = "list";
+
+ public static final String MESSAGE_SUCCESS = "Listed all internships";
+
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredInternshipList(PREDICATE_SHOW_ALL_INTERNSHIPS);
+ model.updateSelectedInternship(null);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/internship/logic/commands/UpcomingCommand.java b/src/main/java/seedu/internship/logic/commands/UpcomingCommand.java
new file mode 100644
index 00000000000..f6555d0efaa
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/commands/UpcomingCommand.java
@@ -0,0 +1,31 @@
+package seedu.internship.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.model.Model.PREDICATE_SHOW_UPCOMING_INTERNSHIPS;
+
+import seedu.internship.logic.commands.exceptions.CommandException;
+import seedu.internship.model.Model;
+
+
+/**
+ * Lists all internships that have deadlines in the upcoming week.
+ */
+public class UpcomingCommand extends Command {
+
+ public static final String COMMAND_WORD = "upcoming";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Lists all internships with events or deadlines in the upcoming week\n"
+ + "No fields required. Any fields will be ignored.\n"
+ + "Example: " + COMMAND_WORD;
+
+ public static final String MESSAGE_SUCCESS = "Listed all internships with events or deadlines "
+ + "in the upcoming week";
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ model.updateFilteredInternshipList(PREDICATE_SHOW_UPCOMING_INTERNSHIPS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/internship/logic/commands/ViewCommand.java b/src/main/java/seedu/internship/logic/commands/ViewCommand.java
new file mode 100644
index 00000000000..4aafefc0b63
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/commands/ViewCommand.java
@@ -0,0 +1,57 @@
+package seedu.internship.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import seedu.internship.commons.core.Messages;
+import seedu.internship.commons.core.index.Index;
+import seedu.internship.logic.commands.exceptions.CommandException;
+import seedu.internship.model.Model;
+import seedu.internship.model.internship.Internship;
+
+/**
+ * Views an internship identified using it's displayed index from InternBuddy.
+ */
+public class ViewCommand extends Command {
+
+ public static final String COMMAND_WORD = "view";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Views the internship identified by the index number used in the displayed internship list.\n"
+ + "Fields: INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ public static final String MESSAGE_VIEW_INTERNSHIP_SUCCESS = "Viewed Internship: %1$s";
+
+ private final Index targetIndex;
+
+ public ViewCommand(Index targetIndex) {
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredInternshipList();
+
+ //Checks for a valid index
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_OUT_OF_RANGE_INTERNSHIP_DISPLAYED_INDEX);
+ }
+
+ //Gets the internship to view
+ Internship internshipToView = lastShownList.get(targetIndex.getZeroBased());
+
+ //Functionality of the view internship command
+ model.updateSelectedInternship(internshipToView);
+ return new CommandResult(String.format(MESSAGE_VIEW_INTERNSHIP_SUCCESS, internshipToView));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ViewCommand // instanceof handles nulls
+ && targetIndex.equals(((ViewCommand) other).targetIndex)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java b/src/main/java/seedu/internship/logic/commands/exceptions/CommandException.java
similarity index 89%
rename from src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
rename to src/main/java/seedu/internship/logic/commands/exceptions/CommandException.java
index a16bd14f2cd..19564e639bd 100644
--- a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
+++ b/src/main/java/seedu/internship/logic/commands/exceptions/CommandException.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.commands.exceptions;
+package seedu.internship.logic.commands.exceptions;
/**
* Represents an error which occurs during execution of a {@link Command}.
diff --git a/src/main/java/seedu/internship/logic/parser/AddCommandParser.java b/src/main/java/seedu/internship/logic/parser/AddCommandParser.java
new file mode 100644
index 00000000000..98bffcb305b
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/parser/AddCommandParser.java
@@ -0,0 +1,64 @@
+package seedu.internship.logic.parser;
+
+import static seedu.internship.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_COMMENT;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_ROLE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_STATUS;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.Set;
+import java.util.stream.Stream;
+
+import seedu.internship.logic.commands.AddCommand;
+import seedu.internship.logic.parser.exceptions.ParseException;
+import seedu.internship.model.internship.Comment;
+import seedu.internship.model.internship.CompanyName;
+import seedu.internship.model.internship.Date;
+import seedu.internship.model.internship.Internship;
+import seedu.internship.model.internship.Role;
+import seedu.internship.model.internship.Status;
+import seedu.internship.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_COMPANY_NAME, PREFIX_ROLE, PREFIX_STATUS, PREFIX_DATE,
+ PREFIX_COMMENT, PREFIX_TAG);
+ //Note that comment and tags are optional
+ if (!arePrefixesPresent(argMultimap, PREFIX_COMPANY_NAME, PREFIX_ROLE, PREFIX_STATUS, PREFIX_DATE)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
+ }
+
+ CompanyName companyName = ParserUtil.parseCompanyName(argMultimap.getValue(PREFIX_COMPANY_NAME).get());
+ Role role = ParserUtil.parseRole(argMultimap.getValue(PREFIX_ROLE).get());
+ Status status = ParserUtil.parseStatus(argMultimap.getValue(PREFIX_STATUS).get());
+ Date date = ParserUtil.parseDate(argMultimap.getValue(PREFIX_DATE).get());
+ Comment comment = ParserUtil.parseComment(argMultimap.getOptionalValue(PREFIX_COMMENT).get());
+ Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
+
+ Internship internship = new Internship(companyName, role, status, date, comment, tagList);
+
+ return new AddCommand(internship);
+ }
+
+ /**
+ * 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/ArgumentMultimap.java b/src/main/java/seedu/internship/logic/parser/ArgumentMultimap.java
similarity index 86%
rename from src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
rename to src/main/java/seedu/internship/logic/parser/ArgumentMultimap.java
index 954c8e18f8e..96a00c19906 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
+++ b/src/main/java/seedu/internship/logic/parser/ArgumentMultimap.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package seedu.internship.logic.parser;
import java.util.ArrayList;
import java.util.HashMap;
@@ -39,6 +39,14 @@ public Optional getValue(Prefix prefix) {
return values.isEmpty() ? Optional.empty() : Optional.of(values.get(values.size() - 1));
}
+ /**
+ * Returns the last value of {@code prefix} for optional fields.
+ */
+ public Optional getOptionalValue(Prefix prefix) {
+ List values = getAllValues(prefix);
+ return values.isEmpty() ? Optional.of("NA") : Optional.of(values.get(values.size() - 1));
+ }
+
/**
* Returns all values of {@code prefix}.
* If the prefix does not exist or has no values, this will return an empty list.
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java b/src/main/java/seedu/internship/logic/parser/ArgumentTokenizer.java
similarity index 99%
rename from src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
rename to src/main/java/seedu/internship/logic/parser/ArgumentTokenizer.java
index 5c9aebfa488..e4cf583c0ff 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
+++ b/src/main/java/seedu/internship/logic/parser/ArgumentTokenizer.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package seedu.internship.logic.parser;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/src/main/java/seedu/internship/logic/parser/CliSyntax.java b/src/main/java/seedu/internship/logic/parser/CliSyntax.java
new file mode 100644
index 00000000000..65c61380ce6
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/parser/CliSyntax.java
@@ -0,0 +1,16 @@
+package seedu.internship.logic.parser;
+
+/**
+ * Contains Command Line Interface (CLI) syntax definitions common to multiple commands
+ */
+public class CliSyntax {
+
+ /* Prefix definitions */
+ public static final Prefix PREFIX_COMPANY_NAME = new Prefix("n/");
+ public static final Prefix PREFIX_ROLE = new Prefix("r/");
+ public static final Prefix PREFIX_STATUS = new Prefix("s/");
+ public static final Prefix PREFIX_DATE = new Prefix("d/");
+ public static final Prefix PREFIX_COMMENT = new Prefix("c/");
+ public static final Prefix PREFIX_TAG = new Prefix("t/");
+
+}
diff --git a/src/main/java/seedu/internship/logic/parser/CopyCommandParser.java b/src/main/java/seedu/internship/logic/parser/CopyCommandParser.java
new file mode 100644
index 00000000000..116d896a3fb
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/parser/CopyCommandParser.java
@@ -0,0 +1,30 @@
+package seedu.internship.logic.parser;
+
+import seedu.internship.commons.core.index.Index;
+import seedu.internship.logic.commands.CopyCommand;
+import seedu.internship.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new CopyCommand object
+ */
+public class CopyCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the CopyCommand
+ * and returns a CopyCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public CopyCommand parse(String args) throws ParseException {
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(args);
+ assert index.getZeroBased() > -1;
+ } catch (ParseException pe) {
+ ParseException e = ParserUtil.handleIndexException(pe, CopyCommand.MESSAGE_USAGE);
+ throw e;
+ }
+ return new CopyCommand(index);
+ }
+
+}
diff --git a/src/main/java/seedu/internship/logic/parser/DeleteFieldCommandParser.java b/src/main/java/seedu/internship/logic/parser/DeleteFieldCommandParser.java
new file mode 100644
index 00000000000..e792919a957
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/parser/DeleteFieldCommandParser.java
@@ -0,0 +1,65 @@
+package seedu.internship.logic.parser;
+
+import static seedu.internship.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.internship.commons.core.Messages.MESSAGE_MISSING_ARGUMENTS;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_ROLE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_STATUS;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.internship.logic.parser.ParserUtil.parseCompanyNamesToString;
+import static seedu.internship.logic.parser.ParserUtil.parseDatesToString;
+import static seedu.internship.logic.parser.ParserUtil.parseRolesToString;
+import static seedu.internship.logic.parser.ParserUtil.parseStatusesToString;
+import static seedu.internship.logic.parser.ParserUtil.parseTagsToString;
+
+import java.util.List;
+
+import seedu.internship.logic.commands.DeleteFieldCommand;
+import seedu.internship.logic.parser.exceptions.ParseException;
+import seedu.internship.model.internship.InternshipContainsKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new DeleteCommand object
+ */
+public class DeleteFieldCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteFieldCommand
+ * and returns a DeleteFieldCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeleteFieldCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_COMPANY_NAME, PREFIX_ROLE, PREFIX_STATUS, PREFIX_DATE,
+ PREFIX_TAG);
+
+ if (!argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteFieldCommand.MESSAGE_USAGE));
+ }
+
+ if (argMultimap.getValue(PREFIX_COMPANY_NAME).isEmpty()
+ && argMultimap.getValue(PREFIX_ROLE).isEmpty()
+ && argMultimap.getValue(PREFIX_STATUS).isEmpty()
+ && argMultimap.getValue(PREFIX_DATE).isEmpty()
+ && argMultimap.getValue(PREFIX_TAG).isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_MISSING_ARGUMENTS, DeleteFieldCommand.MESSAGE_USAGE));
+ }
+
+ List nameList = parseCompanyNamesToString(argMultimap.getAllValues(PREFIX_COMPANY_NAME));
+ List roleList = parseRolesToString(argMultimap.getAllValues(PREFIX_ROLE));
+ List statusList = parseStatusesToString(argMultimap.getAllValues(PREFIX_STATUS));
+ List dateList = parseDatesToString(argMultimap.getAllValues(PREFIX_DATE));
+ List tagList = parseTagsToString(argMultimap.getAllValues(PREFIX_TAG));
+
+ InternshipContainsKeywordsPredicate newPredicate = new InternshipContainsKeywordsPredicate(nameList,
+ roleList, statusList, dateList, tagList);
+
+
+ return new DeleteFieldCommand(newPredicate);
+ }
+
+
+
+}
diff --git a/src/main/java/seedu/internship/logic/parser/DeleteIndexCommandParser.java b/src/main/java/seedu/internship/logic/parser/DeleteIndexCommandParser.java
new file mode 100644
index 00000000000..f49bf231196
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/parser/DeleteIndexCommandParser.java
@@ -0,0 +1,39 @@
+package seedu.internship.logic.parser;
+
+import static seedu.internship.commons.core.Messages.MESSAGE_MISSING_ARGUMENTS;
+
+import java.util.List;
+
+import seedu.internship.commons.core.index.Index;
+import seedu.internship.logic.commands.DeleteIndexCommand;
+import seedu.internship.logic.parser.exceptions.ParseException;
+
+
+/**
+ * Parses input arguments and creates a new DeleteCommand object
+ */
+public class DeleteIndexCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteIndexCommand
+ * and returns a DeleteIndexCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeleteIndexCommand parse(String args) throws ParseException {
+ if (args.trim().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_MISSING_ARGUMENTS, DeleteIndexCommand.MESSAGE_USAGE));
+ }
+
+ List indexes;
+
+ try {
+ indexes = ParserUtil.parseIndexes(args);
+ assert indexes != null;
+ } catch (ParseException pe) {
+ ParseException e = ParserUtil.handleIndexException(pe, DeleteIndexCommand.MESSAGE_USAGE);
+ throw e;
+ }
+
+ return new DeleteIndexCommand(indexes);
+ }
+}
diff --git a/src/main/java/seedu/internship/logic/parser/EditCommandParser.java b/src/main/java/seedu/internship/logic/parser/EditCommandParser.java
new file mode 100644
index 00000000000..e5505989e9e
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/parser/EditCommandParser.java
@@ -0,0 +1,117 @@
+package seedu.internship.logic.parser;
+
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_COMMENT;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_ROLE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_STATUS;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import seedu.internship.commons.core.LogsCenter;
+import seedu.internship.commons.core.index.Index;
+import seedu.internship.logic.commands.EditCommand;
+import seedu.internship.logic.commands.EditCommand.EditInternshipDescriptor;
+import seedu.internship.logic.parser.exceptions.ParseException;
+import seedu.internship.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
+ */
+
+ private static final Logger logger = LogsCenter.getLogger(EditCommandParser.class);
+
+ /**
+ * Parses arguments to construct an {@code EditCommand}
+ *
+ * @param args Raw user input.
+ * @return an {@code EditCommand} encapsulating the user's input.
+ * @throws ParseException if the user's input cannot be parsed into a valid {@code EditCommand}.
+ */
+ public EditCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_COMPANY_NAME, PREFIX_STATUS, PREFIX_ROLE, PREFIX_DATE,
+ PREFIX_COMMENT, PREFIX_TAG);
+
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ ParseException e = ParserUtil.handleIndexException(pe, EditCommand.MESSAGE_USAGE);
+ throw e;
+ }
+
+ EditInternshipDescriptor editInternshipDescriptor = new EditCommand.EditInternshipDescriptor();
+ if (argMultimap.getValue(PREFIX_COMPANY_NAME).isPresent()) {
+ editInternshipDescriptor.setCompanyName(ParserUtil.parseCompanyName(argMultimap.getValue(
+ PREFIX_COMPANY_NAME).get()));
+ }
+ if (argMultimap.getValue(PREFIX_ROLE).isPresent()) {
+ editInternshipDescriptor.setRole(ParserUtil.parseRole(argMultimap.getValue(PREFIX_ROLE).get()));
+ }
+ if (argMultimap.getValue(PREFIX_STATUS).isPresent()) {
+ editInternshipDescriptor.setStatus(ParserUtil.parseStatus(argMultimap.getValue(PREFIX_STATUS).get()));
+ }
+ if (argMultimap.getValue(PREFIX_DATE).isPresent()) {
+ editInternshipDescriptor.setDate(ParserUtil.parseDate(argMultimap.getValue(PREFIX_DATE).get()));
+ }
+ if (argMultimap.getValue(PREFIX_COMMENT).isPresent()) {
+ String commentContent = "";
+ try {
+ String userInput = argMultimap.getValue(PREFIX_COMMENT).get();
+ if (userInput.equals("")) {
+ logger.info("User entered empty comment string, should reset comment to NA");
+ commentContent = "NA";
+ } else {
+ commentContent = userInput;
+ }
+ } catch (NoSuchElementException emptyComment) {
+ //Should not reach here
+ assert(false);
+ }
+ editInternshipDescriptor.setComment(ParserUtil.parseComment(commentContent));
+ }
+
+ parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editInternshipDescriptor::setTags);
+
+ if (!editInternshipDescriptor.isAnyFieldEdited()) {
+ throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
+ }
+
+ return new EditCommand(index, editInternshipDescriptor);
+ }
+
+ /**
+ * 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/internship/logic/parser/FindCommandParser.java b/src/main/java/seedu/internship/logic/parser/FindCommandParser.java
new file mode 100644
index 00000000000..240b929acb8
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/parser/FindCommandParser.java
@@ -0,0 +1,65 @@
+package seedu.internship.logic.parser;
+
+import static seedu.internship.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_COMPANY_NAME;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_DATE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_ROLE;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_STATUS;
+import static seedu.internship.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.internship.logic.parser.ParserUtil.parseCompanyNamesToString;
+import static seedu.internship.logic.parser.ParserUtil.parseDatesToString;
+import static seedu.internship.logic.parser.ParserUtil.parseRolesToString;
+import static seedu.internship.logic.parser.ParserUtil.parseStatusesToString;
+import static seedu.internship.logic.parser.ParserUtil.parseTagsToString;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+import seedu.internship.commons.core.LogsCenter;
+import seedu.internship.logic.commands.FindCommand;
+import seedu.internship.logic.parser.exceptions.ParseException;
+import seedu.internship.model.internship.InternshipContainsKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new FindCommand object
+ */
+public class FindCommandParser implements Parser {
+ private static final Logger logger = LogsCenter.getLogger(FindCommandParser.class);
+
+
+ /**
+ * 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 {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_COMPANY_NAME, PREFIX_ROLE, PREFIX_STATUS, PREFIX_DATE,
+ PREFIX_TAG);
+
+ if (!argMultimap.getPreamble().isEmpty()) {
+ FindCommandParser.logger.info("User inputted find command with non-empty preamble.");
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+
+ if (!argMultimap.getValue(PREFIX_COMPANY_NAME).isPresent()
+ && !argMultimap.getValue(PREFIX_ROLE).isPresent()
+ && !argMultimap.getValue(PREFIX_STATUS).isPresent()
+ && !argMultimap.getValue(PREFIX_DATE).isPresent()
+ && !argMultimap.getValue(PREFIX_TAG).isPresent()) {
+ FindCommandParser.logger.info("User inputted find command with no fields");
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+ //@@author kohkaixun
+ List nameList = parseCompanyNamesToString(argMultimap.getAllValues(PREFIX_COMPANY_NAME));
+ List roleList = parseRolesToString(argMultimap.getAllValues(PREFIX_ROLE));
+ List statusList = parseStatusesToString(argMultimap.getAllValues(PREFIX_STATUS));
+ List dateList = parseDatesToString(argMultimap.getAllValues(PREFIX_DATE));
+ List tagList = parseTagsToString(argMultimap.getAllValues(PREFIX_TAG));
+ //@@author
+ return new FindCommand(new InternshipContainsKeywordsPredicate(nameList, roleList, statusList, dateList,
+ tagList));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/internship/logic/parser/InternBuddyParser.java
similarity index 53%
rename from src/main/java/seedu/address/logic/parser/AddressBookParser.java
rename to src/main/java/seedu/internship/logic/parser/InternBuddyParser.java
index 1e466792b46..1063fb00f95 100644
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ b/src/main/java/seedu/internship/logic/parser/InternBuddyParser.java
@@ -1,26 +1,30 @@
-package seedu.address.logic.parser;
+package seedu.internship.logic.parser;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
+import static seedu.internship.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.internship.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;
+import seedu.internship.logic.commands.AddCommand;
+import seedu.internship.logic.commands.ClearCommand;
+import seedu.internship.logic.commands.Command;
+import seedu.internship.logic.commands.CopyCommand;
+import seedu.internship.logic.commands.DeleteFieldCommand;
+import seedu.internship.logic.commands.DeleteIndexCommand;
+import seedu.internship.logic.commands.EditCommand;
+import seedu.internship.logic.commands.ExitCommand;
+import seedu.internship.logic.commands.FindCommand;
+import seedu.internship.logic.commands.HelpCommand;
+import seedu.internship.logic.commands.ListCommand;
+import seedu.internship.logic.commands.UpcomingCommand;
+import seedu.internship.logic.commands.ViewCommand;
+import seedu.internship.logic.parser.exceptions.ParseException;
/**
* Parses user input.
*/
-public class AddressBookParser {
+public class InternBuddyParser {
/**
* Used for initial separation of command word and args.
@@ -50,8 +54,11 @@ public Command parseCommand(String userInput) throws ParseException {
case EditCommand.COMMAND_WORD:
return new EditCommandParser().parse(arguments);
- case DeleteCommand.COMMAND_WORD:
- return new DeleteCommandParser().parse(arguments);
+ case DeleteIndexCommand.COMMAND_WORD:
+ return new DeleteIndexCommandParser().parse(arguments);
+
+ case DeleteFieldCommand.COMMAND_WORD:
+ return new DeleteFieldCommandParser().parse(arguments);
case ClearCommand.COMMAND_WORD:
return new ClearCommand();
@@ -68,6 +75,15 @@ public Command parseCommand(String userInput) throws ParseException {
case HelpCommand.COMMAND_WORD:
return new HelpCommand();
+ case ViewCommand.COMMAND_WORD:
+ return new ViewCommandParser().parse(arguments);
+
+ case CopyCommand.COMMAND_WORD:
+ return new CopyCommandParser().parse(arguments);
+
+ case UpcomingCommand.COMMAND_WORD:
+ return new UpcomingCommand();
+
default:
throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
}
diff --git a/src/main/java/seedu/address/logic/parser/Parser.java b/src/main/java/seedu/internship/logic/parser/Parser.java
similarity index 71%
rename from src/main/java/seedu/address/logic/parser/Parser.java
rename to src/main/java/seedu/internship/logic/parser/Parser.java
index d6551ad8e3f..244a87311cd 100644
--- a/src/main/java/seedu/address/logic/parser/Parser.java
+++ b/src/main/java/seedu/internship/logic/parser/Parser.java
@@ -1,7 +1,7 @@
-package seedu.address.logic.parser;
+package seedu.internship.logic.parser;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.internship.logic.commands.Command;
+import seedu.internship.logic.parser.exceptions.ParseException;
/**
* Represents a Parser that is able to parse user input into a {@code Command} of type {@code T}.
diff --git a/src/main/java/seedu/internship/logic/parser/ParserUtil.java b/src/main/java/seedu/internship/logic/parser/ParserUtil.java
new file mode 100644
index 00000000000..93dd2a41894
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/parser/ParserUtil.java
@@ -0,0 +1,324 @@
+package seedu.internship.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.internship.commons.core.Messages.MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import seedu.internship.commons.core.index.Index;
+import seedu.internship.commons.util.StringUtil;
+import seedu.internship.logic.parser.exceptions.ParseException;
+import seedu.internship.model.internship.Comment;
+import seedu.internship.model.internship.CompanyName;
+import seedu.internship.model.internship.Date;
+import seedu.internship.model.internship.Role;
+import seedu.internship.model.internship.Status;
+import seedu.internship.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 smaller than 1.";
+ public static final String MESSAGE_INVALID_POSITIVE_SIGNED_INDEX = "Index has positive sign.";
+ public static final String MESSAGE_INVALID_INDEX_FORMAT = "Index is not an 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();
+ try {
+ StringUtil.nonZeroUnsignedIntegerCheck(trimmedIndex);
+ } catch (ParseException pe) {
+ throw pe;
+ }
+ return Index.fromOneBased(Integer.parseInt(trimmedIndex));
+ }
+ /**
+ * Parses {@code oneBasedIndexes} into a {@code List} and returns it. Leading and trailing whitespaces will
+ * be trimmed.
+ * @throws ParseException if any specified index is invalid (not non-zero unsigned integer).
+ */
+ public static List parseIndexes(String oneBasedIndexes) throws ParseException {
+ List tokens = Arrays.asList(oneBasedIndexes.split("\\s+"))
+ .stream()
+ .filter(s -> !s.isEmpty())
+ .collect(Collectors.toList());
+ List result = new ArrayList<>();
+ for (String index: tokens) {
+ result.add(parseIndex(index));
+ }
+
+ return result;
+ }
+
+ /**
+ * Checks index exception error messages and returns corresponding ParseException
+ * @param pe ParseException from parseIndex or parseIndexes method
+ * @param commandFormatMessage Command format message to be contained in ParseException if to be used
+ * @return New ParseException with the corresponding error message according to message in ParseException given
+ */
+ public static ParseException handleIndexException(ParseException pe, String commandFormatMessage) {
+ if (pe.getMessage().equals(ParserUtil.MESSAGE_INVALID_INDEX)) {
+ return new ParseException(MESSAGE_INVALID_INTERNSHIP_DISPLAYED_INDEX);
+ }
+ return new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, commandFormatMessage), pe);
+ }
+
+ /**
+ * Parses a {@code String companyName} into a {@code CompanyName}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @param companyName The raw company name string.
+ * @return a {@CompanyName} object encapsulating the company name.
+ * @throws ParseException if the given {@code companyName} is invalid.
+ */
+ public static CompanyName parseCompanyName(String companyName) throws ParseException {
+ requireNonNull(companyName);
+ String trimmedName = companyName.trim();
+ if (!CompanyName.isValidCompanyName(trimmedName)) {
+ throw new ParseException(CompanyName.MESSAGE_CONSTRAINTS);
+ }
+ return new CompanyName(trimmedName);
+ }
+
+ /**
+ * Parses a {@code String role} into a {@code Role}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @param role The raw role string to be parsed.
+ * @return the {@code Role} object encapsulating the role.
+ * @throws ParseException if the given {@code role} is invalid.
+ */
+ public static Role parseRole(String role) throws ParseException {
+ requireNonNull(role);
+ String trimmedRole = role.trim();
+ if (!Role.isValidRole(trimmedRole)) {
+ throw new ParseException(Role.MESSAGE_CONSTRAINTS);
+ }
+ return new Role(trimmedRole);
+ }
+
+ /**
+ * Parses a {@code String status} into a {@code Status}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @param status The raw status string to be parsed.
+ * @return the {@code Status} object encapsulating the status.
+ * @throws ParseException if the given {@code status} is invalid.
+ */
+ public static Status parseStatus(String status) throws ParseException {
+ requireNonNull(status);
+ String trimmedStatus = status.trim();
+ if (!Status.isValidStatus(trimmedStatus)) {
+ throw new ParseException(Status.MESSAGE_CONSTRAINTS);
+ }
+ return new Status(trimmedStatus);
+ }
+
+ /**
+ * Parses a {@code String date} into an {@code Date}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @param date The raw date string to be parsed.
+ * @return the {@code Date} object encapsulating the date.
+ * @throws ParseException if the given {@code date} is invalid.
+ */
+ public static Date parseDate(String date) throws ParseException {
+ requireNonNull(date);
+ String trimmedDate = date.trim();
+ if (!Date.isValidDate(trimmedDate)) {
+ throw new ParseException(Date.MESSAGE_CONSTRAINTS);
+ }
+ return new Date(trimmedDate);
+ }
+
+ /**
+ * Parses a {@code String comment} into an {@code Comment}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @param commentContent The raw comment to be parsed.
+ * @return a {@code Comment} object encapsulating the comment content.
+ * @throws ParseException if the given {@code comment} is invalid.
+ */
+ public static Comment parseComment(String commentContent) throws ParseException {
+ String trimmedComment = commentContent.trim();
+ if (!Comment.isValidComment(trimmedComment)) {
+ throw new ParseException(Comment.MESSAGE_CONSTRAINTS);
+ }
+ return new Comment(trimmedComment);
+ }
+
+
+ /**
+ * Parses a {@code String tag} into a {@code Tag}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @param tag The raw tag string to be parsed.
+ * @return the {@code Tag} encapsulating the tag string.
+ * @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}.
+ *
+ * @param companyNames The collection of company name strings to be parsed.
+ * @return a set of {@code CompanyName} objects encapsulating the company name strings.
+ */
+ public static Set parseCompanyNames(Collection companyNames) throws ParseException {
+ requireNonNull(companyNames);
+ final Set companyNameSet = new HashSet<>();
+ for (String tagName : companyNames) {
+ companyNameSet.add(parseCompanyName(tagName));
+ }
+ return companyNameSet;
+ }
+
+ /**
+ * Parses {@code Collection tags} into a {@code Set}.
+ *
+ * @param roles The collection of role strings to be parsed.
+ * @return a set of {@code Role} objects encapsulating the role strings.
+ */
+ public static Set parseRoles(Collection roles) throws ParseException {
+ requireNonNull(roles);
+ final Set roleSet = new HashSet<>();
+ for (String role : roles) {
+ roleSet.add(parseRole(role));
+ }
+ return roleSet;
+ }
+
+ /**
+ * Parses {@code Collection tags} into a {@code Set}.
+ *
+ * @param statuses The collection of status strings to be parsed.
+ * @return a set of {@code Tag} objects encapsulating the status strings.
+ */
+ public static Set parseStatuses(Collection statuses) throws ParseException {
+ requireNonNull(statuses);
+ final Set statusSet = new HashSet<>();
+ for (String status : statuses) {
+ statusSet.add(parseStatus(status));
+ }
+ return statusSet;
+ }
+
+ /**
+ * Parses {@code Collection tags} into a {@code Set}.
+ *
+ * @param dates The collection of dates strings to be parsed.
+ * @return a set of {@code Date} objects encapsulating the date strings.
+ */
+ public static Set parseDates(Collection dates) throws ParseException {
+ requireNonNull(dates);
+ final Set dateSet = new HashSet<>();
+ for (String date : dates) {
+ dateSet.add(parseDate(date));
+ }
+ return dateSet;
+ }
+
+ /**
+ * Parses {@code Collection tags} into a {@code Set}.
+ *
+ * @param tags The collection of tag strings to be parsed.
+ * @return a set of {@code Tag} objects encapsulating the tag strings.
+ */
+ 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;
+ }
+
+ //@@author kohkaixun
+
+ /**
+ * Parses {@code List unparsedNames} into a {@code List} of parsed company names.
+ * @param unparsedNames The list of company name strings to be parsed.
+ * @return The list of company name strings that has the correct format.
+ * @throws ParseException if any of the given company names in the list cannot be parsed.
+ */
+ public static List parseCompanyNamesToString(List unparsedNames) throws ParseException {
+ List parsedNames = ParserUtil.parseCompanyNames(unparsedNames).stream()
+ .map(name -> name.fullCompanyName)
+ .collect(Collectors.toList());
+ return parsedNames;
+ }
+
+ /**
+ * Parses {@code List unparsedRoles} into a {@code List} of parsed role names.
+ * @param unparsedRoles The list of role strings to be parsed.
+ * @return The list of role strings that has the correct format.
+ * @throws ParseException if any of the given roles in the list cannot be parsed.
+ */
+ public static List parseRolesToString(List unparsedRoles) throws ParseException {
+ List parsedRoles = ParserUtil.parseRoles(unparsedRoles).stream()
+ .map(role -> role.fullRole)
+ .collect(Collectors.toList());
+ return parsedRoles;
+ }
+
+ /**
+ * Parses {@code List unparsedStatuses} into a {@code List} of parsed statuses.
+ * @param unparsedStatuses The list of status strings to be parsed.
+ * @return The list of status strings that has the correct format.
+ * @throws ParseException if any of the given statuses in the list cannot be parsed.
+ */
+ public static List parseStatusesToString(List unparsedStatuses) throws ParseException {
+ List parsedStatuses = ParserUtil.parseStatuses(unparsedStatuses).stream()
+ .map(status -> status.fullStatus)
+ .collect(Collectors.toList());
+ return parsedStatuses;
+ }
+
+ /**
+ * Parses {@code List unparsedDates} into a {@code List} of parsed dates.
+ * @param unparsedDates The list of date strings to be parsed.
+ * @return The list of date strings that has the correct format.
+ * @throws ParseException if any of the given dates in the list cannot be parsed.
+ */
+ public static List parseDatesToString(List unparsedDates) throws ParseException {
+ List parsedDates = ParserUtil.parseDates(unparsedDates).stream()
+ .map(date -> date.fullDate)
+ .collect(Collectors.toList());
+ return parsedDates;
+ }
+
+ /**
+ * Parses {@code List unparsedTags} into a {@code List} of parsed tags.
+ * @param unparsedTags The list of tag strings to be parsed.
+ * @return The list of tag strings that has the correct format.
+ * @throws ParseException if any of the given tags in the list cannot be parsed.
+ */
+ public static List parseTagsToString(List unparsedTags) throws ParseException {
+ List parsedTags = ParserUtil.parseTags(unparsedTags).stream()
+ .map(tag -> tag.tagName)
+ .collect(Collectors.toList());
+ return parsedTags;
+ }
+ //@@author
+}
diff --git a/src/main/java/seedu/address/logic/parser/Prefix.java b/src/main/java/seedu/internship/logic/parser/Prefix.java
similarity index 95%
rename from src/main/java/seedu/address/logic/parser/Prefix.java
rename to src/main/java/seedu/internship/logic/parser/Prefix.java
index c859d5fa5db..3e88e7fd39d 100644
--- a/src/main/java/seedu/address/logic/parser/Prefix.java
+++ b/src/main/java/seedu/internship/logic/parser/Prefix.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package seedu.internship.logic.parser;
/**
* A prefix that marks the beginning of an argument in an arguments string.
diff --git a/src/main/java/seedu/internship/logic/parser/ViewCommandParser.java b/src/main/java/seedu/internship/logic/parser/ViewCommandParser.java
new file mode 100644
index 00000000000..13bab4c1d5e
--- /dev/null
+++ b/src/main/java/seedu/internship/logic/parser/ViewCommandParser.java
@@ -0,0 +1,30 @@
+package seedu.internship.logic.parser;
+
+import seedu.internship.commons.core.index.Index;
+import seedu.internship.logic.commands.ViewCommand;
+import seedu.internship.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new ViewCommand object
+ */
+public class ViewCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the ViewCommand
+ * and returns a ViewCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public ViewCommand parse(String args) throws ParseException {
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(args);
+ } catch (ParseException pe) {
+ ParseException e = ParserUtil.handleIndexException(pe, ViewCommand.MESSAGE_USAGE);
+ throw e;
+ }
+
+ return new ViewCommand(index);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java b/src/main/java/seedu/internship/logic/parser/exceptions/ParseException.java
similarity index 72%
rename from src/main/java/seedu/address/logic/parser/exceptions/ParseException.java
rename to src/main/java/seedu/internship/logic/parser/exceptions/ParseException.java
index 158a1a54c1c..b72f0f2b459 100644
--- a/src/main/java/seedu/address/logic/parser/exceptions/ParseException.java
+++ b/src/main/java/seedu/internship/logic/parser/exceptions/ParseException.java
@@ -1,6 +1,6 @@
-package seedu.address.logic.parser.exceptions;
+package seedu.internship.logic.parser.exceptions;
-import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.internship.commons.exceptions.IllegalValueException;
/**
* Represents a parse error encountered by a parser.
diff --git a/src/main/java/seedu/internship/model/InternBuddy.java b/src/main/java/seedu/internship/model/InternBuddy.java
new file mode 100644
index 00000000000..120e156e0a9
--- /dev/null
+++ b/src/main/java/seedu/internship/model/InternBuddy.java
@@ -0,0 +1,151 @@
+package seedu.internship.model;
+
+import static java.util.Objects.requireNonNull;
+
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import java.util.List;
+import javax.swing.SwingUtilities;
+
+import javafx.collections.ObservableList;
+import seedu.internship.model.internship.Internship;
+import seedu.internship.model.internship.UniqueInternshipList;
+
+/**
+ * Wraps all data at the InternBuddy level
+ * Duplicates are not allowed (by .isSameInternship comparison)
+ */
+public class InternBuddy implements ReadOnlyInternBuddy {
+
+ private final UniqueInternshipList internships;
+
+ /*
+ * 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.
+ */
+ {
+ internships = new UniqueInternshipList();
+ }
+
+ public InternBuddy() {}
+
+ /**
+ * Creates an InternBuddy using the Internships in the {@code toBeCopied}
+ */
+ public InternBuddy(ReadOnlyInternBuddy toBeCopied) {
+ this();
+ resetData(toBeCopied);
+ }
+
+ //// list overwrite operations
+
+ /**
+ * Replaces the contents of the Internship list with {@code internships}.
+ * {@code internships} must not contain duplicate internships.
+ */
+ public void setInternships(List internships) {
+ this.internships.setInternships(internships);
+ }
+
+ /**
+ * Resets the existing data of this {@code InternBuddy} with {@code newData}.
+ */
+ public void resetData(ReadOnlyInternBuddy newData) {
+ requireNonNull(newData);
+
+ setInternships(newData.getInternshipList());
+ }
+
+ //// internship-level operations
+
+ /**
+ * Returns true if an internship with the same identity as {@code internship} exists in InternBuddy.
+ */
+ public boolean hasInternship(Internship internship) {
+ requireNonNull(internship);
+ return internships.contains(internship);
+ }
+
+ /**
+ * Adds an internship to InternBuddy
+ * The internship must not already exist in InternBuddy.
+ */
+ public void addInternship(Internship p) {
+ internships.add(p);
+ }
+
+ /**
+ * Replaces the given internship {@code target} in the list with {@code editedInternship}.
+ * {@code target} must exist in the intern buddy.
+ * The internship identity of {@code editedInternship} must not be the same as another existing internship
+ * in InternBuddy.
+ */
+ public void setInternship(Internship target, Internship editedInternship) {
+ requireNonNull(editedInternship);
+
+ internships.setInternship(target, editedInternship);
+ }
+
+ /**
+ * Removes {@code key} from this {@code InternBuddy}.
+ * {@code key} must exist in InternBuddy.
+ */
+ public void removeInternship(Internship key) {
+ internships.remove(key);
+ }
+
+ /**
+ * Gets {@code key} from this {@code InternBuddy}.
+ * {@code key} must exist in InternBuddy.
+ *
+ */
+ public void viewInternship(Internship key) {
+ internships.view(key);
+ }
+
+
+ /**
+ * Copies the content of the specific internship to the clipboard
+ * Gets {@code key} from this {@code InternBuddy}.
+ * {@code key} must exist in InternBuddy.
+ */
+ public void copyInternship(Internship key) {
+ String content = "Company Name: " + key.toString();
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ StringSelection selection = new StringSelection(content);
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ clipboard.setContents(selection, null);
+ }
+ });
+ }
+
+ //// util methods
+
+ @Override
+ public String toString() {
+ return internships.asUnmodifiableObservableList().size() + " internships";
+ // TODO: refine later
+ }
+
+ @Override
+ public ObservableList getInternshipList() {
+ return internships.asUnmodifiableObservableList();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof InternBuddy // instanceof handles nulls
+ && internships.equals(((InternBuddy) other).internships));
+ }
+
+ @Override
+ public int hashCode() {
+ return internships.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/internship/model/Model.java b/src/main/java/seedu/internship/model/Model.java
new file mode 100644
index 00000000000..28d1d08a8c1
--- /dev/null
+++ b/src/main/java/seedu/internship/model/Model.java
@@ -0,0 +1,136 @@
+package seedu.internship.model;
+
+import java.nio.file.Path;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Predicate;
+
+import javafx.collections.ObservableList;
+import seedu.internship.commons.core.GuiSettings;
+import seedu.internship.model.internship.Internship;
+
+/**
+ * The API of the Model component.
+ */
+public interface Model {
+ /** {@code Predicate} that always evaluate to true */
+ Predicate PREDICATE_SHOW_ALL_INTERNSHIPS = unused -> true;
+
+ /** {@code Predicate} that shows upcoming internships */
+ Predicate PREDICATE_SHOW_UPCOMING_INTERNSHIPS = internship -> {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+ LocalDate now = LocalDate.now();
+ LocalDate nextWeek = now.plusWeeks(1);
+ LocalDate deadline = LocalDate.parse(internship.getDate().toString(), formatter);
+ String status = internship.getStatus().toString();
+ List acceptedStatuses = new ArrayList<>(Arrays.asList(
+ "new", "offered", "assessment", "interview"));
+ return !deadline.isBefore(now) && deadline.isBefore(nextWeek) && acceptedStatuses.contains(status);
+ };
+
+ /**
+ * 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' InternBuddy file path.
+ */
+ Path getInternBuddyFilePath();
+
+ /**
+ * Sets the user prefs' InternBuddy book file path.
+ */
+ void setInternBuddyFilePath(Path InternBuddyFilePath);
+
+ /**
+ * Replaces InternBuddy data with the data in {@code internbuddy}.
+ */
+ void setInternBuddy(ReadOnlyInternBuddy internBuddy);
+
+ /** Returns the InternBuddy */
+ ReadOnlyInternBuddy getInternBuddy();
+
+ /**
+ * Returns true if an internship with the same identity as {@code Internship} exists in InternBuddy.
+ */
+ boolean hasInternship(Internship internship);
+
+ /**
+ * Deletes the given internship.
+ * The internship must exist in InternBuddy.
+ */
+ void deleteInternship(Internship target);
+
+ /**
+ * Views the given internship.
+ * The {@code internship} must exist in InternBuddy.
+ */
+ void viewInternship(Internship target);
+
+ /**
+ * Adds the given internship.
+ * {@code internship} must not already exist in InternBuddy.
+ */
+ void addInternship(Internship internship);
+
+ /**
+ * Replaces the given internship {@code target} with {@code editedInternship}.
+ * {@code target} must exist in InternBuddy.
+ * The internship identity of {@code editedInternship} must not be the same as another existing internship in
+ * InternBuddy.
+ *
+ * @param target The given internship to be replaced.
+ * @param editedInternship The internship to replace the original one.
+ */
+ void setInternship(Internship target, Internship editedInternship);
+
+ /** Returns an unmodifiable view of the filtered internship list */
+ ObservableList getFilteredInternshipList();
+
+ /**
+ * Updates the filter of the filtered internship list to filter by the given {@code predicate}.
+ * @throws NullPointerException if {@code predicate} is null.
+ */
+ void updateFilteredInternshipList(Predicate predicate);
+
+ /**
+ * Gets the internship that is currently being selected for viewing
+ *
+ * @return the currently selected internship
+ */
+ Internship getSelectedInternship();
+
+
+ /**
+ * Updates the internship that is currently being selected for viewing
+ *
+ * @param target The internship that is selected for viewing
+ */
+ void updateSelectedInternship(Internship target);
+
+ /**
+ * Copies the content of the internship onto the clipboard of the computer
+ * {@code internship} must not already exist in InternBuddy.
+ */
+
+ void copyInternship(Internship target);
+}
diff --git a/src/main/java/seedu/internship/model/ModelManager.java b/src/main/java/seedu/internship/model/ModelManager.java
new file mode 100644
index 00000000000..d5cb29a317e
--- /dev/null
+++ b/src/main/java/seedu/internship/model/ModelManager.java
@@ -0,0 +1,175 @@
+package seedu.internship.model;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.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.internship.commons.core.GuiSettings;
+import seedu.internship.commons.core.LogsCenter;
+import seedu.internship.model.internship.Internship;
+
+/**
+ * Represents the in-memory model of InternBuddy data.
+ */
+public class ModelManager implements Model {
+ private static final Logger logger = LogsCenter.getLogger(ModelManager.class);
+
+ private final InternBuddy internBuddy;
+ private final UserPrefs userPrefs;
+ private final FilteredList filteredInternships;
+ private Internship selectedInternship;
+
+ /**
+ * Initializes a ModelManager with the given internBuddy and userPrefs.
+ */
+ public ModelManager(ReadOnlyInternBuddy internBuddy, ReadOnlyUserPrefs userPrefs) {
+ requireAllNonNull(internBuddy, userPrefs);
+
+ logger.fine("Initializing with InternBuddy: " + internBuddy + " and user prefs " + userPrefs);
+
+ this.internBuddy = new InternBuddy(internBuddy);
+ this.userPrefs = new UserPrefs(userPrefs);
+ filteredInternships = new FilteredList<>(this.internBuddy.getInternshipList());
+ selectedInternship = null;
+ }
+
+ public ModelManager() {
+ this(new InternBuddy(), 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 getInternBuddyFilePath() {
+ return userPrefs.getInternBuddyFilePath();
+ }
+
+ @Override
+ public void setInternBuddyFilePath(Path internBuddyFilePath) {
+ requireNonNull(internBuddyFilePath);
+ userPrefs.setInternBuddyFilePath(internBuddyFilePath);
+ }
+
+ //=========== InternBuddy ================================================================================
+
+ @Override
+ public void setInternBuddy(ReadOnlyInternBuddy internBuddy) {
+ this.internBuddy.resetData(internBuddy);
+ }
+
+ @Override
+ public ReadOnlyInternBuddy getInternBuddy() {
+ return internBuddy;
+ }
+
+ @Override
+ public boolean hasInternship(Internship internship) {
+ requireNonNull(internship);
+ return internBuddy.hasInternship(internship);
+ }
+
+ @Override
+ public void deleteInternship(Internship target) {
+ internBuddy.removeInternship(target);
+ }
+
+ @Override
+ public void viewInternship(Internship target) {
+ internBuddy.viewInternship(target);
+ }
+
+ @Override
+ public void addInternship(Internship internship) {
+ internBuddy.addInternship(internship);
+ updateFilteredInternshipList(PREDICATE_SHOW_ALL_INTERNSHIPS);
+ }
+
+ @Override
+ public void setInternship(Internship target, Internship editedInternship) {
+ requireAllNonNull(target, editedInternship);
+
+ internBuddy.setInternship(target, editedInternship);
+ }
+
+ //=========== Filtered Internship List Accessors =============================================================
+
+ /**
+ * Returns an unmodifiable view of the list of {@code Internship} backed by the internal list of
+ * {@code versionedInternBuddy}
+ */
+ @Override
+ public ObservableList getFilteredInternshipList() {
+ return filteredInternships;
+ }
+
+ @Override
+ public void updateFilteredInternshipList(Predicate predicate) {
+ requireNonNull(predicate);
+ filteredInternships.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 internBuddy.equals(other.internBuddy)
+ && userPrefs.equals(other.userPrefs)
+ && filteredInternships.equals(other.filteredInternships);
+ }
+
+ //=========== Selected internship =============================================================
+
+ @Override
+ public Internship getSelectedInternship() {
+ return this.selectedInternship;
+ }
+
+ @Override
+ public void updateSelectedInternship(Internship target) {
+ this.selectedInternship = target;
+ }
+
+ @Override
+ public void copyInternship(Internship target) {
+ internBuddy.copyInternship(target);
+ }
+
+}
diff --git a/src/main/java/seedu/internship/model/ReadOnlyInternBuddy.java b/src/main/java/seedu/internship/model/ReadOnlyInternBuddy.java
new file mode 100644
index 00000000000..092e5a43a1a
--- /dev/null
+++ b/src/main/java/seedu/internship/model/ReadOnlyInternBuddy.java
@@ -0,0 +1,17 @@
+package seedu.internship.model;
+
+import javafx.collections.ObservableList;
+import seedu.internship.model.internship.Internship;
+
+/**
+ * Unmodifiable view of an InternBuddy
+ */
+public interface ReadOnlyInternBuddy {
+
+ /**
+ * Returns an unmodifiable view of the internships list.
+ * This list will not contain any duplicate internships
+ */
+ ObservableList getInternshipList();
+
+}
diff --git a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java b/src/main/java/seedu/internship/model/ReadOnlyUserPrefs.java
similarity index 56%
rename from src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
rename to src/main/java/seedu/internship/model/ReadOnlyUserPrefs.java
index befd58a4c73..02e61b9f961 100644
--- a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
+++ b/src/main/java/seedu/internship/model/ReadOnlyUserPrefs.java
@@ -1,8 +1,8 @@
-package seedu.address.model;
+package seedu.internship.model;
import java.nio.file.Path;
-import seedu.address.commons.core.GuiSettings;
+import seedu.internship.commons.core.GuiSettings;
/**
* Unmodifiable view of user prefs.
@@ -11,6 +11,6 @@ public interface ReadOnlyUserPrefs {
GuiSettings getGuiSettings();
- Path getAddressBookFilePath();
+ Path getInternBuddyFilePath();
}
diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/internship/model/UserPrefs.java
similarity index 71%
rename from src/main/java/seedu/address/model/UserPrefs.java
rename to src/main/java/seedu/internship/model/UserPrefs.java
index 25a5fd6eab9..cdaa9426c5b 100644
--- a/src/main/java/seedu/address/model/UserPrefs.java
+++ b/src/main/java/seedu/internship/model/UserPrefs.java
@@ -1,4 +1,4 @@
-package seedu.address.model;
+package seedu.internship.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.internship.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 internBuddyFilePath = Paths.get("data" , "internbuddy.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());
+ setInternBuddyFilePath(newUserPrefs.getInternBuddyFilePath());
}
public GuiSettings getGuiSettings() {
@@ -46,14 +46,13 @@ public void setGuiSettings(GuiSettings guiSettings) {
requireNonNull(guiSettings);
this.guiSettings = guiSettings;
}
-
- public Path getAddressBookFilePath() {
- return addressBookFilePath;
+ public Path getInternBuddyFilePath() {
+ return internBuddyFilePath;
}
- public void setAddressBookFilePath(Path addressBookFilePath) {
- requireNonNull(addressBookFilePath);
- this.addressBookFilePath = addressBookFilePath;
+ public void setInternBuddyFilePath(Path internBuddyFilePath) {
+ requireNonNull(internBuddyFilePath);
+ this.internBuddyFilePath = internBuddyFilePath;
}
@Override
@@ -68,19 +67,19 @@ public boolean equals(Object other) {
UserPrefs o = (UserPrefs) other;
return guiSettings.equals(o.guiSettings)
- && addressBookFilePath.equals(o.addressBookFilePath);
+ && internBuddyFilePath.equals(o.internBuddyFilePath);
}
@Override
public int hashCode() {
- return Objects.hash(guiSettings, addressBookFilePath);
+ return Objects.hash(guiSettings, internBuddyFilePath);
}
@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 : " + internBuddyFilePath);
return sb.toString();
}
diff --git a/src/main/java/seedu/internship/model/internship/Comment.java b/src/main/java/seedu/internship/model/internship/Comment.java
new file mode 100644
index 00000000000..fbb30299137
--- /dev/null
+++ b/src/main/java/seedu/internship/model/internship/Comment.java
@@ -0,0 +1,59 @@
+package seedu.internship.model.internship;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a comment in InternBuddy.
+ * Guarantees: immutable; name is valid as declared in {@link #isValidComment(String)}
+ */
+public class Comment {
+
+ public static final String MESSAGE_CONSTRAINTS = "Comments should not blank.";
+ public static final String VALIDATION_REGEX = ".*";
+
+ public final String commentContent;
+
+ /**
+ * Constructs a {@code Comment}
+ *
+ * @param commentContent The string content of the comment
+ */
+ public Comment(String commentContent) {
+ requireNonNull(commentContent);
+ checkArgument(isValidComment(commentContent), MESSAGE_CONSTRAINTS);
+ this.commentContent = commentContent;
+ }
+
+ /**
+ * Returns true if a given string is valid content for a comment
+ *
+ * @param test The string to be tested for comment validity.
+ */
+ public static boolean isValidComment(String test) {
+ if (test.isEmpty() || !test.matches(VALIDATION_REGEX)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Comment // instanceof handles nulls
+ && commentContent.equals(((Comment) other).commentContent)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return commentContent.hashCode();
+ }
+
+ /**
+ * Format state as text for viewing.
+ */
+ public String toString() {
+ return '[' + commentContent + ']';
+ }
+
+}
diff --git a/src/main/java/seedu/internship/model/internship/CompanyName.java b/src/main/java/seedu/internship/model/internship/CompanyName.java
new file mode 100644
index 00000000000..deddf199aa3
--- /dev/null
+++ b/src/main/java/seedu/internship/model/internship/CompanyName.java
@@ -0,0 +1,79 @@
+package seedu.internship.model.internship;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents an Internship's company name in InternBuddy.
+ * Guarantees: immutable; is valid as declared in {@link #isValidCompanyName(String)}
+ */
+public class CompanyName {
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Company names should not be blank, and should be at most 50 characters";
+
+ /*
+ * The first character of the company name must not be a whitespace,
+ * otherwise " " (a blank string) becomes a valid input.
+ */
+ public static final String VALIDATION_REGEX = "^.{1,50}$";
+
+ public final String fullCompanyName;
+
+ /**
+ * Constructs a {@code CompanyName}.
+ *
+ * @param companyName A valid company name.
+ */
+ public CompanyName(String companyName) {
+ requireNonNull(companyName);
+ checkArgument(isValidCompanyName(companyName), MESSAGE_CONSTRAINTS);
+ fullCompanyName = companyName;
+ }
+
+ /**
+ * Returns true if a given string is a valid name.
+ *
+ * @param test The regex to test for a valid name.
+ * @return true if the given input String is a valid company name
+ */
+ public static boolean isValidCompanyName(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+
+ /**
+ * Returns the String representation of the company name.
+ *
+ * @return a string corresponding to the company name.
+ */
+ @Override
+ public String toString() {
+ return fullCompanyName;
+ }
+
+ /**
+ * Determines if an object is equal to the current Internship object.
+ *
+ * @param other The other object to be compared with.
+ * @return true if the object is equal to the current Internship entry, and false otherwise.
+ */
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof CompanyName // instanceof handles nulls
+ && fullCompanyName.toLowerCase().equals((
+ (CompanyName) other).fullCompanyName.toLowerCase())); // state check
+ }
+
+ /**
+ * Generates the hashcode for the company's name.
+ *
+ * @return the hash code representing the company name.
+ */
+ @Override
+ public int hashCode() {
+ return fullCompanyName.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/internship/model/internship/Date.java b/src/main/java/seedu/internship/model/internship/Date.java
new file mode 100644
index 00000000000..b445c698cd1
--- /dev/null
+++ b/src/main/java/seedu/internship/model/internship/Date.java
@@ -0,0 +1,84 @@
+package seedu.internship.model.internship;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.commons.util.AppUtil.checkArgument;
+
+import java.text.SimpleDateFormat;
+
+/**
+ * Represents an Internship's date in InternBuddy. The date is associated with the status of the Internship.
+ * For example, if the Internship's status is ASSESSMENT, then the date will be inferred as the date of assessment.
+ * Guarantees: immutable; is valid as declared in {@link #isValidDate(String)}
+ */
+public class Date {
+ public static final String VALIDATION_REGEX = "^\\d{4}-\\d{2}-\\d{2}$";
+
+ public static final String MESSAGE_CONSTRAINTS = "Date should be of the format YYYY-MM-DD, "
+ + "and it should be a valid date";
+
+ public final String fullDate;
+
+ /**
+ * Constructs an {@code Date}.
+ *
+ * @param date A valid date;
+ */
+ public Date(String date) {
+ requireNonNull(date);
+ checkArgument(isValidDate(date), MESSAGE_CONSTRAINTS);
+ fullDate = date;
+ }
+
+ /**
+ * Returns if a given string is a valid date.
+ *
+ * @returns true if a given string is a valid date string, else returns false.
+ */
+ public static boolean isValidDate(String test) {
+ if (!test.matches(VALIDATION_REGEX)) {
+ return false;
+ }
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+ df.setLenient(false);
+ try {
+ df.parse(test);
+ return true;
+ } catch (Exception ex) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns a String representation for the Date.
+ *
+ * @returns a string representing the date.
+ */
+ @Override
+ public String toString() {
+ return fullDate;
+ }
+
+ /**
+ * Determines if another object is equal to the current {@code Date} object.
+ *
+ * @param other The other object to compare with.
+ * @return true if the other object is a {@code Date} object with the same date string.
+ */
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Date // instanceof handles nulls
+ && fullDate.equals(((Date) other).fullDate)); // state check
+ }
+
+ /**
+ * Gets the hashcode for the date represented by this {@code Date} object.
+ *
+ * @return the hashcode for this {@code Date} object.
+ */
+ @Override
+ public int hashCode() {
+ return fullDate.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/internship/model/internship/Internship.java b/src/main/java/seedu/internship/model/internship/Internship.java
new file mode 100644
index 00000000000..1503f10a49a
--- /dev/null
+++ b/src/main/java/seedu/internship/model/internship/Internship.java
@@ -0,0 +1,181 @@
+package seedu.internship.model.internship;
+
+import static seedu.internship.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+import seedu.internship.model.tag.Tag;
+
+/**
+ * Represents an Internship in InternBuddy.
+ * Guarantees: details are present and not null, field values are validated, immutable.
+ */
+public class Internship {
+
+ // Identity fields
+ private final CompanyName companyName;
+ private final Role role;
+
+ // Data fields
+ private final Status status;
+
+ private final Date date;
+
+ private final Comment comment;
+ private final Set tags = new HashSet<>();
+
+ /**
+ * Constructs an Internship instance where every field must be present and not null.
+ *
+ * @param companyName The name of the company associated with the Internship.
+ * @param role The role or job position associated with the Internship.
+ * @param status The status of the Internship entry.
+ * @param date The date of the Internship entry.
+ * @param comment The comment of the Internship entry.
+ * @param tags The set of tags associated with the Internship.
+ */
+ public Internship(CompanyName companyName, Role role, Status status, Date date, Comment comment, Set tags) {
+ requireAllNonNull(companyName, role, status, date, tags);
+ this.companyName = companyName;
+ this.role = role;
+ this.status = status;
+ this.date = date;
+ this.comment = comment;
+ this.tags.addAll(tags);
+ }
+
+ /**
+ * Gets the company name for the Internship entry.
+ *
+ * @return the company name associated with the Internship entry.
+ */
+ public CompanyName getCompanyName() {
+ return companyName;
+ }
+
+ /**
+ * Gets the role for the Internship entry.
+ *
+ * @return the role associated with the Internship entry.
+ */
+ public Role getRole() {
+ return role;
+ }
+
+ /**
+ * Gets the status for the Internship entry.
+ *
+ * @return the status associated with the Internship entry.
+ */
+ public Status getStatus() {
+ return status;
+ }
+
+ /**
+ * Gets the date for the Internship entry.
+ *
+ * @return the date associated with the Internship entry.
+ */
+ public Date getDate() {
+ return date;
+ }
+
+ /**
+ * Gets the comment for the Internship entry.
+ *
+ * @return the comment associated with the Internship entry.
+ */
+ public Comment getComment() {
+ return comment;
+ }
+
+ /**
+ * Returns an immutable tag set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ *
+ * @return the set of tags associated with this Internship.
+ */
+ public Set getTags() {
+ return Collections.unmodifiableSet(tags);
+ }
+
+ /**
+ * Returns true if both Internships have the same company name.
+ * This defines a weaker notion of equality between two Internships
+ *
+ * @param otherInternship The Internship to compare with.
+ * @return true if both Internships have the same company name.
+ */
+ public boolean isSameInternship(Internship otherInternship) {
+ if (otherInternship == this) {
+ return true;
+ }
+
+ return otherInternship != null
+ && otherInternship.getCompanyName().equals(getCompanyName())
+ && otherInternship.getStatus().equals(getStatus())
+ && otherInternship.getDate().equals(getDate())
+ && otherInternship.getRole().equals(getRole());
+ }
+
+ /**
+ * Returns true if both internships have the same identity and data fields.
+ * This defines a stronger notion of equality between two Internships.
+ *
+ * @param other The other Internship to compare with.
+ * @return true if both internships have the same identity and data fields.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof Internship)) {
+ return false;
+ }
+
+ Internship otherInternship = (Internship) other;
+
+ return otherInternship.getCompanyName().equals(getCompanyName())
+ && otherInternship.getRole().equals(getRole())
+ && otherInternship.getStatus().equals(getStatus())
+ && otherInternship.getDate().equals(getDate())
+ && otherInternship.getComment().equals(getComment())
+ && otherInternship.getTags().equals(getTags());
+ }
+
+ @Override
+ public int hashCode() {
+ // use this method for custom fields hashing instead of implementing your own
+ return Objects.hash(companyName, role, status, date, comment, tags);
+ }
+
+ @Override
+ public String toString() {
+ String status = getStatus().toString();
+ final StringBuilder builder = new StringBuilder();
+ builder.append(getCompanyName())
+ .append("; Role: ")
+ .append(getRole())
+ .append("; Status: ")
+ .append(status.substring(0, 1).toUpperCase() + status.substring(1))
+ .append("; Date: ")
+ .append(getDate())
+ .append("; Comment: ")
+ .append(getComment());
+
+
+
+ Set tags = getTags();
+ if (!tags.isEmpty()) {
+ builder.append("; Tags: ");
+ tags.forEach(builder::append);
+ }
+ return builder.toString();
+ }
+
+}
diff --git a/src/main/java/seedu/internship/model/internship/InternshipContainsKeywordsPredicate.java b/src/main/java/seedu/internship/model/internship/InternshipContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..b329102a2b3
--- /dev/null
+++ b/src/main/java/seedu/internship/model/internship/InternshipContainsKeywordsPredicate.java
@@ -0,0 +1,132 @@
+package seedu.internship.model.internship;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.internship.commons.util.StringUtil;
+
+/**
+ * Tests that a {@code Internship}'s {@code CompanyName} matches any of the keywords given.
+ */
+public class InternshipContainsKeywordsPredicate implements Predicate {
+ private final List nameKeywords;
+ private final List roleKeywords;
+ private final List statusKeywords;
+ private final List keyDates;
+ private final List tagKeywords;
+
+ /**
+ * Constructs a {@code CompanyNameContainsKeywordsPredicate} instance.
+ *
+ * @param nameKeywords The keywords to check for in the Internship's company name.
+ */
+ public InternshipContainsKeywordsPredicate(List nameKeywords, List roleKeywords,
+ List statusKeywords, List keyDates,
+ List tagKeywords) {
+ this.nameKeywords = nameKeywords;
+ this.roleKeywords = roleKeywords;
+ this.statusKeywords = statusKeywords;
+ this.keyDates = keyDates;
+ this.tagKeywords = tagKeywords;
+ }
+
+ /**
+ * Tests if an Internship's company name matches any of the keywords.
+ *
+ * @param internship the input Internship whose name will be checked.
+ * @return true if there is a match with any of the keyword, else false.
+ */
+ @Override
+ public boolean test(Internship internship) {
+ boolean noNameKeywords = this.nameKeywords.isEmpty();
+ boolean noRoleKeywords = this.roleKeywords.isEmpty();
+ boolean noStatusKeywords = this.statusKeywords.isEmpty();
+ boolean noKeyDates = this.keyDates.isEmpty();
+ boolean noTagKeywords = this.tagKeywords.isEmpty();
+
+ if (noNameKeywords && noRoleKeywords && noStatusKeywords && noKeyDates && noTagKeywords) {
+ return false;
+ }
+
+ return this.checkName(noNameKeywords, internship)
+ && this.checkRole(noRoleKeywords, internship)
+ && this.checkStatus(noStatusKeywords, internship)
+ && this.checkDate(noKeyDates, internship)
+ && this.checkTags(noTagKeywords, internship);
+ }
+
+ private boolean checkName(boolean noNameKeywords, Internship internship) {
+ if (!noNameKeywords) {
+ return this.nameKeywords.stream()
+ .anyMatch(keyword -> StringUtil.matchingStringIgnoreCase(
+ internship.getCompanyName().fullCompanyName, keyword));
+ }
+ return true;
+ }
+
+ private boolean checkRole(boolean noRoleKeywords, Internship internship) {
+ if (!noRoleKeywords) {
+ return this.roleKeywords.stream()
+ .anyMatch(keyword -> StringUtil.matchingStringIgnoreCase(
+ internship.getRole().fullRole, keyword));
+ }
+ return true;
+ }
+
+ private boolean checkStatus(boolean noStatusKeywords, Internship internship) {
+ if (!noStatusKeywords) {
+ return this.statusKeywords.stream()
+ .anyMatch(keyword -> StringUtil.matchingStringIgnoreCase(
+ internship.getStatus().fullStatus, keyword));
+ }
+ return true;
+ }
+
+ private boolean checkDate(boolean noKeyDates, Internship internship) {
+ if (!noKeyDates) {
+ return this.keyDates.stream()
+ .anyMatch(keyword -> StringUtil.matchingStringIgnoreCase(
+ internship.getDate().fullDate, keyword));
+ }
+ return true;
+ }
+
+ private boolean checkTags(boolean noTagKeywords, Internship internship) {
+ if (!noTagKeywords) {
+ return this.tagKeywords.stream()
+ .anyMatch(keyword -> internship.getTags().stream()
+ .map(tag -> tag.tagName)
+ .anyMatch(tagName -> StringUtil.matchingStringIgnoreCase(tagName, keyword)));
+ }
+ return true;
+ }
+
+ /**
+ * Determines if an object is equal to the current {@code CompanyNameContainsKeywordsPredicate} instance.
+ *
+ * @param other The other object to compare with
+ * @return true if both are {@code CompanyNameContainsKeywordsPredicate} instances with the same set
+ * of keywords to check for.
+ */
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof InternshipContainsKeywordsPredicate // instanceof handles nulls
+ && nameKeywords.equals(((InternshipContainsKeywordsPredicate) other).nameKeywords) // state check
+ && roleKeywords.equals(((InternshipContainsKeywordsPredicate) other).roleKeywords)
+ && statusKeywords.equals(((InternshipContainsKeywordsPredicate) other).statusKeywords)
+ && keyDates.equals(((InternshipContainsKeywordsPredicate) other).keyDates)
+ && tagKeywords.equals(((InternshipContainsKeywordsPredicate) other).tagKeywords));
+ }
+
+ /**
+ * Determines if the predicate contains no conditions.
+ *
+ * @return true if predicate contains no conditions.
+ */
+ public boolean isEmpty() {
+ return this.nameKeywords.isEmpty() && this.roleKeywords.isEmpty() && this.statusKeywords.isEmpty()
+ && this.tagKeywords.isEmpty() && this.keyDates.isEmpty();
+ }
+
+}
diff --git a/src/main/java/seedu/internship/model/internship/Role.java b/src/main/java/seedu/internship/model/internship/Role.java
new file mode 100644
index 00000000000..9ba8cc1e22c
--- /dev/null
+++ b/src/main/java/seedu/internship/model/internship/Role.java
@@ -0,0 +1,78 @@
+package seedu.internship.model.internship;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents an Internship's role in InternBuddy.
+ * Guarantees: immutable; is valid as declared in {@link #isValidRole(String)}
+ */
+public class Role {
+
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Roles should not be blank, and should be at most 50 characters";
+
+ /*
+ * The first character of the role must not be a whitespace,
+ * otherwise " " (a blank string) becomes a valid input.
+ */
+ public static final String VALIDATION_REGEX = "^.{1,50}$";
+
+ public final String fullRole;
+
+ /**
+ * Constructs a {@code Role}.
+ *
+ * @param role A valid role to be associated with an Internship.
+ */
+ public Role(String role) {
+ requireNonNull(role);
+ checkArgument(isValidRole(role), MESSAGE_CONSTRAINTS);
+ this.fullRole = role;
+ }
+
+ /**
+ * Returns true if a given string is a valid role.
+ *
+ * @param test The string to test against the regex.
+ * @return true if the given string corresponds to a valid string for a role, else returns false.
+ */
+ public static boolean isValidRole(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ /**
+ * Returns the String representation of the Role.
+ *
+ * @return a String representing the role.
+ */
+ @Override
+ public String toString() {
+ return fullRole;
+ }
+
+ /**
+ * Determines if another object is equal to this Role object.
+ *
+ * @param other The other object to compare with.
+ * @return true if the other object is a Role object with the same role string.
+ */
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Role // instanceof handles nulls
+ && fullRole.toLowerCase().equals(((Role) other).fullRole.toLowerCase())); // state check
+ }
+
+ /**
+ * Gets the hash code of the Role object.
+ *
+ * @return the hash code for the role represented by the Role object.
+ */
+ @Override
+ public int hashCode() {
+ return fullRole.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/internship/model/internship/Status.java b/src/main/java/seedu/internship/model/internship/Status.java
new file mode 100644
index 00000000000..eb7078d7be3
--- /dev/null
+++ b/src/main/java/seedu/internship/model/internship/Status.java
@@ -0,0 +1,95 @@
+package seedu.internship.model.internship;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.commons.util.AppUtil.checkArgument;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Represents an Internship's status in InternBuddy
+ * Guarantees: immutable; is valid as declared in {@link #isValidStatus(String)}
+ */
+public class Status {
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Status should only be one of the following: New, Applied, Assessment, Interview, Offered, "
+ + "Accepted or Rejected. It should not be blank too.";
+
+ public static final String NEW = "new";
+ public static final String APPLIED = "applied";
+ public static final String ASSESSMENT = "assessment";
+ public static final String INTERVIEW = "interview";
+ public static final String OFFERED = "offered";
+ public static final String REJECTED = "rejected";
+ public static final String ACCEPTED = "accepted";
+ //A set of valid statuses
+ public static final List LIST_OF_VALID_STATUSES =
+ Arrays.asList(NEW, APPLIED, ASSESSMENT, INTERVIEW, OFFERED, REJECTED, ACCEPTED);
+ public static final HashSet SET_OF_VALID_STATUSES = new HashSet(LIST_OF_VALID_STATUSES);
+
+ public final String fullStatus;
+
+ /**
+ * Constructs a {@code Status}.
+ *
+ * @param status A valid status to be associated with an Internship.
+ */
+ public Status(String status) {
+ requireNonNull(status);
+ status = status.toLowerCase();
+ checkArgument(isValidStatus(status), MESSAGE_CONSTRAINTS);
+ this.fullStatus = status;
+ }
+
+
+ /**
+ * Returns true if a given string is a valid status
+ *
+ * @param test The string to check for.
+ * @return true if the given string corresponds to a valid string for a role, else returns false.
+ * @throws NullPointerException if a null status is passed in
+ */
+ public static boolean isValidStatus(String test) {
+ if (test == null) {
+ throw new NullPointerException();
+ }
+ return SET_OF_VALID_STATUSES.contains(test.toLowerCase());
+ }
+
+ /**
+ * Returns the String representation of the Role.
+ *
+ * @return a String representing the role.
+ */
+ @Override
+ public String toString() {
+ return this.fullStatus;
+ }
+
+
+ /**
+ * Determines if another object is equal to this Status object.
+ *
+ * @param other The other object to compare with.
+ * @return true if the other object is a Status object with the same status string.
+ */
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Status // instanceof handles nulls
+ && fullStatus.equals(((Status) other).fullStatus)); // state check
+ }
+
+ /**
+ * Gets the hash code of the Status object.
+ *
+ * @return the hash code for the status represented by the Status object.
+ */
+ @Override
+ public int hashCode() {
+ return fullStatus.hashCode();
+ }
+}
+
diff --git a/src/main/java/seedu/internship/model/internship/UniqueInternshipList.java b/src/main/java/seedu/internship/model/internship/UniqueInternshipList.java
new file mode 100644
index 00000000000..6cf23ab7f8b
--- /dev/null
+++ b/src/main/java/seedu/internship/model/internship/UniqueInternshipList.java
@@ -0,0 +1,154 @@
+package seedu.internship.model.internship;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.internship.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import seedu.internship.model.internship.exceptions.DuplicateInternshipException;
+import seedu.internship.model.internship.exceptions.InternshipNotFoundException;
+
+/**
+ * A list of Internships that enforces uniqueness between its elements and does not allow nulls.
+ * An Internship is considered unique by comparing using {@code Internship#isSameInternship(Internship)}. As such,
+ * adding and updating of internships uses Internship#isSameInternship(Internship) for equality to ensure that the
+ * internship being added or updated is unique in terms of identity in the UniqueInternshipList. However, the removal
+ * of an internship uses Internship#equals(Object) so to ensure that an Internship with exactly the same fields will be
+ * removed.
+ *
+ * Supports a minimal set of list operations.
+ *
+ * @see Internship#isSameInternship(Internship)
+ */
+public class UniqueInternshipList implements Iterable {
+
+ private final ObservableList internalList = FXCollections.observableArrayList();
+ private final ObservableList internalUnmodifiableList =
+ FXCollections.unmodifiableObservableList(internalList);
+
+ /**
+ * Returns true if the list contains an equivalent internship as the given argument.
+ */
+ public boolean contains(Internship toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::isSameInternship);
+ }
+
+ /**
+ * Adds an internship to the list.
+ * The internship must not already exist in the list.
+ */
+ public void add(Internship toAdd) {
+ requireNonNull(toAdd);
+ if (contains(toAdd)) {
+ throw new DuplicateInternshipException();
+ }
+ internalList.add(toAdd);
+ }
+
+ /**
+ * Replaces the internship {@code target} in the list with {@code editedInternship}.
+ * {@code target} must exist in the list.
+ * The internship identity of {@code editedInternship} must not be the same as another existing internship in
+ * the list.
+ */
+ public void setInternship(Internship target, Internship editedInternship) {
+ requireAllNonNull(target, editedInternship);
+
+ int index = internalList.indexOf(target);
+ if (index == -1) {
+ throw new InternshipNotFoundException();
+ }
+
+ if (!target.isSameInternship(editedInternship) && contains(editedInternship)) {
+ throw new DuplicateInternshipException();
+ }
+
+ internalList.set(index, editedInternship);
+ }
+
+ /**
+ * Removes the equivalent internship from the list.
+ * The internship must exist in the list.
+ */
+ public void remove(Internship toRemove) {
+ requireNonNull(toRemove);
+ if (!internalList.remove(toRemove)) {
+ throw new InternshipNotFoundException();
+ }
+ }
+
+ /**
+ * Views the equivalent internship from the list.
+ * The internship must exist in the list.
+ *
+ * @param toView The internship to be viewed
+ */
+ public void view(Internship toView) {
+ requireNonNull(toView);
+ if (!contains(toView)) {
+ //Desired internship cannot be found
+ throw new InternshipNotFoundException();
+ }
+
+ }
+
+ public void setInternships(UniqueInternshipList replacement) {
+ requireNonNull(replacement);
+ internalList.setAll(replacement.internalList);
+ }
+
+ /**
+ * Replaces the contents of this list with {@code internships}.
+ * {@code internships} must not contain duplicate internships
+ */
+ public void setInternships(List internships) {
+ requireAllNonNull(internships);
+ if (!internshipsAreUnique(internships)) {
+ throw new DuplicateInternshipException();
+ }
+
+ internalList.setAll(internships);
+ }
+
+ /**
+ * 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 UniqueInternshipList // instanceof handles nulls
+ && internalList.equals(((UniqueInternshipList) other).internalList));
+ }
+
+ @Override
+ public int hashCode() {
+ return internalList.hashCode();
+ }
+
+ /**
+ * Returns true if {@code internships} contains only unique internships.
+ */
+ private boolean internshipsAreUnique(List internships) {
+ for (int i = 0; i < internships.size() - 1; i++) {
+ for (int j = i + 1; j < internships.size(); j++) {
+ if (internships.get(i).isSameInternship(internships.get(j))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/seedu/internship/model/internship/exceptions/DuplicateInternshipException.java b/src/main/java/seedu/internship/model/internship/exceptions/DuplicateInternshipException.java
new file mode 100644
index 00000000000..8005d2a1813
--- /dev/null
+++ b/src/main/java/seedu/internship/model/internship/exceptions/DuplicateInternshipException.java
@@ -0,0 +1,11 @@
+package seedu.internship.model.internship.exceptions;
+
+/**
+ * Signals that the operation will result in duplicate Internships (Internships are considered duplicates if they have
+ * the same identity).
+ */
+public class DuplicateInternshipException extends RuntimeException {
+ public DuplicateInternshipException() {
+ super("Operation would result in duplicate internships.");
+ }
+}
diff --git a/src/main/java/seedu/internship/model/internship/exceptions/InternshipNotFoundException.java b/src/main/java/seedu/internship/model/internship/exceptions/InternshipNotFoundException.java
new file mode 100644
index 00000000000..b8759d9467f
--- /dev/null
+++ b/src/main/java/seedu/internship/model/internship/exceptions/InternshipNotFoundException.java
@@ -0,0 +1,6 @@
+package seedu.internship.model.internship.exceptions;
+
+/**
+ * Signals that the operation is unable to find the specified internship
+ */
+public class InternshipNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/internship/model/tag/Tag.java
similarity index 67%
rename from src/main/java/seedu/address/model/tag/Tag.java
rename to src/main/java/seedu/internship/model/tag/Tag.java
index b0ea7e7dad7..f31e9473008 100644
--- a/src/main/java/seedu/address/model/tag/Tag.java
+++ b/src/main/java/seedu/internship/model/tag/Tag.java
@@ -1,16 +1,17 @@
-package seedu.address.model.tag;
+package seedu.internship.model.tag;
import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
+import static seedu.internship.commons.util.AppUtil.checkArgument;
/**
- * Represents a Tag in the address book.
+ * Represents a tag in InternBuddy.
* Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String)}
*/
public class Tag {
- public static final String MESSAGE_CONSTRAINTS = "Tags names should be alphanumeric";
- public static final String VALIDATION_REGEX = "\\p{Alnum}+";
+ public static final String MESSAGE_CONSTRAINTS = "Tags should not be blank, and "
+ + "should be at most 30 characters";
+ public static final String VALIDATION_REGEX = "^.{1,30}$";
public final String tagName;
@@ -27,9 +28,14 @@ public Tag(String tagName) {
/**
* Returns true if a given string is a valid tag name.
+ *
+ * @param test The string to be tested for tag validity.
*/
public static boolean isValidTagName(String test) {
- return test.matches(VALIDATION_REGEX);
+ if (test.isEmpty() || !test.matches(VALIDATION_REGEX)) {
+ return false;
+ }
+ return true;
}
@Override
diff --git a/src/main/java/seedu/internship/model/util/SampleDataUtil.java b/src/main/java/seedu/internship/model/util/SampleDataUtil.java
new file mode 100644
index 00000000000..29d838cf9f9
--- /dev/null
+++ b/src/main/java/seedu/internship/model/util/SampleDataUtil.java
@@ -0,0 +1,63 @@
+package seedu.internship.model.util;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import seedu.internship.model.InternBuddy;
+import seedu.internship.model.ReadOnlyInternBuddy;
+import seedu.internship.model.internship.Comment;
+import seedu.internship.model.internship.CompanyName;
+import seedu.internship.model.internship.Date;
+import seedu.internship.model.internship.Internship;
+import seedu.internship.model.internship.Role;
+import seedu.internship.model.internship.Status;
+import seedu.internship.model.tag.Tag;
+
+/**
+ * Contains utility methods for populating {@code InternBuddy} with sample data.
+ */
+public class SampleDataUtil {
+ public static Internship[] getSampleInternships() {
+ return new Internship[] {
+ new Internship(new CompanyName("Apple"), new Role("iOS Developer"), new Status("applied"),
+ new Date("2023-03-20"), new Comment("Yay! My dream company!"), getTagSet("iOS")),
+ new Internship(new CompanyName("Amazon"), new Role("Cloud Architect"), new Status("new"),
+ new Date("2023-03-28"), new Comment("Need to research more on cloud services."),
+ getTagSet("AWS", "Cloud Services")),
+ new Internship(new CompanyName("Google"), new Role("Software Engineer"), new Status("assessment"),
+ new Date("2023-04-02"), new Comment("Good company culture and environment."),
+ getTagSet("Golang", "Back-end")),
+ new Internship(new CompanyName("Samsung"), new Role("Android Developer"), new Status("interview"),
+ new Date("2023-04-10"), new Comment("To compare with Apple's offer again."),
+ getTagSet("Android", "Mobile")),
+ new Internship(new CompanyName("Grab"), new Role("Frontend Designer"), new Status("offered"),
+ new Date("2023-03-27"), new Comment("Good benefits. Can consider."),
+ getTagSet("React", "CSS")),
+ new Internship(new CompanyName("Paypal"), new Role("Product Designer"), new Status("Accepted"),
+ new Date("2023-03-26"), new Comment("Starting work on 1 May. Excited!"),
+ getTagSet("UI", "UX")),
+ new Internship(new CompanyName("Facebook"), new Role("Backend Developer"), new Status("rejected"),
+ new Date("2023-03-15"), new Comment("Rejected since I lack proficiency in SQL."),
+ getTagSet("SQL")),
+ };
+ }
+
+ public static ReadOnlyInternBuddy getSampleInternBuddy() {
+ InternBuddy sampleAb = new InternBuddy();
+ for (Internship sampleInternship : getSampleInternships()) {
+ sampleAb.addInternship(sampleInternship);
+ }
+ 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/internship/storage/CommandHistory.java b/src/main/java/seedu/internship/storage/CommandHistory.java
new file mode 100644
index 00000000000..f3cf7bf57ff
--- /dev/null
+++ b/src/main/java/seedu/internship/storage/CommandHistory.java
@@ -0,0 +1,57 @@
+package seedu.internship.storage;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+// @@author kohkaixun-reused
+// Solution below adapted from
+// https://github.com/AY2122S2-CS2103T-W13-3/tp/blob/master/src/main/java/seedu/address/storage/UserInputHistory.java
+/**
+ * CommandHistory keeps track of past commands inputted.
+ */
+public class CommandHistory {
+ private final List list;
+ private int index;
+ private final String emptyString = "";
+
+ /**
+ * Creates new CommandHistory object
+ */
+ public CommandHistory() {
+ this.list = new ArrayList<>(Arrays.asList(this.emptyString));
+ this.index = 0;
+ }
+
+ /**
+ * Add new input to CommandHistory object
+ * @param newInput The string representing the new input
+ */
+ public void addInput(String newInput) {
+ this.list.add(this.list.size() - 1, newInput);
+ this.index = this.list.size() - 1;
+ }
+
+ /**
+ * Gets the next older input. If there is not older input, the oldest input is returned again.
+ * @return The next older input or if that doesn't exist, the oldest input.
+ */
+ public String getOlderInput() {
+ if (this.index > 0) {
+ this.index--;
+ }
+ return this.list.get(this.index);
+ }
+
+ /**
+ * Gets the next most recent input. If there isn't any more recent inputs, the most recent input is returned again.
+ * @return The next most recent input or if that doesn't exist, the most recent input.
+ */
+ public String getNewerInput() {
+ if (this.index < this.list.size() - 1) {
+ this.index++;
+ }
+ return this.list.get(this.index);
+ }
+}
+// @@author
diff --git a/src/main/java/seedu/internship/storage/InternBuddyStorage.java b/src/main/java/seedu/internship/storage/InternBuddyStorage.java
new file mode 100644
index 00000000000..56e38724699
--- /dev/null
+++ b/src/main/java/seedu/internship/storage/InternBuddyStorage.java
@@ -0,0 +1,45 @@
+package seedu.internship.storage;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+
+import seedu.internship.commons.exceptions.DataConversionException;
+import seedu.internship.model.ReadOnlyInternBuddy;
+
+/**
+ * Represents a storage for {@link seedu.internship.model.InternBuddy}.
+ */
+public interface InternBuddyStorage {
+
+ /**
+ * Returns the file path of the data file.
+ */
+ Path getInternBuddyFilePath();
+
+ /**
+ * Returns InternBuddy data as a {@link ReadOnlyInternBuddy}.
+ * 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 readInternBuddy() throws DataConversionException, IOException;
+
+ /**
+ * @see #getInternBuddyFilePath()
+ */
+ Optional readInternBuddy(Path filePath) throws DataConversionException, IOException;
+
+ /**
+ * Saves the given {@link ReadOnlyInternBuddy} to the storage.
+ * @param internBuddy cannot be null.
+ * @throws IOException if there was any problem writing to the file.
+ */
+ void saveInternBuddy(ReadOnlyInternBuddy internBuddy) throws IOException;
+
+ /**
+ * @see #saveInternBuddy(ReadOnlyInternBuddy)
+ */
+ void saveInternBuddy(ReadOnlyInternBuddy internBuddy, Path filePath) throws IOException;
+
+}
diff --git a/src/main/java/seedu/internship/storage/JsonAdaptedInternship.java b/src/main/java/seedu/internship/storage/JsonAdaptedInternship.java
new file mode 100644
index 00000000000..860c3125161
--- /dev/null
+++ b/src/main/java/seedu/internship/storage/JsonAdaptedInternship.java
@@ -0,0 +1,123 @@
+package seedu.internship.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.internship.commons.exceptions.IllegalValueException;
+import seedu.internship.model.internship.Comment;
+import seedu.internship.model.internship.CompanyName;
+import seedu.internship.model.internship.Date;
+import seedu.internship.model.internship.Internship;
+import seedu.internship.model.internship.Role;
+import seedu.internship.model.internship.Status;
+import seedu.internship.model.tag.Tag;
+
+/**
+ * Jackson-friendly version of {@link Internship}.
+ */
+class JsonAdaptedInternship {
+
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Internship's %s field is missing!";
+
+ private final String companyName;
+ private final String role;
+ private final String status;
+ private final String date;
+ private final String comment;
+ private final List tagged = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonAdaptedInternship} with the given internship details.
+ */
+ @JsonCreator
+ public JsonAdaptedInternship(@JsonProperty("companyName") String companyName, @JsonProperty("role") String role,
+ @JsonProperty("status") String status, @JsonProperty("date") String date,
+ @JsonProperty("comment") String comment, @JsonProperty("tagged") List tagged) {
+ this.companyName = companyName;
+ this.role = role;
+ this.status = status;
+ this.date = date;
+ if (comment == null) {
+ this.comment = "";
+ } else {
+ this.comment = comment;
+ }
+ if (tagged != null) {
+ this.tagged.addAll(tagged);
+ }
+ }
+
+ /**
+ * Converts a given {@code Internship} into this class for Jackson use.
+ */
+ public JsonAdaptedInternship(Internship source) {
+ companyName = source.getCompanyName().fullCompanyName;
+ role = source.getRole().fullRole;
+ status = source.getStatus().toString();
+ date = source.getDate().fullDate;
+ comment = source.getComment().commentContent;
+ tagged.addAll(source.getTags().stream()
+ .map(JsonAdaptedTag::new)
+ .collect(Collectors.toList()));
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted internship object into the model's {@code Internship} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted internship
+ */
+ public Internship toModelType() throws IllegalValueException {
+ final List internshipTags = new ArrayList<>();
+ for (JsonAdaptedTag tag : tagged) {
+ internshipTags.add(tag.toModelType());
+ }
+
+ if (companyName == null) {
+ throw new IllegalValueException(String.format(
+ MISSING_FIELD_MESSAGE_FORMAT, CompanyName.class.getSimpleName()));
+ }
+ if (!CompanyName.isValidCompanyName(companyName)) {
+ throw new IllegalValueException(CompanyName.MESSAGE_CONSTRAINTS);
+ }
+ final CompanyName modelCompanyName = new CompanyName(companyName);
+
+ if (role == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Role.class.getSimpleName()));
+ }
+ if (!Role.isValidRole(role)) {
+ throw new IllegalValueException(Role.MESSAGE_CONSTRAINTS);
+ }
+ final Role modelRole = new Role(role);
+
+ if (status == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Status.class.getSimpleName()));
+ }
+ if (!Status.isValidStatus(status)) {
+ throw new IllegalValueException(Status.MESSAGE_CONSTRAINTS);
+ }
+ final Status modelStatus = new Status(status);
+
+ if (date == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Date.class.getSimpleName()));
+ }
+ if (!Date.isValidDate(date)) {
+ throw new IllegalValueException(Date.MESSAGE_CONSTRAINTS);
+ }
+ final Date modelDate = new Date(date);
+
+
+ if (!Comment.isValidComment(comment)) {
+ throw new IllegalValueException(Comment.MESSAGE_CONSTRAINTS);
+ }
+ final Comment modelComment = new Comment(comment);
+
+ final Set modelTags = new HashSet<>(internshipTags);
+ return new Internship(modelCompanyName, modelRole, modelStatus, modelDate, modelComment, modelTags);
+ }
+}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTag.java b/src/main/java/seedu/internship/storage/JsonAdaptedTag.java
similarity index 88%
rename from src/main/java/seedu/address/storage/JsonAdaptedTag.java
rename to src/main/java/seedu/internship/storage/JsonAdaptedTag.java
index 0df22bdb754..5d1e60030c5 100644
--- a/src/main/java/seedu/address/storage/JsonAdaptedTag.java
+++ b/src/main/java/seedu/internship/storage/JsonAdaptedTag.java
@@ -1,10 +1,10 @@
-package seedu.address.storage;
+package seedu.internship.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.internship.commons.exceptions.IllegalValueException;
+import seedu.internship.model.tag.Tag;
/**
* Jackson-friendly version of {@link Tag}.
diff --git a/src/main/java/seedu/internship/storage/JsonInternBuddyStorage.java b/src/main/java/seedu/internship/storage/JsonInternBuddyStorage.java
new file mode 100644
index 00000000000..e235476af3f
--- /dev/null
+++ b/src/main/java/seedu/internship/storage/JsonInternBuddyStorage.java
@@ -0,0 +1,80 @@
+package seedu.internship.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.internship.commons.core.LogsCenter;
+import seedu.internship.commons.exceptions.DataConversionException;
+import seedu.internship.commons.exceptions.IllegalValueException;
+import seedu.internship.commons.util.FileUtil;
+import seedu.internship.commons.util.JsonUtil;
+import seedu.internship.model.ReadOnlyInternBuddy;
+
+/**
+ * A class to access InternBuddy data stored as a json file on the hard disk.
+ */
+public class JsonInternBuddyStorage implements InternBuddyStorage {
+
+ private static final Logger logger = LogsCenter.getLogger(JsonInternBuddyStorage.class);
+
+ private Path filePath;
+
+ public JsonInternBuddyStorage(Path filePath) {
+ this.filePath = filePath;
+ }
+
+ public Path getInternBuddyFilePath() {
+ return filePath;
+ }
+
+ @Override
+ public Optional readInternBuddy() throws DataConversionException {
+ return readInternBuddy(filePath);
+ }
+
+ /**
+ * Similar to {@link #readInternBuddy()}.
+ *
+ * @param filePath location of the data. Cannot be null.
+ * @throws DataConversionException if the file is not in the correct format.
+ */
+ public Optional readInternBuddy(Path filePath) throws DataConversionException {
+ requireNonNull(filePath);
+
+ Optional jsonInternBuddy = JsonUtil.readJsonFile(
+ filePath, JsonSerializableInternBuddy.class);
+ if (!jsonInternBuddy.isPresent()) {
+ return Optional.empty();
+ }
+
+ try {
+ return Optional.of(jsonInternBuddy.get().toModelType());
+ } catch (IllegalValueException ive) {
+ logger.info("Illegal values found in " + filePath + ": " + ive.getMessage());
+ throw new DataConversionException(ive);
+ }
+ }
+
+ @Override
+ public void saveInternBuddy(ReadOnlyInternBuddy internBuddy) throws IOException {
+ saveInternBuddy(internBuddy, filePath);
+ }
+
+ /**
+ * Similar to {@link #saveInternBuddy(ReadOnlyInternBuddy)}.
+ *
+ * @param filePath location of the data. Cannot be null.
+ */
+ public void saveInternBuddy(ReadOnlyInternBuddy internBuddy, Path filePath) throws IOException {
+ requireNonNull(internBuddy);
+ requireNonNull(filePath);
+
+ FileUtil.createIfMissing(filePath);
+ JsonUtil.saveJsonFile(new JsonSerializableInternBuddy(internBuddy), filePath);
+ }
+
+}
diff --git a/src/main/java/seedu/internship/storage/JsonSerializableInternBuddy.java b/src/main/java/seedu/internship/storage/JsonSerializableInternBuddy.java
new file mode 100644
index 00000000000..db63dbafda0
--- /dev/null
+++ b/src/main/java/seedu/internship/storage/JsonSerializableInternBuddy.java
@@ -0,0 +1,61 @@
+package seedu.internship.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.internship.commons.exceptions.IllegalValueException;
+import seedu.internship.model.InternBuddy;
+import seedu.internship.model.ReadOnlyInternBuddy;
+import seedu.internship.model.internship.Internship;
+
+/**
+ * An Immutable InternBuddy that is serializable to JSON format.
+ */
+@JsonRootName(value = "internbuddy")
+class JsonSerializableInternBuddy {
+
+ public static final String MESSAGE_DUPLICATE_INTERNSHIP = "Internships list contains duplicate internship(s).";
+
+ private final List internships = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonSerializableInternBuddy} with the given internships
+ */
+ @JsonCreator
+ public JsonSerializableInternBuddy(@JsonProperty("internships") List internships) {
+ this.internships.addAll(internships);
+ }
+
+ /**
+ * Converts a given {@code ReadOnlyInternBuddy} into this class for Jackson use.
+ *
+ * @param source future changes to this will not affect the created {@code JsonSerializableInternBuddy}.
+ */
+ public JsonSerializableInternBuddy(ReadOnlyInternBuddy source) {
+ internships.addAll(source.getInternshipList().stream().map(JsonAdaptedInternship::new)
+ .collect(Collectors.toList()));
+ }
+
+ /**
+ * Converts this InternBuddy into the model's {@code InternBuddy} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated.
+ */
+ public InternBuddy toModelType() throws IllegalValueException {
+ InternBuddy internBuddy = new InternBuddy();
+ for (JsonAdaptedInternship jsonAdaptedInternship : internships) {
+ Internship internship = jsonAdaptedInternship.toModelType();
+ if (internBuddy.hasInternship(internship)) {
+ throw new IllegalValueException(MESSAGE_DUPLICATE_INTERNSHIP);
+ }
+ internBuddy.addInternship(internship);
+ }
+ return internBuddy;
+ }
+
+}
diff --git a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java b/src/main/java/seedu/internship/storage/JsonUserPrefsStorage.java
similarity index 82%
rename from src/main/java/seedu/address/storage/JsonUserPrefsStorage.java
rename to src/main/java/seedu/internship/storage/JsonUserPrefsStorage.java
index bc2bbad84aa..6dcd0db1da5 100644
--- a/src/main/java/seedu/address/storage/JsonUserPrefsStorage.java
+++ b/src/main/java/seedu/internship/storage/JsonUserPrefsStorage.java
@@ -1,13 +1,13 @@
-package seedu.address.storage;
+package seedu.internship.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.internship.commons.exceptions.DataConversionException;
+import seedu.internship.commons.util.JsonUtil;
+import seedu.internship.model.ReadOnlyUserPrefs;
+import seedu.internship.model.UserPrefs;
/**
* A class to access UserPrefs stored in the hard disk as a json file
diff --git a/src/main/java/seedu/internship/storage/Storage.java b/src/main/java/seedu/internship/storage/Storage.java
new file mode 100644
index 00000000000..606d9de6926
--- /dev/null
+++ b/src/main/java/seedu/internship/storage/Storage.java
@@ -0,0 +1,32 @@
+package seedu.internship.storage;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+
+import seedu.internship.commons.exceptions.DataConversionException;
+import seedu.internship.model.ReadOnlyInternBuddy;
+import seedu.internship.model.ReadOnlyUserPrefs;
+import seedu.internship.model.UserPrefs;
+
+/**
+ * API of the Storage component
+ */
+public interface Storage extends InternBuddyStorage, UserPrefsStorage {
+
+ @Override
+ Optional readUserPrefs() throws DataConversionException, IOException;
+
+ @Override
+ void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException;
+
+ @Override
+ Path getInternBuddyFilePath();
+
+ @Override
+ Optional readInternBuddy() throws DataConversionException, IOException;
+
+ @Override
+ void saveInternBuddy(ReadOnlyInternBuddy internBuddy) throws IOException;
+
+}
diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/internship/storage/StorageManager.java
similarity index 50%
rename from src/main/java/seedu/address/storage/StorageManager.java
rename to src/main/java/seedu/internship/storage/StorageManager.java
index 6cfa0162164..31cac596166 100644
--- a/src/main/java/seedu/address/storage/StorageManager.java
+++ b/src/main/java/seedu/internship/storage/StorageManager.java
@@ -1,30 +1,30 @@
-package seedu.address.storage;
+package seedu.internship.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;
+import seedu.internship.commons.core.LogsCenter;
+import seedu.internship.commons.exceptions.DataConversionException;
+import seedu.internship.model.ReadOnlyInternBuddy;
+import seedu.internship.model.ReadOnlyUserPrefs;
+import seedu.internship.model.UserPrefs;
/**
- * Manages storage of AddressBook data in local storage.
+ * Manages storage of InternBuddy data in local storage.
*/
public class StorageManager implements Storage {
private static final Logger logger = LogsCenter.getLogger(StorageManager.class);
- private AddressBookStorage addressBookStorage;
+ private InternBuddyStorage internBuddyStorage;
private UserPrefsStorage userPrefsStorage;
/**
- * Creates a {@code StorageManager} with the given {@code AddressBookStorage} and {@code UserPrefStorage}.
+ * Creates a {@code StorageManager} with the given {@code InternBuddyStorage} and {@code UserPrefStorage}.
*/
- public StorageManager(AddressBookStorage addressBookStorage, UserPrefsStorage userPrefsStorage) {
- this.addressBookStorage = addressBookStorage;
+ public StorageManager(InternBuddyStorage internBuddyStorage, UserPrefsStorage userPrefsStorage) {
+ this.internBuddyStorage = internBuddyStorage;
this.userPrefsStorage = userPrefsStorage;
}
@@ -46,33 +46,33 @@ public void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException {
}
- // ================ AddressBook methods ==============================
+ // ================ InternBuddy methods ==============================
@Override
- public Path getAddressBookFilePath() {
- return addressBookStorage.getAddressBookFilePath();
+ public Path getInternBuddyFilePath() {
+ return internBuddyStorage.getInternBuddyFilePath();
}
@Override
- public Optional readAddressBook() throws DataConversionException, IOException {
- return readAddressBook(addressBookStorage.getAddressBookFilePath());
+ public Optional readInternBuddy() throws DataConversionException, IOException {
+ return readInternBuddy(internBuddyStorage.getInternBuddyFilePath());
}
@Override
- public Optional readAddressBook(Path filePath) throws DataConversionException, IOException {
+ public Optional readInternBuddy(Path filePath) throws DataConversionException, IOException {
logger.fine("Attempting to read data from file: " + filePath);
- return addressBookStorage.readAddressBook(filePath);
+ return internBuddyStorage.readInternBuddy(filePath);
}
@Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, addressBookStorage.getAddressBookFilePath());
+ public void saveInternBuddy(ReadOnlyInternBuddy internBuddy) throws IOException {
+ saveInternBuddy(internBuddy, internBuddyStorage.getInternBuddyFilePath());
}
@Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
+ public void saveInternBuddy(ReadOnlyInternBuddy internBuddy, Path filePath) throws IOException {
logger.fine("Attempting to write to data file: " + filePath);
- addressBookStorage.saveAddressBook(addressBook, filePath);
+ internBuddyStorage.saveInternBuddy(internBuddy, filePath);
}
}
diff --git a/src/main/java/seedu/address/storage/UserPrefsStorage.java b/src/main/java/seedu/internship/storage/UserPrefsStorage.java
similarity index 70%
rename from src/main/java/seedu/address/storage/UserPrefsStorage.java
rename to src/main/java/seedu/internship/storage/UserPrefsStorage.java
index 29eef178dbc..1436161a5aa 100644
--- a/src/main/java/seedu/address/storage/UserPrefsStorage.java
+++ b/src/main/java/seedu/internship/storage/UserPrefsStorage.java
@@ -1,15 +1,15 @@
-package seedu.address.storage;
+package seedu.internship.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.internship.commons.exceptions.DataConversionException;
+import seedu.internship.model.ReadOnlyUserPrefs;
+import seedu.internship.model.UserPrefs;
/**
- * Represents a storage for {@link seedu.address.model.UserPrefs}.
+ * Represents a storage for {@link seedu.internship.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.internship.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/internship/ui/CommandBox.java
similarity index 53%
rename from src/main/java/seedu/address/ui/CommandBox.java
rename to src/main/java/seedu/internship/ui/CommandBox.java
index 9e75478664b..60fb9c0a4a7 100644
--- a/src/main/java/seedu/address/ui/CommandBox.java
+++ b/src/main/java/seedu/internship/ui/CommandBox.java
@@ -1,12 +1,15 @@
-package seedu.address.ui;
+package seedu.internship.ui;
+import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
+import javafx.scene.input.KeyEvent;
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.internship.logic.commands.CommandResult;
+import seedu.internship.logic.commands.exceptions.CommandException;
+import seedu.internship.logic.parser.exceptions.ParseException;
+import seedu.internship.storage.CommandHistory;
/**
* The UI component that is responsible for receiving user command inputs.
@@ -17,6 +20,7 @@ public class CommandBox extends UiPart {
private static final String FXML = "CommandBox.fxml";
private final CommandExecutor commandExecutor;
+ private final CommandHistory commandHistory;
@FXML
private TextField commandTextField;
@@ -29,6 +33,12 @@ public CommandBox(CommandExecutor commandExecutor) {
this.commandExecutor = commandExecutor;
// calls #setStyleToDefault() whenever there is a change to the text of the command box.
commandTextField.textProperty().addListener((unused1, unused2, unused3) -> setStyleToDefault());
+ this.commandHistory = new CommandHistory();
+ // @@author kohkaixun-reused
+ // Reused from
+ // https://github.com/AY2122S2-CS2103T-W13-3/tp/blob/master/src/main/java/seedu/address/ui/CommandBox.java
+ this.commandTextField.addEventFilter(KeyEvent.KEY_PRESSED, this::handleUpDownButtonEvent);
+ // @@author
}
/**
@@ -41,6 +51,8 @@ private void handleCommandEntered() {
return;
}
+ this.commandHistory.addInput(commandText);
+
try {
commandExecutor.execute(commandText);
commandTextField.setText("");
@@ -49,6 +61,39 @@ private void handleCommandEntered() {
}
}
+ @FXML
+ private void handleUpDownButtonEvent(KeyEvent event) {
+ // @@author kohkaixun-reused
+ // Reused from
+ // https://github.com/AY2122S2-CS2103T-W13-3/tp/blob/master/src/main/java/seedu/address/ui/CommandBox.java
+ if (event.getCode().isArrowKey()) {
+ switch (event.getCode()) {
+ case UP:
+ String olderInput = this.commandHistory.getOlderInput();
+ commandTextField.setText(olderInput);
+ // @@author kohkaixun-reused
+ // Reused from
+ // https://stackoverflow.com/q/8293774
+ Platform.runLater(new Runnable() {
+ @Override
+ public void run() {
+ commandTextField.end();
+ }
+ });
+ // @@author kohkaixun-reused
+ break;
+
+ case DOWN:
+ commandTextField.setText(this.commandHistory.getNewerInput());
+ break;
+
+ default:
+ break;
+ }
+ }
+ // @@author
+ }
+
/**
* Sets the command box style to use the default style.
*/
@@ -77,7 +122,7 @@ public interface CommandExecutor {
/**
* Executes the command and returns the result.
*
- * @see seedu.address.logic.Logic#execute(String)
+ * @see seedu.internship.logic.Logic#execute(String)
*/
CommandResult execute(String commandText) throws CommandException, ParseException;
}
diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/seedu/internship/ui/HelpWindow.java
similarity index 65%
rename from src/main/java/seedu/address/ui/HelpWindow.java
rename to src/main/java/seedu/internship/ui/HelpWindow.java
index 3f16b2fcf26..61a8bcfce7f 100644
--- a/src/main/java/seedu/address/ui/HelpWindow.java
+++ b/src/main/java/seedu/internship/ui/HelpWindow.java
@@ -1,31 +1,31 @@
-package seedu.address.ui;
+package seedu.internship.ui;
+import java.awt.Desktop;
+import java.net.URI;
import java.util.logging.Logger;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
-import javafx.scene.control.Label;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.stage.Stage;
-import seedu.address.commons.core.LogsCenter;
+import seedu.internship.commons.core.LogsCenter;
/**
* Controller for a help page
*/
public class HelpWindow extends UiPart {
- public static final String USERGUIDE_URL = "https://se-education.org/addressbook-level3/UserGuide.html";
- public static final String HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL;
-
+ public static final String USERGUIDE_URL = "https://ay2223s2-cs2103t-t14-3.github.io/tp/UserGuide.html";
private static final Logger logger = LogsCenter.getLogger(HelpWindow.class);
private static final String FXML = "HelpWindow.fxml";
@FXML
private Button copyButton;
-
@FXML
- private Label helpMessage;
+ private ImageView helpImage;
/**
* Creates a new HelpWindow.
@@ -34,7 +34,6 @@ public class HelpWindow extends UiPart {
*/
public HelpWindow(Stage root) {
super(FXML, root);
- helpMessage.setText(HELP_MESSAGE);
}
/**
@@ -64,6 +63,7 @@ public HelpWindow() {
*/
public void show() {
logger.fine("Showing help page about the application.");
+ helpImage.setImage(new Image(this.getClass().getResourceAsStream("/images/internbuddy-help.png")));
getRoot().show();
getRoot().centerOnScreen();
}
@@ -99,4 +99,27 @@ private void copyUrl() {
url.putString(USERGUIDE_URL);
clipboard.setContent(url);
}
+
+ /**
+ * Opens the user guide in a browser
+ */
+ @FXML
+ private void goToUserGuide() {
+ //@author eugenetangkj-reused
+ //Adapted with modifications from
+ // https://stackoverflow.com/questions/5226212/how-to-open-the-default-webbrowser-using-java
+ if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
+ try {
+ Desktop.getDesktop().browse(new URI(USERGUIDE_URL));
+ } catch (Exception e) {
+ //Should not reach here
+ e.printStackTrace();
+ assert (false);
+ }
+ }
+ }
+
+ public ImageView getHelpImage() {
+ return this.helpImage;
+ }
}
diff --git a/src/main/java/seedu/internship/ui/InternshipCard.java b/src/main/java/seedu/internship/ui/InternshipCard.java
new file mode 100644
index 00000000000..6fdf2f7dd7d
--- /dev/null
+++ b/src/main/java/seedu/internship/ui/InternshipCard.java
@@ -0,0 +1,166 @@
+package seedu.internship.ui;
+
+import static seedu.internship.model.internship.Status.ACCEPTED;
+import static seedu.internship.model.internship.Status.APPLIED;
+import static seedu.internship.model.internship.Status.ASSESSMENT;
+import static seedu.internship.model.internship.Status.INTERVIEW;
+import static seedu.internship.model.internship.Status.NEW;
+import static seedu.internship.model.internship.Status.OFFERED;
+import static seedu.internship.model.internship.Status.REJECTED;
+
+import java.util.Comparator;
+import java.util.HashMap;
+
+import javafx.fxml.FXML;
+import javafx.geometry.Insets;
+import javafx.scene.control.Label;
+import javafx.scene.layout.Background;
+import javafx.scene.layout.BackgroundFill;
+import javafx.scene.layout.CornerRadii;
+import javafx.scene.layout.FlowPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import javafx.scene.paint.Color;
+import seedu.internship.model.internship.Internship;
+
+
+/**
+ * A UI component that displays information of a {@code Internship}.
+ */
+public class InternshipCard extends UiPart {
+ public static final String ROLE_LABEL = "Role: ";
+ private static final String FXML = "InternshipListCard.fxml";
+
+ /**
+ * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
+ * As a consequence, UI elements' variable names cannot be set to such keywords
+ * or an exception will be thrown by JavaFX during runtime.
+ *
+ * @see The issue on AddressBook level 4
+ */
+
+ public final Internship internship;
+
+ @FXML
+ private HBox cardPane;
+ @FXML
+ private Label companyName;
+ @FXML
+ private Label id;
+ @FXML
+ private Label role;
+ @FXML
+ private Label date;
+ @FXML
+ private FlowPane tags;
+ @FXML
+ private Label statusLabel;
+
+
+ /**
+ * Creates a {@code InternshipCode} with the given {@code Internship} and index to display.
+ */
+ public InternshipCard(Internship internship, int displayedIndex) {
+ super(FXML);
+ this.internship = internship;
+ //Add Id
+ id.setText(displayedIndex + ". ");
+
+ //Add Company Name
+ companyName.setText(internship.getCompanyName().fullCompanyName);
+
+ //Add Role
+ role.setText(ROLE_LABEL + internship.getRole().fullRole);
+
+ //Add Date
+ String dateLabel = getDateLabel(internship.getStatus().toString());
+ date.setText(dateLabel + internship.getDate().fullDate);
+
+ //Add Tags
+ internship.getTags().stream()
+ .sorted(Comparator.comparing(tag -> tag.tagName))
+ .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
+
+
+ //Set up status label
+ String statusString = internship.getStatus().toString();
+ HashMap colorMap = setupColours();
+ Color statusColor = colorMap.get(statusString);
+ statusLabel.setText(statusString.toUpperCase());
+ statusLabel.setBackground(new Background(new BackgroundFill(
+ statusColor, new CornerRadii(10), new Insets(-5))));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof InternshipCard)) {
+ return false;
+ }
+
+ // state check
+ InternshipCard card = (InternshipCard) other;
+ return id.getText().equals(card.id.getText())
+ && internship.equals(card.internship);
+ }
+
+
+ /**
+ * Initialises the colours associated with the status label.
+ *
+ * @return a hashmap containing the colors associated with each status type
+ */
+ public static HashMap setupColours() {
+ //Hashmap that stores the colours associated with each status
+ HashMap colorMap = new HashMap();
+ colorMap.put(ACCEPTED, Color.rgb(42, 174, 79, 1.0));
+ colorMap.put(REJECTED, Color.rgb(250, 68, 68, 1.0));
+ colorMap.put(OFFERED, Color.rgb(42, 174, 166, 1.0));
+ colorMap.put(INTERVIEW, Color.rgb(126, 68, 250, 1.0));
+ colorMap.put(ASSESSMENT, Color.rgb(250, 68, 155, 1.0));
+ colorMap.put(APPLIED, Color.rgb(68, 170, 250, 1.0));
+ colorMap.put(NEW, Color.rgb(250, 155, 68, 1.0));
+ return colorMap;
+ }
+
+
+ /**
+ * Returns the label for the date field in Internship Card.
+ *
+ * @param statusString The current status of the associated Internship.
+ *
+ * @return the corresponding String as a label for the date.
+ */
+ public static String getDateLabel(String statusString) {
+ String dateLabel;
+ switch (statusString) {
+ case ACCEPTED:
+ dateLabel = "Date of Acceptance: ";
+ break;
+ case REJECTED:
+ dateLabel = "Date of Rejection: ";
+ break;
+ case OFFERED:
+ dateLabel = "Deadline of Offer Acceptance: ";
+ break;
+ case INTERVIEW:
+ dateLabel = "Date of Interview: ";
+ break;
+ case APPLIED:
+ dateLabel = "Date Applied: ";
+ break;
+ case ASSESSMENT:
+ dateLabel = "Date of Assessment: ";
+ break;
+
+ default:
+ dateLabel = "Deadline of Application: ";
+ }
+ return dateLabel;
+ }
+}
diff --git a/src/main/java/seedu/internship/ui/InternshipDetailsCard.java b/src/main/java/seedu/internship/ui/InternshipDetailsCard.java
new file mode 100644
index 00000000000..fce32059ca1
--- /dev/null
+++ b/src/main/java/seedu/internship/ui/InternshipDetailsCard.java
@@ -0,0 +1,167 @@
+package seedu.internship.ui;
+
+import static seedu.internship.model.internship.Status.ACCEPTED;
+import static seedu.internship.model.internship.Status.APPLIED;
+import static seedu.internship.model.internship.Status.ASSESSMENT;
+import static seedu.internship.model.internship.Status.INTERVIEW;
+import static seedu.internship.model.internship.Status.OFFERED;
+import static seedu.internship.model.internship.Status.REJECTED;
+
+import java.util.Comparator;
+import java.util.HashMap;
+
+import javafx.fxml.FXML;
+import javafx.geometry.Insets;
+import javafx.scene.Scene;
+import javafx.scene.control.Label;
+import javafx.scene.layout.Background;
+import javafx.scene.layout.BackgroundFill;
+import javafx.scene.layout.CornerRadii;
+import javafx.scene.layout.FlowPane;
+import javafx.scene.layout.Region;
+import javafx.scene.layout.VBox;
+import javafx.scene.paint.Color;
+import javafx.scene.text.Text;
+import seedu.internship.model.internship.Internship;
+
+
+/**
+ * A UI component that displays information of a {@code Internship}.
+ */
+public class InternshipDetailsCard extends UiPart {
+ public static final String ROLE_LABEL = "Role: ";
+
+ private static final String FXML = "InternshipDetailsCard.fxml";
+
+ /**
+ * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
+ * As a consequence, UI elements' variable names cannot be set to such keywords
+ * or an exception will be thrown by JavaFX during runtime.
+ *
+ * @see The issue on AddressBook level 4
+ */
+
+ public final Internship internship;
+
+ @FXML
+ private VBox cardPane;
+ @FXML
+ private Text companyName;
+
+ @FXML
+ private Text role;
+ @FXML
+ private Label date;
+ @FXML
+ private Text comment;
+ @FXML
+ private FlowPane tags;
+ @FXML
+ private Label statusLabel;
+ @FXML
+ private VBox tipBox;
+ @FXML
+ private Text tips;
+
+ /**
+ * A UI component that displays the detailed information and tips of a {@code Internship}.
+ */
+ public InternshipDetailsCard(Internship internship, Scene scene) {
+ super(FXML);
+ this.internship = internship;
+
+ //Add Company Name
+ companyName.setText(internship.getCompanyName().fullCompanyName);
+
+ //Add Role
+ role.setText(ROLE_LABEL + internship.getRole().fullRole);
+
+ //Add Date
+ String dateLabel = InternshipCard.getDateLabel(internship.getStatus().toString());
+ date.setText(dateLabel + internship.getDate().fullDate);
+
+ //Add Comment
+ comment.setText(internship.getComment().commentContent);
+ //@@author eugenetangkj-reused
+ //Reused with modifications from https://stackoverflow.com/questions/29315469/javafx-resize-text-with-window
+ comment.wrappingWidthProperty().bind(scene.widthProperty().multiply(0.4));
+
+ //Add Tags
+ internship.getTags().stream()
+ .sorted(Comparator.comparing(tag -> tag.tagName))
+ .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
+
+
+ //Set up status label
+ String statusString = internship.getStatus().toString();
+ HashMap colorMap = InternshipCard.setupColours();
+ Color statusColor = colorMap.get(statusString);
+ statusLabel.setText(statusString.toUpperCase());
+ statusLabel.setBackground(new Background(new BackgroundFill(
+ statusColor, new CornerRadii(10), new Insets(-5))));
+
+ //Set up tips
+ tips.setText(getTips());
+
+ //@@author eugenetangkj-reused
+ //Reused with modifications from https://stackoverflow.com/questions/29315469/javafx-resize-text-with-window
+ companyName.wrappingWidthProperty().bind(scene.widthProperty().multiply(0.3));
+ role.wrappingWidthProperty().bind(scene.widthProperty().multiply(0.3));
+ tips.wrappingWidthProperty().bind(scene.widthProperty().multiply(0.4));
+
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof InternshipDetailsCard)) {
+ return false;
+ }
+
+ // state check with comparison of company name, role and date
+ InternshipDetailsCard details = (InternshipDetailsCard) other;
+ return internship.equals(details.internship);
+ }
+
+
+ /**
+ * Gets the corresponding tips according to the status
+ *
+ * @return the tips for a specific status
+ */
+ public String getTips() {
+ switch (this.internship.getStatus().toString()) {
+ case APPLIED:
+ return "While waiting for the company's response, you can try applying to other companies as well"
+ + " to have a higher chance of landing an internship.";
+ case ASSESSMENT:
+ return "Practice makes perfect! Visit sites such as HackerRank and LeetCode to practice your algorithms"
+ + " and problem-solving skills. You could also attempt the practices under a time trial to give"
+ + " you a better sense of the actual coding assignment.";
+ case INTERVIEW:
+ return "Be natural! The role of the interviewer is not to put you in a tight position, but rather to"
+ + " learn more about who you are as a person. It's good if you could share what makes you special"
+ + " and about your personalised experience that makes you suitable for the job.";
+ case OFFERED:
+ return "Congratulations! Your hard work has paid off. Remember to read through the details of the"
+ + " letter of offer such as job scope and working hours before committing to the offer.";
+ case REJECTED:
+ return "Fret not! The process of landing an internship is not a smooth-sailing one, and failures are"
+ + " part of the journey. Continue your search and you will eventually a suitable internship."
+ + " Fighting!";
+ case ACCEPTED:
+ return "Congratulations! This is a chance to build new skills, make connections, and explore your "
+ + "interests in a real-world setting. Embrace every moment of this journey and "
+ + "don't be afraid to ask questions, seek guidance, and take risks.";
+ default:
+ return "If possible, try to apply early because once companies receive applications, they would start"
+ + " screening for potential candidates. Also, remember to do a thorough check of your resume"
+ + " before sending out your application.";
+ }
+ }
+}
diff --git a/src/main/java/seedu/internship/ui/InternshipListPanel.java b/src/main/java/seedu/internship/ui/InternshipListPanel.java
new file mode 100644
index 00000000000..66d99f36f74
--- /dev/null
+++ b/src/main/java/seedu/internship/ui/InternshipListPanel.java
@@ -0,0 +1,64 @@
+package seedu.internship.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.internship.commons.core.LogsCenter;
+import seedu.internship.model.Model;
+import seedu.internship.model.internship.Internship;
+
+/**
+ * Panel containing the list of internships
+ */
+public class InternshipListPanel extends UiPart {
+ private static final String FXML = "InternshipListPanel.fxml";
+ private final Logger logger = LogsCenter.getLogger(InternshipListPanel.class);
+
+ private Model model;
+
+ private MainWindow mainWindow;
+ @FXML
+ private ListView internshipListView;
+
+ /**
+ * Creates a {@code InternshipListPanel} with the given {@code ObservableList}.
+ */
+ public InternshipListPanel(ObservableList internshipList, Model selectedModel,
+ MainWindow selectedMainWindow) {
+ super(FXML);
+ internshipListView.setItems(internshipList);
+ internshipListView.setCellFactory(listView -> new InternshipListViewCell());
+ model = selectedModel;
+ mainWindow = selectedMainWindow;
+ // @@author potty10-reused
+ // Reused from https://stackoverflow.com/a/34646172
+ // with minor modifications
+ internshipListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
+ model.updateSelectedInternship(newValue);
+ mainWindow.updateRightPanel();
+ });
+ // @@author
+ }
+
+ /**
+ * Custom {@code ListCell} that displays the graphics of a {@code Internship} using a {@code InternshipCard}.
+ */
+ class InternshipListViewCell extends ListCell {
+ @Override
+ protected void updateItem(Internship internship, boolean empty) {
+ super.updateItem(internship, empty);
+
+ if (empty || internship == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(new InternshipCard(internship, getIndex() + 1).getRoot());
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/internship/ui/MainWindow.java
similarity index 69%
rename from src/main/java/seedu/address/ui/MainWindow.java
rename to src/main/java/seedu/internship/ui/MainWindow.java
index 9106c3aa6e5..c0cee87eb88 100644
--- a/src/main/java/seedu/address/ui/MainWindow.java
+++ b/src/main/java/seedu/internship/ui/MainWindow.java
@@ -1,21 +1,27 @@
-package seedu.address.ui;
+package seedu.internship.ui;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
+import javafx.geometry.Pos;
import javafx.scene.control.MenuItem;
+import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextInputControl;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
+import javafx.scene.text.Text;
import javafx.stage.Stage;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.logic.Logic;
-import seedu.address.logic.commands.CommandResult;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.internship.commons.core.GuiSettings;
+import seedu.internship.commons.core.LogsCenter;
+import seedu.internship.logic.Logic;
+import seedu.internship.logic.commands.CommandResult;
+import seedu.internship.logic.commands.exceptions.CommandException;
+import seedu.internship.logic.parser.exceptions.ParseException;
+import seedu.internship.model.internship.Internship;
/**
* The Main Window. Provides the basic application layout containing
@@ -31,9 +37,10 @@ public class MainWindow extends UiPart