diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index 07acb40a13d..4b85caa869c 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -1,6 +1,6 @@
name: Java CI
-on: [push, pull_request]
+on: [pull_request]
jobs:
build:
diff --git a/.gitignore b/.gitignore
index 71c9194e8bd..c604ada1ceb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,12 @@ src/main/resources/docs/
/preferences.json
/*.log.*
+# Other files/folders
+.classpath
+.project
+.settings/
+bin/
+
# Test sandbox files
src/test/data/sandbox/
diff --git a/README.md b/README.md
index 13f5c77403f..7eb0e9fdba3 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,34 @@
-[![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.
+[![Java CI](https://github.com/AY2122S1-CS2103-F09-3/tp/actions/workflows/gradle.yml/badge.svg?branch=master)](https://github.com/AY2122S1-CS2103-F09-3/tp/actions)
+[![codecov](https://codecov.io/gh/AY2122S1-CS2103-F09-3/tp/branch/master/graph/badge.svg?token=KLKGJOEN9F)](https://codecov.io/gh/AY2122S1-CS2103-F09-3/tp)
+
+![Ui](docs/images/Ui_v1.4.png)
+![Ui](docs/images/commands/DashboardCommand/dashboard.png)
+
+* ProgrammerError (P|E in short) is an application developed based on the `AddressBook Level 3` application.
+* This is an application made for CS2100 Teaching Assistants (TAs) to track their students' task progress and
+ performance
+
+## Feature List
+
+1. [General Features](#general-features)
+ 1. [View Help: `help`](#view-help)
+ 2. [View Dashboard `dashboard`](#view-dashboard)
+ 3. [Exit: `exit`](#exit)
+2. [Data Features](#data-features)
+ 1. [Fill Sample Data: `fill`](#fill-sample-data)
+ 2. [Purge All Data: `purge`](#purge-all-data)
+ 3. [Download Data: `download`](#download-data)
+ 4. [Upload Data: `upload`](#upload-data)
+3. [Student Features](#student-features)
+ 1. [Add Student: `add`](#add-student)
+ 2. [Edit Student Details: `edit`](#edit-student)
+ 3. [Delete Student: `delete`](#delete-student)
+ 4. [Filter Students: `filter`](#filter-student)
+ 5. [Show Student Details: `show`](#show-student)
+ 6. [List All Students: `list`](#list-students)
+4. [Lab Features](#lab-features)
+ 1. [Add Lab: `addlab`](#add-lab)
+ 2. [Edit Lab: `editlab`](#edit-lab)
+ 3. [Delete Lab: `dellab`](#delete-lab)
+
+This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
diff --git a/build.gradle b/build.gradle
index be2d2905dde..c608bb243e6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,7 +6,7 @@ plugins {
id 'jacoco'
}
-mainClassName = 'seedu.address.Main'
+mainClassName = 'seedu.programmer.Main'
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
@@ -20,6 +20,10 @@ checkstyle {
toolVersion = '8.29'
}
+run {
+ enableAssertions = true
+}
+
test {
useJUnitPlatform()
finalizedBy jacocoTestReport
@@ -44,6 +48,10 @@ dependencies {
String jUnitVersion = '5.4.0'
String javaFxVersion = '11'
+ compile group: 'org.json', name: 'org.json', version: 'chargebee-1.0'
+ implementation 'com.opencsv:opencsv:4.6'
+
+ implementation group: 'commons-io', name: 'commons-io', version: '2.6'
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win'
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac'
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux'
@@ -66,7 +74,7 @@ dependencies {
}
shadowJar {
- archiveName = 'addressbook.jar'
+ archiveName = 'ProgrammerError.jar'
}
defaultTasks 'clean', 'test'
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 1c9514e966a..286ed19f028 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -5,55 +5,56 @@ title: About Us
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`
+You can reach us at the email `shermannws@u.nus.edu`.
## Project team
-### John Doe
+### Allard Quek
-
+
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[homepage](https://allardquek.tech)]
+[[github](https://github.com/AllardQuek)]
+[[portfolio](team/allardquek.md)]
-* Role: Project Advisor
+- Role: Project Advisor
-### Jane Doe
+### Erwin Quek
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[personal site](https://erwinquek.vercel.app)]
+[[github](http://github.com/erwinqxy)]
+[[portfolio](team/erwinqxy.md)]
-* Role: Team Lead
-* Responsibilities: UI
+- Role: Team Lead
+- Responsibilities: Data
-### Johnny Doe
+### Samay Sagar
-
+
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](http://github.com/reddevil1313)] [[portfolio](team/reddevil1313.md)]
-* Role: Developer
-* Responsibilities: Data
+- Role: Developer
+- Responsibilities: Data
-### Jean Doe
+### Sherman Ng Wei Sheng
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/shermannws)]
+[[portfolio](team/shermannws.md)]
-* Role: Developer
-* Responsibilities: Dev Ops + Threading
+- Role: Developer
+- Responsibilities: Backend
-### James Doe
+### Zhao Peiduo
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/ZhaoPeiduo)]
+[[portfolio](team/zhaopeiduo.md)]
* Role: Developer
-* Responsibilities: UI
+* Responsibilities: UI design
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 46eae8ee565..3584a88a0f3 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -2,246 +2,910 @@
layout: page
title: Developer Guide
---
-* Table of Contents
-{:toc}
+
+## **Table of Contents**
+
+1. [**Acknowledgements**](#Acknowledgements)
+2. [**Getting started**](#Setting up)
+3. [**Glossary**](#Glossary)
+4. [**Design**](#Design)
+ 1. [Architecture](#Architecture)
+ 2. [UI Component](#UI component)
+ 3. [Logic Component](#Logic component)
+ 4. [Model Component](#Model component)
+ 5. [Storage Component](#Storage component)
+ 6. [Common Classes](#common-classes)
+5. [**Implementations**](#Implementations)
+ 1. [`Add` Student Feature](#add student)
+ 2. [`Filter` Student List Feature](#filter student)
+ 3. [`Show` lab results Feature](#show lab)
+ 4. [`EditLab` Feature](#edit lab)
+ 5. [`Download` Data Feature](#download data)
+ 6. [`Purge` Feature](#purge data)
+ 7. [\[Proposed\] `Undo`/`Redo` Feature](#undoredo)
+6. [**Documentation, logging, testing, configuration, dev-ops**](#Documentation)
+7. [**Appendix: Requirements**](#Appendix Requirements)
+ 1. [Product Scope](#Product Scope)
+ 2. [User Stories](#User Stories)
+ 3. [Use Cases](#Use Cases)
+ 1. [Use Case: UC1 Purge/Delete all sample student records](#Use Case1)
+ 2. [Use Case: UC2 Create a student record](#Use Case2)
+ 3. [Use Case: UC3 Upload student records](#Use Case3)
+ 4. [Use Case: UC4 View a student record](#Use Case4)
+ 5. [Use Case: UC5 Delete a student record](#Use Case5)
+ 6. [Use Case: UC6 Edit a student record](#Use Case6)
+ 7. [Use Case: UC7 Download student records](#Use Case7)
+ 8. [Use Case: UC8 Create a lab record](#Use Case8)
+ 9. [Use Case: UC9 Edit a lab record](#Use Case9)
+ 10. [Use case: UC10 View dashboard of student records](#Use Case10)
+ 11. [Use case: UC11 Filter student records](#Use Case11)
+ 4. [Non-Functional Requirements](#Non-Functional Requirements)
+8. [**Appendix: Instructions for Manual Testing**](#manual-testing)
+ 1. [Launch and Shutdown](#Launch and Shutdown)
+ 2. [Deleting a Student](#Del student)
+ 3. [Show a Student's Lab Result](#show lab student)
+ 4. [Upload Data](#upload-data)
+ 5. [Download Data](#download-data)
+ 6. [Dashboard](#dashboard)
+9. [**Appendix: Effort**](#Appendix Effort)
+ 1. [Rewriting the Command Syntax](#Rewriting the Command Syntax)
+ 2. [Designing New UI Components](#Designing New UI components)
+ 3. [Working with Third-Party Libraries](#Working with Third-Party Libraries)
+ 4. [Implementing Dynamic Features](#Implementing Dynamic Features)
--------------------------------------------------------------------------------------------------------------------
-## **Acknowledgements**
+## **1. Acknowledgements**
+
+ProgrammerError(PE) makes use of the following third-party libraries:
-* {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson)
+ , [JSON In Java](https://mvnrepository.com/artifact/org.json/json), [opencsv](http://opencsv.sourceforge.net/)
+ , [JUnit5](https://github.com/junit-team/junit5)
--------------------------------------------------------------------------------------------------------------------
-## **Setting up, getting started**
+## **2. Setting up, getting started**
Refer to the guide [_Setting up and getting started_](SettingUp.md).
--------------------------------------------------------------------------------------------------------------------
-## **Design**
+## **3. Glossary**
+
+- **Mainstream OS**: Windows, Linux, Unix, OS-X
+- **Student ID**: NUS student matriculation number (AXXXXXXXY)
+- **Email**: NUS student email (eXXXXXXX@u.nus.edu)
+- **TA**: CS2100 lab teaching assistant
+- **PE**: ProgrammerError
+- **CSV**: Comma-Separated Values
+
+--------------------------------------------------------------------------------------------------------------------
+
+## **4. Design**
-: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.
+:bulb: **Tip:** The `.puml` files used to create diagrams in this document can be found in
+the [diagrams](https://github.com/AY2122S1-CS2103-F09-3/tp/tree/master/docs/diagrams) folder.
-### Architecture
-
-
+### **4.1 Architecture**
-The ***Architecture Diagram*** given above explains the high-level design of the App.
+
+
+
+
+ Figure 4.1.1: Architecture diagram of PE
+
+
+The ***Architecture Diagram*** given above in Figure 4.1.1 explains the high-level design of PE.
Given below is a quick overview of 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/AY2122S1-CS2103-F09-3/tp/blob/master/src/main/java/seedu/programmer/Main.java)
+and [`MainApp`](https://github.com/AY2122S1-CS2103-F09-3/tp/blob/master/src/main/java/seedu/programmer/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.
-[**`Commons`**](#common-classes) represents a collection of classes used by multiple other components.
-
The rest of the App consists of four components.
-* [**`UI`**](#ui-component): The UI 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.
-
+* [**`UI`**](#UI component): ProgrammerError's UI.
+* [**`Logic`**](#Logic component): The command executor.
+* [**`Model`**](#Model component): Holds the data of ProgrammerError in memory.
+* [**`Storage`**](#Storage component): Reads data from, and writes data to, the hard disk.
**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`.
-
-
-
+The *Sequence Diagram* in Figure 4.1.2 shows how the components interact with each other for the scenario where the user issues
+the command `delete 1`.
+
+
+
+
+ Figure 4.1.2: Sequence diagram showing interactions between the components
+
+
Each of the four main components (also shown in the diagram above),
* 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.
+* 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 Figure 4.1.3 below.
+
+
+
+
+
+ Figure 4.1.3: Partial class diagram showing interactions through interfaces
+
+
+The sections below give more details of each component.
-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.
+### **4.2 UI component**
-
+The **API** of this component is specified
+in [`Ui.java`](https://github.com/AY2122S1-CS2103-F09-3/tp/blob/master/src/main/java/seedu/programmer/ui/Ui.java)
-The sections below give more details of each component.
+At a high level, the `MainWindow` component interacts with 3 other main components: `Logic`, `PopupManager` and `FileManager` (Figure 4.2.1).
+Note that the components under `MainWindow` have been omitted for simplicity and will be shown in greater detail in Figure 4.2.2.
-### UI component
+1. Firstly, `MainWindow` interacts with the `Logic` component to determine which data to display to the user.
+2. Secondly, `MainWindow` conducts file operations on the UI through a `FileManager`.
+ For instance, the `FileManager` handles situations where the user is required to select files or directories.
+3. Thirdly, to manage the display of popup windows to the user, `MainWindow` interacts with a `PopupManager` which handles
+ the configuration, creation and showing of popups on the UI.
-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)
+In addition, there are two additional windows that the UI can display: `HelpWindow` and `DashboardWindow`. They inherit
+from the abstract class `PopupWindow`, which captures the commonalities between classes that represent popup information
+to be displayed to the user.
-![Structure of the UI Component](images/UiClassDiagram.png)
+
+
+
+
+ Figure 4.2.1: Overview of UI components
+
+
+
+Now taking a closer look at the `MainWindow` component, it consists of a number of parts e.g.`CommandBox`, `ResultDisplay`, `StudentListPanel`
+, `StatusBarFooter` etc. (Figure 4.2.2). These components, including the `MainWindow`, inherit from the abstract `UiPart` class which captures
+the commonalities between classes that represent parts of the visible GUI. The following is a summary of the parts of the `MainWindow`.
-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 4.2.2: MainWindow UI components
+
+
+Note that the `UI` component uses the JavaFx UI framework.
-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 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/AY2122S1-CS2103-F09-3/tp/blob/master/src/main/java/seedu/programmer/ui/MainWindow.java)
+ is specified
+ in [`MainWindow.fxml`](https://github.com/AY2122S1-CS2103-F09-3/tp/blob/master/src/main/resources/view/MainWindow.fxml)
+
+- The styling of the UI components are defined in the `src/main/resources/view/css` folder.
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`.
-
-### Logic component
+* depends on some classes in the `Model` component, as it displays `Student` object residing in the `Model`.
-**API** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java)
+### **4.3 Logic component**
-Here's a (partial) class diagram of the `Logic` component:
+**API** : [`Logic.java`](https://github.com/AY2122S1-CS2103-F09-3/tp/blob/master/src/main/java/seedu/programmer/logic/Logic.java)
-
+Figure 4.3.1 shows a (partial) class diagram of the `Logic` component:
+
+
+
+
+ Figure 4.3.1: Overview of Logic components
+
+
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`.
-The Sequence Diagram below illustrates the interactions within the `Logic` component for the `execute("delete 1")` API call.
+1. When `Logic` is called upon to execute a command, it uses the `ProgrammerErrorParser` 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 student).
+1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`.
-![Interactions Inside the Logic Component for the `delete 1` Command](images/DeleteSequenceDiagram.png)
+The Sequence Diagram in Figure 4.3.2 below illustrates the interactions within the `Logic` component for the `execute("delete 1")` API
+call.
+
+
+
+
+ Figure 4.3.2: Sequence diagram illustrating interactions within the Logic component
+
+
: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.
+Figure 4.3.3 illustrates the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command:
-Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command:
+
+
+
+
+ Figure 4.3.3: Partial class diagram showing the structure of the Parser classes
+
+
+How the parsing works:
-
+* When called upon to parse a user command, the `ProgrammerErrorParser` 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 `ProgrammerErrorParser` 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.
-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.
+### **4.4 Model component**
+
+**API** : [`Model.java`](https://github.com/AY2122S1-CS2103-F09-3/tp/blob/master/src/main/java/seedu/programmer/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 4.4.1: Overview of the Model components
+
+
+The `Model` components as seen in Figure 4.4.1,
+
+* stores the ProgrammerError data i.e., all `Student` objects (which are contained in a `UniqueStudentList` object).
+* stores the currently 'selected' `Student` 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)
+
+
+### **4.5 Storage component**
+
+**API** : [`Storage.java`](https://github.com/AY2122S1-CS2103-F09-3/tp/blob/master/src/main/java/seedu/programmer/storage/Storage.java)
+
+
+
+
+ Figure 4.5.1: Overview of Storage components
+
+
+The `Storage` components as seen in Figure 4.5.1,
-
+* can save both ProgrammerError data and user preference data in json format, and read them back into corresponding
+ objects.
+* inherits from both `ProgrammerErrorStorage` 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`)
+### **4.6 Common classes**
-The `Model` component,
+Classes used by multiple components are in the `seedu.programmer.commons` package. [**`Commons`**](#common-classes) represents a collection of classes used by multiple other components.
-* 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 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.
+## **5. Implementation**
-
+This section describes some noteworthy details on how certain features are implemented.
+### **5.1 `Add` Student Feature**
+
+#### Implementation
+
+The add student feature allows the CS2100 Lab TAs to add a new student into the student list. Its implementation
+introduces the following classes:
+
+- `AddCommand` that extends `Command`
+- `AddCommandParser` that implements `Parser`
+- Student information: `Student`, `Name`, `StudentId`, `ClassId`, `Email`, `UniqueStudentList`
+
+The syntax of this command is `add -n -sid -cid -email `. For instance,
+`add -n Erwin -sid A0234596H -cid B02 -email e0543221@u.nus.edu` will create a student with the given name, student id,
+class id and email.
+
+Given below is a possible usage scenario:
+
+The CS2100 TA keys in the command `add -n Erwin -sid A0234596H -cid B02 -email e0543221@u.nus.edu`.
+
+The mechanism is as described below:
+- Upon detecting `add` as the command word. `ProgrammerErrorParser` will create a `AddCommandParser` with the input
+name, student id, class id and email.
+- `AddCommandParser` parses the name, student id, class id and email and creates a `Student` object. It will then
+create a `AddCommand` with the new `Student` object.
+- `AddCommand` receives the new `Student` object and checks if any student in `UniqueStudentList` shares the same `studentId` and `email`
+with the newly created student.
+- If the new `Student` is unique it will be added to the `UniqueStudentList`.
+- ProgrammerError will show a success message for adding the student. For example, `New student added: Erwin; Student ID: A0234596H; Class ID: B02; Email: e0543221@u.nus.edu`
+in the `resultDisplay`, informing the user that the add operation is valid.
+
+
+The following (partial) sequence diagram in Figure 5.1.1 shows how the add command works:
+- Note: toAdd in the sequence diagram represents the new `Student` object to be added.
+- Refer to [Logic component](#Logic component) for a review of the Logic Component.
+
+
+
+
+
+ Figure 5.1.1: Sequence diagram illustrating the execution of add command
+
+
+The following activity diagram in Figure 5.1.2 summarizes what happens when a CS2100 TA executes a new command:
+
+
+
+
+
+ Figure 5.1.2: Activity diagram for executing add command
+
+
+
+#### Design considerations:
+
+#### Aspect: Only unique Student ID and email is accepted:
+- Each student object should have unique Student ID and email.
+ - Pros:
+ - Ensures that each student is unique and easily identifiable with the key attributes.
+ - Ensures that there are no duplicates and redundant data.
+ - Cons:
+ - The strict checks on the `UniqueStudentList` will affect `EditCommand` when the user tries to edit an existing student.
+ This will happen when the user only wants to edit one of the attribute. (For example, studentId.)
+ This newly edited student will have an old copy of the email. This side effect will cause the newly created `student` to clash with its old instance in `UniqueStudentList`,
+ causing the command to fail, even though it should be valid. As such, it makes it hard to implement, as we have to
+ ensure that it works with `EditCommand` as well.
+
+### **5.2 `Filter` Student List Feature**
+
+#### Implementation
+
+The filter feature allows the CS2100 Lab TAs to filter the student list in ProgrammerError based on any combinations
+(but at least one) of the following 4 optional parameters: `Name`, `StudentId`, `ClassId` and/or `Email`.
+Its implementation introduces the following classes:
+* `FilterCommand` that extends `Command`
+* `FilterCommandParser` that implements `Parser`
+* `QueryStudentDescriptor` that contains the user input of the corresponding student information to be queried with.
+* `StudentDetailContainsQueryPredicate` that implements `Predicate` to test if a student matches the fields as
+specified in `QueryStudentDescriptor`.
+
+The syntax of this command is `filter [-n ] [-sid ] [-cid ] [-email ]`.
+For instance, `filter -cid B01` will filter and show all the students in the list whose class ID contains the character
+sequence "B01".
+This is designed for the target users who are fast typists to efficiently filter the list as desired.
+
+The implementation of the filter mechanism is facilitated by the `StudentDetailContainsQueryPredicate` that contains a
+private field of type `QueryStudentDescriptor` that will be used to test if a given student to the predicate matches all
+the query fields in the `QueryStudentDescriptor`.
+
+The following methods are further explained in greater detail for ease of understanding:
+* `StudentDetailContainsQueryPredicate#test(Student)` — Evaluates the predicate on the given `Student` argument.
+* `QueryStudentDescriptor#doesStudentMatchDescriptor(Student)` — Evaluates if the `QueryStudentDescriptor` fields
+ matches with the corresponding fields of the `Student` argument. It is a match as long as the corresponding fields of
+ the `Student` argument **contains the character sequence** as specified in the `QueryStudentDescriptor`.
+
+These operations are exposed in the `Model` interface as `Model#updateFilteredStudentList(Predicate)`.
+
+Given below is an example usage scenario and how the list filtering mechanism behaves.
+
+Step 1. The CS2100 TA launches the application.
+
+Step 2. The CS2100 TA executes `filter -cid B01` to display all the students whose Class ID matches `B01`.
+
+The following UML sequence diagrams shows how the filter command works:
+
+* Figure 5.2.1 focuses on modelling the interactions between components to first create the `FilterCommand` object.
+
+
+
+
+
+ Figure 5.2.1: Partial sequence diagram showing the creation of FilterCommand object
+
+
+* In the next sequence diagram, Figure 5.2.2 focuses on the interactions between components when the `FilterCommand` is
+being executed.
+
+
+
+
+
+ Figure 5.2.2: Partial sequence diagram showing the execution of FilterCommand object
+
+
:information_source: **Note:** The lifeline for `StudentDetailContainsPredicate`
+, `QueryStudentDescriptor` and `FilterCommand` should end at the destroy marker (X) but due to a limitation of PlantUML,
+the lifeline reaches the end of diagram.
+
-### Storage component
+Figure 5.2.3 shows the UML activity diagram summarizing what happens when a CS2100 TA executes a new filter command.
-**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java)
+
+
+
+
+ Figure 5.2.3: Activity diagram for executing filter command
+
+
-
+#### Design Consideration
-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).
-* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`)
+**Aspect: How filter command executes**
-### Common classes
+* **Alternative 1 (current choice):** Filter commands can take in any combination of query parameters
+(`-n`, `-cid`, `-sid` and `-email`)
+ * Pros: Allow for flexibility in the way the CS2100 Lab TA wants to filter the list.
+ * Cons: More difficult to implement and proper handling of the combinations of query parameters is needed.
-Classes used by multiple components are in the `seedu.addressbook.commons` package.
+* **Alternative 2:** A different type of filter command to filter by each of the student's attribute.
+ * Pros: Implementation does not need to consider the combination of query parameters.
+ * Cons: Multiple commands have to be executed to filter the list in more than one query dimension.
---------------------------------------------------------------------------------------------------------------------
+**Aspect: How to handle combination of query parameters**
-## **Implementation**
+* **Alternative 1 (current choice):** Design a `QueryStudentDescriptor` class that abstracts the handling of the input
+ query parameters.
+ * Pros: Need not explicitly handle the different argument combinations at the higher-level abstractions
+ (e.g. `FilterCommandParser` class). Code is more maintainable.
+ * Cons: Was more difficult to implement which required time to design the interactions among the components.
-This section describes some noteworthy details on how certain features are implemented.
+* **Alternative 2:** Handle the different argument combinations in the `FilterCommandParser` class.
+ * Pros: Easier to handle empty argument cases with explicit conditional checking.
+ * Cons: Bad use of abstraction, SLAP violated and long nested conditional statements. Code made harder for future
+ extension.
-### \[Proposed\] Undo/redo feature
+**Aspect: Naming the function**
-#### Proposed Implementation
+* **Alternative 1 (current choice):** Calling it `filter`.
+ * Pros: `filter` is an intuitive command word for the expected functionality.
+ * Cons: From the user experience perspective, it is slightly longer than type than other alternative.
-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:
+* **Alternative 2:** Calling it `view`.
+ * Pros: It is shorter to type and less refactoring required from the code that this project evolved from.
+ * Cons: `view` is not as intuitive as other alternatives.
-* `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.
+* **Alternative 3 (future consideration):** Providing a shortcut command for `filter`.
+ * Pros: Allows for users to type less for the same expected behaviour.
+ * Cons: New users may be confused with such shortcut commands.
-These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively.
+### **5.3 `Show` Lab Results Feature**
-Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
+#### Implementation
+
+The show lab results feature allows the CS2100 TA to view the lab result list of a particular student. Its
+implementation introduces the following classes:
+
+* `ShowCommand`that extends `Command`
+* `ShowCommandParser` that implements `Parser`
+* `ShowCommandResult` that extends `CommandResult`
+
+The syntax of this command is `show `. For instance, `show 1` asks ProgrammerError to display the lab
+results of student at index 1 of the current list.
+
+Given below is a possible usage scenario:
+
+[Pre-Condition] There are 2 students in ProgrammerError, and the CS2100 TA has created some lab results for each of
+them.
+
+Step 1. The CS2100 TA keys in the command `show 1`: The information of the student at index 1 as well as his/her lab
+results are displayed on the side panel.
-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.
+The mechanism is as described below:
-![UndoRedoState0](images/UndoRedoState0.png)
+* Upon detecting 'show' as the command word. `ProgrammerErrorParser` will create a `ShowCommandParser` with the input
+ index.
-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)
+* `ShowCommandParser` parses the index and creates a `ShowCommand`, which finds the student to be shown according to the
+ index and creates a `ShowCommandResult` with the student identified.
+
+Step 2. The CS2100 TA keys in `show 2`: The side panel is updated with the information and lab results of the student at
+index 2
-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`.
+Step 3. The CS2100 TA keys in `show 3`: ProgrammerError will show an error message in the `resultDisplay`, warning the
+user that the index is invalid. This is triggered by `CommandException`, which is thrown by `ShowCommand`.
-![UndoRedoState2](images/UndoRedoState2.png)
+The following sequence diagram in Figure 5.3.1 shows how the show command works:
-
: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`.
+
+
+
+
+ Figure 5.3.1: Sequence diagram illustrating the execution of show command
+
+
+
+The following activity diagram in Figure 5.3.2 summarizes what happens when a CS2100 TA executes a new command:
+
+
+
+
+ Figure 5.3.2: Activity diagram for executing show command
+
-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.
+#### Design considerations:
-![UndoRedoState3](images/UndoRedoState3.png)
+**Aspect: How Show Lab Results executes:**
-
: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.
+* **Alternative 1 (current choice):** Each student object keeps track of its own lab results by an ObservableList.
+ * Pros: Easy to implement; Lower chance of having mismatched student and lab records.
+ * Cons: Have to pass a `Student` instance across different classes; May have performance issue if more attributes
+ are added for `Student`
+
+* **Alternative 2:** An ObservableList of lab results of every student in ProgrammerError itself.
+ * Pros: Potential improvement in performance by passing an index, instead of a `Student` instance, across different
+ classes.
+ * Cons: Hard to implement, as we have to ensure the ObservableList of lab results and students have matching index
+ (ie `Student` instance at index 1 of student list has its lab results at index 1 of lab results list), given that
+ other operations such as add and delete can change the indexes easily.
+
+
+### **5.4 `EditLab` Feature**
+
+#### Implementation
+The edit lab feature allows the CS2100 TA to edit the lab information for all students in the list. Its
+implementation introduces the following classes:
+
+* `EditLabCommand`that extends `Command`
+* `EditLabCommandParser` that implements `Parser`
+
+The syntax of this command is `editlab -ln [-nln ] [-ts ]`.
+For instance,`editlab -ln 1 -nln 2 -ts 20` asks ProgrammerError to edit the lab with lab number 1 to a new
+lab number 2 with a new total score of 20.
+
+Given below is a possible usage scenario:
+
+[Pre-Condition] There are 10 students in ProgrammerError, and the CS2100 TA has created lab 1 for all of them.
+
+The CS2100 TA keys in the command `editlab -ln 1 -nln 2 -ts 20`.
+
+The mechanism is as described below:
+
+* Upon detecting `editlab` as the command word. `ProgrammerErrorParser` will create a `EditLabCommandParser` with the input
+ lab number, new lab number and total score.
+
+
+* `EditLabCommandParser` parses the lab number, new lab number and total score and creates a `Lab` Object.
+ It will then create a `EditLabCommand` with the existing Lab Object, the new Lab Object and the total score.
+* `EditLabCommand` receives the existing Lab Object, new Lab Object and total score. It then
+ checks if the original lab exists, if the new lab does not exist and the total score is a valid number.
+* If the original lab exists, new lab does not exist and total score is a valid number, the lab will be
+ edited for all the students in the list.
+* ProgrammerError will then show a success message for editing the lab. For example, `Updated Lab 1!` in the
+`resultDisplay`, informing the user that the editlab operation is valid.
+
+The following sequence diagram in Figure 5.4.1 shows how the `editlab` command works:
+
+
+
+
+
+ Figure 5.4.1: Sequence diagram illustrating the execution of editlab command
+
+The following activity diagram in Figure 5.4.2 summarizes what happens when a CS2100 TA executes a new command:
+
+
+
+
+
+ Figure 5.4.2: Activity diagram for executing editlab command
+
+
+
+#### Design considerations:
-The following sequence diagram shows how the undo operation works:
+**Aspect: How Edit Lab Results executes:**
-![UndoSequenceDiagram](images/UndoSequenceDiagram.png)
+* **Alternative 1 (current choice):** The lab is edited individually for each Student.
+ * Pros: Easier to implement; Easier to keep track of lab classes and have separate instances to lower dependency.
+ * Cons: Inefficient; Need to loop through each individual student.
-
: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.
+* **Alternative 2:** An ObservableList of all lab templates without actual score in ProgrammerError itself.
+ * Pros: Potential improvement in performance by only needing to change one list for all students.
+ * Cons: Hard to implement, as we have to ensure that students refer to latest ObservableList of lab templates
+ for their own scores and will still need to create a copy of the template for their own reference.
+
+### **5.5 `Download` Data Feature**
+
+The download data feature allows the CS2100 TA to download student data as a CSV file in a directory location of their
+choice.
+
+#### Implementation
+The implementation details of this feature can be found mainly in `MainWindow` as most of the necessary operations are
+related to the UI. In addition, the following classes are utilized:
+
+- `DownloadCommand`: for generating the `DownloadCommandResult`
+- `DownloadCommandResult`: for displaying the feedback to the CS2100 TA
+- `MainWindow.fxml`: for the addition of a 'Download' button on the MainWindow
+- `Popup.css`: for the customisation of styles for pop-up messages
+
+The `download` command works in a similar fashion to the [`show` command](#show lab) in the `Logic` components, except that it does
+not require its own parser.
+
+
+The following sequence diagram in Figure 5.5.1 shows how the `download` command works in greater detail.
+
+1. After receiving a `DownloadCommandResult` from the `Logic` component, the `MainWindow` handles the download by first
+ calling `JsonUtil.getJsonData(filePath)` to get the JSON student data from the default storage location `programmerError.json`.
+2. The `MainWindow` then prompts the user to select a directory to save the CSV file to be created to.
+3. Finally, the `MainWindow` calls the `JsonUtil.writeCSV(jsonData, file)` method to write the CSV file to the
+ selected directory.
+
+
+
+
+
+ Figure 5.5.1: Sequence diagram illustrating the execution of download command
+
-The `redo` command does the opposite — it calls `Model#redoAddressBook()`, which shifts the `currentStatePointer` once to the right, pointing to the previously undone state, and restores the address book to that state.
+The following activity diagram in Figure 5.5.2 summarizes what happens when a CS2100 TA executes the `download` command.
+The main two possible scenarios are:
-
: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.
+1. There is student data present to download. If so, the user proceeds to select a destination folder and the data will
+ be stored in a file named `programmerError.csv` in the selected directory.
+2. There is no student data present to download. In this case, the user is simply notified that there is no data to download.
+
+
+
+
+ Figure 5.5.2: Activity diagram for executing download command
+
+
+#### Design Considerations
+
+One of the main considerations was to deal with reading and writing files only when necessary. This meant checking if
+there is any data to begin with. Only if there exists any data will the CS2100 TA be prompted to select a directory location.
+
+Additionally, a pop-up message was chosen to be displayed for two reasons.
+
+1. First, it provides the user a clear visual indicator of the result of their command, as compared to the typical textual output they would see.
+2. Second, using a pop-up message right at the end of this operation means we can customize the message depending on whether the download was a
+success. This is because we would only know whether the data was successfully downloaded or not after the textual response is shown to the user.
+
+#### Alternatives
+
+1. One alternative could be to not use a third-party package (`org.json`), and instead manually parse the json file and
+ write the corresponding values to a CSV file which ProgrammerError would create. We chose not to go down this route
+ as it is much more tedious with little reward in terms of code management and code quality.
+
+2. Another alternative with respect to the CS2100 TA experience could be to disallow the user from selecting a folder to save
+ their data to. Instead, a default location could be chosen so as to save the CS2100 TA some time in getting their data
+ downloaded quickly. However, since we wanted to make ProgrammerError more flexible and adaptable to different users,
+ we opted to include the functionality of allowing the CS2100 TA to select a folder destination.
+
+### **5.6 `Purge` Feature**
+
+#### Implementation
+
+The purge feature allows the CS2100 TA to purge all existing sample or user data from ProgrammerError. Its
+implementation introduces the following classes:
+
+* `PurgeCommand`that extends `Command`
-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.
+The syntax of this command is `purge`.
+For instance,`purge` asks ProgrammerError to purge all data from it.
-![UndoRedoState4](images/UndoRedoState4.png)
+Given below is a possible usage scenario:
-Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add n/David …` command. This is the behavior that most modern desktop applications follow.
+The CS2100 TA keys in the command `purge`.
-![UndoRedoState5](images/UndoRedoState5.png)
+The mechanism is as described below:
-The following activity diagram summarizes what happens when a user executes a new command:
+* Upon detecting 'purge' as the command word. `ProgrammerErrorParser` will create a `PurgeCommand`.
+* `PurgeCommand` then checks if the model has students or not.
+* If there is some data in the model, all data will be purged.
+* ProgrammerError will then show a success message for purging the data. For example,
+ `ProgrammerError has been purged of data!` in the
+ `resultDisplay`, informing the user that the purge operation is valid.
-
+The following sequence diagram in Figure 5.6.1 shows how the purge command works:
+
+
+
+
+
+ Figure 5.6.1: Sequence diagram illustrating the execution of purge command
+
+
+The following activity diagram in Figure 5.6.2 summarizes what happens when a CS2100 TA executes a new command:
+
+
+
+
+
+ Figure 5.6.2: Activity diagram for executing purge command
+
+
#### Design considerations:
-**Aspect: How undo & redo executes:**
+**Aspect: When the command should purge data:**
+
+* **Alternative 1 (current choice):** Command purges both sample and existing data
+ * Pros: Easier to implement; don't need to check for sample data.
+ * Cons: User might accidentally purge his/her own data.
+
+* **Alternative 2:** Additionally Ask yes or no for purge data as a safety check.
+ * Pros: Prevents user from accidentally deleting his/her own data
+ * Cons: Hard to implement, as we have to distinguish between sample data and user data.
+ Need to implement a new prompt from scratch.
+
+### **5.7 \[Proposed\] Undo/redo feature**
+
+#### Proposed Implementation
+
+The proposed undo/redo mechanism is facilitated by `VersionedProgrammerError`. It extends `ProgrammerError` with an
+undo/redo history, stored internally as an `programmerErrorStateList` and `currentStatePointer`. Additionally, it
+implements the following operations:
+
+* `VersionedProgrammerError#commit()` — Saves the current ProgrammerError state in its history.
+* `VersionedProgrammerError#undo()` — Restores the previous ProgrammerError state from its history.
+* `VersionedProgrammerError#redo()`
+* ores a previously undone ProgrammerError state from its history.
+
+These operations are exposed in the `Model` interface as `Model#commitProgrammerError()`, `Model#undoProgrammerError()`
+and `Model#redoProgrammerError()` respectively.
+
+Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
+
+Step 1. The user launches the application for the first time. The `VersionedProgrammerError` will be initialized with the
+initial ProgrammerError state, and the `currentStatePointer` pointing to that single ProgrammerError state as seen in
+Figure 5.7.1.
+
+
+
+
+
+ Figure 5.7.1: Object diagram after Step 1
+
+
+
+Step 2. The user executes `delete 5` command to delete the 5th student in the ProgrammerError. The `delete` command
+calls `Model#commitProgrammerError()`, causing the modified state of the ProgrammerError after the `delete 5` command executes
+to be saved in the `programmerErrorStateList`, and the `currentStatePointer` is shifted to the newly inserted ProgrammerError
+state as seen in Figure 5.7.2.
+
+
+
+
+
+ Figure 5.7.2: Object diagram after Step 2
+
+
+
+Step 3. The user executes `add -n David …` to add a new student. The `add` command also
+calls `Model#commitProgrammerError()`, causing another modified ProgrammerError state to be saved into
+the `programmerErrorStateList` as seen in Figure 5.7.3.
+
+
+
+
+
+ Figure 5.7.3: Object diagram after Step 3
+
+
+
+
:information_source: **Note:** If a command fails its execution, it will not call `Model#commitProgrammerError()`, so the ProgrammerError state will not be saved into the `programmerErrorStateList`.
+
+
+
+Step 4. The user now decides that adding the student was a mistake, and decides to undo that action by executing
+the `undo` command. The `undo` command will call `Model#undoProgrammerError()`, which will shift the `currentStatePointer`
+once to the left, pointing it to the previous ProgrammerError state, and restores the ProgrammerError to that state as
+seen in Figure 5.7.4.
+
+
+
+
+
+ Figure 5.7.4: Object diagram after Step 4
+
+
+
+
:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial ProgrammerError state, then there are no previous ProgrammerError states to restore. The `undo` command uses `Model#canUndoProgrammerError()` to check if this is the case. If so, it will return an error to the user rather
+than attempting to perform the undo.
+
+
+The following sequence diagram in Figure 5.7.5 shows how the undo operation works:
+
+
+
+
+
+ Figure 5.7.5: Sequence diagram illustrating the execution of undo command
+
+
-* **Alternative 1 (current choice):** Saves the entire address book.
- * Pros: Easy to implement.
- * Cons: May have performance issues in terms of memory usage.
+
: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.
-* **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.
+
-_{more aspects and alternatives to be added}_
+The `redo` command does the opposite — it calls `Model#redoProgrammerError()`, which shifts the `currentStatePointer` once
+to the right, pointing to the previously undone state, and restores the ProgrammerError to that state.
-### \[Proposed\] Data archiving
+
:information_source: **Note:** If the `currentStatePointer` is at index `pProgrammerErrorStateList.size() - 1`, pointing to the latest ProgrammerError state, then there are no undone ProgrammerError states to restore. The `redo` command uses `Model#canRedoProgrammerError()` to check if this is the case. If so, it will return an error to the CS2100 TA rather than attempting to perform the redo.
-_{Explain here how the data archiving feature will be implemented}_
+
+Step 5. The CS2100 TA then decides to execute the command `list`. Commands that do not modify the ProgrammerError, such
+as `list`, will usually not call `Model#commitProgrammerError()`, `Model#undoProgrammerError()` or `Model#redoProgrammerError()`.
+Thus, the `programmerErrorStateList` remains unchanged as seen in Figure 5.7.6.
+
+
+
+
+
+ Figure 5.7.6: Object diagram after Step 5
+
+
+
+Step 6. The CS2100 TA executes `purge`, which calls `Model#commitProgrammerError()`. Since the `currentStatePointer` is not
+pointing at the end of the `programmerErrorStateList`, all ProgrammerError states after the `currentStatePointer` will be
+purged as seen in Figure 5.7.7. Reason: It no longer makes sense to redo the `add -n David …` command. This is the behavior that most modern
+desktop applications follow.
+
+
+
+
+
+ Figure 5.7.7: Object diagram after Step 6
+
+
+The following activity diagram in Figure 5.7.8 summarizes what happens when a CS2100 TA executes a new command:
+
+
+
+
+
+ Figure 5.7.8: Activity diagram showing the saving of state after command execution
+
+
+
+
+#### Design considerations:
+
+**Aspect: How undo & redo executes:**
+
+* **Alternative 1 (current choice):** Saves the entire ProgrammerError.
+ * Pros: Easy to implement.
+ * Cons: May have performance issues in terms of memory usage.
+
+* **Alternative 2:** Individual command knows how to undo/redo by itself.
+ * Pros: Will use less memory (e.g. for `delete`, just save the student being deleted).
+ * Cons: We must ensure that the implementation of each individual command are correct.
+
--------------------------------------------------------------------------------------------------------------------
-## **Documentation, logging, testing, configuration, dev-ops**
+## **6. Documentation, logging, testing, configuration, dev-ops**
* [Documentation guide](Documentation.md)
* [Testing guide](Testing.md)
@@ -251,50 +915,185 @@ _{Explain here how the data archiving feature will be implemented}_
--------------------------------------------------------------------------------------------------------------------
-## **Appendix: Requirements**
+## **7. Appendix: Requirements**
+
+### **7.1 Product Scope**
-### Product scope
**Target user profile**:
-* has a need to manage a significant number of contacts
-* prefer desktop apps over other types
+CS2100 Lab TAs who
+
+* have to manage a number of students across different classes
+* keep track of the students' lab results
+* keep track of the students' details (eg. Student ID, email)
+* prefer and comfortable with CLI tools
* can type fast
-* prefers typing to mouse interactions
-* is reasonably comfortable using CLI apps
+* are proficient with Unix commands
+* prefer typing to mouse interactions
-**Value proposition**: manage contacts faster than a typical mouse/GUI driven app
+**Value proposition**:
+CS2100 Lab TAs who use ProgrammerError enjoys greater productivity and efficiency when managing their classes of students.
-### User stories
+### **7.2 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 |
+| Priority | As a … | I want to … | So that I can…
+| -------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------
+| `* * *` | potential CS2100 TA exploring the app | see the app populated with sample data| easily see how the app will look like when it is in use.
+| `* * *` | CS2100 TA ready to start using the app | purge all current data | get rid of data in the app.
+| `* * *` | CS2100 TA | be able to create records of individual students: (Name, Student ID, Class ID, email)| so that I can identify and track their progress separately.
+| `* * *` | CS2100 TA | be able to sort the class records| have an organized class record.
+| `* * *` | CS2100 TA | delete the details of a student| clear the information of students who have dropped out of the class.
+| `* * *` | new CS2100 TA | use the in-build help feature | learn how to use the app quickly.
+| `* * *` | CS2100 TA | be able to view (read) the records of individual students| know more about the student's current performance and email.
+| `* * *` | CS2100 TA | be able to update the details of a student| correct any mistakes that I have made.
+| `* * *` | CS2100 TA | be able to save the data in a CSV file| upload to LumiNUS and share with the CS2100 Instructors.
+| `* * *` | proficient programmer / CS2100 TA | navigate ProgrammerError seamlessly with the use of Unix command| efficiently manage my class.
+| `* * ` | CS2100 TA with multiple devices | export the data in my ProgrammerError | import it on another device.
+| `* * ` | busy CS2100 TA | view students' statistics formatted in a standard form | avoid sorting the information on my own.
+| `* * ` | CS2100 TA | use the app to track students' performance | identify those who need more help.
+| `* * ` | CS2100 TA | know that the software and data will be available 99.999 percent of the time I try to access it | don't get frustrated and find another software to use.
+| `* *` | CS2100 TA who is an undergraduate myself | spend little time updating ProgrammerError | have have sufficient time for my other commitments.
+| `* *` | CS2100 TA with overwhelming work | be greeted with a nice interface | enjoy the process of doing admin tasks.
+| `* *` | CS2100 TA | upload the students' lab results to LumiNUS conveniently |
+| `* *` | impatient CS2100 TA with overwhelming work | be greeted with a nice interface | quickly retrieve a student's particular/email from the database.
+| `* *` | CS2100 TA who loves using the keyboard | type commands | practice my typing skills.
+| `* *` | CS2100 TA | generate weekly feedbacks via email for my students with ease |
+| `* *` | CS2100 admin | have a dashboard to have a bird eye view of my class statistics | be updated quickly on my class progress.
+| `* *` | CS2100 TA | use tags to identify which labs are marked or unmarked | know which what labs to mark next.
+| `*` | CS2100 TA with multiple classes | filter the contact list by name, classes, email | easily identify those in the current class. |
+| `*` | CS2100 TA | archive previous batch statistics | compare current batch performance with them |
+| `*` | expert CS2100 TA | archive/hide unused data | avoid being distracted by irrelevant data.
+| `*` | a CS2100 TA with many students and classes | store vital information of my students | query it when the need arises.
+| `*` | CS2100 Teaching Staff | easily search and update student's contact details | I can reach them throughout the module.
+
+### **7.3 Use Cases**
+
+For all use cases below, the **System** is the `ProgrammerError` and the **Actor** is the
+CS2100 Teaching Assistant (CS2100 TA in short), unless otherwise specified.
+
+#### **7.3.1 Use case: UC1 Purge/Delete all sample student records**
+
+Precondition: CS2100 TA opens ProgrammerError for the first time
+
+**MSS**
+
+1. CS2100 TA requests to list student records.
+2. ProgrammerError shows a list of sample student records.
+3. CS2100 TA requests to purge sample student records.
+4. ProgrammerError deletes all sample student records.
+
+ Use case ends.
+
+#### **7.3.2 Use case: UC2 Create a student record**
+
+**MSS**
+
+1. CS2100 TA requests to list student records.
+2. ProgrammerError shows a list of student records.
+3. CS2100 TA specifies the student's details.
+4. ProgrammerError creates a student record.
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+
+ Use case ends.
+
+* 3a. The student details given are incomplete.
+
+ * 3a1. ProgrammerError shows an error message.
+
+ Use case resumes at step 3.
+
+* 3b. The student email or ID given are not unique.
+
+ * 3b1. ProgrammerError shows an error message.
+
+ Use case resumes at step 3.
+
+#### **7.3.3 Use case: UC3 Upload student records**
+
+**MSS**
+
+1. CS2100 TA requests to upload student records from a CSV file.
+2. ProgrammerError requests for the TA to select a CSV file.
+3. ProgrammerError uploads the student records from the CSV file.
+
+ Use case ends.
+
+**Extensions:**
+
+* 2a. CS2100 TA chooses to cancel the upload.
+
+ Use case ends.
+
+* 3a. CSV file data is invalid.
+ * 3a1. ProgrammerError informs the TA of the error.
+
+ Use case ends.
+
+#### **7.3.4 Use case: UC4 View a student record**
+
+**MSS**
+
+1. CS2100 TA requests to list student records.
+2. ProgrammerError shows a list of student records.
+3. CS2100 TA requests to view a specific student record.
+4. ProgrammerError shows the student record's details.
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+
+ Use case ends.
+
+* 3a. The given index is invalid.
+
+ * 3a1. ProgrammerError shows an error message.
+
+ Use case resumes at step 2.
+
+#### **7.3.5 Use case: UC5 Delete a student record**
+
+**MSS**
+
+1. CS2100 TA requests to list student records.
+2. ProgrammerError shows a list of student records.
+3. CS2100 TA requests to delete a specific student record in the list.
+4. ProgrammerError deletes the student record.
+
+ Use case ends.
-*{More to be added}*
+**Extensions**
+
+* 2a. The list is empty.
+
+ Use case ends.
+
+* 3a. The given index is invalid.
-### Use cases
+ * 3a1. ProgrammerError shows an error message.
-(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
+ Use case resumes at step 2.
-**Use case: Delete a person**
+#### **7.3.6 Use case: UC6 Edit a student record**
**MSS**
-1. User requests to list persons
-2. AddressBook shows a list of persons
-3. User requests to delete a specific person in the list
-4. AddressBook deletes the person
+1. CS2100 TA requests to list student records.
+2. ProgrammerError shows a list of student records.
+3. CS2100 TA requests to edit a specific student record.
+4. ProgrammerError updates the student record.
- Use case ends.
+ Use case ends.
**Extensions**
@@ -304,28 +1103,127 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli
* 3a. The given index is invalid.
- * 3a1. AddressBook shows an error message.
+ * 3a1. ProgrammerError shows an error message.
+
+ Use case resumes at step 2.
+
+* 3b. CS2100 TA requests to edit a lab number without providing a new lab score
+
+ * 3b1. ProgrammerError shows an error message.
+
+ Use case resumes at step 2.
+
+#### **7.3.7 Use case: UC7 Download student records**
+
+**MSS**
+
+1. CS2100 TA requests to download student data to a CSV file.
+2. ProgrammerError requests for the TA to select a directory to download the CSV file to.
+3. ProgrammerError downloads the student data to a CSV file in the chosen directory.
+
+ Use case ends.
- Use case resumes at step 2.
+**Extensions:**
-*{More to be added}*
+* 1a. CS2100 TA chooses to cancel the download.
-### Non-Functional Requirements
+ Use case ends.
+
+* 3a. There is no student data.
+ * 3a1. ProgrammerError informs the TA there is no data to download.
-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 ends.
-*{More to be added}*
+#### **7.3.8 Use case: UC8 Create a lab record**
+
+**MSS**
+
+1. CS2100 TA requests to create a new lab record.
+2. ProgrammerError requests for the lab number and lab total score.
+3. CS2100 TA specifies the lab number and total score.
+4. ProgrammerError creates a lab record for every student.
+
+ Use case ends.
+
+**Extensions**
-### Glossary
+* 3a. The given lab number is not unique, or lab number not an integer between 1 and 13 (inclusive), or lab score not a positive integer between 1 and 100 (inclusive).
+ * 3a1. ProgrammerError shows an error message.
+
+ Use case resumes at 2.
+
+ Use case ends.
+
+#### **7.3.9 Use case: UC9 Edit a lab record**
+
+**MSS**
+
+1. CS2100 TA requests to view a particular student's record using a show command (UC3) .
+2. ProgrammerError show the student's record.
+3. CS2100 TA specifies lab number and actual score or total score.
+4. ProgrammerError updates the student's record.
+
+ Use case ends.
+
+**Extensions**
+
+* 3a. The given lab score is not a positive integer between 1 and 100 (inclusive), or actual score > total score.
+ * 3a1. ProgrammerError shows an error message.
+
+ Use case resumes at 2.
+
+ Use case ends.
+
+#### **7.3.10 Use case: UC10 View dashboard of student records**
+
+**MSS**
+
+1. CS2100 TA requests to view the dashboard of student data.
+2. ProgrammerError displays the dashboard showing the number of students, classes, labs.
+as well as the number of labs unmarked for each class.
+3. ProgrammerError automatically updates the dashboard when changes are made to the student data.
+
+ Use case ends.
+
+#### **7.3.11 Use case: UC11 Filter student records**
+
+**MSS**
+
+1. CS2100 TA requests to list student records.
+2. ProgrammerError shows a list of student records.
+3. CS2100 TA requests to filter the records based on certain parameters.
+4. ProgrammerError displays a filtered list of student records.
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+
+ Use case ends.
+
+
+### **7.4 Non-Functional Requirements**
+
+1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed.
+2. A TA with above average typing speed for code should be able to accomplish most of the tasks faster using commands
+ than using the mouse.
+3. The data should be stored locally and should be in a human editable CSV file.
+4. The product should be for a single user at a time (i.e. not a multi-user product).
+5. No DBMS should be used to store data.
+6. The software should follow the Object-oriented paradigm primarily. (with the possibility of allowing a mix of other
+ styles when justifiable).
+7. The final product should be a result of evolving the given code base. (i.e. allowed to replace all existing code with
+ new code, as long as it is done incrementally)
+8. The GUI should work well (i.e., should not cause any resolution-related inconveniences to the user) for standard
+ screen resolutions 1920x1080 and higher, and screen scales 100% and 125%.
+9. the GUI should be usable (i.e., all functions can be used even if the user experience is not optimal) for resolutions
+ 1280x720 and higher, and screen scales 150%.
-* **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**
+## **8. Appendix: Instructions for manual testing**
Given below are instructions to test the app manually.
@@ -334,44 +1232,109 @@ testers are expected to do more *exploratory* testing.
-### Launch and shutdown
+### **8.1 Launch and Shutdown**
+
+1. Initial launch
+ 1. Download the jar file and copy into an empty folder
+ 2. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be
+ optimum.
+
+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 is retained.
-1. Initial launch
- 1. Download the jar file and copy into an empty folder
+### **8.2 Deleting a Student**
- 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
+- Deleting a student while all students are being shown
-1. Saving window preferences
+1. Prerequisites: List all students using the `list` command. Multiple students in the list.
- 1. Resize the window to an optimum size. Move the window to a different location. Close the window.
+2. Test case: `delete 1`
+ Expected: First student is deleted from the list. Details of the deleted student shown in the result display box.
- 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained.
+3. Test case: `delete 0`
+ Expected: No student is deleted. Error details shown in the result display box.
-1. _{ more test cases … }_
+4. Other incorrect delete commands to try: `delete`, `delete x` (where x is larger than the list size)
+ Expected: Similar to previous.
-### Deleting a person
+### **8.3 Show a Student's Lab Results**
+1. Showing a student's lab results while all students are being shown
+ 1. Prerequisites: List all students using the `list` command. Multiple students in the list.
+ 2. Test case: `show 1` shows the information and list of lab results of the student with index 1 on the right panel.
+ 3. Test case: `show 0`
+ Expected: Error details shown in the result display box. The last shown student's lab results remains on the right 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. Updating shown content for student-related features
+ 1. Prerequisites: There is at least 1 student in ProgrammerError's storage.
+ 2. Test case (AddCommand):
+ * Add a student by keying in `add -n Sherwin -sid A1234567X -cid B01 -email e0542421@u.nus.edu`
+ * The information shown on the right panel is updated to show Sherwin's information, with a list of unmarked labs that all other students have.
+ 3. Test case (DeleteCommand):
+ * Delete a student by keying in `delete 1`
+ * The information shown on the right panel is cleared.
+ 4. Test case (EditCommand):
+ * Edit a student by keying in `edit 1 -n John Doe`
+ * The information shown on the right panel is updated to show the student whose name is edited to `John Doe`.
- 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.
- 1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.
+3. Updating shown content for lab-related features
+ 1. Prerequisites: There are at least 1 student in ProgrammerError's storage.
+ 2. Test case (AddLabCommand):
+ * Add a lab for all students by keying in `addlab -ln 1 -ts 20`, assuming that Lab 1 does not exist.
+ * If the right panel is currently empty, it remains to be empty.
+ * If the right panel is showing a student's lab results, a red `Lab1` tag and a Lab card with title `Lab1`, actual score `-` and total score `20` is added.
+ 3. Test case (DeleteLabCommand):
+ * Delete a lab for all students by keying in `deleteLab -ln 1`, assuming that Lab 1 already exists.
+ * If the right panel is currently empty, it remains to be empty.
+ * If the right panel is showing a student's lab results, the `Lab1` tag and the Lab card with title `Lab1` is deleted.
+ 4. Test case (EditLabCommand):
+ * Edit a lab for all students by keying in `editlab -ln 1 -nln 2`, assuming that Lab 1 already exists.
+ * If the right panel is currently empty, it remains to be empty.
+ * If the right panel is showing a student's lab results, the `Lab1` tag is updated to `Lab2` and the Lab card with title `Lab1` is edited to have title `Lab2`.
- 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous.
+### **8.4 Upload Data**
+
+1. Select CSV file from file chooser window to upload data from:
+ 1. To cancel, click 'cancel' to return to the main window.
+ 2. If the data in the CSV file is valid, ProgrammerError will save the student data.
+
+### **8.5 Download Data**
+
+1. Select folder from directory chooser window to save data to:
+ 1. To cancel, click 'cancel' to return to the main window.
+ 2. In the chosen folder, ProgrammerError will save a CSV file of the students' data named `programmerError.csv`.
+
+
+### **8.6 Dashboard**
+
+1. Enter dashboard as a command or press F5 to view the dashboard.
+ 1. CS2100 TA will be able to view the number of students, number of classes, number of labs.
+ 2. CS2100 TA will also be able to see the number of labs left to mark for each class.
+
+--------------------------------------------------------------------------------------------------------------------
+
+## **9. Appendix: Effort**
+The following is a non-exhaustive list of challenges we encountered during the development of ProgrammerError:
-1. _{ more test cases … }_
+### **9.1 Rewriting the Command Syntax**
+ * This was challenging as it required a nuanced understanding of how CLI syntax is constructed and following standard conventions.
+ * Not all of us were familiar with Unix syntax, which made it more difficult to design a solution that would be suitable for users who prefer typing.
-### Saving data
+### **9.2 Designing New UI components**
+ * AB3 uses simple components with an (arguably) poor user interface (UI) and user experience (UX). On the other hand, our team revamped the look and feel of the application, customizing the dark theme specially (using GitHub's color scheme) to suit TAs. This involved much experimentation with color schemes and building new components, such as popup windows to enhance the user experience.
+ * Other examples include: color-coding the labs which are marked or unmarked (displayed as green or red respectively), as well as customizing the Help window and Dashboard Window to incorporate our new Dark Theme.
-1. Dealing with missing/corrupted data files
+### **9.3 Working with Third-Party Libraries**
+ * Compared to AB3 which uses minimal third-party libraries for its features, our team integrated two additional external libraries to develop our `upload` and `download` features.
+ * This was more challenging than it initially seemed as it required trying out multiple potential candidate libraries to find those which are most suitable for our use case and would be compatible across multiple operating systems.
+ * Through this process, we also encountered dependency issues with the new libraries and spent significant time and effort debugging these issues.
- 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
+### **9.4 Implementing Dynamic Features**
+ * AB3's features typically work by having the user type in text commands to be executed. We felt this was core, but we wanted to go a step further and implement our features to minimize the TA having to type unnecessary commands.
+ * For instance, the list of students always remains sorted whenever updates are made to the student data. This required many checks and careful organization of the student data so that the sorting can be done efficiently at minimal cost to the user TA.
+ * Additionally, the `show` panel and `dashboard` window were also designed to update dynamically whenever changes are made to the student data. This saves the TA much time in keeping track of the labs they have yet to mark, thereby enhancing their user experience and satisfaction.
-1. _{ more test cases … }_
diff --git a/docs/SettingUp.md b/docs/SettingUp.md
index 275445bd551..fe8fa7f532b 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.programmer.Main` and try a few commands.
1. [Run the tests](Testing.md) to ensure they all pass.
--------------------------------------------------------------------------------------------------------------------
@@ -45,7 +45,7 @@ If you plan to use Intellij IDEA (highly recommended):
1. **Learn the design**
- When you are ready to start coding, we recommend that you get some sense of the overall design by reading about [AddressBook’s architecture](DeveloperGuide.md#architecture).
+ When you are ready to start coding, we recommend that you get some sense of the overall design by reading about [ProgrammerError’s architecture](DeveloperGuide.md#architecture).
1. **Do the tutorials**
These tutorials will help you get acquainted with the codebase.
diff --git a/docs/Testing.md b/docs/Testing.md
index 8a99e82438a..3689550e202 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.programmer.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.programmer.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.programmer.logic.LogicManagerTest`
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 3716f3ca8a4..cf60bc748a1 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -3,190 +3,392 @@ 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.
+ProgrammerError (PE) is a desktop app for managing students' information, optimized for use via a Command Line
+Interface (CLI) while still having the benefits of a Graphical User Interface (GUI). Designed for CS2100 Lab Teaching
+Assistants (TAs), this application is optimized to track personal particulars, emails and lab results of your students across different
+classes. If you are familiar with Unix commands, this is definitely for you!
+
+## Table of Contents
+
+- [Glossary](#Glossary)
+- [Quick Start](#quick-start)
+- [Features](#features)
+ 1. [Parameter Summary](#parameter-summary)
+ 2. [General Features](#general-features)
+ 1. [View Help: `help`](#view-help)
+ 2. [View Dashboard `dashboard`](#view-dashboard)
+ 3. [Exit: `exit`](#exit)
+ 3. [Data Features](#data-features)
+ 1. [Fill Sample Data: `fill`](#fill-sample-data)
+ 2. [Purge All Data: `purge`](#purge-all-data)
+ 3. [Upload Data: `upload`](#upload-data)
+ 4. [Download Data: `download`](#download-data)
+ 5. [Edit The Data File Directly (For advanced users)](#edit-data-file)
+ 4. [Student Features](#student-features)
+ 1. [Add Student: `add`](#add-student)
+ 2. [Edit Student Details: `edit`](#edit-student)
+ 3. [Delete Student: `delete`](#delete-student)
+ 4. [Filter Students: `filter`](#filter-student)
+ 5. [Show Student Details: `show`](#show-student)
+ 6. [List All Students: `list`](#list-students)
+ 5. [Lab Features](#lab-features)
+ 1. [Add Lab: `addlab`](#add-lab)
+ 2. [Edit Lab: `editlab`](#edit-lab)
+ 3. [Delete Lab: `dellab`](#delete-lab)
+- [Command Summary](#command-summary)
+
+## Glossary
+
+- **Student ID**: NUS student matriculation number (AXXXXXXXY)
+- **Email**: NUS student email (eXXXXXXX@u.nus.edu)
+- **TA**: CS2100 lab teaching assistant
+- **PE**: ProgrammerError
+- **CSV**: Comma-Separated Values
+
+## Quick Start
+
+1. Ensure you have `Java 11` or above installed in your Computer.
+2. Download the latest `programmerError.jar`
+ from [here](https://github.com/AY2122S1-CS2103-F09-3/tp/releases).
+3. Copy the file to the folder you want to use as the _home folder_ for your ProgrammerError.
+4. Double-click the file to start the app. The GUI similar to the below should appear in a few seconds. Note how the app
+ contains some sample data.
+
+
+
+5. Type the command in the command box and press Enter to execute it. For example, typing **`help`** and pressing Enter
+ will open the help window.
+ Here are some example commands you can try:
+ * `add -n Sherwin -sid A1234567X -cid B01 -email e0523451@u.nus.edu`: Adds a student named `Sherwin` to PE with his
+ Student ID, Class ID and Email.
+ * `edit 1 -n Sherwin`: Updates the name of the student at index 1 of the displayed list (1-indexed) to Sherwin.
+ * `delete 1`: Deletes the student at index 1 of the displayed list (1-indexed).
+ * `filter -sid A1234567X`: Filters the list of students to display the student(s) whose student ID contains
+ `A1234567X` (case-insensitive).
+6. Refer to the [Features](#features) below for details on all available commands. Take note that command parameters
+ wrapped with `[` `]` listed in this guide signifies that the parameter is optional.
+
+## Features
-* Table of Contents
-{:toc}
+
---------------------------------------------------------------------------------------------------------------------
+**Notes about the command format (Unix Command Syntax):**
+
+- Similar to Unix CLI, the up and down arrow keys can be used to navigate the history of commands executed.
+ - Up Arrow Key: Navigate to an older command.
+ - Down Arrow Key: Navigate to a more recent command.
+ - Command will only be stored after `Enter` has been pressed.
+- Flags will be used to specify different options for the commands. For example, the `-sid` flag can be used to specify
+ a student's student ID.
+- Parameters can be in any order. e.g. if the command specifies `-n -sid `
+ , `-sid -n `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 `-n Allard -n Xian Yi` , only `-n Xian Yi` will be taken.
+- Extraneous parameters for commands that do not take in parameters (such as `help`, `exit` and `purge`) will be
+ ignored. e.g. if the command specifies `help 123`, it will be interpreted as `help`.
-## Quick start
+
-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).
+## 1. Parameter Summary
+
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+:exclamation: **Note:**
+Take note that all the commands that require the corresponding parameter follows the constraints as specified in the table below, apart from `filter` command.
+
+`filter` command filters the list based on partial character sequence matching and hence does not have to follow the constraints strictly.
+
-1. Double-click the file to start the app. The GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
- ![Ui](images/Ui.png)
+Parameter | What it means | Constraints
+--------| ---------------------- | -------
+**-n** | Name of Student | Alphanumeric characters and spaces
+**-sid** | Student ID of Student | AXXXXXXXY, where X is a digit from 0 to 9 and Y is an alphabet
+**-cid** | Class ID of Student | BXX, where X is a digit from 0 to 9
+**-email** | Email of Student | eXXXXXXX@u.nus.edu, where X is a digit from 0 to 9
+**-ln** | Lab Number | An integer between 1 and 13 (inclusive)
+**-nln** | New Lab Number | An integer between 1 and 13 (inclusive)
+**-ts** | Lab Total Score | A positive integer between 1 and 100 (inclusive)
+**-s** | Lab Score of Student | A non-negative integer, not greater than the corresponding lab total score
-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.
+## 2. General Features
- * **`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.
+### 2.1 View Help: `help` or F2 on keyboard
- * **`delete`**`3` : Deletes the 3rd contact shown in the current list.
+Shows a message explaining how to access the help page.
- * **`clear`** : Deletes all contacts.
+### 2.2 View Dashboard: `dashboard`
- * **`exit`** : Exits the app.
+Displays a dashboard window that updates dynamically showing the following data:
-1. Refer to the [Features](#features) below for details of each command.
+1. Number of students
+2. Number of classes
+3. Number of labs
+4. Number of labs unmarked for each class
---------------------------------------------------------------------------------------------------------------------
+Below is an example of a dashboard window when the `dashboard` command is executed.
+
+
+
-## Features
+### 2.3 Exit: `exit` or F1 on keyboard
-
+Exits ProgrammerError and closes the GUI.
+
+
+## 3. Data Features
+
+### 3.1 Fill Sample Data: `fill`
-**:information_source: Notes about the command format:**
+Fills the program with sample data if no data is already present. Otherwise, throws an error message.
-* 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`.
+
:exclamation: **Note:**
+As this is a mass operation, it might take a couple of seconds to complete.
+
+
+### 3.2 Purge all Data: `purge`
-* 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`.
+Clears all data in PE. This can be used to delete pre-existing sample data or existing student data.
+Otherwise, throws an error if no pre-existing data.
-* 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.
+### 3.3 Upload Data: `upload` or F4 on keyboard
-* 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.
+Uploads student data via a CSV file with the following header: `studentId,classId,name,email`. Note that the data
+should contain **only** the student ID, class ID, name and email field respectively and spaces directly before or after
+commas should be avoided.
-* 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.
+Here is an [example CSV file](https://github.com/AY2122S1-CS2103-F09-3/tp/blob/master/sample_upload/validDataForUpload.csv) on GitHub.
+You may download files from GitHub following the instructions [here](https://stackoverflow.com/questions/4604663/download-single-files-from-github).
-* 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`.
+
:exclamation: **Note:**
+the CSV should *not* contain students' lab results since this functionality is only meant for the TA to automate the adding of students to PE.
+
+- If there are already existing students, the upload will **overwrite** the existing data rather than
+ append to it. This is because in a typical use case, the TA would not want to have the existing data kept if they
+ would like to use student data from their own CSV file.
+- Furthermore, simply uploading the CSV obtained via the `download` command will result in the file being rejected
-### Viewing help : `help`
+In summary:
+1. Select a valid CSV file (with header: `studentId,classId,name,email`) from the file chooser.
+2. Note that this command is **not** meant for uploading lab results. Rather, it is only for automating the adding of
+ students to PE.
+
+### 3.4 Download Data: `download` or F3 on keyboard
+
+Downloads the student data to a CSV file in the chosen directory. The file will be automatically named `programmerError.csv`.
+
+### 3.5 Edit The Data File Directly (For advanced users)
+
+Instead of using commands to edit students' details and lab results, you may change the json file directly.
-Shows a message explaning how to access the help page.
+Note that ProgrammerError will only accept data files fulfilling the restrictions specified in the [parameter summary](#parameter-summary).
+The absence of an attribute and/or invalid value for an attribute will result in an error message shown in the logger, and ProgrammerError
+will start with an empty json data file instead.
-![help message](images/helpMessage.png)
+Here are some examples of corrupted data that is not accepted by ProgrammerError.
-Format: `help`
+ //Absent attribute example: labNumValue attribute is missing
+ labResultList" : [ {
+ "actualScoreValue" : 10,
+ "totalScoreValue" : 20
+ }
-### Adding a person: `add`
+ //Invalid attribute example: labNumValue is not between 1 to 13
+ "labResultList" : [ {
+ "labNumValue" : 20,
+ "actualScoreValue" : 15,
+ "totalScoreValue" : 20
+ }
-Adds a person to the address book.
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
+## 4. Student Features
+
+### 4.1 Add Student: `add`
+
+Adds a student to ProgrammerError with their student ID, class ID and email. Both the student ID and email must be unique.
+
+Format: `add -n -sid -cid -email `
+
+
+
+**Example:**
+
+- `add -n Sherwin -sid A1234567X -cid B01 -email e0542421@u.nus.edu` Adds the student called Sherwin with student ID
+ A1234567X, class ID B01 and email e0542421@u.nus.edu PE.
-
: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`
+### 4.2 Edit Student's Details or Lab Result : `edit`
+
+Edits the details or grade of an existing student in PE as specified by the `INDEX_IN_LIST` argument.
+The corresponding fields of the student will be updated according to the input arguments.
-### Listing all persons : `list`
+* Both the student ID and email must be unique.
+* 1-indexing is used here as according to the displayed list.
+* Any combination of the optional arguments can be provided.
+* At least one of the optional argument must be provided.
+* Take note that the parameters `-ln` and `-s` needs to be specified together.
-Shows a list of all persons in the address book.
+Format: `edit [-n ] [-sid ] [-cid ] [-email ] [-ln -s ]`
-Format: `list`
+
-### Editing a person : `edit`
+**Examples:**
-Edits an existing person in the address book.
+- `edit 1 -n Elon Musk` Updates the name of the student at index 1 (1-indexed) to 'Elon Musk'.
+- `edit 1 -ln 4 -s 29` Updates the lab 4 result of the student at index 1 (1-indexed) to 29.
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
+
+
+### 4.3 Delete Student: `delete`
-* 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.
+Deletes the specified student from the PE. Take note that `INDEX_IN_LIST` is 1-indexed.
-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.
+Format: `delete `
-### Locating persons by name: `find`
+
-Finds persons whose names contain any of the given keywords.
+**Example:**
-Format: `find KEYWORD [MORE_KEYWORDS]`
+- `delete 23` Deletes the data of the student at index 23
-* 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`
+
-Examples:
-* `find John` returns `john` and `John Doe`
-* `find alex david` returns `Alex Yeoh`, `David Li`
- ![result for 'find alex david'](images/findAlexDavidResult.png)
+### 4.4 Filter Students: `filter`
-### Deleting a person : `delete`
+Filter the students in ProgrammerError based on the specified arguments provided (name, student ID, class ID and email).
+* Any combination of the optional arguments can be provided.
+* At least one of the optional argument must be provided.
+* Arguments can be provided in any order and are **case-insensitive**.
+* ProgrammerError will display the filtered list of students whose details matches all the specified arguments.
+* The arguments are matched to the corresponding details as long as the details of the students contains the
+sequence of characters provided in the argument string.
+* `filter` command does not follow the constraints as specified in [parameter summary](#parameter-summary).
-Deletes the specified person from the address book.
+Format: `filter [-n ] [-sid ] [-cid ] [-email ]`
-Format: `delete INDEX`
+Below shows an example when `filter -cid B01` is executed with 4 students from class B01 filtered out.
+
+
+
-* 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, …
-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.
+
-### Clearing all entries : `clear`
+**Examples:**
-Clears all entries from the address book.
+- `filter -sid A1234567X` Lists all students whose student ID contains `A1234567X`.
+- `filter -n abc` Lists all students whose name contains `abc`.
+- `filter -cid B01` Lists all students whose class ID contains the character sequence `B01`.
+- `filter -email e1234567` Lists all students whose email contains the character sequence `e1234567`.
+- `filter -n Sherwin -cid B01` Lists all students whose name contains the character sequence `Sherwin` and belongs to a
+ class with the class ID containing the character sequence `B01`.
-Format: `clear`
+
-### Exiting the program : `exit`
+### 4.5 Show Student Details: `show`
-Exits the program.
+Shows a particular student's details including their scores for each lab.
-Format: `exit`
+The student particular and lab results will be updated if other commands modify their fields.
-### Saving the data
+Format: `show `
-AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+
+
+
-### Editing the data file
+
-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.
+**Example:**
+
+- `show 1` Shows the particulars and lab results of student at index 1 as displayed in the list.
-
: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.
-### Archiving data files `[coming in v2.0]`
+### 4.6 List All Students: `list`
+
+Displays a list of all students in the left panel. This list is ordered first by class ID followed by student name.
-_Details coming soon ..._
---------------------------------------------------------------------------------------------------------------------
-## FAQ
-**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.
+## 5. Lab Features
---------------------------------------------------------------------------------------------------------------------
+
:exclamation: **Note:**
+As the following commands are mass operations, they might take slightly longer than usual.
+
-## Command summary
+### 5.1 Add Lab: `addlab`
-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`
+Adds a lab to every student with the lab number and total score.
+
+Format: `addlab -ln -ts `
+
+
+
+
+**Examples:**
+
+- `addlab -ln 1 -ts 20` Adds a lab with number 1 and total score 20 for all students.
+- `addlab -ln 2 -ts 30` Adds a lab with number 2 and total score 30 for all students.
+
+
+
+### 5.2 Edit Lab: `editlab`
+
+Edits the details of an existing lab for every student.
+* Any combination of the optional arguments can be provided.
+* At least one of the optional argument must be provided.
+
+Format: `editlab -ln [-nln ] [-ts ]`
+
+
+
+**Examples:**
+
+- `editlab -ln 1 -ts 30` Changes the total score of lab 1 to 30 for all students.
+- `editlab -ln 1 -nln 2` Changes the number of an existing lab from 1 to 2 for all students.
+- `editlab -ln 1 -nln 2 -ts 30` Changes the number of an existing lab from 1 to 2 and the total score of the same lab to 30 for all students.
+
+
+
+### 5.3 Delete Lab: `dellab`
+
+Deletes an existing lab from every student in ProgrammerError.
+
+Format: `dellab -ln `
+
+
+
+**Example:**
+
+- `dellab -ln 1`: Deletes lab 1 for all students if it exists.
+
+
+
+
+## Command Summary
+
+Command | Format & Examples
+--------| ----------------------
+**Add** | `add -n -sid -cid -email `
+**Add Lab** | `addlab -ln -ts `
+**Dashboard** | `dashboard`
+**Delete** | `delete `
+**Delete Lab** | `dellab -ln `
+**Download** | `download`
+**Edit** | `edit [-n ] [-sid ] [-cid ] [-email ] [-ln -s ]`
+**Edit Lab** | `editlab -ln [-nln ] [-ts ]`
+**Exit** | `exit`
+**Fill** | `fill`
+**Filter** | `filter [-n ] [-sid ] [-cid ] [-email ]`
**Help** | `help`
+**Purge** | `purge`
+**Show** | `show `
+**Upload** | `upload`
+
+
diff --git a/docs/_config.yml b/docs/_config.yml
index 6bd245d8f4e..d6978955225 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,4 +1,4 @@
-title: "AB-3"
+title: "ProgrammerError"
theme: minima
header_pages:
@@ -8,7 +8,7 @@ header_pages:
markdown: kramdown
-repository: "se-edu/addressbook-level3"
+repository: "AY2122S1-CS2103-F09-3/tp"
github_icon: "images/github-icon.png"
plugins:
diff --git a/docs/_includes/android-chrome-192x192.png b/docs/_includes/android-chrome-192x192.png
new file mode 100644
index 00000000000..444cf93132f
Binary files /dev/null and b/docs/_includes/android-chrome-192x192.png differ
diff --git a/docs/_includes/android-chrome-512x512.png b/docs/_includes/android-chrome-512x512.png
new file mode 100644
index 00000000000..edda93040fd
Binary files /dev/null and b/docs/_includes/android-chrome-512x512.png differ
diff --git a/docs/_includes/apple-touch-icon.png b/docs/_includes/apple-touch-icon.png
new file mode 100644
index 00000000000..36a2f56f6c8
Binary files /dev/null and b/docs/_includes/apple-touch-icon.png differ
diff --git a/docs/_includes/browserconfig.xml b/docs/_includes/browserconfig.xml
new file mode 100644
index 00000000000..b3930d0f047
--- /dev/null
+++ b/docs/_includes/browserconfig.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+ #da532c
+
+
+
diff --git a/docs/_includes/custom-head.html b/docs/_includes/custom-head.html
index 8559a67ffad..2b20d3c4624 100644
--- a/docs/_includes/custom-head.html
+++ b/docs/_includes/custom-head.html
@@ -4,3 +4,10 @@
1. Head over to https://realfavicongenerator.net/ to add your own favicons.
2. Customize default _includes/custom-head.html in your source directory and insert the given code snippet.
{% endcomment %}
+
+
+
+
+
+
+
diff --git a/docs/_includes/favicon-16x16.png b/docs/_includes/favicon-16x16.png
new file mode 100644
index 00000000000..d382940931c
Binary files /dev/null and b/docs/_includes/favicon-16x16.png differ
diff --git a/docs/_includes/favicon-32x32.png b/docs/_includes/favicon-32x32.png
new file mode 100644
index 00000000000..b98d0a08b74
Binary files /dev/null and b/docs/_includes/favicon-32x32.png differ
diff --git a/docs/_includes/favicon.ico b/docs/_includes/favicon.ico
new file mode 100644
index 00000000000..478c8176f66
Binary files /dev/null and b/docs/_includes/favicon.ico differ
diff --git a/docs/_includes/mstile-150x150.png b/docs/_includes/mstile-150x150.png
new file mode 100644
index 00000000000..609bb046cbb
Binary files /dev/null and b/docs/_includes/mstile-150x150.png differ
diff --git a/docs/_includes/site.webmanifest b/docs/_includes/site.webmanifest
new file mode 100644
index 00000000000..b20abb7cbb2
--- /dev/null
+++ b/docs/_includes/site.webmanifest
@@ -0,0 +1,19 @@
+{
+ "name": "",
+ "short_name": "",
+ "icons": [
+ {
+ "src": "/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "/android-chrome-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ],
+ "theme_color": "#ffffff",
+ "background_color": "#ffffff",
+ "display": "standalone"
+}
diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss
index 0d3f6e80ced..01459c53c2d 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: "ProgrammerError";
font-size: 32px;
}
}
diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml
index ef81d18c337..fb590932017 100644
--- a/docs/diagrams/ArchitectureSequenceDiagram.puml
+++ b/docs/diagrams/ArchitectureSequenceDiagram.puml
@@ -13,13 +13,13 @@ activate ui UI_COLOR
ui -[UI_COLOR]> logic : execute("delete 1")
activate logic LOGIC_COLOR
-logic -[LOGIC_COLOR]> model : deletePerson(p)
+logic -[LOGIC_COLOR]> model : deleteStudent(p)
activate model MODEL_COLOR
model -[MODEL_COLOR]-> logic
deactivate model
-logic -[LOGIC_COLOR]> storage : saveAddressBook(addressBook)
+logic -[LOGIC_COLOR]> storage : saveProgrammerError(programmerError)
activate storage STORAGE_COLOR
storage -[STORAGE_COLOR]> storage : Save to file
diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml
index 5731f9cbaa1..ebe63435eeb 100644
--- a/docs/diagrams/BetterModelClassDiagram.puml
+++ b/docs/diagrams/BetterModelClassDiagram.puml
@@ -4,18 +4,14 @@ 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
+ProgrammerError *-right-> "1" UniqueStudentList
-UniqueTagList *-right-> "*" Tag
-UniquePersonList -right-> Person
+UniqueStudentList -right-> "*"Student
-Person -up-> "*" Tag
+Student *--> "1"Name
+Student *--> "1"StudentId
+Student *--> "1"ClassId
+Student *--> "1"Email
+Student *--> "*"Lab
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
@enduml
diff --git a/docs/diagrams/CommitActivityDiagram.puml b/docs/diagrams/CommitActivityDiagram.puml
index 6a6b23a006f..25b21e6b927 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 ProgrammerError])
:Purge redundant states;
- :Save AddressBook to
- addressBookStateList;
+ :Save ProgrammerError to
+ ProgrammerErrorStateList;
else ([else])
endif
stop
diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml
index 6d14b17b361..4473b070496 100644
--- a/docs/diagrams/LogicClassDiagram.puml
+++ b/docs/diagrams/LogicClassDiagram.puml
@@ -6,7 +6,7 @@ skinparam classBackgroundColor LOGIC_COLOR
package Logic {
-Class AddressBookParser
+Class ProgrammerErrorParser
Class XYZCommand
Class CommandResult
Class "{abstract}\nCommand" as Command
@@ -27,8 +27,8 @@ Class HiddenOutside #FFFFFF
HiddenOutside ..> Logic
LogicManager .right.|> Logic
-LogicManager -right->"1" AddressBookParser
-AddressBookParser ..> XYZCommand : creates >
+LogicManager -right->"1" ProgrammerErrorParser
+ProgrammerErrorParser ..> XYZCommand : creates >
XYZCommand -up-|> Command
LogicManager .left.> Command : executes >
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 1122257bd9a..cb3d401d0a4 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -5,50 +5,52 @@ skinparam arrowColor MODEL_COLOR
skinparam classBackgroundColor MODEL_COLOR
Package Model <>{
-Interface ReadOnlyAddressBook <>
+Interface ReadOnlyProgrammerError <>
Interface ReadOnlyUserPrefs <>
Interface Model <>
-Class AddressBook
-Class ReadOnlyAddressBook
+Class ProgrammerError
+Class ReadOnlyProgrammerError
Class Model
Class ModelManager
Class UserPrefs
Class ReadOnlyUserPrefs
-Class UniquePersonList
-Class Person
-Class Address
-Class Email
+Class UniqueStudentList
Class Name
-Class Phone
-Class Tag
+Class Student
+Class StudentId
+Class ClassId
+Class Email
+Class Lab
}
Class HiddenOutside #FFFFFF
HiddenOutside ..> Model
-AddressBook .up.|> ReadOnlyAddressBook
+ProgrammerError .up.|> ReadOnlyProgrammerError
ModelManager .up.|> Model
Model .right.> ReadOnlyUserPrefs
-Model .left.> ReadOnlyAddressBook
-ModelManager -left-> "1" AddressBook
+Model .left.> ReadOnlyProgrammerError
+ModelManager -left-> "1" ProgrammerError
ModelManager -right-> "1" UserPrefs
UserPrefs .up.|> ReadOnlyUserPrefs
-AddressBook *--> "1" UniquePersonList
-UniquePersonList --> "~* all" Person
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
-Person *--> "*" Tag
-Name -[hidden]right-> Phone
-Phone -[hidden]right-> Address
-Address -[hidden]right-> Email
+ProgrammerError *--> "1" UniqueStudentList
+UniqueStudentList --> "~* all" Student
+Student *--> "1" Name
+Student *--> "1" StudentId
+Student *--> "1" ClassId
+Student *--> "1" Email
+Student *--> "*" Lab
-ModelManager -->"~* filtered" Person
+Name -[hidden]right-> StudentId
+StudentId -[hidden]right-> ClassId
+ClassId -[hidden]right-> Email
+
+ModelManager -->"~* filtered" Student
@enduml
+
diff --git a/docs/diagrams/ParserClasses.puml b/docs/diagrams/ParserClasses.puml
index 6ba585cba01..637c24e745b 100644
--- a/docs/diagrams/ParserClasses.puml
+++ b/docs/diagrams/ParserClasses.puml
@@ -9,7 +9,7 @@ Class XYZCommand
package "Parser classes"{
Interface Parser <>
-Class AddressBookParser
+Class ProgrammerErrorParser
Class XYZCommandParser
Class CliSyntax
Class ParserUtil
@@ -19,12 +19,12 @@ Class Prefix
}
Class HiddenOutside #FFFFFF
-HiddenOutside ..> AddressBookParser
+HiddenOutside ..> ProgrammerErrorParser
-AddressBookParser .down.> XYZCommandParser: creates >
+ProgrammerErrorParser .down.> XYZCommandParser: creates >
XYZCommandParser ..> XYZCommand : creates >
-AddressBookParser ..> Command : returns >
+ProgrammerErrorParser ..> Command : returns >
XYZCommandParser .up.|> Parser
XYZCommandParser ..> ArgumentMultimap
XYZCommandParser ..> ArgumentTokenizer
diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml
index 85ac3ea2dee..8534a132f36 100644
--- a/docs/diagrams/StorageClassDiagram.puml
+++ b/docs/diagrams/StorageClassDiagram.puml
@@ -14,12 +14,11 @@ Class JsonUserPrefsStorage
Interface Storage <>
Class StorageManager
-package "AddressBook Storage" #F4F6F6{
-Interface AddressBookStorage <>
-Class JsonAddressBookStorage
-Class JsonSerializableAddressBook
-Class JsonAdaptedPerson
-Class JsonAdaptedTag
+package "ProgrammerError Storage" #F4F6F6{
+Interface ProgrammerErrorStorage <>
+Class JsonProgrammerErrorStorage
+Class JsonSerializableProgrammerError
+Class JsonAdaptedStudent
}
}
@@ -29,15 +28,14 @@ HiddenOutside ..> Storage
StorageManager .up.|> Storage
StorageManager -up-> "1" UserPrefsStorage
-StorageManager -up-> "1" AddressBookStorage
+StorageManager -up-> "1" ProgrammerErrorStorage
Storage -left-|> UserPrefsStorage
-Storage -right-|> AddressBookStorage
+Storage -right-|> ProgrammerErrorStorage
JsonUserPrefsStorage .up.|> UserPrefsStorage
-JsonAddressBookStorage .up.|> AddressBookStorage
-JsonAddressBookStorage ..> JsonSerializableAddressBook
-JsonSerializableAddressBook --> "*" JsonAdaptedPerson
-JsonAdaptedPerson --> "*" JsonAdaptedTag
+JsonProgrammerErrorStorage .up.|> ProgrammerErrorStorage
+JsonProgrammerErrorStorage ..> JsonSerializableProgrammerError
+JsonSerializableProgrammerError --> "*" JsonAdaptedStudent
@enduml
diff --git a/docs/diagrams/UndoRedoState1.puml b/docs/diagrams/UndoRedoState1.puml
deleted file mode 100644
index 01fcb9b2b96..00000000000
--- a/docs/diagrams/UndoRedoState1.puml
+++ /dev/null
@@ -1,22 +0,0 @@
-@startuml
-!include style.puml
-skinparam ClassFontColor #000000
-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__"
-}
-
-State1 -[hidden]right-> State2
-State2 -[hidden]right-> State3
-
-hide State3
-
-class Pointer as "Current State" #FFFFF
-
-Pointer -up-> State2
-@end
diff --git a/docs/diagrams/UndoRedoState2.puml b/docs/diagrams/UndoRedoState2.puml
deleted file mode 100644
index bccc230a5d1..00000000000
--- a/docs/diagrams/UndoRedoState2.puml
+++ /dev/null
@@ -1,20 +0,0 @@
-@startuml
-!include style.puml
-skinparam ClassFontColor #000000
-skinparam ClassBorderColor #000000
-
-title After command "add n/David"
-
-package States <> {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab2:AddressBook__"
-}
-
-State1 -[hidden]right-> State2
-State2 -[hidden]right-> State3
-
-class Pointer as "Current State" #FFFFF
-
-Pointer -up-> State3
-@end
diff --git a/docs/diagrams/UndoRedoState5.puml b/docs/diagrams/UndoRedoState5.puml
deleted file mode 100644
index 88927be32bc..00000000000
--- a/docs/diagrams/UndoRedoState5.puml
+++ /dev/null
@@ -1,21 +0,0 @@
-@startuml
-!include style.puml
-skinparam ClassFontColor #000000
-skinparam ClassBorderColor #000000
-
-title After command "clear"
-
-package States <> {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab3:AddressBook__"
-}
-
-State1 -[hidden]right-> State2
-State2 -[hidden]right-> State3
-
-class Pointer as "Current State" #FFFFF
-
-Pointer -up-> State3
-note right on link: State ab2 deleted.
-@end
diff --git a/docs/diagrams/UndoSequenceDiagram.puml b/docs/diagrams/UndoSequenceDiagram.puml
deleted file mode 100644
index 410aab4e412..00000000000
--- a/docs/diagrams/UndoSequenceDiagram.puml
+++ /dev/null
@@ -1,53 +0,0 @@
-@startuml
-!include style.puml
-
-box Logic LOGIC_COLOR_T1
-participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser 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
-end box
-[-> LogicManager : execute(undo)
-activate LogicManager
-
-LogicManager -> AddressBookParser : parseCommand(undo)
-activate AddressBookParser
-
-create UndoCommand
-AddressBookParser -> UndoCommand
-activate UndoCommand
-
-UndoCommand --> AddressBookParser
-deactivate UndoCommand
-
-AddressBookParser --> LogicManager : u
-deactivate AddressBookParser
-
-LogicManager -> UndoCommand : execute()
-activate UndoCommand
-
-UndoCommand -> Model : undoAddressBook()
-activate Model
-
-Model -> VersionedAddressBook : undo()
-activate VersionedAddressBook
-
-VersionedAddressBook -> VersionedAddressBook :resetData(ReadOnlyAddressBook)
-VersionedAddressBook --> Model :
-deactivate VersionedAddressBook
-
-Model --> UndoCommand
-deactivate Model
-
-UndoCommand --> LogicManager : result
-deactivate UndoCommand
-UndoCommand -[hidden]-> LogicManager : result
-destroy UndoCommand
-
-[<--LogicManager
-deactivate LogicManager
-@enduml
diff --git a/docs/diagrams/commands/AddCommandAbstractSequenceDiagram.puml b/docs/diagrams/commands/AddCommandAbstractSequenceDiagram.puml
new file mode 100644
index 00000000000..101c6aa7d7b
--- /dev/null
+++ b/docs/diagrams/commands/AddCommandAbstractSequenceDiagram.puml
@@ -0,0 +1,42 @@
+@startuml
+!include ../style.puml
+
+box Logic LOGIC_COLOR_T1
+participant "a:AddCommand" as AddCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+
+create AddCommand
+
+[-> AddCommand : execute()
+activate AddCommand
+
+AddCommand -> Model : hasStudent(toAdd)
+activate Model
+
+Model --> AddCommand
+deactivate Model
+
+AddCommand -> Model : addStudent(toAdd)
+activate Model
+
+
+
+Model --> AddCommand
+deactivate Model
+
+create CommandResult
+AddCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> AddCommand
+deactivate CommandResult
+
+
+@enduml
+
diff --git a/docs/diagrams/commands/AddCommandActivityDiagram.puml b/docs/diagrams/commands/AddCommandActivityDiagram.puml
new file mode 100644
index 00000000000..61f43112681
--- /dev/null
+++ b/docs/diagrams/commands/AddCommandActivityDiagram.puml
@@ -0,0 +1,15 @@
+AddCommandActivityDiagram.puml@startuml
+'https://plantuml.com/activity-diagram-beta
+
+start
+:User executes add command with Name, Student ID, Class ID, Email;
+if () then ([Invalid inputs])
+ :Display error message in result;
+else ([Valid inputs])
+ : Creates a new Student object with the user inputs;
+endif
+
+stop
+
+@enduml
+
diff --git a/docs/diagrams/commands/AddCommandSequenceDiagram.puml b/docs/diagrams/commands/AddCommandSequenceDiagram.puml
new file mode 100644
index 00000000000..6c3e75353a2
--- /dev/null
+++ b/docs/diagrams/commands/AddCommandSequenceDiagram.puml
@@ -0,0 +1,79 @@
+@startuml
+!include ../style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":ProgrammerErrorParser" as ProgrammerErrorParser LOGIC_COLOR
+participant ":AddCommandParser" as AddCommandParser LOGIC_COLOR
+participant "a:AddCommand" as AddCommand 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(CommandText)
+activate LogicManager
+
+LogicManager -> ProgrammerErrorParser : parseCommand(CommandText)
+activate ProgrammerErrorParser
+
+create AddCommandParser
+ProgrammerErrorParser -> AddCommandParser
+activate AddCommandParser
+
+AddCommandParser --> ProgrammerErrorParser
+deactivate AddCommandParser
+
+ProgrammerErrorParser -> AddCommandParser : parse(CommandText)
+activate AddCommandParser
+
+create AddCommand
+AddCommandParser -> AddCommand
+activate AddCommand
+
+AddCommand --> AddCommandParser : a
+deactivate AddCommand
+
+AddCommandParser --> ProgrammerErrorParser : a
+deactivate AddCommandParser
+
+AddCommandParser -[hidden]-> ProgrammerErrorParser
+destroy AddCommandParser
+
+ProgrammerErrorParser --> LogicManager : a
+deactivate ProgrammerErrorParser
+
+LogicManager -> AddCommand : execute()
+activate AddCommand
+
+AddCommand -> Model : hasStudent(toAdd)
+activate Model
+
+Model --> AddCommand
+deactivate Model
+
+
+AddCommand -> Model : addStudent(toAdd)
+activate Model
+
+
+
+Model --> AddCommand
+deactivate Model
+
+create CommandResult
+AddCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> AddCommand
+deactivate CommandResult
+
+AddCommand --> LogicManager : result
+deactivate AddCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
+
diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/commands/DeleteSequenceDiagram.puml
similarity index 68%
rename from docs/diagrams/DeleteSequenceDiagram.puml
rename to docs/diagrams/commands/DeleteSequenceDiagram.puml
index 1dc2311b245..de92a757b58 100644
--- a/docs/diagrams/DeleteSequenceDiagram.puml
+++ b/docs/diagrams/commands/DeleteSequenceDiagram.puml
@@ -1,9 +1,9 @@
@startuml
-!include style.puml
+!include ../style.puml
box Logic LOGIC_COLOR_T1
participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":ProgrammerErrorParser" as ProgrammerErrorParser LOGIC_COLOR
participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR
participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR
participant ":CommandResult" as CommandResult LOGIC_COLOR
@@ -16,17 +16,17 @@ end box
[-> LogicManager : execute("delete 1")
activate LogicManager
-LogicManager -> AddressBookParser : parseCommand("delete 1")
-activate AddressBookParser
+LogicManager -> ProgrammerErrorParser : parseCommand("delete 1")
+activate ProgrammerErrorParser
create DeleteCommandParser
-AddressBookParser -> DeleteCommandParser
+ProgrammerErrorParser -> DeleteCommandParser
activate DeleteCommandParser
-DeleteCommandParser --> AddressBookParser
+DeleteCommandParser --> ProgrammerErrorParser
deactivate DeleteCommandParser
-AddressBookParser -> DeleteCommandParser : parse("1")
+ProgrammerErrorParser -> DeleteCommandParser : parse("1")
activate DeleteCommandParser
create DeleteCommand
@@ -36,19 +36,19 @@ activate DeleteCommand
DeleteCommand --> DeleteCommandParser : d
deactivate DeleteCommand
-DeleteCommandParser --> AddressBookParser : d
+DeleteCommandParser --> ProgrammerErrorParser : d
deactivate DeleteCommandParser
'Hidden arrow to position the destroy marker below the end of the activation bar.
-DeleteCommandParser -[hidden]-> AddressBookParser
+DeleteCommandParser -[hidden]-> ProgrammerErrorParser
destroy DeleteCommandParser
-AddressBookParser --> LogicManager : d
-deactivate AddressBookParser
+ProgrammerErrorParser --> LogicManager : d
+deactivate ProgrammerErrorParser
LogicManager -> DeleteCommand : execute()
activate DeleteCommand
-DeleteCommand -> Model : deletePerson(1)
+DeleteCommand -> Model : deleteStudent(1)
activate Model
Model --> DeleteCommand
diff --git a/docs/diagrams/commands/DownloadActivityDiagram.puml b/docs/diagrams/commands/DownloadActivityDiagram.puml
new file mode 100644
index 00000000000..972fd4afcb4
--- /dev/null
+++ b/docs/diagrams/commands/DownloadActivityDiagram.puml
@@ -0,0 +1,16 @@
+@startuml
+start
+:User executes Download command;
+
+'Since the beta syntax does not support placing the condition outside the
+'diamond we place it as the true branch instead.
+
+if (data is present) then ([command downloads data])
+ : user selects destination folder;
+ : write ProgrammerError.json data to CSV file;
+ : display success pop-up message;
+else ([else])
+ : display error pop-up message;
+endif
+stop
+@enduml
diff --git a/docs/diagrams/commands/DownloadSequenceDiagram.puml b/docs/diagrams/commands/DownloadSequenceDiagram.puml
new file mode 100644
index 00000000000..f1628a240b4
--- /dev/null
+++ b/docs/diagrams/commands/DownloadSequenceDiagram.puml
@@ -0,0 +1,33 @@
+@startuml
+!include ../style.puml
+
+
+box UI UI_COLOR_T1
+Participant ":MainWindow" as mw UI_COLOR
+end box
+
+box Util STORAGE_COLOR
+Participant "<>\nJsonUtil" as ju STORAGE_COLOR
+end box
+
+--> mw : DownloadCommandResult
+
+activate mw
+
+mw -> mw : handleDownload()
+activate mw
+ mw -> ju : getJsonData(filePath)
+ activate ju
+ mw <-- ju : jsonData
+ deactivate ju
+
+ mw -> mw : promptUserForFileDestination()
+ mw -> ju :writeJsonToCsv(jsonData, file)
+
+ activate ju
+ mw <-- ju
+ deactivate mw
+ <-- mw
+deactivate mw
+
+@enduml
diff --git a/docs/diagrams/commands/DownloadSequenceDiagram1.puml b/docs/diagrams/commands/DownloadSequenceDiagram1.puml
new file mode 100644
index 00000000000..4e590e95bb3
--- /dev/null
+++ b/docs/diagrams/commands/DownloadSequenceDiagram1.puml
@@ -0,0 +1,18 @@
+@startuml
+!include ../style.puml
+
+Participant ":LogicManager" as logic LOGIC_COLOR
+Participant ":ProgrammerErrorParser" as abp LOGIC_COLOR
+Participant ":DownloadCommand" as dc LOGIC_COLOR
+
+[-> logic : execute
+activate logic
+logic -> abp ++: parseCommand(commandText)
+create dc
+abp -> dc
+abp -> dc ++: execute(model)
+dc --> abp --: command
+abp --> logic --: command
+<-- logic : DownloadCommandResult
+
+@enduml
diff --git a/docs/diagrams/commands/EditLabActivityDiagram.puml b/docs/diagrams/commands/EditLabActivityDiagram.puml
new file mode 100644
index 00000000000..0549777a7e2
--- /dev/null
+++ b/docs/diagrams/commands/EditLabActivityDiagram.puml
@@ -0,0 +1,32 @@
+@startuml
+title EditLabCommand
+start
+: User executes editlab
+command with a lab number;
+
+if () then ([Valid lab number])
+ if (Valid new lab number
+and/or new total score) then (true)
+ if () then ([both fields
+specified])
+ : Change lab number and
+ total score for all students;
+ else if () then ([only new
+lab number])
+ : Change lab number
+ for all students;
+ else ([only new
+total score])
+ : Change total score
+ for all students;
+ endif
+ else (false)
+ : Display error message
+ in resultDisplay;
+ endif
+else ([Invalid lab number])
+ : Display error message
+ in resultDisplay;
+endif
+stop
+@enduml
diff --git a/docs/diagrams/commands/EditLabSequenceDiagram.puml b/docs/diagrams/commands/EditLabSequenceDiagram.puml
new file mode 100644
index 00000000000..4f82ec46d2d
--- /dev/null
+++ b/docs/diagrams/commands/EditLabSequenceDiagram.puml
@@ -0,0 +1,35 @@
+@startuml
+!include ../style.puml
+
+box Logic LOGIC_COLOR_T1
+participant "e:EditLabCommand" as EditLabCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> EditLabCommand : execute()
+activate EditLabCommand
+
+EditLabCommand -> Model : getAllStudents()
+activate Model
+
+Model --> EditLabCommand
+deactivate Model
+
+loop number of students in ProgrammerError
+ EditLabCommand -> Model : setStudent(std, editedStd)
+end
+
+create CommandResult
+EditLabCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> EditLabCommand
+deactivate CommandResult
+
+[<--EditLabCommand : result
+deactivate EditLabCommand
+@enduml
diff --git a/docs/diagrams/commands/FilterCommandActivityDiagram.puml b/docs/diagrams/commands/FilterCommandActivityDiagram.puml
new file mode 100644
index 00000000000..1d2afecf855
--- /dev/null
+++ b/docs/diagrams/commands/FilterCommandActivityDiagram.puml
@@ -0,0 +1,17 @@
+FilterCommandActivityDiagram.puml
+@startuml
+'https://plantuml.com/activity-diagram-beta
+
+start
+:User executes filter command with specified arguments;
+if () then ([Valid arguments])
+ :Displays a filtered list of students whose
+ details matches the corresponding arguments;
+else ([Invalid arguments])
+ :Displays error message;
+endif
+
+stop
+
+@enduml
+
diff --git a/docs/diagrams/commands/FilterSequenceDiagram.puml b/docs/diagrams/commands/FilterSequenceDiagram.puml
new file mode 100644
index 00000000000..ae07687e42c
--- /dev/null
+++ b/docs/diagrams/commands/FilterSequenceDiagram.puml
@@ -0,0 +1,78 @@
+@startuml
+!include ../style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":FilterCommandParser" as FilterCommandParser LOGIC_COLOR
+participant "f:FilterCommand" as FilterCommand LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "m:Model" as Model MODEL_COLOR
+participant "d:QueryStudentDescriptor" as QueryStudentDescriptor MODEL_COLOR
+participant "p:StudentDetailContainsPredicate" as StudentDetailContainsPredicate MODEL_COLOR
+end box
+
+[-> LogicManager : execute("filter -cid BO1")
+activate LogicManager
+
+LogicManager -> FilterCommandParser : parseCommand("filter -cid BO1")
+activate FilterCommandParser
+
+create QueryStudentDescriptor
+FilterCommandParser -> QueryStudentDescriptor : QueryStudentDescriptor(null, null, "B01")
+activate QueryStudentDescriptor
+
+QueryStudentDescriptor --> FilterCommandParser
+deactivate QueryStudentDescriptor
+
+create StudentDetailContainsPredicate
+FilterCommandParser -> StudentDetailContainsPredicate : StudentDetailContainsPredicate(d)
+activate StudentDetailContainsPredicate
+
+StudentDetailContainsPredicate --> FilterCommandParser
+deactivate StudentDetailContainsPredicate
+
+create FilterCommand
+FilterCommandParser -> FilterCommand: FilterCommand(p)
+activate FilterCommand
+
+FilterCommand --> FilterCommandParser
+deactivate FilterCommand
+
+FilterCommandParser --> LogicManager : f
+deactivate FilterCommandParser
+
+LogicManager -> FilterCommand : execute(m)
+activate FilterCommand
+
+FilterCommand -> Model : updateFilteredStudentList(p)
+activate Model
+
+loop number of students in ProgrammerError
+ Model -> StudentDetailContainsPredicate : test(Student)
+ activate StudentDetailContainsPredicate
+
+ StudentDetailContainsPredicate -> QueryStudentDescriptor : doesStudentMatchDescriptor(Student)
+ activate QueryStudentDescriptor
+
+ QueryStudentDescriptor --> StudentDetailContainsPredicate
+ deactivate QueryStudentDescriptor
+
+ StudentDetailContainsPredicate --> Model
+ deactivate StudentDetailContainsPredicate
+end
+destroy QueryStudentDescriptor
+destroy StudentDetailContainsPredicate
+
+Model --> FilterCommand
+deactivate Model
+
+FilterCommand --> LogicManager : result
+deactivate FilterCommand
+FilterCommand -[hidden]-> LogicManager : result
+destroy FilterCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/commands/FilterSequenceDiagram2.puml b/docs/diagrams/commands/FilterSequenceDiagram2.puml
new file mode 100644
index 00000000000..d63860c277f
--- /dev/null
+++ b/docs/diagrams/commands/FilterSequenceDiagram2.puml
@@ -0,0 +1,45 @@
+@startuml
+!include ../style.puml
+
+box Logic LOGIC_COLOR_T1
+participant "f:FilterCommand" as FilterCommand LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "m:Model" as Model MODEL_COLOR
+participant "d:QueryStudentDescriptor" as QueryStudentDescriptor MODEL_COLOR
+participant "p:StudentDetailContainsPredicate" as StudentDetailContainsPredicate MODEL_COLOR
+end box
+
+
+[-> FilterCommand : execute(m)
+activate FilterCommand
+
+FilterCommand -> Model : updateFilteredStudentList(p)
+activate Model
+
+loop number of students in ProgrammerError
+ Model -> StudentDetailContainsPredicate : test(Student)
+ activate StudentDetailContainsPredicate
+
+ StudentDetailContainsPredicate -> QueryStudentDescriptor : doesStudentMatchDescriptor(Student)
+ activate QueryStudentDescriptor
+
+ QueryStudentDescriptor --> StudentDetailContainsPredicate
+ deactivate QueryStudentDescriptor
+
+ StudentDetailContainsPredicate --> Model
+ deactivate StudentDetailContainsPredicate
+end
+destroy QueryStudentDescriptor
+destroy StudentDetailContainsPredicate
+
+Model --> FilterCommand
+deactivate Model
+
+[<-- FilterCommand : result
+deactivate FilterCommand
+FilterCommand -[hidden]-> : result
+destroy FilterCommand
+
+@enduml
diff --git a/docs/diagrams/commands/FilterSequenceDiagram3.puml b/docs/diagrams/commands/FilterSequenceDiagram3.puml
new file mode 100644
index 00000000000..cbdab1cb11e
--- /dev/null
+++ b/docs/diagrams/commands/FilterSequenceDiagram3.puml
@@ -0,0 +1,40 @@
+@startuml
+!include ../style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":FilterCommandParser" as FilterCommandParser LOGIC_COLOR
+participant "f:FilterCommand" as FilterCommand LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "d:QueryStudentDescriptor" as QueryStudentDescriptor MODEL_COLOR
+participant "p:StudentDetailContainsPredicate" as StudentDetailContainsPredicate MODEL_COLOR
+end box
+
+[-> FilterCommandParser : parseCommand("filter -cid BO1")
+activate FilterCommandParser
+
+create QueryStudentDescriptor
+FilterCommandParser -> QueryStudentDescriptor : QueryStudentDescriptor(null, null, "B01")
+activate QueryStudentDescriptor
+
+QueryStudentDescriptor --> FilterCommandParser
+deactivate QueryStudentDescriptor
+
+create StudentDetailContainsPredicate
+FilterCommandParser -> StudentDetailContainsPredicate : StudentDetailContainsPredicate(d)
+activate StudentDetailContainsPredicate
+
+StudentDetailContainsPredicate --> FilterCommandParser
+deactivate StudentDetailContainsPredicate
+
+create FilterCommand
+FilterCommandParser -> FilterCommand: FilterCommand(p)
+activate FilterCommand
+
+FilterCommand --> FilterCommandParser
+deactivate FilterCommand
+
+[<-- FilterCommandParser: f
+
+@enduml
diff --git a/docs/diagrams/commands/PurgeActivityDiagram.puml b/docs/diagrams/commands/PurgeActivityDiagram.puml
new file mode 100644
index 00000000000..89df8e1f430
--- /dev/null
+++ b/docs/diagrams/commands/PurgeActivityDiagram.puml
@@ -0,0 +1,11 @@
+@startuml
+start
+:User executes purge command;
+
+if () then ([Existing data])
+ : Purge the data from ProgrammerError;
+else ([No existing data])])
+ : Display error message in resultDisplay;
+endif
+stop
+@enduml
diff --git a/docs/diagrams/commands/PurgeSequenceDiagram.puml b/docs/diagrams/commands/PurgeSequenceDiagram.puml
new file mode 100644
index 00000000000..ba93e05e8fa
--- /dev/null
+++ b/docs/diagrams/commands/PurgeSequenceDiagram.puml
@@ -0,0 +1,43 @@
+@startuml
+!include ../style.puml
+
+box Logic LOGIC_COLOR_T1
+participant "p:PurgeCommand" as PurgeCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> PurgeCommand : execute()
+activate PurgeCommand
+
+PurgeCommand -> Model : getAllStudents()
+activate Model
+Model --> PurgeCommand
+
+PurgeCommand -> Model : setProgrammerError
+Model --> PurgeCommand
+
+PurgeCommand -> Model : updateFilteredStudentList
+Model --> PurgeCommand
+
+PurgeCommand -> Model : clearSelectedInformation()
+Model --> PurgeCommand
+
+PurgeCommand -> Model : clearLabsTracker()
+Model --> PurgeCommand
+deactivate Model
+
+
+create CommandResult
+PurgeCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> PurgeCommand
+deactivate CommandResult
+
+[<--PurgeCommand : result
+deactivate PurgeCommand
+@enduml
diff --git a/docs/diagrams/commands/ShowActivityDiagram.puml b/docs/diagrams/commands/ShowActivityDiagram.puml
new file mode 100644
index 00000000000..a33d67d6a42
--- /dev/null
+++ b/docs/diagrams/commands/ShowActivityDiagram.puml
@@ -0,0 +1,11 @@
+@startuml
+start
+:User executes show command with an index;
+
+if () then ([Valid index])
+ : Show the student's lab results;
+else ([Invalid index])
+ : Display error message in resultDisplay;
+endif
+stop
+@enduml
diff --git a/docs/diagrams/commands/ShowSequenceDiagram.puml b/docs/diagrams/commands/ShowSequenceDiagram.puml
new file mode 100644
index 00000000000..e24b86e3c32
--- /dev/null
+++ b/docs/diagrams/commands/ShowSequenceDiagram.puml
@@ -0,0 +1,73 @@
+@startuml
+!include ../style.puml
+
+box UI UI_COLOR_T1
+participant "CommandBox" as CommandBox UI_COLOR
+end box
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":ProgrammerErrorParser" as ProgrammerErrorParser LOGIC_COLOR
+participant ":ShowCommandParser" as ShowCommandParser LOGIC_COLOR
+participant "s:ShowCommand" as ShowCommand LOGIC_COLOR
+participant ":ShowCommandResult" as ShowCommandResult LOGIC_COLOR
+end box
+
+[-> CommandBox : "show 1"
+activate CommandBox
+
+CommandBox -> LogicManager:execute("show 1")
+deactivate CommandBox
+activate LogicManager
+
+
+LogicManager -> ProgrammerErrorParser : parseCommand("show 1")
+activate ProgrammerErrorParser
+
+create ShowCommandParser
+ProgrammerErrorParser -> ShowCommandParser
+activate ShowCommandParser
+
+ShowCommandParser --> ProgrammerErrorParser
+deactivate ShowCommandParser
+
+ProgrammerErrorParser -> ShowCommandParser : parse("1")
+activate ShowCommandParser
+
+create ShowCommand
+ShowCommandParser -> ShowCommand
+activate ShowCommand
+
+ShowCommand --> ShowCommandParser : s
+deactivate ShowCommand
+
+ShowCommandParser --> ProgrammerErrorParser : s
+deactivate ShowCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+ShowCommandParser -[hidden]-> ProgrammerErrorParser
+destroy ShowCommandParser
+
+ProgrammerErrorParser --> LogicManager : s
+deactivate ProgrammerErrorParser
+
+LogicManager -> ShowCommand : execute()
+activate ShowCommand
+
+
+create ShowCommandResult
+ShowCommand -> ShowCommandResult
+activate ShowCommandResult
+
+ShowCommandResult --> ShowCommand
+deactivate ShowCommandResult
+
+ShowCommand --> LogicManager : showCommandResult(feedback, std)
+deactivate ShowCommand
+
+LogicManager --> CommandBox : showCommandResult(feedback, std)
+deactivate LogicManager
+activate CommandBox
+[<--CommandBox
+
+
+@enduml
diff --git a/docs/diagrams/UndoRedoState0.puml b/docs/diagrams/commands/UndoRedoState0.puml
similarity index 52%
rename from docs/diagrams/UndoRedoState0.puml
rename to docs/diagrams/commands/UndoRedoState0.puml
index 96e30744d24..1d0652a5382 100644
--- a/docs/diagrams/UndoRedoState0.puml
+++ b/docs/diagrams/commands/UndoRedoState0.puml
@@ -1,20 +1,20 @@
@startuml
-!include style.puml
+!include ../style.puml
skinparam ClassFontColor #000000
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 "__pe0:ProgrammerError__"
+ class State2 as "__pe1:ProgrammerError__"
+ class State3 as "__pe2:ProgrammerError__"
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
hide State2
hide State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFF
Pointer -up-> State1
-@end
+@enduml
diff --git a/docs/diagrams/commands/UndoRedoState1.puml b/docs/diagrams/commands/UndoRedoState1.puml
new file mode 100644
index 00000000000..1899dfdc11b
--- /dev/null
+++ b/docs/diagrams/commands/UndoRedoState1.puml
@@ -0,0 +1,22 @@
+@startuml
+!include ../style.puml
+skinparam ClassFontColor #000000
+skinparam ClassBorderColor #000000
+
+title After command "delete 2"
+
+package States <> {
+ class State1 as "__pe0:ProgrammerError__"
+ class State2 as "__pe1:ProgrammerError__"
+ class State3 as "__pe2:ProgrammerError__"
+}
+
+State1 -[hidden]right-> State2
+State2 -[hidden]right-> State3
+
+hide State3
+
+class Pointer as "Current State" #FFF
+
+Pointer -up-> State2
+@enduml
diff --git a/docs/diagrams/commands/UndoRedoState2.puml b/docs/diagrams/commands/UndoRedoState2.puml
new file mode 100644
index 00000000000..992b50b2772
--- /dev/null
+++ b/docs/diagrams/commands/UndoRedoState2.puml
@@ -0,0 +1,20 @@
+@startuml
+!include ../style.puml
+skinparam ClassFontColor #000000
+skinparam ClassBorderColor #000000
+
+title After command "add -n Bob -sid A0212345H -cid B18 -email e0532221@u.nus.edu"
+
+package States <> {
+ class State1 as "__pe0:ProgrammerError__"
+ class State2 as "__pe1:ProgrammerError__"
+ class State3 as "__pe2:ProgrammerError__"
+}
+
+State1 -[hidden]right-> State2
+State2 -[hidden]right-> State3
+
+class Pointer as "Current State" #FFF
+
+Pointer -up-> State3
+@enduml
diff --git a/docs/diagrams/UndoRedoState3.puml b/docs/diagrams/commands/UndoRedoState3.puml
similarity index 52%
rename from docs/diagrams/UndoRedoState3.puml
rename to docs/diagrams/commands/UndoRedoState3.puml
index ea29c9483e4..75a06d2f4a3 100644
--- a/docs/diagrams/UndoRedoState3.puml
+++ b/docs/diagrams/commands/UndoRedoState3.puml
@@ -1,20 +1,20 @@
@startuml
-!include style.puml
+!include ../style.puml
skinparam ClassFontColor #000000
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 "__pe0:ProgrammerError__"
+ class State2 as "__pe1:ProgrammerError__"
+ class State3 as "__pe2:ProgrammerError__"
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFF
Pointer -up-> State2
-@end
+@enduml
diff --git a/docs/diagrams/UndoRedoState4.puml b/docs/diagrams/commands/UndoRedoState4.puml
similarity index 52%
rename from docs/diagrams/UndoRedoState4.puml
rename to docs/diagrams/commands/UndoRedoState4.puml
index 1b784cece80..07a3bbdbea3 100644
--- a/docs/diagrams/UndoRedoState4.puml
+++ b/docs/diagrams/commands/UndoRedoState4.puml
@@ -1,20 +1,20 @@
@startuml
-!include style.puml
+!include ../style.puml
skinparam ClassFontColor #000000
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 "__pe:ProgrammerError__"
+ class State2 as "__pe1:ProgrammerError__"
+ class State3 as "__pe2:ProgrammerError__"
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
-class Pointer as "Current State" #FFFFF
+class Pointer as "Current State" #FFF
Pointer -up-> State2
-@end
+@enduml
diff --git a/docs/diagrams/commands/UndoRedoState5.puml b/docs/diagrams/commands/UndoRedoState5.puml
new file mode 100644
index 00000000000..9d59abcf6d2
--- /dev/null
+++ b/docs/diagrams/commands/UndoRedoState5.puml
@@ -0,0 +1,22 @@
+@startuml
+!include ../style.puml
+skinparam ClassFontColor #000000
+skinparam ClassBorderColor #000000
+
+title After command "purge"
+
+package States <> {
+ class State1 as "__pe0:ProgrammerError__"
+ class State2 as "__pe1:ProgrammerError__"
+ class State3 as "__pe3:ProgrammerError__"
+}
+
+State1 -[hidden]right-> State2
+State2 -[hidden]right-> State3
+
+class Pointer as "Current State" #FFF
+
+Pointer -up-> State3
+note right on link: State pe2 deleted.
+@enduml
+
diff --git a/docs/diagrams/commands/UndoSequenceDiagram.puml b/docs/diagrams/commands/UndoSequenceDiagram.puml
new file mode 100644
index 00000000000..4944ed01ea5
--- /dev/null
+++ b/docs/diagrams/commands/UndoSequenceDiagram.puml
@@ -0,0 +1,55 @@
+@startuml
+!include ../style.puml
+
+actor User
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":ProgrammerErrorParser" as ProgrammerErrorParser LOGIC_COLOR
+participant "u:UndoCommand" as UndoCommand LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+participant ":VersionedProgrammerError" as VersionedProgrammerError MODEL_COLOR
+end box
+[-> LogicManager : execute(undo)
+activate LogicManager
+
+LogicManager -> ProgrammerErrorParser : parseCommand(undo)
+activate ProgrammerErrorParser
+
+create UndoCommand
+ProgrammerErrorParser -> UndoCommand
+activate UndoCommand
+
+UndoCommand --> ProgrammerErrorParser
+deactivate UndoCommand
+
+ProgrammerErrorParser --> LogicManager : u
+deactivate ProgrammerErrorParser
+
+LogicManager -> UndoCommand : execute()
+activate UndoCommand
+
+UndoCommand -> Model : undoProgrammerError()
+activate Model
+
+Model -> VersionedProgrammerError : undo()
+activate VersionedProgrammerError
+
+VersionedProgrammerError -> VersionedProgrammerError :resetData(ReadOnlyProgrammerError)
+VersionedProgrammerError --> Model :
+deactivate VersionedProgrammerError
+
+Model --> UndoCommand
+deactivate Model
+
+UndoCommand --> LogicManager : result
+deactivate UndoCommand
+UndoCommand -[hidden]-> LogicManager : result
+destroy UndoCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/style.puml b/docs/diagrams/style.puml
index fad8b0adeaa..e2e39e566d0 100644
--- a/docs/diagrams/style.puml
+++ b/docs/diagrams/style.puml
@@ -12,6 +12,8 @@
!define UI_COLOR_T2 #3FC71B
!define UI_COLOR_T3 #166800
!define UI_COLOR_T4 #0E4100
+!define UI_COLOR_WINDOW #097969
+!define UI_COLOR_MANAGER #5F8575
!define LOGIC_COLOR #3333C4
!define LOGIC_COLOR_T1 #C8C8FA
@@ -32,6 +34,7 @@
!define STORAGE_COLOR_T2 #544400
!define USER_COLOR #000000
+!define YELLOW_COLOR #FFDD10
skinparam BackgroundColor #FFFFFFF
diff --git a/docs/diagrams/tracing/LogicSequenceDiagram.puml b/docs/diagrams/tracing/LogicSequenceDiagram.puml
index fdcbe1c0ccc..5806902c754 100644
--- a/docs/diagrams/tracing/LogicSequenceDiagram.puml
+++ b/docs/diagrams/tracing/LogicSequenceDiagram.puml
@@ -2,7 +2,7 @@
!include ../style.puml
Participant ":LogicManager" as logic LOGIC_COLOR
-Participant ":AddressBookParser" as abp LOGIC_COLOR
+Participant ":ProgrammerErrorParser" as abp LOGIC_COLOR
Participant ":EditCommandParser" as ecp LOGIC_COLOR
Participant "command:EditCommand" as ec LOGIC_COLOR
diff --git a/docs/diagrams/ui/UiClassDiagram.puml b/docs/diagrams/ui/UiClassDiagram.puml
new file mode 100644
index 00000000000..0339436b727
--- /dev/null
+++ b/docs/diagrams/ui/UiClassDiagram.puml
@@ -0,0 +1,71 @@
+@startuml
+!include ../style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor UI_COLOR_T4
+skinparam classBackgroundColor UI_COLOR
+
+package UI <>{
+Interface Ui <>
+Class "{abstract}\nUiPart" as UiPart
+Class UiManager
+Class MainWindow
+Class HelpWindow
+Class ResultDisplay
+Class StudentListPanel
+Class StudentCard
+Class StatusBarFooter
+Class CommandBox
+Class CommandHistory
+Class LabResultListPanel
+}
+
+package Model <> {
+Class HiddenModel #FFFFFF
+}
+
+package Logic <> {
+Class HiddenLogic #FFFFFF
+}
+
+Class HiddenOutside #FFFFFF
+HiddenOutside ..> Ui
+
+UiManager .left.|> Ui
+UiManager -down-> "1" MainWindow
+MainWindow *-down-> "1" CommandBox
+MainWindow *-down-> "1" ResultDisplay
+MainWindow *-down-> "1" StatusBarFooter
+MainWindow *-down-> "0..1" HelpWindow
+MainWindow *-down-> "0..1" DashboardWindow
+MainWindow *-down-> "1" LabResultListPanel
+MainWindow *-down-> "1" StudentListPanel
+
+CommandBox -down-> "1" CommandHistory
+StudentListPanel --> "*" StudentCard
+LabResultListPanel --> "*" LabResultCard
+LabResultListPanel --> "1" StudentCard
+
+MainWindow -left-|> UiPart
+
+ResultDisplay --|> UiPart
+CommandBox --|> UiPart
+StudentListPanel --|> UiPart
+StudentCard --|> UiPart
+StatusBarFooter --|> UiPart
+LabResultListPanel --|> UiPart
+HelpWindow --|> UiPart
+DashboardWindow --|> UiPart
+
+StudentCard .left.> Model
+UiManager -right-> Logic
+MainWindow -left-> Logic
+
+LabResultCard -[hidden]right- LabResultListPanel
+StudentListPanel -[hidden]left- HelpWindow
+HelpWindow -[hidden]left- CommandBox
+CommandBox -[hidden]left- ResultDisplay
+ResultDisplay -[hidden]left- StatusBarFooter
+StatusBarFooter -[hidden]left- LabResultListPanel
+
+MainWindow -[hidden]-|> UiPart
+@enduml
diff --git a/docs/diagrams/ui/UiClassDiagramMainComponents.puml b/docs/diagrams/ui/UiClassDiagramMainComponents.puml
new file mode 100644
index 00000000000..aed279756b2
--- /dev/null
+++ b/docs/diagrams/ui/UiClassDiagramMainComponents.puml
@@ -0,0 +1,50 @@
+@startuml
+!include ../style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor UI_COLOR_T4
+skinparam classBackgroundColor UI_COLOR_T4
+
+package UI <> UI_COLOR_T1 {
+Class "{abstract}\nUiPart" as UiPart UI_COLOR_T4
+Class MainWindow
+Class ResultDisplay
+Class StudentListPanel
+Class StudentCard
+Class LabResultListPanel
+Class LabResultCard
+Class StatusBarFooter
+Class CommandBox
+Class CommandHistory
+}
+
+package Model MODEL_COLOR_T1 {}
+package Logic LOGIC_COLOR_T1 {}
+
+Class HiddenOutside #FFFFFF
+
+HiddenOutside ..> MainWindow
+MainWindow *-down-> "1" CommandBox
+MainWindow *-down-> "\t\t1" ResultDisplay
+MainWindow *-down-> "\t1" StatusBarFooter
+MainWindow *-down-> "\t1" StudentListPanel
+MainWindow *-down-> "\t1" LabResultListPanel
+
+CommandBox -down--> "\t1" CommandHistory
+StudentListPanel --> " *" StudentCard
+LabResultListPanel --> "1\t" StudentCard
+LabResultListPanel -down-> "\t*" LabResultCard
+
+ResultDisplay --|> UiPart
+CommandBox --|> UiPart
+StudentListPanel --|> UiPart
+StudentCard --|> UiPart
+LabResultListPanel --|> UiPart
+StatusBarFooter -|> UiPart
+
+StudentCard .right.> Model
+MainWindow -right-> Logic
+
+ResultDisplay -[hidden]left- StatusBarFooter
+StatusBarFooter -[hidden]left- LabResultListPanel
+
+@enduml
diff --git a/docs/diagrams/ui/UiClassDiagramOverview.puml b/docs/diagrams/ui/UiClassDiagramOverview.puml
new file mode 100644
index 00000000000..5a91c7d17dc
--- /dev/null
+++ b/docs/diagrams/ui/UiClassDiagramOverview.puml
@@ -0,0 +1,42 @@
+@startuml
+!include ../style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor UI_COLOR_T4
+skinparam classBackgroundColor UI_COLOR_T4
+
+
+package UI <> UI_COLOR_T1 {
+ Interface Ui <>
+ Class "{abstract}\nUiPart" as UiPart UI_COLOR_T4
+ Class "{abstract}\nUiPart" as UiPartRegion UI_COLOR_T4
+ Class UiManager
+ Class MainWindow
+ Class "{abstract}\nPopupWindow" as PopupWindow UI_COLOR_WINDOW
+ Class HelpWindow UI_COLOR_WINDOW
+ Class DashboardWindow UI_COLOR_WINDOW
+ Class PopupManager UI_COLOR_MANAGER
+ Class FileManager UI_COLOR_MANAGER
+ package MainComponents YELLOW_COLOR {}
+}
+
+package Logic LOGIC_COLOR_T1 {}
+
+Class HiddenOutside #FFFFFF
+HiddenOutside ..> Ui
+
+UiManager .left.|> Ui
+UiManager -down-> "\t1" MainWindow
+HelpWindow -up-|> PopupWindow
+DashboardWindow -up-|> PopupWindow
+MainWindow *-down-> "*" MainComponents
+PopupWindow -up-|> "\t\t\t*" UiPart
+MainComponents -down-|> "\t\t*" UiPartRegion
+MainWindow -up-|> UiPart
+
+UiManager -right-> Logic
+MainWindow -up-> Logic
+MainWindow -down-> "\t1" PopupManager
+MainWindow -down-> "\t1" FileManager
+DashboardWindow -up-> Logic
+
+@enduml
diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/ui/UiOriginalClassDiagram.puml
similarity index 98%
rename from docs/diagrams/UiClassDiagram.puml
rename to docs/diagrams/ui/UiOriginalClassDiagram.puml
index ecae4876432..3066cf9489b 100644
--- a/docs/diagrams/UiClassDiagram.puml
+++ b/docs/diagrams/ui/UiOriginalClassDiagram.puml
@@ -1,5 +1,5 @@
@startuml
-!include style.puml
+!include ../style.puml
skinparam arrowThickness 1.1
skinparam arrowColor UI_COLOR_T4
skinparam classBackgroundColor UI_COLOR
diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png
index 2f1346869d0..c774c31d75b 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 1ec62caa2a5..9e3f85a3714 100644
Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ
diff --git a/docs/images/CommitActivityDiagram.png b/docs/images/CommitActivityDiagram.png
index c08c13f5c8b..d6031a083b3 100644
Binary files a/docs/images/CommitActivityDiagram.png and b/docs/images/CommitActivityDiagram.png differ
diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png
deleted file mode 100644
index fa327b39618..00000000000
Binary files a/docs/images/DeleteSequenceDiagram.png and /dev/null differ
diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png
index c3028aa1cda..d673d9f4e87 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 39d7aec4b33..abdf096b636 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 58ad22ce16a..469bb0bc54d 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 82c66f8f16e..0c9d24c35a8 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 91488fd1a0f..15cf90531aa 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
deleted file mode 100644
index 4bb8b2ce591..00000000000
Binary files a/docs/images/UiClassDiagram.png and /dev/null differ
diff --git a/docs/images/Ui_v1.3.1.png b/docs/images/Ui_v1.3.1.png
new file mode 100644
index 00000000000..4abb32ad5f6
Binary files /dev/null and b/docs/images/Ui_v1.3.1.png differ
diff --git a/docs/images/Ui_v1.4.png b/docs/images/Ui_v1.4.png
new file mode 100644
index 00000000000..15cf90531aa
Binary files /dev/null and b/docs/images/Ui_v1.4.png differ
diff --git a/docs/images/UndoRedoState0.png b/docs/images/UndoRedoState0.png
deleted file mode 100644
index 8f7538cd884..00000000000
Binary files a/docs/images/UndoRedoState0.png and /dev/null differ
diff --git a/docs/images/UndoRedoState1.png b/docs/images/UndoRedoState1.png
deleted file mode 100644
index df9908d0948..00000000000
Binary files a/docs/images/UndoRedoState1.png and /dev/null differ
diff --git a/docs/images/UndoRedoState2.png b/docs/images/UndoRedoState2.png
deleted file mode 100644
index 36519c1015b..00000000000
Binary files a/docs/images/UndoRedoState2.png and /dev/null differ
diff --git a/docs/images/UndoRedoState3.png b/docs/images/UndoRedoState3.png
deleted file mode 100644
index 19959d01712..00000000000
Binary files a/docs/images/UndoRedoState3.png and /dev/null differ
diff --git a/docs/images/UndoRedoState4.png b/docs/images/UndoRedoState4.png
deleted file mode 100644
index 4c623e4f2c5..00000000000
Binary files a/docs/images/UndoRedoState4.png and /dev/null differ
diff --git a/docs/images/UndoRedoState5.png b/docs/images/UndoRedoState5.png
deleted file mode 100644
index 84ad2afa6bd..00000000000
Binary files a/docs/images/UndoRedoState5.png and /dev/null differ
diff --git a/docs/images/UndoSequenceDiagram.png b/docs/images/UndoSequenceDiagram.png
deleted file mode 100644
index 6addcd3a8d9..00000000000
Binary files a/docs/images/UndoSequenceDiagram.png and /dev/null differ
diff --git a/docs/images/allardquek.png b/docs/images/allardquek.png
new file mode 100644
index 00000000000..eece7293966
Binary files /dev/null and b/docs/images/allardquek.png differ
diff --git a/docs/images/commands/AddCommand/AddCommandAbstractSequenceDiagram.png b/docs/images/commands/AddCommand/AddCommandAbstractSequenceDiagram.png
new file mode 100644
index 00000000000..5d301547013
Binary files /dev/null and b/docs/images/commands/AddCommand/AddCommandAbstractSequenceDiagram.png differ
diff --git a/docs/images/commands/AddCommand/AddCommandActivityDiagram.png b/docs/images/commands/AddCommand/AddCommandActivityDiagram.png
new file mode 100644
index 00000000000..276dcbba964
Binary files /dev/null and b/docs/images/commands/AddCommand/AddCommandActivityDiagram.png differ
diff --git a/docs/images/commands/AddCommand/AddCommandSequenceDiagram.png b/docs/images/commands/AddCommand/AddCommandSequenceDiagram.png
new file mode 100644
index 00000000000..97ced528c57
Binary files /dev/null and b/docs/images/commands/AddCommand/AddCommandSequenceDiagram.png differ
diff --git a/docs/images/commands/DashboardCommand/dashboard.png b/docs/images/commands/DashboardCommand/dashboard.png
new file mode 100644
index 00000000000..b017557d4ef
Binary files /dev/null and b/docs/images/commands/DashboardCommand/dashboard.png differ
diff --git a/docs/images/commands/DeleteCommand/DeleteCommandSequenceDiagram.png b/docs/images/commands/DeleteCommand/DeleteCommandSequenceDiagram.png
new file mode 100644
index 00000000000..838c50104d1
Binary files /dev/null and b/docs/images/commands/DeleteCommand/DeleteCommandSequenceDiagram.png differ
diff --git a/docs/images/commands/DownloadCommand/DownloadActivityDiagram.png b/docs/images/commands/DownloadCommand/DownloadActivityDiagram.png
new file mode 100644
index 00000000000..651bf67b92f
Binary files /dev/null and b/docs/images/commands/DownloadCommand/DownloadActivityDiagram.png differ
diff --git a/docs/images/commands/DownloadCommand/DownloadSequenceDiagram.png b/docs/images/commands/DownloadCommand/DownloadSequenceDiagram.png
new file mode 100644
index 00000000000..a3067e49ebf
Binary files /dev/null and b/docs/images/commands/DownloadCommand/DownloadSequenceDiagram.png differ
diff --git a/docs/images/commands/DownloadCommand/DownloadSequenceDiagram1.png b/docs/images/commands/DownloadCommand/DownloadSequenceDiagram1.png
new file mode 100644
index 00000000000..d7ed9e11837
Binary files /dev/null and b/docs/images/commands/DownloadCommand/DownloadSequenceDiagram1.png differ
diff --git a/docs/images/commands/EditLabCommand/EditLabActivityDiagram.png b/docs/images/commands/EditLabCommand/EditLabActivityDiagram.png
new file mode 100644
index 00000000000..90b5fd13b89
Binary files /dev/null and b/docs/images/commands/EditLabCommand/EditLabActivityDiagram.png differ
diff --git a/docs/images/commands/EditLabCommand/EditLabSequenceDiagram.png b/docs/images/commands/EditLabCommand/EditLabSequenceDiagram.png
new file mode 100644
index 00000000000..17235056151
Binary files /dev/null and b/docs/images/commands/EditLabCommand/EditLabSequenceDiagram.png differ
diff --git a/docs/images/commands/FilterCommand/FilterActivityDiagram.png b/docs/images/commands/FilterCommand/FilterActivityDiagram.png
new file mode 100644
index 00000000000..ae117cd2681
Binary files /dev/null and b/docs/images/commands/FilterCommand/FilterActivityDiagram.png differ
diff --git a/docs/images/commands/FilterCommand/FilterSequenceDiagram.png b/docs/images/commands/FilterCommand/FilterSequenceDiagram.png
new file mode 100644
index 00000000000..670119ae35c
Binary files /dev/null and b/docs/images/commands/FilterCommand/FilterSequenceDiagram.png differ
diff --git a/docs/images/commands/FilterCommand/FilterSequenceDiagramExecute.png b/docs/images/commands/FilterCommand/FilterSequenceDiagramExecute.png
new file mode 100644
index 00000000000..9c9a556ecf7
Binary files /dev/null and b/docs/images/commands/FilterCommand/FilterSequenceDiagramExecute.png differ
diff --git a/docs/images/commands/FilterCommand/FilterSequenceDiagramParse.png b/docs/images/commands/FilterCommand/FilterSequenceDiagramParse.png
new file mode 100644
index 00000000000..48d09698057
Binary files /dev/null and b/docs/images/commands/FilterCommand/FilterSequenceDiagramParse.png differ
diff --git a/docs/images/commands/FilterCommand/filter.png b/docs/images/commands/FilterCommand/filter.png
new file mode 100644
index 00000000000..e5c84bdb981
Binary files /dev/null and b/docs/images/commands/FilterCommand/filter.png differ
diff --git a/docs/images/findAlexDavidResult.png b/docs/images/commands/FilterCommand/findAlexDavidResult.png
similarity index 100%
rename from docs/images/findAlexDavidResult.png
rename to docs/images/commands/FilterCommand/findAlexDavidResult.png
diff --git a/docs/images/commands/HelpCommand/help.png b/docs/images/commands/HelpCommand/help.png
new file mode 100644
index 00000000000..34f5cf6f07e
Binary files /dev/null and b/docs/images/commands/HelpCommand/help.png differ
diff --git a/docs/images/commands/PurgeCommand/PurgeActivityDiagram.png b/docs/images/commands/PurgeCommand/PurgeActivityDiagram.png
new file mode 100644
index 00000000000..26acb325ec2
Binary files /dev/null and b/docs/images/commands/PurgeCommand/PurgeActivityDiagram.png differ
diff --git a/docs/images/commands/PurgeCommand/PurgeSequenceDiagram.png b/docs/images/commands/PurgeCommand/PurgeSequenceDiagram.png
new file mode 100644
index 00000000000..956feb2feff
Binary files /dev/null and b/docs/images/commands/PurgeCommand/PurgeSequenceDiagram.png differ
diff --git a/docs/images/commands/ShowCommand/ShowActivityDiagram.png b/docs/images/commands/ShowCommand/ShowActivityDiagram.png
new file mode 100644
index 00000000000..8d54518c972
Binary files /dev/null and b/docs/images/commands/ShowCommand/ShowActivityDiagram.png differ
diff --git a/docs/images/commands/ShowCommand/ShowSequenceDiagram.png b/docs/images/commands/ShowCommand/ShowSequenceDiagram.png
new file mode 100644
index 00000000000..c88747002b4
Binary files /dev/null and b/docs/images/commands/ShowCommand/ShowSequenceDiagram.png differ
diff --git a/docs/images/commands/ShowCommand/show.png b/docs/images/commands/ShowCommand/show.png
new file mode 100644
index 00000000000..af372fe625d
Binary files /dev/null and b/docs/images/commands/ShowCommand/show.png differ
diff --git a/docs/images/commands/UndoCommand/UndoRedoState0.png b/docs/images/commands/UndoCommand/UndoRedoState0.png
new file mode 100644
index 00000000000..2509e628f36
Binary files /dev/null and b/docs/images/commands/UndoCommand/UndoRedoState0.png differ
diff --git a/docs/images/commands/UndoCommand/UndoRedoState1.png b/docs/images/commands/UndoCommand/UndoRedoState1.png
new file mode 100644
index 00000000000..33154db14dc
Binary files /dev/null and b/docs/images/commands/UndoCommand/UndoRedoState1.png differ
diff --git a/docs/images/commands/UndoCommand/UndoRedoState2.png b/docs/images/commands/UndoCommand/UndoRedoState2.png
new file mode 100644
index 00000000000..3003bf54a1d
Binary files /dev/null and b/docs/images/commands/UndoCommand/UndoRedoState2.png differ
diff --git a/docs/images/commands/UndoCommand/UndoRedoState3.png b/docs/images/commands/UndoCommand/UndoRedoState3.png
new file mode 100644
index 00000000000..65323ee433f
Binary files /dev/null and b/docs/images/commands/UndoCommand/UndoRedoState3.png differ
diff --git a/docs/images/commands/UndoCommand/UndoRedoState4.png b/docs/images/commands/UndoCommand/UndoRedoState4.png
new file mode 100644
index 00000000000..354b3e369fe
Binary files /dev/null and b/docs/images/commands/UndoCommand/UndoRedoState4.png differ
diff --git a/docs/images/commands/UndoCommand/UndoRedoState5.png b/docs/images/commands/UndoCommand/UndoRedoState5.png
new file mode 100644
index 00000000000..ee1a9c21a3c
Binary files /dev/null and b/docs/images/commands/UndoCommand/UndoRedoState5.png differ
diff --git a/docs/images/commands/UndoCommand/UndoSequenceDiagram.png b/docs/images/commands/UndoCommand/UndoSequenceDiagram.png
new file mode 100644
index 00000000000..8a965a30384
Binary files /dev/null and b/docs/images/commands/UndoCommand/UndoSequenceDiagram.png differ
diff --git a/docs/images/erwinqxy.png b/docs/images/erwinqxy.png
new file mode 100644
index 00000000000..0679fdc253c
Binary files /dev/null and b/docs/images/erwinqxy.png differ
diff --git a/docs/images/helpMessage.png b/docs/images/helpMessage.png
deleted file mode 100644
index b1f70470137..00000000000
Binary files a/docs/images/helpMessage.png and /dev/null differ
diff --git a/docs/images/reddevil1313.png b/docs/images/reddevil1313.png
new file mode 100644
index 00000000000..ce4f432e26c
Binary files /dev/null and b/docs/images/reddevil1313.png differ
diff --git a/docs/images/shermannws.png b/docs/images/shermannws.png
new file mode 100644
index 00000000000..5e89014bcc8
Binary files /dev/null and b/docs/images/shermannws.png differ
diff --git a/docs/images/ui/UiClassDiagram.png b/docs/images/ui/UiClassDiagram.png
new file mode 100644
index 00000000000..b27ff30741c
Binary files /dev/null and b/docs/images/ui/UiClassDiagram.png differ
diff --git a/docs/images/ui/UiClassDiagramMainComponents.png b/docs/images/ui/UiClassDiagramMainComponents.png
new file mode 100644
index 00000000000..ddac6ddf605
Binary files /dev/null and b/docs/images/ui/UiClassDiagramMainComponents.png differ
diff --git a/docs/images/ui/UiClassDiagramOverview.png b/docs/images/ui/UiClassDiagramOverview.png
new file mode 100644
index 00000000000..8be2ffccb89
Binary files /dev/null and b/docs/images/ui/UiClassDiagramOverview.png differ
diff --git a/docs/images/zhaopeiduo.png b/docs/images/zhaopeiduo.png
new file mode 100644
index 00000000000..79696f1d094
Binary files /dev/null and b/docs/images/zhaopeiduo.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..b4de7ad5dbd 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,19 +1,19 @@
---
layout: page
-title: AddressBook Level-3
+title: ProgrammerError
---
-[![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)
+[![Java CI](https://github.com/AY2122S1-CS2103-F09-3/tp/actions/workflows/gradle.yml/badge.svg)](https://github.com/AY2122S1-CS2103-F09-3/tp/actions/workflows/gradle.yml)
+[![codecov](https://codecov.io/gh/AY2122S1-CS2103-F09-3/tp/branch/master/graph/badge.svg?token=KLKGJOEN9F)](https://codecov.io/gh/AY2122S1-CS2103-F09-3/tp)
-![Ui](images/Ui.png)
+![Ui](images/commands/DashboardCommand/dashboard.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).
+**ProgrammerError is a desktop application for CS2100 tutors to manage students' lab results.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
-* If you are interested in using AddressBook, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
-* If you are interested about developing AddressBook, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
+* If you are interested in using ProgrammerError, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
+* If you are interested in developing ProgrammerError, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
**Acknowledgements**
-* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5)
+* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JSON In Java](https://mvnrepository.com/artifact/org.json/json), [opencsv](http://opencsv.sourceforge.net/), [JUnit5](https://github.com/junit-team/junit5)
diff --git a/docs/team/allardquek.md b/docs/team/allardquek.md
new file mode 100644
index 00000000000..bd3229d6f07
--- /dev/null
+++ b/docs/team/allardquek.md
@@ -0,0 +1,235 @@
+---
+layout: page
+title: Allard Quek's Project Portfolio Page
+---
+
+[ProgrammerError](https://github.com/AY2122S1-CS2103-F09-3/tp) is a desktop application which helps CS2100 tutors manage
+their students’ lab results in a simple and efficient manner, allowing them to spend less time on administrative
+processes and more time teaching students.
+
+The following is a summary of my contributions to the
+project. ([View Reposense](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/#breakdown=true&search=allardquek))
+
+#### Features
+
+1. **Added the ability to upload student data**
+ - What it does: Allows the TA to upload a CSV file containing students' student ID, class ID, name and email
+ - Justification: So that the TA can automate the process of adding students to their classes without having to
+ manually type the add command
+ - Highlights: This feature involved using different third-party libraries and evaluating their suitability
+ (based on their size, ease-of-use, functionality offered). Challenges included handling the multiple
+ possibilities for invalid user input with intuitive error messages and good design.
+ - Credits: [opencsv](http://opencsv.sourceforge.net/) (third-party library), Stackoverflow
+2. **Added the ability to download student data**
+ - What it does: Allows the TA to download the current student data into a CSV format
+ - Justification: So that the TA can upload the students' lab results onto Luminus gradebook or share them with other
+ TAs.
+ - Highlights: This feature was challenging as it required integrating a third-party library into the project for the
+ first time and ensuring the feature works across different devices. To improve the user experience, I also created
+ a popup message to be which required significant exploration with CSS properties and display sizes.
+ - Credits: [org.json](https://mvnrepository.com/artifact/org.json/json) (third-party library), Stackoverflow
+3. **Added the ability to view a dashboard of student and lab data**
+ - What it does: Shows the total number of students, labs, classes, and the number of labs left to marked for each class
+ - Justification: So that the TA can track their progress in marking their students' labs conveniently, especially
+ when they have many students
+ - Highlights: This feature required using a TreeMap to store and retrieve students' lab data efficiently so that the dashboard can be
+ updated dynamically with minimal delay without using a database.
+ Additionally, this feature required learning more about javafx components
+ and CSS properties to make the dashboard interface more user-friendly.
+
+#### Other Contributions
+
+1. **Project management:**
+ 1. Managed releases 1.3-1.3b (2 releases) and issue tracker on GitHub
+ 2. Set up the GitHub team org, repo, issue labels, Gradle and Notion
+ 3. Recorded and edited demo videos for v1.3-v1.4 (2 videos)
+2. **Enhancements to existing features:**
+ - Refactored code and improve code quality for existing features:
+ e.g. [#65](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/65)
+ , [#79](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/79/files)
+ , [#115](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/115)
+ , [#117](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/117)
+ , [#128](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/128)
+ , [#152](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/152)
+ , [#155](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/155)
+ , [#176](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/176)
+ , [#211](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/211)
+ , [#232](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/232)
+ - Improve testing: e.g. [#100](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/100)
+ , [#103](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/103)
+ , [#106](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/106/files)
+ , [#108](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/108/files)
+ , [#130](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/130/files)
+ - Various bug fixes for other features: e.g. [#74](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/74)
+ , [#200](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/200)
+ , [#268](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/268)
+ , [#359](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/359/files)
+ , [#360](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/360/files)
+ , [#389](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/389)
+3. **Documentation:**
+ - User Guide: Added documentation for table of contents, command syntax information, `upload`, `download`
+ , `dashboard`
+ - Developer Guide: Added implementation details for the `download` command, diagrams to explain the Ui component structure,
+ and effort section detailing the team's challenges and achievements
+4. **Review and Mentoring Contributions:**
+ - PRs reviewed (with non-trivial review comments): [#68](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/68)
+ , [#113](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/113)
+ , [#160](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/160)
+ , [#161](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/161)
+ , [#211](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/211#issuecomment-950448914)
+ , [#375](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/375)
+ - Contributed to forum discussions: [#142](https://github.com/nus-cs2103-AY2122S1/forum/issues/142)
+ , [#297](https://github.com/nus-cs2103-AY2122S1/forum/issues/297) [#322](https://github.com/nus-cs2103-AY2122S1/forum/issues/322)
+ , [#335](https://github.com/nus-cs2103-AY2122S1/forum/issues/335)
+ , [#350](https://github.com/nus-cs2103-AY2122S1/forum/issues/350#issuecomment-954135759)
+ , [#352](https://github.com/nus-cs2103-AY2122S1/forum/issues/352)
+ - Reported bugs and suggestions for other teams in the class: [#10](https://github.com/AllardQuek/ped/issues/10)
+ , [#11](https://github.com/AllardQuek/ped/issues/11), [#14](https://github.com/AllardQuek/ped/issues/14)
+ , [#16](https://github.com/AllardQuek/ped/issues/16), [#18](https://github.com/AllardQuek/ped/issues/18)
+ , [#19](https://github.com/AllardQuek/ped/issues/19), [#255](https://github.com/AY2122S1-CS2103-W14-1/tp/pull/255)
+
+
+
+
+## Sample User Guide Contribution
+
+### 3.3 Upload Data: `upload` or F4 on keyboard
+
+Uploads student data via a CSV file with the following header: `studentId,classId,name,email`. Note that the data
+should contain **only** the student ID, class ID, name and email field respectively and spaces directly before or after
+commas should be avoided.
+
+Here is an [example CSV file](https://github.com/AY2122S1-CS2103-F09-3/tp/blob/master/sample_upload/validDataForUpload.csv) on GitHub.
+You may download files from GitHub following the instructions [here](https://stackoverflow.com/questions/4604663/download-single-files-from-github).
+
+
:exclamation: **Note:**
+the CSV should *not* contain students' lab results since this functionality is only meant for the TA to automate the adding of students to PE.
+
+- If there are already existing students, the upload will **overwrite** the existing data rather than
+ append to it. This is because in a typical use case, the TA would not want to have the existing data kept if they
+ would like to use student data from their own CSV file.
+- Furthermore, simply uploading the CSV obtained via the `download` command will result in the file being rejected
+
+
+In summary:
+1. Select a valid CSV file (with header: `studentId,classId,name,email`) from the file chooser.
+2. Note that this command is **not** meant for uploading lab results. Rather, it is only for automating the adding of
+ students to PE.
+
+
+
+## Sample Developer Guide Contributions
+
+### **UI Component**
+
+The **API** of this component is specified
+in [`Ui.java`](https://github.com/AY2122S1-CS2103-F09-3/tp/blob/master/src/main/java/seedu/programmer/ui/Ui.java)
+
+At a high level, the `MainWindow` component interacts with 3 other main components: `Logic`, `PopupManager` and `FileManager` (Figure 4.2.1).
+Note that the components under `MainWindow` have been omitted for simplicity and will be shown in greater detail in the next diagram.
+
+
+
+
+
+ Figure 4.2.1: Overview of Ui components
+
+
+1. Firstly, `MainWindow` interacts with the `Logic` component to determine which data to display to the user.
+2. Secondly, `MainWindow` conducts file operations on the Ui through a `FileManager`.
+ For instance, the `FileManager` handles situations where the user is required to select files or directories.
+3. Thirdly, to manage the display of popup windows to the user, `MainWindow` interacts with a `PopupManager` which handles
+ the configuration, creation and showing of popups on the Ui.
+
+In addition, there are two additional windows that the UI can display: `HelpWindow` and `DashboardWindow`. They inherit
+from the abstract class `PopupWindow`, which captures the commonalities between classes that represent popup information
+to be displayed to the user.
+
+Now taking a closer look at the `MainWindow` component, it consists of a number of parts e.g.`CommandBox`, `ResultDisplay`, `StudentListPanel`
+, `StatusBarFooter` etc. (Figure 4.2.2). These components, including the `MainWindow`, inherit from the abstract `UiPart` class which captures
+the commonalities between classes that represent parts of the visible GUI. The following is a summary of the parts of the `MainWindow`.
+
+
+
+
+
+ Figure 4.2.2: MainWindow Ui components
+
+
+Note that 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 styling of the UI components are defined in the `src/main/resources/view/css` folder.
+
+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 `Student` object residing in the `Model`.
+
+
+### **Download Command**
+
+#### Implementation
+
+The implementation details of this feature can be found mainly in `MainWindow` as most of the necessary operations are
+related to the UI. In addition, the following classes are utilized:
+
+- `DownloadCommand`: for generating the `DownloadCommandResult`
+- `DownloadCommandResult`: for displaying the feedback to the CS2100 TA
+- `MainWindow.fxml`: for the addition of a 'Download' button on the MainWindow
+- `Popup.css`: for the customisation of styles for pop-up messages
+
+In the `Logic` components, the `download` command works in a similar fashion to the `show` command, except that it does
+not require its own parser.
+
+
+This sequence diagram in Figure 5.5.1 shows how the `download` command works at a lower level:
+
+
+
+
+
+ Figure 5.5.1: Sequence diagram illustrating the execution of download command
+
+
+
+The following activity diagram in Figure 5.5.2 summarizes what happens when a CS2100 TA executes the download command:
+
+
+
+
+
+ Figure 5.5.2: Activity diagram for executing download command
+
+
+
+#### Design Considerations
+
+One of the main considerations was to deal with reading and writing files only when necessary. This meant checking if
+there is any data to begin with. Only if there exists any data will the CS2100 TA be prompted to select a folder
+destination.
+
+Additionally, a pop-up message was chosen to be displayed for two reasons. First, it provides the user a clear visual
+indicator of the result of their command, as compared to the typical textual output they would see. Second, we would
+only know if the data was successfully downloaded after the textual response is shown to the user. Using a pop-up
+message right at the end of this operation means we can customize the message depending on whether the download was a
+success.
+
+#### Alternatives
+
+1. One alternative could be to not use a third-party package (`org.json`), and instead manually parse the json file and
+ write the corresponding values to a CSV file which ProgrammerError would create. We chose not to go down this route
+ as it is much more tedious with little reward in terms of code management and code quality.
+
+
+2. Another alternative with respect to the CS2100 TA experience could be to disallow the user from selecting a folder to save
+ their data to. Instead, a default location could be chosen so as to save the CS2100 TA some time in getting their data
+ downloaded quickly. However, since we wanted to make ProgrammerError more flexible and adaptable to different users, we opted to include the
+ functionality of allowing the CS2100 TA to select a folder destination.
diff --git a/docs/team/erwinqxy.md b/docs/team/erwinqxy.md
new file mode 100644
index 00000000000..a71f257f8c4
--- /dev/null
+++ b/docs/team/erwinqxy.md
@@ -0,0 +1,107 @@
+---
+layout: page
+title: Erwin Quek's Project Portfolio Page
+---
+### Project: ProgrammerError
+
+[ProgrammerError](https://github.com/AY2122S1-CS2103-F09-3/tp) is a desktop application which helps CS2100 tutors manage
+their students’ lab results in a simple and efficient manner, allowing them to spend less time on administrative
+processes and more time teaching students.
+
+The following is a summary of my contributions to the
+project. ([View Reposense](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2021-09-17&tabOpen=true&tabType=zoom&zA=erwinqxy&zR=AY2122S1-CS2103-F09-3%2Ftp%5Bmaster%5D&zACS=215.4376936697654&zS=2021-09-17&zFS=&zU=2021-11-08&zMG=false&zFTF=commit&zFGS=groupByRepos&zFR=false))
+
+### Features
+
+1. **New Feature**: Automatic sorting of the student list.
+ * What it does: it helps to ensure that the student list is always sorted whenever an add or edit command is executed.
+ * Justification: This feature improves the product significantly as it helps to simulate a real-life nominal roll
+ where the students will always be sorted by class and name, giving the user an organized set of student data.
+ * Highlights: This enhancement provides the user with a more convenient and accessible experience in finding his /
+ her students.
+2. **Improved Feature**: Added Student ID, Class ID, and Email
+ * What it does: it provides more information pertaining to a student.
+ * Justification: This feature improves the product by providing important information to identify the student by.
+ * Highlights: This feature will be used in other commands such as add, edit, and filter. This feature was tedious as
+ it required an overhaul of the existing AB3 features and test cases. This feature also overlaps with the sample
+ data.
+3. **Improved Feature**: Added a new set of Sample Data.
+ * What it does: it helps to populate ProgrammerError with some students.
+ * Justification: This feature improves the testability of the product where it allows first-time users to explore
+ and learn the various features provided by the product.
+4. **New Feature**: Implemented a feature to help generate random lab scores.
+ * What it does: add randomized lab scores to the students in the sample data.
+ * Justification This feature improves the testability of the product, providing randomized lab scores to the user.
+ * Highlight: This feature requires getting the total lab score of a particular lab as an upper bound for the
+ randomization to work to avoid generating an invalid score.
+5. **Improved Feature**: Implement unique email.
+ * What it does: it ensures that only unique email inputs are valid when executing add or edit student commands.
+ * Justification: simulating a real-world constraint, there will never be two students with the same email address.
+ It also helps to ensure the filter command results are consistent and accurate.
+ * Highlight: Initially I thought that this will be a straightforward implementation. However, after implementing
+ this feature, I discovered a few bugs which I will explain below.
+6. **Improved Feature**: Implement error messages for duplicate email and student id.
+ * What it does: it helps inform the user what is the error with his input command, duplicate student id, or a
+ duplicate email. This will help provide the user with a better understanding of the error.
+ * Justification: previously, we only implemented a duplicate student error which is vague and does not provide the
+ user with enough feedback to correct his command input.
+ * Highlight: After enforcing this feature and together with feature 5, there was a bug where the user is forced to
+ input a unique email and student id. But users were now unable to edit the existing student id or email. Hence, it
+ required some troubleshooting.
+7. **Minor Fix**: Helped to refactor and update the entire project file to match our product name.
+
+### Other Contributions
+
+1. **Code
+ contributed**: [RepoSense link](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2021-09-17&tabOpen=true&tabType=authorship&tabAuthor=erwinqxy&tabRepo=AY2122S1-CS2103-F09-3%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false)
+
+2. **Project management**: Managed releases `v1.2a`, `v1.4`, `v1.4.1` (3 releases) on GitHub
+
+3. **Enhancements to existing features**:
+ * Refactor the entire project structure to fit our
+ product [#61](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/61)
+ , [#91](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/91)
+ , [#99](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/99)
+ , [#382](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/382)
+ * Fix Parser Test Cases [#68](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/68)
+ * Implement automatic sorting [#161](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/161)
+ , [#192](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/192)
+ * Populate sample data [#169](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/169)
+ * Fix cosmetic error
+ message [#324](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/324) [#328](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/328)
+ * Fix duplicate email [#427](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/427)
+
+4. **PRs Reviewed:**
+ * [#98](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/98)
+ , [#100](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/100)
+ , [#108](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/108),
+ [#109](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/109)
+ , [#110](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/110)
+ , [#152](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/152),
+ [#153](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/153)
+ , [#252](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/252)
+ , [#413](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/413),
+ [#417](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/417)
+ , [#460](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/460/files),
+ [#541](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/541#pullrequestreview-799559192)
+
+5. **Documentation - Updated documentations for user guide and developer guide:**
+ - [#165](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/165)
+ , [#240](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/240)
+ , [#246](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/246),
+ [#474](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/474)
+ , [#482](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/482) , [#496](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/496),
+ [#522](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/522), [#533](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/533),
+ [#614](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/614), [#615](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/615), [#616](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/616)
+
+6. **Community Contributions**:
+ * Provided some feedback and bug reporting to another team during
+ PED: [#1](https://github.com/erwinqxy/ped/issues/1),
+ [#2](https://github.com/erwinqxy/ped/issues/2), [#3](https://github.com/erwinqxy/ped/issues/3),
+ [#4](https://github.com/erwinqxy/ped/issues/4), [#5](https://github.com/erwinqxy/ped/issues/5),
+ [#6](https://github.com/erwinqxy/ped/issues/6), [#7](https://github.com/erwinqxy/ped/issues/7),
+ [#8](https://github.com/erwinqxy/ped/issues/8), [#9](https://github.com/erwinqxy/ped/issues/9),
+ [#10](https://github.com/erwinqxy/ped/issues/10), [#11](https://github.com/erwinqxy/ped/issues/11),
+ [#12](https://github.com/erwinqxy/ped/issues/12), [#13](https://github.com/erwinqxy/ped/issues/13),
+ [#14](https://github.com/erwinqxy/ped/issues/13)
+
diff --git a/docs/team/reddevil1313.md b/docs/team/reddevil1313.md
new file mode 100644
index 00000000000..cd0d9efdfcd
--- /dev/null
+++ b/docs/team/reddevil1313.md
@@ -0,0 +1,101 @@
+---
+layout: page
+title: Samay Sagar's Project Portfolio Page
+---
+
+### Project: ProgrammerError
+
+[ProgrammerError](https://github.com/AY2122S1-CS2103-F09-3/tp) is a desktop application which helps CS2100 tutors manage
+their students’ lab results in a simple and efficient manner, allowing them to spend less time on administrative
+processes and more time teaching students.
+
+The following is a summary of my contributions to the
+project. ([View Reposense](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2021-09-17&tabOpen=true&tabType=zoom&tabAuthor=reddevil1313&tabRepo=AY2122S1-CS2103-F09-3%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code~other&authorshipIsBinaryFileTypeChecked=false&zA=reddevil1313&zR=AY2122S1-CS2103-F09-3%2Ftp%5Bmaster%5D&zACS=213.68089453967534&zS=2021-09-17&zFS=&zU=2021-11-08&zMG=false&zFTF=commit&zFGS=groupByRepos&zFR=false))
+
+### Features
+
+1. Added the ability to purge existing data and fill it with using sample data
+
+ * What it does: Allows the TA to purge existing data using the purge command and fill it with sample data using the fill
+ command.
+ * Justification: So that the TA can remove existing data to input his/her own data or try out the commands on a sample
+ database.
+ * Highlights: This feature seemed simple at first as it just required to modify the existing clear feature but the fill
+ command required understanding of how the data was stored in the json file and how to perform checks on whether the
+ program already had data or not.
+
+2. Added the ability to add labs and edit their details for the entire student base
+
+ * What it does: Allows the TA to add and edit labs ranging from 0 to 14 for the entire student base in the application.
+ * Justification: Primary purpose of the application; So that the TA can keep track of the scores of labs under him/her.
+ * Highlights: This feature posed various challenges along the way. Earlier we had implemented the attributes of the Lab
+ class using data values but then shifted to wrapper classes which required very tedious refactoring and debugging as a
+ lot of unwanted bugs came about. Changes made to the storing of the data in the json file to accomodate for the new
+ labs encountered a lot of bugs as well.
+
+3. Added the ability to store individual grades for each student
+
+ * What it does: Allows the TA to edit individual grades for each student in the program.
+ * Justification: So that the TA can keep track of how many labs he/she has marked and how many of them are
+ still left to mark.
+ * Highlights: This feature required changes to the existing edit command and thus, understanding of the command's
+ optional inputs. One of the major highlights was solving a bug where once a newly added lab was edited for one
+ student, it was being edited to all.
+
+### Other Contributions
+
+#### **Project management**:
+
+* Managed the issue tracker and made sure that all issues were labelled, assigned to teammate and belonged to a
+ milestone.
+
+#### **Enhancements to existing features**:
+
+* Improve Testing: e.g. [#84](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/84)
+ , [#85](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/85)
+ , [#170](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/170)
+ , [#220](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/220)
+ , [#224](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/224)
+ , [#233](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/233)
+ , [#234](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/234)
+ , [#235](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/235)
+ , [#241](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/241)
+ , [#417](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/417)
+ , [#419](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/419)
+ , [#447](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/447)
+ , [#579](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/579)
+ , [#583](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/583)
+* Bug fixes: e.g. [#417](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/417)
+ , [#425](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/425)
+ , [#432](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/432)
+ , [#447](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/447)
+ , [#500](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/500)
+ , [#561](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/561)
+ , [#591](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/591)
+
+#### **Review and Mentoring Contributions**:
+
+* PRs reviewed (with non-trivial review comments): [#47](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/47)
+ , [#113](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/113)
+ , [#232](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/232)
+ , [#244](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/244)
+ , [#324](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/324)
+* Reported bugs and suggestions for other teams in the class: [#1](https://github.com/reddevil1313/ped/issues/1)
+ , [#2](https://github.com/reddevil1313/ped/issues/2), [#3](https://github.com/reddevil1313/ped/issues/3)
+ , [#4](https://github.com/reddevil1313/ped/issues/4), [#5](https://github.com/reddevil1313/ped/issues/5)
+ , [#9](https://github.com/reddevil1313/ped/issues/9), [#12](https://github.com/reddevil1313/ped/issues/12)
+
+#### **Documentation**:
+
+* User Guide:
+ * Added documentation for the features `purge`
+ and `fill` [#31](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/31)
+ * Added documentation for all the lab commands: `addlab`, `editlab` and `deletelab`:
+ [#236](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/236)
+* Developer Guide:
+ * Added high priority user stories [#43](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/43)
+ * Sequence and Activity Diagram for EditLabCommand [#519](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/519)
+ * Added feature description for purge and editlab commands
+ [#571](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/571)
+ , [#574](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/574)
+
diff --git a/docs/team/shermannws.md b/docs/team/shermannws.md
new file mode 100644
index 00000000000..90d6a7cff8e
--- /dev/null
+++ b/docs/team/shermannws.md
@@ -0,0 +1,99 @@
+---
+layout: page
+title: Sherman Ng's Project Portfolio Page
+---
+
+### Project: ProgrammerError
+
+[ProgrammerError](https://github.com/AY2122S1-CS2103-F09-3/tp) (PE) is a desktop application which helps CS2100 Lab
+Teaching Assistants (TAs) manage their students’ lab results in a simple and efficient manner, allowing them to spend
+less time on administrative processes and more time teaching students. It is optimized for use via a Command Line
+Interface (CLI) while still having the benefits of a Graphical User Interface (GUI) developed with Java and JavaFX.
+
+Please find below my contributions to the project. My contributions to the project code base can also be found at the
+following [RepoSense link](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/?search=F09-3&sort=groupTitle&sortWithin=title&since=2021-09-17&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=false&tabOpen=true&tabType=authorship&tabAuthor=shermannws&tabRepo=AY2122S1-CS2103-F09-3%2Ftp%5Bmaster%5D&authorshipIsMergeGroup=false&authorshipFileTypes=docs~functional-code~test-code&authorshipIsBinaryFileTypeChecked=false).
+
+
+
+#### Features
+
+1. **New Feature**: Added the ability to filter the list of students based on different query parameters.
+ * What it does:
+ Filters the list of students stored in PE by displaying all the students that matches the query parameters. Tutors
+ can specify the filter criteria based on any combination of students' particulars.
+ * Justification:
+ So that tutors are able to quickly filter out the students' of interest out of their large number of students
+ using known parameters (e.g. Class ID).
+ * Highlights:
+ This feature was challenging as it involved filtering students based on any combination of query parameters
+ provided. This also involved creating a whole new command from scratch which requires comprehensive
+ understanding of all the classes in PE.
+
+2. **New Feature**: Added a command history feature that allows tutors to navigate to previous commands using up/down
+ keys.
+ * What it does: Allows tutors to navigate previously executed commands, similar to the Unix CLI.
+ * Justification: So that fast-typists tutors are able to be more efficient when using PE.
+ * Highlights: This involved a self-directed learning experience using online materials to properly implement an
+ "onKeyPressed" event listener. Deep thoughts were also required in the consideration of the edge cases to ensure that this feature is free of bug.
+
+
+
+#### Other Contributions
+
+1. **Project management**:
+ * Created and set up the GitHub team organisation, repo, pages and actions.
+ * Managed and ensured the prompt delivery of
+ releases [v1.3.trial](https://github.com/AY2122S1-CS2103-F09-3/tp/releases/tag/v1.3.trial)
+ & [v1.3.1](https://github.com/AY2122S1-CS2103-F09-3/tp/releases/tag/v1.3.1) (2 releases) on GitHub.
+ * Labelled and referenced all the figures in the DG (PR [\#603](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/603)).
+ * Solved bug that prevented User Guide and Developer Guide from being linked as one of the header pages in
+ the team's `index.md` page (PR [\#276](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/276)).
+
+2. **Enhancements to existing features**:
+ * Enhanced the `edit` feature to accommodate the changing requirements of PE (PRs [\#121](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/121),
+ [\#387](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/387),
+ [\#403](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/403),
+ [\#488](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/488)).
+ * Modified generic utility classes for the integration of the new PE requirements (PR [\#274](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/274)).
+ * Increased user feedback by putting in place better exceptions throwing mechanism and more detailed description (PRs [\#272](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/272),
+ [\#287](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/287),
+ [\#373](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/373),
+ [\#387](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/387),
+ [\#403](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/403),
+ [\#416](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/416)).
+ * Increased code quality (PRs [\#206](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/206),
+ [\#495](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/495),
+ [\#509](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/509),
+ [\#622](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/622)).
+ * Various bugfixes (PRs [\#150](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/150),
+ [\#362](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/362),
+ [\#375](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/375),
+ [\#634](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/634)).
+
+3. **Documentation**:
+ * User Guide:
+ * Added documentation for the command history navigation feature and for features `filter`
+ and `edit` (PRs [\#35](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/35),
+ [\#148](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/148),
+ [\#160](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/160),
+ [\#210](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/210),
+ [\#385](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/385)).
+ * Created and maintained the command summary at the bottom of the User Guide (PRs [\#35](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/35),
+ [\#517](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/517)).
+ * Developer Guide:
+ * Added implementation details of the `filter` feature
+ (PRs [\#162](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/162), [\#549](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/549), [\#576](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/576)).
+ * Added use case scenario for `filter` feature (PR [\#598](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/598)).
+
+4. **Community**:
+ * PRs with non-trivial comments: [\#113](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/113),
+ [\#121](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/121),
+ [\#160](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/160),
+ [\#211](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/211),
+ [\#389](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/389),
+ [\#500](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/500)
+ * Contributed to forum discussions (examples: [1](https://github.com/nus-cs2103-AY2122S1/forum/issues/348),
+ [2](https://github.com/nus-cs2103-AY2122S1/forum/issues/324)).
+ * Reported bugs and suggestions for other teams in the class (examples: [1](https://github.com/shermannws/ped/issues/7),
+ [2](https://github.com/shermannws/ped/issues/17),
+ [3](https://github.com/shermannws/ped/issues/5) and [16 other issues](https://github.com/shermannws/ped/issues)).
diff --git a/docs/team/zhaopeiduo.md b/docs/team/zhaopeiduo.md
new file mode 100644
index 00000000000..84764023a20
--- /dev/null
+++ b/docs/team/zhaopeiduo.md
@@ -0,0 +1,77 @@
+---
+layout: page
+title: Zhao Peiduo's Project Portfolio Page
+---
+
+### Project: ProgrammerError
+
+[ProgrammerError](https://github.com/AY2122S1-CS2103-F09-3/tp) (PE) is a desktop application which helps CS2100 tutors
+manage their students’ lab results in a simple and efficient manner, allowing them to spend less time on administrative
+processes and more time teaching students.
+
+Given below are my contributions to the project. My contribution to the project code base is also shown in the
+[RepoSense link](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByRepos&breakdown=true&checkedFileTypes=docs~functional-code~test-code~other&since=2021-09-17).
+
+### New Features
+
+1. Added to ability to show a student's lab results on the side panel
+ * What it does: Allow CS2100 TAs to check a student's lab record on the side panel.
+ * Justification: This feature provides a convenient way for CS2100 TAs to view a student's lab record on
+ ProgrammerError's UI.
+ * Highlights:
+ * Developing the ability to use javaFX to design UI by creating a side panel on the MainWindow.
+ * Immediate update of student's information and lab results after every command, which requires a modification to
+ all existing commands to keep track of the selected student and his/her lab results.
+ * Credits: [JavaFX8Docs](https://docs.oracle.com/javase/8/javafx/api/toc.htm) for guidelines on how to use different
+ containers.
+
+2. Added colour-coded tags to each student in ProgrammerError
+ * What it does: Green tags represent the marked labs while red ones represent the unmarked labs
+ * Justification: This feature allows CS2100 TAs to have a bird view of the marking status of the labs, without a need to
+ show student by student.
+ * Highlights: Immediate update of tags' color after every command requires a record of the status of the labs similar to
+ the show feature.
+ * Credits:
+
+### Other Contributions
+
+#### **Enhancements to existing features**:
+
+* Improve the help feature by adding a table of command syntax to the HelpWindow.
+* Add a button bar with buttons for exit, help, download, upload and dashboard features. Enabled keyboard shortcut to be
+ more keyboard-friendly.
+* Add/Modify test cases for various commands: [\#69](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/69),
+ [\#530](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/530),
+ [\#572](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/572).
+* Bug fixes: [\#238](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/238),
+ [\#280](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/280),
+ [\#351](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/351),
+ [\#357](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/357),
+ [\#374](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/374),
+ [\#381](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/381),
+ [\#429](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/429),
+ [\#430](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/430).
+
+#### **Project management**:
+
+* Utilize the issue tracker for bug reports and new feature proposals.
+
+#### **Documentation**:
+
+* User Guide:
+ * Added documentation for the features `delete` and `show`: [\#34](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/34),
+ [\#279](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/279).
+ * Added section on editing the data file directly: [\#589](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/589).
+* Developer Guide:
+ * Added use cases for ProgrammerError: [\#46](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/46/files).
+ * Added implementation details of the `show` feature: [\#159](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/159).
+ * Updated the UML diagrams for ProgrammerError: [\#158](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/159)
+ , [\#393](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/393).
+ * Added instruction for manual testing for `show`: [\#541](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/541)
+
+#### **Community**:
+
+* PRs reviewed (with non-trivial review comments): [\#194](https://github.com/AY2122S1-CS2103-F09-3/tp/pull/194).
+* Contributed to forum discussions: [\#290](https://github.com/nus-cs2103-AY2122S1/forum/issues/290).
+* Reported bugs and suggestions for other teams in the class: [\#3](https://github.com/ZhaoPeiduo/ped/issues/3)
+ , [\#5](https://github.com/ZhaoPeiduo/ped/issues/5) from PE-D.
diff --git a/docs/tutorials/AddRemark.md b/docs/tutorials/AddRemark.md
index 8919d8eaa17..b59b3210800 100644
--- a/docs/tutorials/AddRemark.md
+++ b/docs/tutorials/AddRemark.md
@@ -5,7 +5,7 @@ title: "Tutorial: Adding a command"
Let's walk you through the implementation of a new command — `remark`.
-This command allows users of the AddressBook application to add optional remarks to people in their address book and edit it if required. The command should have the following format:
+This command allows users of the AddressBook application to add optional remarks to people in their ProgrammerError and edit it if required. The command should have the following format:
`remark INDEX r/REMARK` (e.g., `remark 2 r/Likes baseball`)
@@ -23,12 +23,12 @@ For now, let’s keep `RemarkCommand` as simple as possible and print some outpu
**`RemarkCommand.java`:**
``` java
-package seedu.address.logic.commands;
+package seedu.programmer.logic.commands;
-import seedu.address.model.Model;
+import seedu.programmer.model.Model;
/**
- * Changes the remark of an existing person in the address book.
+ * Changes the remark of an existing student in the address book.
*/
public class RemarkCommand extends Command {
@@ -43,7 +43,7 @@ public class RemarkCommand extends Command {
### Hook `RemarkCommand` into the application
-Now that we have our `RemarkCommand` ready to be executed, we need to update `AddressBookParser#parseCommand()` to recognize the `remark` keyword. Add the new command to the `switch` block by creating a new `case` that returns a new instance of `RemarkCommand`.
+Now that we have our `RemarkCommand` ready to be executed, we need to update `ProgrammerErrorParser#parseCommand()` to recognize the `remark` keyword. Add the new command to the `switch` block by creating a new `case` that returns a new instance of `RemarkCommand`.
You can refer to the changes in this [diff](https://github.com/se-edu/addressbook-level3/commit/35eb7286f18a029d39cb7a29df8f172a001e4fd8#diff-34ace715a8a8d2e5a66e71289f017b47).
@@ -65,8 +65,8 @@ Following the convention in other commands, we add relevant messages as constant
``` java
public static final String MESSAGE_USAGE = COMMAND_WORD
- + ": Edits the remark of the person identified "
- + "by the index number used in the last person listing. "
+ + ": Edits the remark of the student identified "
+ + "by the index number used in the last student listing. "
+ "Existing remark will be overwritten by the input.\n"
+ "Parameters: INDEX (must be a positive integer) "
+ "r/ [REMARK]\n"
@@ -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.programmer.commons.util.CollectionUtil.requireAllNonNull;
//...
public class RemarkCommand extends Command {
//...
@@ -101,8 +101,8 @@ public class RemarkCommand extends Command {
private final String remark;
/**
- * @param index of the person in the filtered person list to edit the remark
- * @param remark of the person to be updated to
+ * @param index of the student in the filtered student list to edit the remark
+ * @param remark of the student to be updated to
*/
public RemarkCommand(Index index, String remark) {
requireAllNonNull(index, remark);
@@ -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.programmer.logic.parser` package. The class must extend the `Parser` interface.
![The relationship between Parser and RemarkCommandParser](../images/add-remark/ParserInterface.png)
@@ -216,7 +216,7 @@ public RemarkCommand parse(String args) throws ParseException {
-:information_source: Don’t forget to update `AddressBookParser` to use our new `RemarkCommandParser`!
+:information_source: Don’t forget to update `ProgrammerErrorParser` to use our new `RemarkCommandParser`!
@@ -225,11 +225,12 @@ If you are stuck, check out the sample
## Add `Remark` to the model
-Now that we have all the information that we need, let’s lay the groundwork for propagating the remarks added into the in-memory storage of person data. We achieve that by working with the `Person` model. Each field in a Person is implemented as a separate class (e.g. a `Name` object represents the person’s name). That means we should add a `Remark` class so that we can use a `Remark` object to represent a remark given to a person.
+Now that we have all the information that we need, let’s lay the groundwork for propagating the remarks added into the in-memory storage of student data. We achieve that by working with the `Student` model. Each field in a Student is implemented as a separate class (e.g. a `Name` object represents the student’s name). That means we should add a `Remark` class so that we can use a `Remark` object to represent a remark given to a student.
### 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.programmer.model.person`. Since a `Remark` is a field that is similar to `Address`, we can reuse a significant bit of code.
+
A copy-paste and search-replace later, you should have something like [this](https://github.com/se-edu/addressbook-level3/commit/4516e099699baa9e2d51801bd26f016d812dedcc#diff-af2f075d24dfcd333876f0fbce321f25). Note how `Remark` has no constrains and thus does not require input
validation.
@@ -240,11 +241,12 @@ Let’s change `RemarkCommand` and `RemarkCommandParser` to use the new `Remark`
## Add a placeholder element for remark to the UI
-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.
+Without getting too deep into `fxml`, let’s go on a 5 minute adventure to get some placeholder text to show up for each student.
+
+Simply add the following to [`seedu.programmer.ui.PersonCard`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-0c6b6abcfac8c205e075294f25e851fe).
-Simply add the following to [`seedu.address.ui.PersonCard`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-0c6b6abcfac8c205e075294f25e851fe).
-**`PersonCard.java`:**
+**`StudentCard.java`:**
``` java
@FXML
@@ -254,9 +256,9 @@ private Label remark;
`@FXML` is an annotation that marks a private or protected field and makes it accessible to FXML. It might sound like Greek to you right now, don’t worry — we will get back to it later.
-Then insert the following into [`main/resources/view/PersonListCard.fxml`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-12580431f55d7880578aa4c16f249e71).
+Then insert the following into [`main/resources/view/StudentListCard.fxml`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-12580431f55d7880578aa4c16f249e71).
-**`PersonListCard.fxml`:**
+**`StudentListCard.fxml`:**
``` xml
@@ -266,21 +268,21 @@ That’s it! Fire up the application again and you should see something like thi
![$remark shows up in each entry](../images/add-remark/$Remark.png)
-## Modify `Person` to support a `Remark` field
+## Modify `Student` to support a `Remark` field
-Since `PersonCard` displays data from a `Person`, we need to update `Person` to get our `Remark` displayed!
+Since `StudentCard` displays data from a `Student`, we need to update `Student` to get our `Remark` displayed!
-### Modify `Person`
+### Modify `Student`
-We change the constructor of `Person` to take a `Remark`. We will also need to define new fields and accessors accordingly to store our new addition.
+We change the constructor of `Student` to take a `Remark`. We will also need to define new fields and accessors accordingly to store our new addition.
-### Update other usages of `Person`
+### Update other usages of `Student`
-Unfortunately, a change to `Person` will cause other commands to break, you will have to modify these commands to use the updated `Person`!
+Unfortunately, a change to `Student` will cause other commands to break, you will have to modify these commands to use the updated `Student`!
-:bulb: Use the `Find Usages` feature in IntelliJ IDEA on the `Person` class to find these commands.
+:bulb: Use the `Find Usages` feature in IntelliJ IDEA on the `Student` class to find these commands.
@@ -289,7 +291,7 @@ Refer to [this commit](https://github.com/se-edu/addressbook-level3/commit/ce998
## Updating Storage
-AddressBook stores data by serializing `JsonAdaptedPerson` into `json` with the help of an external library — Jackson. Let’s update `JsonAdaptedPerson` to work with our new `Person`!
+AddressBook stores data by serializing `JsonAdaptedStudent` into `json` with the help of an external library — Jackson. Let’s update `JsonAdaptedStudent` to work with our new `Student`!
While the changes to code may be minimal, the test data will have to be updated as well.
@@ -304,16 +306,16 @@ to see what the changes entail.
## Finalizing the UI
-Now that we have finalized the `Person` class and its dependencies, we can now bind the `Remark` field to the UI.
+Now that we have finalized the `Student` class and its dependencies, we can now bind the `Remark` field to the UI.
Just add [this one line of code!](https://github.com/se-edu/addressbook-level3/commit/5b98fee11b6b3f5749b6b943c4f3bd3aa049b692)
-**`PersonCard.java`:**
+**`StudentCard.java`:**
``` java
-public PersonCard(Person person, int displayedIndex) {
+public StudentCard(Student student, int displayedIndex) {
//...
- remark.setText(person.getRemark().value);
+ remark.setText(student.getRemark().value);
}
```
@@ -325,43 +327,43 @@ After the previous step, we notice a peculiar regression — we went from di
### Update `RemarkCommand` and `RemarkCommandParser`
-In this last step, we modify `RemarkCommand#execute()` to change the `Remark` of a `Person`. Since all fields in a `Person` are immutable, we create a new instance of a `Person` with the values that we want and
-save it with `Model#setPerson()`.
+In this last step, we modify `RemarkCommand#execute()` to change the `Remark` of a `Student`. Since all fields in a `Student` are immutable, we create a new instance of a `Student` with the values that we want and
+save it with `Model#setStudent()`.
**`RemarkCommand.java`:**
``` java
//...
- public static final String MESSAGE_ADD_REMARK_SUCCESS = "Added remark to Person: %1$s";
- public static final String MESSAGE_DELETE_REMARK_SUCCESS = "Removed remark from Person: %1$s";
+ public static final String MESSAGE_ADD_REMARK_SUCCESS = "Added remark to Student: %1$s";
+ public static final String MESSAGE_DELETE_REMARK_SUCCESS = "Removed remark from Student: %1$s";
//...
@Override
public CommandResult execute(Model model) throws CommandException {
- List lastShownList = model.getFilteredPersonList();
+ List lastShownList = model.getFilteredStudentList();
if (index.getZeroBased() >= lastShownList.size()) {
throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
}
- Person personToEdit = lastShownList.get(index.getZeroBased());
- Person editedPerson = new Person(
- personToEdit.getName(), personToEdit.getPhone(), personToEdit.getEmail(),
- personToEdit.getAddress(), remark, personToEdit.getTags());
+ Student studentToEdit = lastShownList.get(index.getZeroBased());
+ Student editedStudent = new Student(
+ studentToEdit.getName(), studentToEdit.getPhone(), studentToEdit.getEmail(),
+ studentToEdit.getAddress(), remark, studentToEdit.getTags());
- model.setPerson(personToEdit, editedPerson);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ model.setStudent(studentToEdit, editedStudent);
+ model.updateFilteredStudentList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(generateSuccessMessage(editedPerson));
+ return new CommandResult(generateSuccessMessage(editedStudent));
}
/**
* Generates a command execution success message based on whether
* the remark is added to or removed from
- * {@code personToEdit}.
+ * {@code studentToEdit}.
*/
- private String generateSuccessMessage(Person personToEdit) {
+ private String generateSuccessMessage(Student studentToEdit) {
String message = !remark.value.isEmpty() ? MESSAGE_ADD_REMARK_SUCCESS : MESSAGE_DELETE_REMARK_SUCCESS;
- return String.format(message, personToEdit);
+ return String.format(message, studentToEdit);
}
```
diff --git a/docs/tutorials/RemovingFields.md b/docs/tutorials/RemovingFields.md
index f29169bc924..162c01111bd 100644
--- a/docs/tutorials/RemovingFields.md
+++ b/docs/tutorials/RemovingFields.md
@@ -8,7 +8,7 @@ title: "Tutorial: Removing Fields"
> — Antoine de Saint-Exupery
When working on an existing code base, you will most likely find that some features that are no longer necessary.
-This tutorial aims to give you some practice on such a code 'removal' activity by removing the `address` field from `Person` class.
+This tutorial aims to give you some practice on such a code 'removal' activity by removing the `address` field from `Student` class.
@@ -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 `Student` is actually an instance of the `seedu.address.model.student.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)
@@ -37,11 +37,11 @@ Choose to `View Usages` and you should be presented with a list of `Safe Delete
![List of conflicts](../images/remove/SafeDeleteConflicts.png)
-Remove usages of `Address` by performing `Safe Delete`s on each entry i.e., double-click on the entry (which takes you to the code in concern, right-click on that entity, and choose `Refactor` -> `Safe delete` as before). You will need to exercise discretion when removing usages of `Address`. Functions like `ParserUtil#parseAddress()` can be safely removed but its usages must be removed as well. Other usages like in `EditPersonDescriptor` may require more careful inspection.
+Remove usages of `Address` by performing `Safe Delete`s on each entry i.e., double-click on the entry (which takes you to the code in concern, right-click on that entity, and choose `Refactor` -> `Safe delete` as before). You will need to exercise discretion when removing usages of `Address`. Functions like `ParserUtil#parseAddress()` can be safely removed but its usages must be removed as well. Other usages like in `EditStudentDescriptor` may require more careful inspection.
-Let’s try removing references to `Address` in `EditPersonDescriptor`.
+Let’s try removing references to `Address` in `EditStudentDescriptor`.
-1. Safe delete the field `address` in `EditPersonDescriptor`.
+1. Safe delete the field `address` in `EditStudentDescriptor`.
1. Select `Yes` when prompted to remove getters and setters.
@@ -52,7 +52,7 @@ Let’s try removing references to `Address` in `EditPersonDescriptor`.
- :bulb: **Tip:** Removing usages may result in errors. Exercise discretion and fix them. For example, removing the `address` field from the `Person` class will require you to modify its constructor.
+ :bulb: **Tip:** Removing usages may result in errors. Exercise discretion and fix them. For example, removing the `address` field from the `Student` class will require you to modify its constructor.
1. Repeat the steps for the remaining usages of `Address`
@@ -63,13 +63,13 @@ After you are done, verify that the application still works by compiling and run
Unfortunately, there are usages of `Address` that IntelliJ IDEA cannot identify. You can find them by searching for instances of the word `address` in your code (`Edit` \> `Find` \> `Find in path`).
-Places of interest to look out for would be resources used by the application. `main/resources` contains images and `fxml` files used by the application and `test/resources` contains test data. For example, there is a `$address` in each `PersonCard` that has not been removed nor identified.
+Places of interest to look out for would be resources used by the application. `main/resources` contains images and `fxml` files used by the application and `test/resources` contains test data. For example, there is a `$address` in each `StudentCard` that has not been removed nor identified.
![$address](../images/remove/$address.png)
-A quick look at the `PersonCard` class and its `fxml` file quickly reveals why it slipped past the automated refactoring.
+A quick look at the `StudentCard` class and its `fxml` file quickly reveals why it slipped past the automated refactoring.
-**`PersonCard.java`**
+**`StudentCard.java`**
``` java
...
@@ -78,7 +78,7 @@ private Label address;
...
```
-**`PersonCard.fxml`**
+**`StudentCard.fxml`**
``` xml
...
@@ -96,12 +96,12 @@ At this point, your application is working as intended and all your tests are pa
In `src/test/data/`, data meant for testing purposes are stored. While keeping the `address` field in the json files does not cause the tests to fail, it is not good practice to let cruft from old features accumulate.
-**`invalidPersonAddressBook.json`:**
+**`invalidStudentAddressBook.json`:**
```json
{
- "persons": [ {
- "name": "Person with invalid name field: Ha!ns Mu@ster",
+ "students": [ {
+ "name": "Student with invalid name field: Ha!ns Mu@ster",
"phone": "9482424",
"email": "hans@example.com",
"address": "4th street"
diff --git a/docs/tutorials/TracingCode.md b/docs/tutorials/TracingCode.md
index 4fb62a83ef6..1344ed9e958 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.programmer.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.programmer.logic.Logic` (an extract given below) confirms that this indeed might be what we’re looking for.
```java
public interface Logic {
@@ -120,7 +120,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
CommandResult commandResult;
//Parse user input from String to a Command
- Command command = addressBookParser.parseCommand(commandText);
+ Command command = ProgrammerErrorParser.parseCommand(commandText);
//Executes the Command and stores the result
commandResult = command.execute(model);
@@ -141,7 +141,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
1. _Step over_ the logging code since it is of no interest to us now.
![StepOver](../images/tracing/StepOver.png)
-1. _Step into_ the line where user input in parsed from a String to a Command, which should bring you to the `AddressBookParser#parseCommand()` method (partial code given below):
+1. _Step into_ the line where user input in parsed from a String to a Command, which should bring you to the `ProgrammerErrorParser#parseCommand()` method (partial code given below):
``` java
public Command parseCommand(String userInput) throws ParseException {
...
@@ -171,7 +171,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
1. Stepping through the method shows that it calls `ArgumentTokenizer#tokenize()` and `ParserUtil#parseIndex()` to obtain the arguments and index required.
-1. The rest of the method seems to exhaustively check for the existence of each possible parameter of the `edit` command and store any possible changes in an `EditPersonDescriptor`. Recall that we can verify the contents of `editPersonDesciptor` through the 'Variables' window.
+1. The rest of the method seems to exhaustively check for the existence of each possible parameter of the `edit` command and store any possible changes in an `EditStudentDescriptor`. Recall that we can verify the contents of `editStudentDesciptor` through the 'Variables' window.
![EditCommand](../images/tracing/EditCommand.png)
1. As you just traced through some code involved in parsing a command, you can take a look at this class diagram to see where the various parsing-related classes you encountered fit into the design of the `Logic` component.
@@ -189,22 +189,22 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
@Override
public CommandResult execute(Model model) throws CommandException {
...
- Person personToEdit = lastShownList.get(index.getZeroBased());
- Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
- if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
+ Student studentToEdit = lastShownList.get(index.getZeroBased());
+ Student editedStudent = createEditedStudent(studentToEdit, editStudentDescriptor);
+ if (!studentToEdit.isSameStudent(editedStudent) && model.hasStudent(editedStudent)) {
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));
+ model.setStudent(studentToEdit, editedStudent);
+ model.updateFilteredStudentList(PREDICATE_SHOW_ALL_PERSONS);
+ return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedStudent));
}
```
1. As suspected, `command#execute()` does indeed make changes to the `model` object. Specifically,
- * it uses the `setPerson()` method (defined in the interface `Model` and implemented in `ModelManager` as per the usual pattern) to update the person data.
- * it uses the `updateFilteredPersonList` method to ask the `Model` to populate the 'filtered list' with _all_ persons.
- FYI, The 'filtered list' is the list of persons resulting from the most recent operation that will be shown to the user immediately after. For the `edit` command, we populate it with all the persons so that the user can see the edited person along with all other persons. If this was a `find` command, we would be setting that list to contain the search results instead.
- To provide some context, given below is the class diagram of the `Model` component. See if you can figure out where the 'filtered list' of persons is being tracked.
+ * it uses the `setStudent()` method (defined in the interface `Model` and implemented in `ModelManager` as per the usual pattern) to update the student data.
+ * it uses the `updateFilteredStudentList` method to ask the `Model` to populate the 'filtered list' with _all_ students.
+ FYI, The 'filtered list' is the list of students resulting from the most recent operation that will be shown to the user immediately after. For the `edit` command, we populate it with all the students so that the user can see the edited student along with all other students. If this was a `find` command, we would be setting that list to contain the search results instead.
+ To provide some context, given below is the class diagram of the `Model` component. See if you can figure out where the 'filtered list' of students is being tracked.
* :bulb: This may be a good time to read through the [`Model` component section of the DG](../DeveloperGuide.html#model-component)
@@ -231,15 +231,15 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
* {@code JsonSerializableAddressBook}.
*/
public JsonSerializableAddressBook(ReadOnlyAddressBook source) {
- persons.addAll(
- source.getPersonList()
+ students.addAll(
+ source.getStudentList()
.stream()
- .map(JsonAdaptedPerson::new)
+ .map(JsonAdaptedStudent::new)
.collect(Collectors.toList()));
}
```
-1. It appears that a `JsonAdaptedPerson` is created for each `Person` and then added to the `JsonSerializableAddressBook`.
+1. It appears that a `JsonAdaptedStudent` is created for each `Student` and then added to the `JsonSerializableAddressBook`.
This is because regular Java objects need to go through an _adaptation_ for them to be suitable to be saved in JSON format.
1. While you are stepping through the classes in the `Storage` component, here is the component's class diagram to help you understand how those classes fit into the structure of the component.
@@ -296,6 +296,6 @@ Here are some quick questions you can try to answer based on your execution path
4. Add a new command
- 5. Add a new field to `Person`
+ 5. Add a new field to `Student`
6. Add a new entity to the address book
diff --git a/sample_upload/validDataForUpload.csv b/sample_upload/validDataForUpload.csv
new file mode 100644
index 00000000000..54bebcf3f39
--- /dev/null
+++ b/sample_upload/validDataForUpload.csv
@@ -0,0 +1,37 @@
+studentId,classId,name,email
+A0212421H,B01,Allard Quek,e0518431@u.nus.edu
+A0214264D,B09,Ammamaria McJarrow,e0518239@u.nus.edu
+A0214272E,B07,Andra Caville,e0518247@u.nus.edu
+A0214265E,B10,Ansley Silverlock,e0518240@u.nus.edu
+A0214259D,B04,Bea Affron,e0518234@u.nus.edu
+A0214269B,B04,Berny Murie,e0518244@u.nus.edu
+A0224129E,B03,Cole Jacques,e0518253@u.nus.edu
+A0214260E,B05,Darn Siddons,e0518235@u.nus.edu
+A0212424H,B04,David Li,e0518641@u.nus.edu
+A0214257B,B02,Dennie Povey,e0518232@u.nus.edu
+A0214262B,B07,Ernst Sproston,e0518237@u.nus.edu
+A0212423H,B03,Erwin Quek,e0538441@u.nus.edu
+A0224130T,B04,Ferdinand Westrey,e0518254@u.nus.edu
+A0214267G,B02,Gavrielle Staner,e0518242@u.nus.edu
+A0214261A,B06,Inessa Mellmoth,e0518236@u.nus.edu
+A0212425H,B05,Irfan Ibrahim,e0558441@u.nus.edu
+A0224134B,B08,Judd Chatenet,e0518258@u.nus.edu
+A0224124F,B08,Kala Worsell,e0518248@u.nus.edu
+A0214258C,B03,Linette Mitri,e0518233@u.nus.edu
+A0224132D,B06,Meade Thomen,e0518256@u.nus.edu
+A0224133E,B07,Nadeen Kliemke,e0518257@u.nus.edu
+A0224126A,B10,Nancie Strivens,e0518250@u.nus.edu
+A0224135A,B09,Pebrook Chaim,e0518259@u.nus.edu
+A0214266F,B01,Perkin Tant,e0518241@u.nus.edu
+A0214256A,B01,Remington Meiner,e0518231@u.nus.edu
+A0214271D,B06,Ronnie Claworth,e0518246@u.nus.edu
+A0212426H,B06,Roy Balakrishnan,e0518481@u.nus.edu
+A0214268A,B03,Salomo Evreux,e0518243@u.nus.edu
+A0212422H,B02,Samay Sagar,e0513441@u.nus.edu
+A0224131G,B05,Sonja Hake,e0518255@u.nus.edu
+A0214270C,B05,Teirtza Fish,e0518245@u.nus.edu
+A0224128A,B02,Thorndike Conor,e0518252@u.nus.edu
+A0267423H,B07,Tom Jerry,e0535541@u.nus.edu
+A0214263C,B08,Trude Antwis,e0518238@u.nus.edu
+A0224125G,B09,Walker Hartzenberg,e0518249@u.nus.edu
+A0224127F,B01,Warde Mularkey,e0518251@u.nus.edu
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/FileUtil.java b/src/main/java/seedu/address/commons/util/FileUtil.java
deleted file mode 100644
index b1e2767cdd9..00000000000
--- a/src/main/java/seedu/address/commons/util/FileUtil.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package seedu.address.commons.util;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.InvalidPathException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-/**
- * Writes and reads files
- */
-public class FileUtil {
-
- private static final String CHARSET = "UTF-8";
-
- public static boolean isFileExists(Path file) {
- return Files.exists(file) && Files.isRegularFile(file);
- }
-
- /**
- * Returns true if {@code path} can be converted into a {@code Path} via {@link Paths#get(String)},
- * otherwise returns false.
- * @param path A string representing the file path. Cannot be null.
- */
- public static boolean isValidPath(String path) {
- try {
- Paths.get(path);
- } catch (InvalidPathException ipe) {
- return false;
- }
- return true;
- }
-
- /**
- * Creates a file if it does not exist along with its missing parent directories.
- * @throws IOException if the file or directory cannot be created.
- */
- public static void createIfMissing(Path file) throws IOException {
- if (!isFileExists(file)) {
- createFile(file);
- }
- }
-
- /**
- * Creates a file if it does not exist along with its missing parent directories.
- */
- public static void createFile(Path file) throws IOException {
- if (Files.exists(file)) {
- return;
- }
-
- createParentDirsOfFile(file);
-
- Files.createFile(file);
- }
-
- /**
- * Creates parent directories of file if it has a parent directory
- */
- public static void createParentDirsOfFile(Path file) throws IOException {
- Path parentDir = file.getParent();
-
- if (parentDir != null) {
- Files.createDirectories(parentDir);
- }
- }
-
- /**
- * Assumes file exists
- */
- public static String readFromFile(Path file) throws IOException {
- return new String(Files.readAllBytes(file), CHARSET);
- }
-
- /**
- * Writes given string to a file.
- * Will create the file if it does not exist yet.
- */
- public static void writeToFile(Path file, String content) throws IOException {
- Files.write(file, content.getBytes(CHARSET));
- }
-
-}
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/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java
deleted file mode 100644
index 9d9c6d15bdc..00000000000
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package seedu.address.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;
-
-/**
- * The main LogicManager of the app.
- */
-public class LogicManager implements Logic {
- public static final String FILE_OPS_ERROR_MESSAGE = "Could not save data to file: ";
- private final Logger logger = LogsCenter.getLogger(LogicManager.class);
-
- private final Model model;
- private final Storage storage;
- private final AddressBookParser addressBookParser;
-
- /**
- * Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}.
- */
- public LogicManager(Model model, Storage storage) {
- this.model = model;
- this.storage = storage;
- addressBookParser = new AddressBookParser();
- }
-
- @Override
- public CommandResult execute(String commandText) throws CommandException, ParseException {
- logger.info("----------------[USER COMMAND][" + commandText + "]");
-
- CommandResult commandResult;
- Command command = addressBookParser.parseCommand(commandText);
- commandResult = command.execute(model);
-
- try {
- storage.saveAddressBook(model.getAddressBook());
- } catch (IOException ioe) {
- throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe);
- }
-
- return commandResult;
- }
-
- @Override
- public ReadOnlyAddressBook getAddressBook() {
- return model.getAddressBook();
- }
-
- @Override
- public ObservableList getFilteredPersonList() {
- return model.getFilteredPersonList();
- }
-
- @Override
- public Path getAddressBookFilePath() {
- return model.getAddressBookFilePath();
- }
-
- @Override
- public GuiSettings getGuiSettings() {
- return model.getGuiSettings();
- }
-
- @Override
- public void setGuiSettings(GuiSettings guiSettings) {
- model.setGuiSettings(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/CommandResult.java b/src/main/java/seedu/address/logic/commands/CommandResult.java
deleted file mode 100644
index 92f900b7916..00000000000
--- a/src/main/java/seedu/address/logic/commands/CommandResult.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.Objects;
-
-/**
- * Represents the result of a command execution.
- */
-public class CommandResult {
-
- private final String feedbackToUser;
-
- /** Help information should be shown to the user. */
- private final boolean showHelp;
-
- /** The application should exit. */
- private final boolean exit;
-
- /**
- * Constructs a {@code CommandResult} with the specified fields.
- */
- public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
- this.feedbackToUser = requireNonNull(feedbackToUser);
- this.showHelp = showHelp;
- this.exit = exit;
- }
-
- /**
- * Constructs a {@code CommandResult} with the specified {@code feedbackToUser},
- * and other fields set to their default value.
- */
- public CommandResult(String feedbackToUser) {
- this(feedbackToUser, false, false);
- }
-
- public String getFeedbackToUser() {
- return feedbackToUser;
- }
-
- public boolean isShowHelp() {
- return showHelp;
- }
-
- public boolean isExit() {
- return exit;
- }
-
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof CommandResult)) {
- return false;
- }
-
- CommandResult otherCommandResult = (CommandResult) other;
- return feedbackToUser.equals(otherCommandResult.feedbackToUser)
- && showHelp == otherCommandResult.showHelp
- && exit == otherCommandResult.exit;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(feedbackToUser, showHelp, exit);
- }
-
-}
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/ExitCommand.java b/src/main/java/seedu/address/logic/commands/ExitCommand.java
deleted file mode 100644
index 3dd85a8ba90..00000000000
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package seedu.address.logic.commands;
-
-import seedu.address.model.Model;
-
-/**
- * Terminates the program.
- */
-public class ExitCommand extends Command {
-
- public static final String COMMAND_WORD = "exit";
-
- public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ...";
-
- @Override
- public CommandResult execute(Model model) {
- return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
- }
-
-}
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/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java
deleted file mode 100644
index bf824f91bd0..00000000000
--- a/src/main/java/seedu/address/logic/commands/HelpCommand.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package seedu.address.logic.commands;
-
-import seedu.address.model.Model;
-
-/**
- * Format full help instructions for every command for display.
- */
-public class HelpCommand extends Command {
-
- public static final String COMMAND_WORD = "help";
-
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows program usage instructions.\n"
- + "Example: " + COMMAND_WORD;
-
- public static final String SHOWING_HELP_MESSAGE = "Opened help window.";
-
- @Override
- public CommandResult execute(Model model) {
- return new CommandResult(SHOWING_HELP_MESSAGE, true, false);
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java
deleted file mode 100644
index 84be6ad2596..00000000000
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
-
-import seedu.address.model.Model;
-
-/**
- * Lists all persons in the address book to the user.
- */
-public class ListCommand extends Command {
-
- public static final String COMMAND_WORD = "list";
-
- public static final String MESSAGE_SUCCESS = "Listed all persons";
-
-
- @Override
- public CommandResult execute(Model model) {
- requireNonNull(model);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(MESSAGE_SUCCESS);
- }
-}
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
deleted file mode 100644
index 3b8bfa035e8..00000000000
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import java.util.Set;
-import java.util.stream.Stream;
-
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Parses input arguments and creates a new AddCommand object
- */
-public class AddCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the AddCommand
- * and returns an AddCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public AddCommand parse(String args) throws ParseException {
- ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
-
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
- || !argMultimap.getPreamble().isEmpty()) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
- }
-
- Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
- Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get());
- Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get());
- Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get());
- Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
-
- Person person = new Person(name, phone, email, address, tagList);
-
- return new AddCommand(person);
- }
-
- /**
- * Returns true if none of the prefixes contains empty {@code Optional} values in the given
- * {@code ArgumentMultimap}.
- */
- private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
- return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
deleted file mode 100644
index 1e466792b46..00000000000
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.commons.core.Messages.MESSAGE_UNKNOWN_COMMAND;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.commands.ClearCommand;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.commands.DeleteCommand;
-import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.ExitCommand;
-import seedu.address.logic.commands.FindCommand;
-import seedu.address.logic.commands.HelpCommand;
-import seedu.address.logic.commands.ListCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
-
-/**
- * Parses user input.
- */
-public class AddressBookParser {
-
- /**
- * Used for initial separation of command word and args.
- */
- private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)");
-
- /**
- * Parses user input into command for execution.
- *
- * @param userInput full user input string
- * @return the command based on the user input
- * @throws ParseException if the user input does not conform the expected format
- */
- public Command parseCommand(String userInput) throws ParseException {
- final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
- if (!matcher.matches()) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
- }
-
- final String commandWord = matcher.group("commandWord");
- final String arguments = matcher.group("arguments");
- switch (commandWord) {
-
- case AddCommand.COMMAND_WORD:
- return new AddCommandParser().parse(arguments);
-
- case EditCommand.COMMAND_WORD:
- return new EditCommandParser().parse(arguments);
-
- case DeleteCommand.COMMAND_WORD:
- return new DeleteCommandParser().parse(arguments);
-
- case ClearCommand.COMMAND_WORD:
- return new ClearCommand();
-
- case FindCommand.COMMAND_WORD:
- return new FindCommandParser().parse(arguments);
-
- case ListCommand.COMMAND_WORD:
- return new ListCommand();
-
- case ExitCommand.COMMAND_WORD:
- return new ExitCommand();
-
- case HelpCommand.COMMAND_WORD:
- return new HelpCommand();
-
- default:
- throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
- }
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/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/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
deleted file mode 100644
index 845644b7dea..00000000000
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package seedu.address.logic.parser;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Optional;
-import java.util.Set;
-
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.tag.Tag;
-
-/**
- * Parses input arguments and creates a new EditCommand object
- */
-public class EditCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the EditCommand
- * and returns an EditCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public EditCommand parse(String args) throws ParseException {
- requireNonNull(args);
- ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
-
- Index index;
-
- try {
- index = ParserUtil.parseIndex(argMultimap.getPreamble());
- } catch (ParseException pe) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe);
- }
-
- EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
- if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
- editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
- }
- if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
- editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
- }
- if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
- editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
- }
- if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
- editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
- }
- parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
-
- if (!editPersonDescriptor.isAnyFieldEdited()) {
- throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
- }
-
- return new EditCommand(index, editPersonDescriptor);
- }
-
- /**
- * Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty.
- * If {@code tags} contain only one element which is an empty string, it will be parsed into a
- * {@code Set} containing zero tags.
- */
- private Optional> parseTagsForEdit(Collection tags) throws ParseException {
- assert tags != null;
-
- if (tags.isEmpty()) {
- return Optional.empty();
- }
- Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
- return Optional.of(ParserUtil.parseTags(tagSet));
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
deleted file mode 100644
index 4fb71f23103..00000000000
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-
-import java.util.Arrays;
-
-import seedu.address.logic.commands.FindCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-
-/**
- * Parses input arguments and creates a new FindCommand object
- */
-public class FindCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the FindCommand
- * and returns a FindCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public FindCommand parse(String args) throws ParseException {
- String trimmedArgs = args.trim();
- if (trimmedArgs.isEmpty()) {
- throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
- }
-
- String[] nameKeywords = trimmedArgs.split("\\s+");
-
- return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
deleted file mode 100644
index b117acb9c55..00000000000
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package seedu.address.logic.parser;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-import seedu.address.commons.core.index.Index;
-import seedu.address.commons.util.StringUtil;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Contains utility methods used for parsing strings in the various *Parser classes.
- */
-public class ParserUtil {
-
- public static final String MESSAGE_INVALID_INDEX = "Index is not a non-zero unsigned integer.";
-
- /**
- * Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be
- * trimmed.
- * @throws ParseException if the specified index is invalid (not non-zero unsigned integer).
- */
- public static Index parseIndex(String oneBasedIndex) throws ParseException {
- String trimmedIndex = oneBasedIndex.trim();
- if (!StringUtil.isNonZeroUnsignedInteger(trimmedIndex)) {
- throw new ParseException(MESSAGE_INVALID_INDEX);
- }
- return Index.fromOneBased(Integer.parseInt(trimmedIndex));
- }
-
- /**
- * Parses a {@code String name} into a {@code Name}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code name} is invalid.
- */
- public static Name parseName(String name) throws ParseException {
- requireNonNull(name);
- String trimmedName = name.trim();
- if (!Name.isValidName(trimmedName)) {
- throw new ParseException(Name.MESSAGE_CONSTRAINTS);
- }
- return new Name(trimmedName);
- }
-
- /**
- * Parses a {@code String phone} into a {@code Phone}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code phone} is invalid.
- */
- public static Phone parsePhone(String phone) throws ParseException {
- requireNonNull(phone);
- String trimmedPhone = phone.trim();
- if (!Phone.isValidPhone(trimmedPhone)) {
- throw new ParseException(Phone.MESSAGE_CONSTRAINTS);
- }
- return new Phone(trimmedPhone);
- }
-
- /**
- * Parses a {@code String address} into an {@code Address}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code address} is invalid.
- */
- public static Address parseAddress(String address) throws ParseException {
- requireNonNull(address);
- String trimmedAddress = address.trim();
- if (!Address.isValidAddress(trimmedAddress)) {
- throw new ParseException(Address.MESSAGE_CONSTRAINTS);
- }
- return new Address(trimmedAddress);
- }
-
- /**
- * Parses a {@code String email} into an {@code Email}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code email} is invalid.
- */
- public static Email parseEmail(String email) throws ParseException {
- requireNonNull(email);
- String trimmedEmail = email.trim();
- if (!Email.isValidEmail(trimmedEmail)) {
- throw new ParseException(Email.MESSAGE_CONSTRAINTS);
- }
- return new Email(trimmedEmail);
- }
-
- /**
- * Parses a {@code String tag} into a {@code Tag}.
- * Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code tag} is invalid.
- */
- public static Tag parseTag(String tag) throws ParseException {
- requireNonNull(tag);
- String trimmedTag = tag.trim();
- if (!Tag.isValidTagName(trimmedTag)) {
- throw new ParseException(Tag.MESSAGE_CONSTRAINTS);
- }
- return new Tag(trimmedTag);
- }
-
- /**
- * Parses {@code Collection tags} into a {@code Set}.
- */
- public static Set parseTags(Collection tags) throws ParseException {
- requireNonNull(tags);
- final Set tagSet = new HashSet<>();
- for (String tagName : tags) {
- tagSet.add(parseTag(tagName));
- }
- return tagSet;
- }
-}
diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java
deleted file mode 100644
index 1a943a0781a..00000000000
--- a/src/main/java/seedu/address/model/AddressBook.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package seedu.address.model;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.List;
-
-import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.UniquePersonList;
-
-/**
- * Wraps all data at the address-book level
- * Duplicates are not allowed (by .isSamePerson comparison)
- */
-public class AddressBook implements ReadOnlyAddressBook {
-
- private final UniquePersonList persons;
-
- /*
- * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
- * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
- *
- * Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication
- * among constructors.
- */
- {
- persons = new UniquePersonList();
- }
-
- public AddressBook() {}
-
- /**
- * Creates an AddressBook using the Persons in the {@code toBeCopied}
- */
- public AddressBook(ReadOnlyAddressBook toBeCopied) {
- this();
- resetData(toBeCopied);
- }
-
- //// list overwrite operations
-
- /**
- * Replaces the contents of the person list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
- */
- public void setPersons(List persons) {
- this.persons.setPersons(persons);
- }
-
- /**
- * Resets the existing data of this {@code AddressBook} with {@code newData}.
- */
- public void resetData(ReadOnlyAddressBook newData) {
- requireNonNull(newData);
-
- setPersons(newData.getPersonList());
- }
-
- //// person-level operations
-
- /**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
- */
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return persons.contains(person);
- }
-
- /**
- * Adds a person to the address book.
- * The person must not already exist in the address book.
- */
- public void addPerson(Person p) {
- persons.add(p);
- }
-
- /**
- * Replaces the given person {@code target} in the list with {@code editedPerson}.
- * {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
- */
- public void setPerson(Person target, Person editedPerson) {
- requireNonNull(editedPerson);
-
- persons.setPerson(target, editedPerson);
- }
-
- /**
- * Removes {@code key} from this {@code AddressBook}.
- * {@code key} must exist in the address book.
- */
- public void removePerson(Person key) {
- persons.remove(key);
- }
-
- //// util methods
-
- @Override
- public String toString() {
- return persons.asUnmodifiableObservableList().size() + " persons";
- // TODO: refine later
- }
-
- @Override
- public ObservableList getPersonList() {
- return persons.asUnmodifiableObservableList();
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof AddressBook // instanceof handles nulls
- && persons.equals(((AddressBook) other).persons));
- }
-
- @Override
- public int hashCode() {
- return persons.hashCode();
- }
-}
diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java
deleted file mode 100644
index d54df471c1f..00000000000
--- a/src/main/java/seedu/address/model/Model.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package seedu.address.model;
-
-import java.nio.file.Path;
-import java.util.function.Predicate;
-
-import javafx.collections.ObservableList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.model.person.Person;
-
-/**
- * The API of the Model component.
- */
-public interface Model {
- /** {@code Predicate} that always evaluate to true */
- Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true;
-
- /**
- * Replaces user prefs data with the data in {@code userPrefs}.
- */
- void setUserPrefs(ReadOnlyUserPrefs userPrefs);
-
- /**
- * Returns the user prefs.
- */
- ReadOnlyUserPrefs getUserPrefs();
-
- /**
- * Returns the user prefs' GUI settings.
- */
- GuiSettings getGuiSettings();
-
- /**
- * Sets the user prefs' GUI settings.
- */
- void setGuiSettings(GuiSettings guiSettings);
-
- /**
- * Returns the user prefs' address book file path.
- */
- Path getAddressBookFilePath();
-
- /**
- * Sets the user prefs' address book file path.
- */
- void setAddressBookFilePath(Path addressBookFilePath);
-
- /**
- * Replaces address book data with the data in {@code addressBook}.
- */
- void setAddressBook(ReadOnlyAddressBook addressBook);
-
- /** Returns the AddressBook */
- ReadOnlyAddressBook getAddressBook();
-
- /**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
- */
- boolean hasPerson(Person person);
-
- /**
- * Deletes the given person.
- * The person must exist in the address book.
- */
- void deletePerson(Person target);
-
- /**
- * Adds the given person.
- * {@code person} must not already exist in the address book.
- */
- void addPerson(Person person);
-
- /**
- * Replaces the given person {@code target} with {@code editedPerson}.
- * {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
- */
- void setPerson(Person target, Person editedPerson);
-
- /** Returns an unmodifiable view of the filtered person list */
- ObservableList getFilteredPersonList();
-
- /**
- * Updates the filter of the filtered person list to filter by the given {@code predicate}.
- * @throws NullPointerException if {@code predicate} is null.
- */
- void updateFilteredPersonList(Predicate predicate);
-}
diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java
deleted file mode 100644
index 0650c954f5c..00000000000
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package seedu.address.model;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.nio.file.Path;
-import java.util.function.Predicate;
-import java.util.logging.Logger;
-
-import javafx.collections.ObservableList;
-import javafx.collections.transformation.FilteredList;
-import seedu.address.commons.core.GuiSettings;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.model.person.Person;
-
-/**
- * Represents the in-memory model of the address book data.
- */
-public class ModelManager implements Model {
- private static final Logger logger = LogsCenter.getLogger(ModelManager.class);
-
- private final AddressBook addressBook;
- private final UserPrefs userPrefs;
- private final FilteredList filteredPersons;
-
- /**
- * Initializes a ModelManager with the given addressBook and userPrefs.
- */
- public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) {
- super();
- requireAllNonNull(addressBook, userPrefs);
-
- logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs);
-
- this.addressBook = new AddressBook(addressBook);
- this.userPrefs = new UserPrefs(userPrefs);
- filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
- }
-
- public ModelManager() {
- this(new AddressBook(), new UserPrefs());
- }
-
- //=========== UserPrefs ==================================================================================
-
- @Override
- public void setUserPrefs(ReadOnlyUserPrefs userPrefs) {
- requireNonNull(userPrefs);
- this.userPrefs.resetData(userPrefs);
- }
-
- @Override
- public ReadOnlyUserPrefs getUserPrefs() {
- return userPrefs;
- }
-
- @Override
- public GuiSettings getGuiSettings() {
- return userPrefs.getGuiSettings();
- }
-
- @Override
- public void setGuiSettings(GuiSettings guiSettings) {
- requireNonNull(guiSettings);
- userPrefs.setGuiSettings(guiSettings);
- }
-
- @Override
- public Path getAddressBookFilePath() {
- return userPrefs.getAddressBookFilePath();
- }
-
- @Override
- public void setAddressBookFilePath(Path addressBookFilePath) {
- requireNonNull(addressBookFilePath);
- userPrefs.setAddressBookFilePath(addressBookFilePath);
- }
-
- //=========== AddressBook ================================================================================
-
- @Override
- public void setAddressBook(ReadOnlyAddressBook addressBook) {
- this.addressBook.resetData(addressBook);
- }
-
- @Override
- public ReadOnlyAddressBook getAddressBook() {
- return addressBook;
- }
-
- @Override
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return addressBook.hasPerson(person);
- }
-
- @Override
- public void deletePerson(Person target) {
- addressBook.removePerson(target);
- }
-
- @Override
- public void addPerson(Person person) {
- addressBook.addPerson(person);
- updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- }
-
- @Override
- public void setPerson(Person target, Person editedPerson) {
- requireAllNonNull(target, editedPerson);
-
- addressBook.setPerson(target, editedPerson);
- }
-
- //=========== Filtered Person List Accessors =============================================================
-
- /**
- * Returns an unmodifiable view of the list of {@code Person} backed by the internal list of
- * {@code versionedAddressBook}
- */
- @Override
- public ObservableList getFilteredPersonList() {
- return filteredPersons;
- }
-
- @Override
- public void updateFilteredPersonList(Predicate predicate) {
- requireNonNull(predicate);
- filteredPersons.setPredicate(predicate);
- }
-
- @Override
- public boolean equals(Object obj) {
- // short circuit if same object
- if (obj == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(obj instanceof ModelManager)) {
- return false;
- }
-
- // state check
- ModelManager other = (ModelManager) obj;
- return addressBook.equals(other.addressBook)
- && userPrefs.equals(other.userPrefs)
- && filteredPersons.equals(other.filteredPersons);
- }
-
-}
diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
deleted file mode 100644
index 6ddc2cd9a29..00000000000
--- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package seedu.address.model;
-
-import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-
-/**
- * Unmodifiable view of an address book
- */
-public interface ReadOnlyAddressBook {
-
- /**
- * Returns an unmodifiable view of the persons list.
- * This list will not contain any duplicate persons.
- */
- ObservableList getPersonList();
-
-}
diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/person/Address.java
deleted file mode 100644
index 60472ca22a0..00000000000
--- a/src/main/java/seedu/address/model/person/Address.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Person's address in the address book.
- * Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)}
- */
-public class Address {
-
- public static final String MESSAGE_CONSTRAINTS = "Addresses can take any values, and it should not be blank";
-
- /*
- * The first character of the address must not be a whitespace,
- * otherwise " " (a blank string) becomes a valid input.
- */
- public static final String VALIDATION_REGEX = "[^\\s].*";
-
- public final String value;
-
- /**
- * Constructs an {@code Address}.
- *
- * @param address A valid address.
- */
- public Address(String address) {
- requireNonNull(address);
- checkArgument(isValidAddress(address), MESSAGE_CONSTRAINTS);
- value = address;
- }
-
- /**
- * Returns true if a given string is a valid email.
- */
- public static boolean isValidAddress(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public String toString() {
- return value;
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Address // instanceof handles nulls
- && value.equals(((Address) other).value)); // state check
- }
-
- @Override
- public int hashCode() {
- return value.hashCode();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/seedu/address/model/person/Email.java
deleted file mode 100644
index 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/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/tag/Tag.java b/src/main/java/seedu/address/model/tag/Tag.java
deleted file mode 100644
index b0ea7e7dad7..00000000000
--- a/src/main/java/seedu/address/model/tag/Tag.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package seedu.address.model.tag;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Tag in the address book.
- * 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 final String tagName;
-
- /**
- * Constructs a {@code Tag}.
- *
- * @param tagName A valid tag name.
- */
- public Tag(String tagName) {
- requireNonNull(tagName);
- checkArgument(isValidTagName(tagName), MESSAGE_CONSTRAINTS);
- this.tagName = tagName;
- }
-
- /**
- * Returns true if a given string is a valid tag name.
- */
- public static boolean isValidTagName(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof Tag // instanceof handles nulls
- && tagName.equals(((Tag) other).tagName)); // state check
- }
-
- @Override
- public int hashCode() {
- return tagName.hashCode();
- }
-
- /**
- * Format state as text for viewing.
- */
- public String toString() {
- return '[' + tagName + ']';
- }
-
-}
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/JsonAdaptedTag.java b/src/main/java/seedu/address/storage/JsonAdaptedTag.java
deleted file mode 100644
index 0df22bdb754..00000000000
--- a/src/main/java/seedu/address/storage/JsonAdaptedTag.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package seedu.address.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;
-
-/**
- * Jackson-friendly version of {@link Tag}.
- */
-class JsonAdaptedTag {
-
- private final String tagName;
-
- /**
- * Constructs a {@code JsonAdaptedTag} with the given {@code tagName}.
- */
- @JsonCreator
- public JsonAdaptedTag(String tagName) {
- this.tagName = tagName;
- }
-
- /**
- * Converts a given {@code Tag} into this class for Jackson use.
- */
- public JsonAdaptedTag(Tag source) {
- tagName = source.tagName;
- }
-
- @JsonValue
- public String getTagName() {
- return tagName;
- }
-
- /**
- * Converts this Jackson-friendly adapted tag object into the model's {@code Tag} object.
- *
- * @throws IllegalValueException if there were any data constraints violated in the adapted tag.
- */
- public Tag toModelType() throws IllegalValueException {
- if (!Tag.isValidTagName(tagName)) {
- throw new IllegalValueException(Tag.MESSAGE_CONSTRAINTS);
- }
- return new Tag(tagName);
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java b/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
deleted file mode 100644
index dfab9daaa0d..00000000000
--- a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package seedu.address.storage;
-
-import static java.util.Objects.requireNonNull;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-import java.util.logging.Logger;
-
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.commons.util.FileUtil;
-import seedu.address.commons.util.JsonUtil;
-import seedu.address.model.ReadOnlyAddressBook;
-
-/**
- * A class to access AddressBook data stored as a json file on the hard disk.
- */
-public class JsonAddressBookStorage implements AddressBookStorage {
-
- private static final Logger logger = LogsCenter.getLogger(JsonAddressBookStorage.class);
-
- private Path filePath;
-
- public JsonAddressBookStorage(Path filePath) {
- this.filePath = filePath;
- }
-
- public Path getAddressBookFilePath() {
- return filePath;
- }
-
- @Override
- public Optional readAddressBook() throws DataConversionException {
- return readAddressBook(filePath);
- }
-
- /**
- * Similar to {@link #readAddressBook()}.
- *
- * @param filePath location of the data. Cannot be null.
- * @throws DataConversionException if the file is not in the correct format.
- */
- public Optional readAddressBook(Path filePath) throws DataConversionException {
- requireNonNull(filePath);
-
- Optional jsonAddressBook = JsonUtil.readJsonFile(
- filePath, JsonSerializableAddressBook.class);
- if (!jsonAddressBook.isPresent()) {
- return Optional.empty();
- }
-
- try {
- return Optional.of(jsonAddressBook.get().toModelType());
- } catch (IllegalValueException ive) {
- logger.info("Illegal values found in " + filePath + ": " + ive.getMessage());
- throw new DataConversionException(ive);
- }
- }
-
- @Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, filePath);
- }
-
- /**
- * Similar to {@link #saveAddressBook(ReadOnlyAddressBook)}.
- *
- * @param filePath location of the data. Cannot be null.
- */
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
- requireNonNull(addressBook);
- requireNonNull(filePath);
-
- FileUtil.createIfMissing(filePath);
- JsonUtil.saveJsonFile(new JsonSerializableAddressBook(addressBook), filePath);
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
deleted file mode 100644
index 5efd834091d..00000000000
--- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package seedu.address.storage;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonRootName;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
-
-/**
- * An Immutable AddressBook that is serializable to JSON format.
- */
-@JsonRootName(value = "addressbook")
-class JsonSerializableAddressBook {
-
- public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s).";
-
- private final List persons = new ArrayList<>();
-
- /**
- * Constructs a {@code JsonSerializableAddressBook} with the given persons.
- */
- @JsonCreator
- public JsonSerializableAddressBook(@JsonProperty("persons") List persons) {
- this.persons.addAll(persons);
- }
-
- /**
- * Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use.
- *
- * @param source future changes to this will not affect the created {@code JsonSerializableAddressBook}.
- */
- public JsonSerializableAddressBook(ReadOnlyAddressBook source) {
- persons.addAll(source.getPersonList().stream().map(JsonAdaptedPerson::new).collect(Collectors.toList()));
- }
-
- /**
- * Converts this address book into the model's {@code AddressBook} object.
- *
- * @throws IllegalValueException if there were any data constraints violated.
- */
- public AddressBook toModelType() throws IllegalValueException {
- AddressBook addressBook = new AddressBook();
- for (JsonAdaptedPerson jsonAdaptedPerson : persons) {
- Person person = jsonAdaptedPerson.toModelType();
- if (addressBook.hasPerson(person)) {
- throw new IllegalValueException(MESSAGE_DUPLICATE_PERSON);
- }
- addressBook.addPerson(person);
- }
- return addressBook;
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/seedu/address/storage/Storage.java
deleted file mode 100644
index beda8bd9f11..00000000000
--- a/src/main/java/seedu/address/storage/Storage.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
-
-/**
- * API of the Storage component
- */
-public interface Storage extends AddressBookStorage, UserPrefsStorage {
-
- @Override
- Optional readUserPrefs() throws DataConversionException, IOException;
-
- @Override
- void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException;
-
- @Override
- Path getAddressBookFilePath();
-
- @Override
- Optional readAddressBook() throws DataConversionException, IOException;
-
- @Override
- void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException;
-
-}
diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/address/storage/StorageManager.java
deleted file mode 100644
index 79868290974..00000000000
--- a/src/main/java/seedu/address/storage/StorageManager.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-import java.util.logging.Logger;
-
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
-
-/**
- * Manages storage of AddressBook data in local storage.
- */
-public class StorageManager implements Storage {
-
- private static final Logger logger = LogsCenter.getLogger(StorageManager.class);
- private AddressBookStorage addressBookStorage;
- private UserPrefsStorage userPrefsStorage;
-
- /**
- * Creates a {@code StorageManager} with the given {@code AddressBookStorage} and {@code UserPrefStorage}.
- */
- public StorageManager(AddressBookStorage addressBookStorage, UserPrefsStorage userPrefsStorage) {
- super();
- this.addressBookStorage = addressBookStorage;
- this.userPrefsStorage = userPrefsStorage;
- }
-
- // ================ UserPrefs methods ==============================
-
- @Override
- public Path getUserPrefsFilePath() {
- return userPrefsStorage.getUserPrefsFilePath();
- }
-
- @Override
- public Optional readUserPrefs() throws DataConversionException, IOException {
- return userPrefsStorage.readUserPrefs();
- }
-
- @Override
- public void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException {
- userPrefsStorage.saveUserPrefs(userPrefs);
- }
-
-
- // ================ AddressBook methods ==============================
-
- @Override
- public Path getAddressBookFilePath() {
- return addressBookStorage.getAddressBookFilePath();
- }
-
- @Override
- public Optional readAddressBook() throws DataConversionException, IOException {
- return readAddressBook(addressBookStorage.getAddressBookFilePath());
- }
-
- @Override
- public Optional readAddressBook(Path filePath) throws DataConversionException, IOException {
- logger.fine("Attempting to read data from file: " + filePath);
- return addressBookStorage.readAddressBook(filePath);
- }
-
- @Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, addressBookStorage.getAddressBookFilePath());
- }
-
- @Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
- logger.fine("Attempting to write to data file: " + filePath);
- addressBookStorage.saveAddressBook(addressBook, filePath);
- }
-
-}
diff --git a/src/main/java/seedu/address/ui/CommandBox.java b/src/main/java/seedu/address/ui/CommandBox.java
deleted file mode 100644
index 9e75478664b..00000000000
--- a/src/main/java/seedu/address/ui/CommandBox.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package seedu.address.ui;
-
-import javafx.collections.ObservableList;
-import javafx.fxml.FXML;
-import javafx.scene.control.TextField;
-import javafx.scene.layout.Region;
-import seedu.address.logic.commands.CommandResult;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.logic.parser.exceptions.ParseException;
-
-/**
- * The UI component that is responsible for receiving user command inputs.
- */
-public class CommandBox extends UiPart {
-
- public static final String ERROR_STYLE_CLASS = "error";
- private static final String FXML = "CommandBox.fxml";
-
- private final CommandExecutor commandExecutor;
-
- @FXML
- private TextField commandTextField;
-
- /**
- * Creates a {@code CommandBox} with the given {@code CommandExecutor}.
- */
- public CommandBox(CommandExecutor commandExecutor) {
- super(FXML);
- this.commandExecutor = commandExecutor;
- // calls #setStyleToDefault() whenever there is a change to the text of the command box.
- commandTextField.textProperty().addListener((unused1, unused2, unused3) -> setStyleToDefault());
- }
-
- /**
- * Handles the Enter button pressed event.
- */
- @FXML
- private void handleCommandEntered() {
- String commandText = commandTextField.getText();
- if (commandText.equals("")) {
- return;
- }
-
- try {
- commandExecutor.execute(commandText);
- commandTextField.setText("");
- } catch (CommandException | ParseException e) {
- setStyleToIndicateCommandFailure();
- }
- }
-
- /**
- * Sets the command box style to use the default style.
- */
- private void setStyleToDefault() {
- commandTextField.getStyleClass().remove(ERROR_STYLE_CLASS);
- }
-
- /**
- * Sets the command box style to indicate a failed command.
- */
- private void setStyleToIndicateCommandFailure() {
- ObservableList styleClass = commandTextField.getStyleClass();
-
- if (styleClass.contains(ERROR_STYLE_CLASS)) {
- return;
- }
-
- styleClass.add(ERROR_STYLE_CLASS);
- }
-
- /**
- * Represents a function that can execute commands.
- */
- @FunctionalInterface
- public interface CommandExecutor {
- /**
- * Executes the command and returns the result.
- *
- * @see seedu.address.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/address/ui/HelpWindow.java
deleted file mode 100644
index 9a665915949..00000000000
--- a/src/main/java/seedu/address/ui/HelpWindow.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package seedu.address.ui;
-
-import java.util.logging.Logger;
-
-import javafx.fxml.FXML;
-import javafx.scene.control.Button;
-import javafx.scene.control.Label;
-import javafx.scene.input.Clipboard;
-import javafx.scene.input.ClipboardContent;
-import javafx.stage.Stage;
-import seedu.address.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;
-
- private static final Logger logger = LogsCenter.getLogger(HelpWindow.class);
- private static final String FXML = "HelpWindow.fxml";
-
- @FXML
- private Button copyButton;
-
- @FXML
- private Label helpMessage;
-
- /**
- * Creates a new HelpWindow.
- *
- * @param root Stage to use as the root of the HelpWindow.
- */
- public HelpWindow(Stage root) {
- super(FXML, root);
- helpMessage.setText(HELP_MESSAGE);
- }
-
- /**
- * Creates a new HelpWindow.
- */
- public HelpWindow() {
- this(new Stage());
- }
-
- /**
- * Shows the help window.
- * @throws IllegalStateException
- *
- *
- * if this method is called on a thread other than the JavaFX Application Thread.
- *
- *
- * if this method is called during animation or layout processing.
- *
- *
- * if this method is called on the primary stage.
- *
- *
- * if {@code dialogStage} is already showing.
- *
- *
- */
- public void show() {
- logger.fine("Showing help page about the application.");
- getRoot().show();
- getRoot().centerOnScreen();
- }
-
- /**
- * Returns true if the help window is currently being shown.
- */
- public boolean isShowing() {
- return getRoot().isShowing();
- }
-
- /**
- * Hides the help window.
- */
- public void hide() {
- getRoot().hide();
- }
-
- /**
- * Focuses on the help window.
- */
- public void focus() {
- getRoot().requestFocus();
- }
-
- /**
- * Copies the URL to the user guide to the clipboard.
- */
- @FXML
- private void copyUrl() {
- final Clipboard clipboard = Clipboard.getSystemClipboard();
- final ClipboardContent url = new ClipboardContent();
- url.putString(USERGUIDE_URL);
- clipboard.setContent(url);
- }
-}
diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java
deleted file mode 100644
index 9106c3aa6e5..00000000000
--- a/src/main/java/seedu/address/ui/MainWindow.java
+++ /dev/null
@@ -1,196 +0,0 @@
-package seedu.address.ui;
-
-import java.util.logging.Logger;
-
-import javafx.event.ActionEvent;
-import javafx.fxml.FXML;
-import javafx.scene.control.MenuItem;
-import javafx.scene.control.TextInputControl;
-import javafx.scene.input.KeyCombination;
-import javafx.scene.input.KeyEvent;
-import javafx.scene.layout.StackPane;
-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;
-
-/**
- * The Main Window. Provides the basic application layout containing
- * a menu bar and space where other JavaFX elements can be placed.
- */
-public class MainWindow extends UiPart {
-
- private static final String FXML = "MainWindow.fxml";
-
- private final Logger logger = LogsCenter.getLogger(getClass());
-
- private Stage primaryStage;
- private Logic logic;
-
- // Independent Ui parts residing in this Ui container
- private PersonListPanel personListPanel;
- private ResultDisplay resultDisplay;
- private HelpWindow helpWindow;
-
- @FXML
- private StackPane commandBoxPlaceholder;
-
- @FXML
- private MenuItem helpMenuItem;
-
- @FXML
- private StackPane personListPanelPlaceholder;
-
- @FXML
- private StackPane resultDisplayPlaceholder;
-
- @FXML
- private StackPane statusbarPlaceholder;
-
- /**
- * Creates a {@code MainWindow} with the given {@code Stage} and {@code Logic}.
- */
- public MainWindow(Stage primaryStage, Logic logic) {
- super(FXML, primaryStage);
-
- // Set dependencies
- this.primaryStage = primaryStage;
- this.logic = logic;
-
- // Configure the UI
- setWindowDefaultSize(logic.getGuiSettings());
-
- setAccelerators();
-
- helpWindow = new HelpWindow();
- }
-
- public Stage getPrimaryStage() {
- return primaryStage;
- }
-
- private void setAccelerators() {
- setAccelerator(helpMenuItem, KeyCombination.valueOf("F1"));
- }
-
- /**
- * Sets the accelerator of a MenuItem.
- * @param keyCombination the KeyCombination value of the accelerator
- */
- private void setAccelerator(MenuItem menuItem, KeyCombination keyCombination) {
- menuItem.setAccelerator(keyCombination);
-
- /*
- * TODO: the code below can be removed once the bug reported here
- * https://bugs.openjdk.java.net/browse/JDK-8131666
- * is fixed in later version of SDK.
- *
- * According to the bug report, TextInputControl (TextField, TextArea) will
- * consume function-key events. Because CommandBox contains a TextField, and
- * ResultDisplay contains a TextArea, thus some accelerators (e.g F1) will
- * not work when the focus is in them because the key event is consumed by
- * the TextInputControl(s).
- *
- * For now, we add following event filter to capture such key events and open
- * help window purposely so to support accelerators even when focus is
- * in CommandBox or ResultDisplay.
- */
- getRoot().addEventFilter(KeyEvent.KEY_PRESSED, event -> {
- if (event.getTarget() instanceof TextInputControl && keyCombination.match(event)) {
- menuItem.getOnAction().handle(new ActionEvent());
- event.consume();
- }
- });
- }
-
- /**
- * Fills up all the placeholders of this window.
- */
- void fillInnerParts() {
- personListPanel = new PersonListPanel(logic.getFilteredPersonList());
- personListPanelPlaceholder.getChildren().add(personListPanel.getRoot());
-
- resultDisplay = new ResultDisplay();
- resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot());
-
- StatusBarFooter statusBarFooter = new StatusBarFooter(logic.getAddressBookFilePath());
- statusbarPlaceholder.getChildren().add(statusBarFooter.getRoot());
-
- CommandBox commandBox = new CommandBox(this::executeCommand);
- commandBoxPlaceholder.getChildren().add(commandBox.getRoot());
- }
-
- /**
- * Sets the default size based on {@code guiSettings}.
- */
- private void setWindowDefaultSize(GuiSettings guiSettings) {
- primaryStage.setHeight(guiSettings.getWindowHeight());
- primaryStage.setWidth(guiSettings.getWindowWidth());
- if (guiSettings.getWindowCoordinates() != null) {
- primaryStage.setX(guiSettings.getWindowCoordinates().getX());
- primaryStage.setY(guiSettings.getWindowCoordinates().getY());
- }
- }
-
- /**
- * Opens the help window or focuses on it if it's already opened.
- */
- @FXML
- public void handleHelp() {
- if (!helpWindow.isShowing()) {
- helpWindow.show();
- } else {
- helpWindow.focus();
- }
- }
-
- void show() {
- primaryStage.show();
- }
-
- /**
- * Closes the application.
- */
- @FXML
- private void handleExit() {
- GuiSettings guiSettings = new GuiSettings(primaryStage.getWidth(), primaryStage.getHeight(),
- (int) primaryStage.getX(), (int) primaryStage.getY());
- logic.setGuiSettings(guiSettings);
- helpWindow.hide();
- primaryStage.hide();
- }
-
- public PersonListPanel getPersonListPanel() {
- return personListPanel;
- }
-
- /**
- * Executes the command and returns the result.
- *
- * @see seedu.address.logic.Logic#execute(String)
- */
- private CommandResult executeCommand(String commandText) throws CommandException, ParseException {
- try {
- CommandResult commandResult = logic.execute(commandText);
- logger.info("Result: " + commandResult.getFeedbackToUser());
- resultDisplay.setFeedbackToUser(commandResult.getFeedbackToUser());
-
- if (commandResult.isShowHelp()) {
- handleHelp();
- }
-
- if (commandResult.isExit()) {
- handleExit();
- }
-
- return commandResult;
- } catch (CommandException | ParseException e) {
- logger.info("Invalid command: " + commandText);
- resultDisplay.setFeedbackToUser(e.getMessage());
- throw e;
- }
- }
-}
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/ui/Ui.java b/src/main/java/seedu/address/ui/Ui.java
deleted file mode 100644
index 17aa0b494fe..00000000000
--- a/src/main/java/seedu/address/ui/Ui.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package seedu.address.ui;
-
-import javafx.stage.Stage;
-
-/**
- * API of UI component
- */
-public interface Ui {
-
- /** Starts the UI (and the App). */
- void start(Stage primaryStage);
-
-}
diff --git a/src/main/java/seedu/address/AppParameters.java b/src/main/java/seedu/programmer/AppParameters.java
similarity index 93%
rename from src/main/java/seedu/address/AppParameters.java
rename to src/main/java/seedu/programmer/AppParameters.java
index ab552c398f3..d19d3653b15 100644
--- a/src/main/java/seedu/address/AppParameters.java
+++ b/src/main/java/seedu/programmer/AppParameters.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.programmer;
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.programmer.commons.core.LogsCenter;
+import seedu.programmer.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/programmer/Main.java
similarity index 97%
rename from src/main/java/seedu/address/Main.java
rename to src/main/java/seedu/programmer/Main.java
index 052a5068631..17e77e3aa6e 100644
--- a/src/main/java/seedu/address/Main.java
+++ b/src/main/java/seedu/programmer/Main.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.programmer;
import javafx.application.Application;
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/programmer/MainApp.java
similarity index 65%
rename from src/main/java/seedu/address/MainApp.java
rename to src/main/java/seedu/programmer/MainApp.java
index 4133aaa0151..d4d8f4aba91 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/seedu/programmer/MainApp.java
@@ -1,4 +1,4 @@
-package seedu.address;
+package seedu.programmer;
import java.io.IOException;
import java.nio.file.Path;
@@ -7,29 +7,29 @@
import javafx.application.Application;
import javafx.stage.Stage;
-import seedu.address.commons.core.Config;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.commons.core.Version;
-import seedu.address.commons.exceptions.DataConversionException;
-import seedu.address.commons.util.ConfigUtil;
-import seedu.address.commons.util.StringUtil;
-import seedu.address.logic.Logic;
-import seedu.address.logic.LogicManager;
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.UserPrefs;
-import seedu.address.model.util.SampleDataUtil;
-import seedu.address.storage.AddressBookStorage;
-import seedu.address.storage.JsonAddressBookStorage;
-import seedu.address.storage.JsonUserPrefsStorage;
-import seedu.address.storage.Storage;
-import seedu.address.storage.StorageManager;
-import seedu.address.storage.UserPrefsStorage;
-import seedu.address.ui.Ui;
-import seedu.address.ui.UiManager;
+import seedu.programmer.commons.core.Config;
+import seedu.programmer.commons.core.LogsCenter;
+import seedu.programmer.commons.core.Version;
+import seedu.programmer.commons.exceptions.DataConversionException;
+import seedu.programmer.commons.util.ConfigUtil;
+import seedu.programmer.commons.util.StringUtil;
+import seedu.programmer.logic.Logic;
+import seedu.programmer.logic.LogicManager;
+import seedu.programmer.model.Model;
+import seedu.programmer.model.ModelManager;
+import seedu.programmer.model.ProgrammerError;
+import seedu.programmer.model.ReadOnlyProgrammerError;
+import seedu.programmer.model.ReadOnlyUserPrefs;
+import seedu.programmer.model.UserPrefs;
+import seedu.programmer.model.util.SampleDataUtil;
+import seedu.programmer.storage.JsonProgrammerErrorStorage;
+import seedu.programmer.storage.JsonUserPrefsStorage;
+import seedu.programmer.storage.ProgrammerErrorStorage;
+import seedu.programmer.storage.Storage;
+import seedu.programmer.storage.StorageManager;
+import seedu.programmer.storage.UserPrefsStorage;
+import seedu.programmer.ui.Ui;
+import seedu.programmer.ui.UiManager;
/**
* Runs the application.
@@ -48,7 +48,7 @@ public class MainApp extends Application {
@Override
public void init() throws Exception {
- logger.info("=============================[ Initializing AddressBook ]===========================");
+ logger.info("=============================[ Initializing ProgrammerError ]===========================");
super.init();
AppParameters appParameters = AppParameters.parse(getParameters());
@@ -56,38 +56,37 @@ 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);
+ ProgrammerErrorStorage programmerErrorStorage = new JsonProgrammerErrorStorage(
+ userPrefs.getProgrammerErrorFilePath());
+ storage = new StorageManager(programmerErrorStorage, userPrefsStorage);
initLogging(config);
-
model = initModelManager(storage, userPrefs);
-
logic = new LogicManager(model, storage);
-
ui = new UiManager(logic);
}
/**
- * 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 ProgrammerError and {@code userPrefs}.
+ * The data from the sample ProgrammerError will be used instead if {@code storage}'s ProgrammerError is not found,
+ * or an empty ProgrammerError will be used instead if errors occur when reading {@code storage}'s ProgrammerError.
*/
private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
- Optional addressBookOptional;
- ReadOnlyAddressBook initialData;
+ Optional programmerErrorOptional;
+ ReadOnlyProgrammerError initialData;
try {
- addressBookOptional = storage.readAddressBook();
- if (!addressBookOptional.isPresent()) {
- logger.info("Data file not found. Will be starting with a sample AddressBook");
+ programmerErrorOptional = storage.readProgrammerError();
+ if (programmerErrorOptional.isEmpty()) {
+ logger.info("Data file not found. Will be starting with a sample ProgrammerError");
}
- initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook);
+ initialData = programmerErrorOptional.orElseGet(SampleDataUtil::getSampleProgrammerError);
+ storage.saveProgrammerError(initialData);
} 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 ProgrammerError");
+ initialData = new ProgrammerError();
} 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 ProgrammerError");
+ initialData = new ProgrammerError();
}
return new ModelManager(initialData, userPrefs);
@@ -151,7 +150,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 ProgrammerError");
initializedPrefs = new UserPrefs();
}
@@ -167,13 +166,13 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
@Override
public void start(Stage primaryStage) {
- logger.info("Starting AddressBook " + MainApp.VERSION);
+ logger.info("Starting ProgrammerError " + MainApp.VERSION);
ui.start(primaryStage);
}
@Override
public void stop() {
- logger.info("============================ [ Stopping Address Book ] =============================");
+ logger.info("============================ [ Stopping ProgrammerError ] =============================");
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/programmer/commons/core/Config.java
similarity index 82%
rename from src/main/java/seedu/address/commons/core/Config.java
rename to src/main/java/seedu/programmer/commons/core/Config.java
index 91145745521..888dfa6969f 100644
--- a/src/main/java/seedu/address/commons/core/Config.java
+++ b/src/main/java/seedu/programmer/commons/core/Config.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.programmer.commons.core;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -6,7 +6,7 @@
import java.util.logging.Level;
/**
- * Config values used by the app
+ * Config values used by the app.
*/
public class Config {
@@ -54,10 +54,8 @@ public int hashCode() {
@Override
public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("Current log level : " + logLevel);
- sb.append("\nPreference file Location : " + userPrefsFilePath);
- return sb.toString();
+ return "Current log level : " + logLevel
+ + "\nPreference file Location : " + userPrefsFilePath;
}
}
diff --git a/src/main/java/seedu/address/commons/core/GuiSettings.java b/src/main/java/seedu/programmer/commons/core/GuiSettings.java
similarity index 87%
rename from src/main/java/seedu/address/commons/core/GuiSettings.java
rename to src/main/java/seedu/programmer/commons/core/GuiSettings.java
index ba33653be67..79171c1138e 100644
--- a/src/main/java/seedu/address/commons/core/GuiSettings.java
+++ b/src/main/java/seedu/programmer/commons/core/GuiSettings.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.programmer.commons.core;
import java.awt.Point;
import java.io.Serializable;
@@ -70,10 +70,8 @@ public int hashCode() {
@Override
public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("Width : " + windowWidth + "\n");
- sb.append("Height : " + windowHeight + "\n");
- sb.append("Position : " + windowCoordinates);
- return sb.toString();
+ return "Width : " + windowWidth + "\n"
+ + "Height : " + windowHeight + "\n"
+ + "Position : " + windowCoordinates;
}
}
diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/seedu/programmer/commons/core/LogsCenter.java
similarity index 97%
rename from src/main/java/seedu/address/commons/core/LogsCenter.java
rename to src/main/java/seedu/programmer/commons/core/LogsCenter.java
index 431e7185e76..1fd281f1136 100644
--- a/src/main/java/seedu/address/commons/core/LogsCenter.java
+++ b/src/main/java/seedu/programmer/commons/core/LogsCenter.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.programmer.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 = "ProgrammerError.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/programmer/commons/core/Messages.java b/src/main/java/seedu/programmer/commons/core/Messages.java
new file mode 100644
index 00000000000..ecd66a9d581
--- /dev/null
+++ b/src/main/java/seedu/programmer/commons/core/Messages.java
@@ -0,0 +1,17 @@
+package seedu.programmer.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_STUDENT_DISPLAYED_INDEX = "The student index provided is invalid";
+ public static final String MESSAGE_UNKNOWN_ARGUMENT_FLAG = "Unknown flag(s) detected for this command: %1$s \n%2$s";
+ public static final String MESSAGE_EMPTY_ARGUMENT = "Empty argument(s) provided for this command!\n%1$s";
+ public static final String MESSAGE_MISSING_ARGUMENT = "Missing argument(s) provided for this command!\n%1$s";
+ public static final String MESSAGE_TEMPLATE = "%1$s\n%2$s";
+ public static final String MESSAGE_STUDENTS_FILTERED = "%1$d student(s) has been filtered out!";
+
+}
diff --git a/src/main/java/seedu/address/commons/core/Version.java b/src/main/java/seedu/programmer/commons/core/Version.java
similarity index 96%
rename from src/main/java/seedu/address/commons/core/Version.java
rename to src/main/java/seedu/programmer/commons/core/Version.java
index 12142ec1e32..f2c52d0ee2d 100644
--- a/src/main/java/seedu/address/commons/core/Version.java
+++ b/src/main/java/seedu/programmer/commons/core/Version.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core;
+package seedu.programmer.commons.core;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -64,7 +64,7 @@ public static Version fromString(String versionString) throws IllegalArgumentExc
return new Version(Integer.parseInt(versionMatcher.group(1)),
Integer.parseInt(versionMatcher.group(2)),
Integer.parseInt(versionMatcher.group(3)),
- versionMatcher.group(4) == null ? false : true);
+ versionMatcher.group(4) != null);
}
@JsonValue
diff --git a/src/main/java/seedu/address/commons/core/index/Index.java b/src/main/java/seedu/programmer/commons/core/index/Index.java
similarity index 97%
rename from src/main/java/seedu/address/commons/core/index/Index.java
rename to src/main/java/seedu/programmer/commons/core/index/Index.java
index 19536439c09..ee19028e560 100644
--- a/src/main/java/seedu/address/commons/core/index/Index.java
+++ b/src/main/java/seedu/programmer/commons/core/index/Index.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.core.index;
+package seedu.programmer.commons.core.index;
/**
* Represents a zero-based or one-based index.
diff --git a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java b/src/main/java/seedu/programmer/commons/exceptions/DataConversionException.java
similarity index 78%
rename from src/main/java/seedu/address/commons/exceptions/DataConversionException.java
rename to src/main/java/seedu/programmer/commons/exceptions/DataConversionException.java
index 1f689bd8e3f..cc14b6b59fb 100644
--- a/src/main/java/seedu/address/commons/exceptions/DataConversionException.java
+++ b/src/main/java/seedu/programmer/commons/exceptions/DataConversionException.java
@@ -1,7 +1,7 @@
-package seedu.address.commons.exceptions;
+package seedu.programmer.commons.exceptions;
/**
- * Represents an error during conversion of data from one format to another
+ * Represents an error during conversion of data from one format to another.
*/
public class DataConversionException extends Exception {
public DataConversionException(Exception cause) {
diff --git a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java b/src/main/java/seedu/programmer/commons/exceptions/IllegalValueException.java
similarity index 64%
rename from src/main/java/seedu/address/commons/exceptions/IllegalValueException.java
rename to src/main/java/seedu/programmer/commons/exceptions/IllegalValueException.java
index 19124db485c..edab05baf22 100644
--- a/src/main/java/seedu/address/commons/exceptions/IllegalValueException.java
+++ b/src/main/java/seedu/programmer/commons/exceptions/IllegalValueException.java
@@ -1,19 +1,23 @@
-package seedu.address.commons.exceptions;
+package seedu.programmer.commons.exceptions;
/**
* Signals that some given data does not fulfill some constraints.
*/
public class IllegalValueException extends Exception {
/**
- * @param message should contain relevant information on the failed constraint(s)
+ * Class constructor with a {@code message}.
+ *
+ * @param message should contain relevant information on the failed constraint(s).
*/
public IllegalValueException(String message) {
super(message);
}
/**
- * @param message should contain relevant information on the failed constraint(s)
- * @param cause of the main exception
+ * Class constructor with a {@code message} and a {@code cause}.
+ *
+ * @param message should contain relevant information on the failed constraint(s).
+ * @param cause of the main exception.
*/
public IllegalValueException(String message, Throwable cause) {
super(message, cause);
diff --git a/src/main/java/seedu/address/commons/util/AppUtil.java b/src/main/java/seedu/programmer/commons/util/AppUtil.java
similarity index 89%
rename from src/main/java/seedu/address/commons/util/AppUtil.java
rename to src/main/java/seedu/programmer/commons/util/AppUtil.java
index 87aa89c0326..7a03d1463bf 100644
--- a/src/main/java/seedu/address/commons/util/AppUtil.java
+++ b/src/main/java/seedu/programmer/commons/util/AppUtil.java
@@ -1,12 +1,12 @@
-package seedu.address.commons.util;
+package seedu.programmer.commons.util;
import static java.util.Objects.requireNonNull;
import javafx.scene.image.Image;
-import seedu.address.MainApp;
+import seedu.programmer.MainApp;
/**
- * A container for App specific utility functions
+ * A container for App specific utility functions.
*/
public class AppUtil {
diff --git a/src/main/java/seedu/address/commons/util/CollectionUtil.java b/src/main/java/seedu/programmer/commons/util/CollectionUtil.java
similarity index 85%
rename from src/main/java/seedu/address/commons/util/CollectionUtil.java
rename to src/main/java/seedu/programmer/commons/util/CollectionUtil.java
index eafe4dfd681..807905fe037 100644
--- a/src/main/java/seedu/address/commons/util/CollectionUtil.java
+++ b/src/main/java/seedu/programmer/commons/util/CollectionUtil.java
@@ -1,4 +1,4 @@
-package seedu.address.commons.util;
+package seedu.programmer.commons.util;
import static java.util.Objects.requireNonNull;
@@ -8,11 +8,13 @@
import java.util.stream.Stream;
/**
- * Utility methods related to Collections
+ * Utility methods related to Collections.
*/
public class CollectionUtil {
- /** @see #requireAllNonNull(Collection) */
+ /**
+ * @see #requireAllNonNull(Collection)
+ */
public static void requireAllNonNull(Object... items) {
requireNonNull(items);
Stream.of(items).forEach(Objects::requireNonNull);
diff --git a/src/main/java/seedu/address/commons/util/ConfigUtil.java b/src/main/java/seedu/programmer/commons/util/ConfigUtil.java
similarity index 76%
rename from src/main/java/seedu/address/commons/util/ConfigUtil.java
rename to src/main/java/seedu/programmer/commons/util/ConfigUtil.java
index f7f8a2bd44c..77dacea2813 100644
--- a/src/main/java/seedu/address/commons/util/ConfigUtil.java
+++ b/src/main/java/seedu/programmer/commons/util/ConfigUtil.java
@@ -1,11 +1,11 @@
-package seedu.address.commons.util;
+package seedu.programmer.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.programmer.commons.core.Config;
+import seedu.programmer.commons.exceptions.DataConversionException;
/**
* A class for accessing the Config File.
diff --git a/src/main/java/seedu/programmer/commons/util/FileUtil.java b/src/main/java/seedu/programmer/commons/util/FileUtil.java
new file mode 100644
index 00000000000..1f187c77983
--- /dev/null
+++ b/src/main/java/seedu/programmer/commons/util/FileUtil.java
@@ -0,0 +1,151 @@
+package seedu.programmer.commons.util;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.logging.Logger;
+
+import com.opencsv.CSVReader;
+
+import seedu.programmer.commons.core.LogsCenter;
+import seedu.programmer.commons.exceptions.IllegalValueException;
+import seedu.programmer.model.student.ClassId;
+import seedu.programmer.model.student.Email;
+import seedu.programmer.model.student.Name;
+import seedu.programmer.model.student.Student;
+import seedu.programmer.model.student.StudentId;
+
+/**
+ * Writes and reads files.
+ */
+public class FileUtil {
+
+ private static final Logger logger = LogsCenter.getLogger(FileUtil.class);
+ private static final String CHARSET = "UTF-8";
+
+ public static boolean isFileExists(Path file) {
+ return Files.exists(file) && Files.isRegularFile(file);
+ }
+
+ /**
+ * Returns true if {@code path} can be converted into a {@code Path} via {@link Paths#get(String)},
+ * otherwise returns false.
+ *
+ * @param path A string representing the file path. Cannot be null.
+ */
+ public static boolean isValidPath(String path) {
+ try {
+ Paths.get(path);
+ } catch (InvalidPathException ipe) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Creates a file if it does not exist along with its missing parent directories.
+ *
+ * @param file File to create if it is missing.
+ * @throws IOException if the file or directory cannot be created.
+ */
+ public static void createIfMissing(Path file) throws IOException {
+ if (!isFileExists(file)) {
+ createFile(file);
+ }
+ }
+
+ /**
+ * Creates a file if it does not exist along with its missing parent directories.
+ *
+ * @param file File to create.
+ */
+ public static void createFile(Path file) throws IOException {
+ if (Files.exists(file)) {
+ return;
+ }
+
+ createParentDirsOfFile(file);
+
+ Files.createFile(file);
+ }
+
+ /**
+ * Creates parent directories of file if it has a parent directory.
+ *
+ * @param file File to create parent directories of.
+ */
+ public static void createParentDirsOfFile(Path file) throws IOException {
+ Path parentDir = file.getParent();
+
+ if (parentDir != null) {
+ Files.createDirectories(parentDir);
+ }
+ }
+
+ /**
+ * Assumes file exists.
+ */
+ public static String readFromFile(Path file) throws IOException {
+ return new String(Files.readAllBytes(file), CHARSET);
+ }
+
+ /**
+ * Writes given string to a file.
+ * Will create the file if it does not exist yet.
+ *
+ * @param file File to write to.
+ * @param content String content to write to file.
+ */
+ public static void writeToFile(Path file, String content) throws IOException {
+ Files.write(file, content.getBytes(CHARSET));
+ }
+
+ /**
+ * Gets a List of Students from CSV file of student data.
+ *
+ * @param chosenFile File chosen by user.
+ * @return List of Students in the CSV file.
+ * @throws IllegalArgumentException If CSV contains invalid input.
+ * @throws IOException If error reading the file.
+ */
+ public static List getStudentsFromCsv(File chosenFile) throws IllegalArgumentException, IOException,
+ IllegalValueException {
+ List stuList = new ArrayList<>();
+
+ CSVReader reader = new CSVReader(new FileReader(chosenFile));
+ String[] headers = reader.readNext();
+ String[] expectedHeaders = {"studentId", "classId", "name", "email"};
+ if (!Arrays.equals(headers, expectedHeaders)) {
+ throw new IllegalValueException("Sorry! Your CSV file header should be: `studentId,classId,name,email`");
+ }
+
+ String [] nextLine;
+ while ((nextLine = reader.readNext()) != null) {
+ addStudentFromCsvLine(stuList, nextLine);
+ }
+
+ return stuList;
+ }
+
+ /**
+ * Adds a Student to a List of Students.
+ *
+ * @param stuList Student list to add to.
+ * @param nextLine Line in a CSV file of student data.
+ */
+ private static void addStudentFromCsvLine(List stuList, String[] nextLine) {
+ StudentId sid = new StudentId(nextLine[0].trim());
+ ClassId cid = new ClassId(nextLine[1].trim());
+ Name name = new Name(nextLine[2].trim());
+ Email email = new Email(nextLine[3].trim());
+ Student s = new Student(name, sid, cid, email);
+ stuList.add(s);
+ }
+}
diff --git a/src/main/java/seedu/address/commons/util/JsonUtil.java b/src/main/java/seedu/programmer/commons/util/JsonUtil.java
similarity index 63%
rename from src/main/java/seedu/address/commons/util/JsonUtil.java
rename to src/main/java/seedu/programmer/commons/util/JsonUtil.java
index 8ef609f055d..f603c2002b3 100644
--- a/src/main/java/seedu/address/commons/util/JsonUtil.java
+++ b/src/main/java/seedu/programmer/commons/util/JsonUtil.java
@@ -1,14 +1,26 @@
-package seedu.address.commons.util;
+package seedu.programmer.commons.util;
import static java.util.Objects.requireNonNull;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.json.CDL;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
@@ -20,11 +32,12 @@
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.programmer.commons.core.LogsCenter;
+import seedu.programmer.commons.exceptions.DataConversionException;
+import seedu.programmer.commons.exceptions.IllegalValueException;
/**
- * Converts a Java object instance to JSON and vice versa
+ * Converts a Java object instance to JSON and vice versa.
*/
public class JsonUtil {
@@ -51,9 +64,10 @@ static T deserializeObjectFromJsonFile(Path jsonFile, Class classOfObject
/**
* Returns the Json object from the given file or {@code Optional.empty()} object if the file is not found.
* If any values are missing from the file, default values will be used, as long as the file is a valid json file.
+ *
* @param filePath cannot be null.
* @param classOfObjectToDeserialize Json file has to correspond to the structure in the class given here.
- * @throws DataConversionException if the file format is not as expected.
+ * @throws DataConversionException If the file format is not as expected.
*/
public static Optional readJsonFile(
Path filePath, Class classOfObjectToDeserialize) throws DataConversionException {
@@ -79,9 +93,10 @@ public static Optional readJsonFile(
/**
* Saves the Json object to the specified file.
* Overwrites existing file if it exists, creates a new file if it doesn't.
- * @param jsonFile cannot be null
- * @param filePath cannot be null
- * @throws IOException if there was an error during writing to the file
+ *
+ * @param jsonFile Cannot be null.
+ * @param filePath cannot be null.
+ * @throws IOException if there was an error during writing to the file.
*/
public static void saveJsonFile(T jsonFile, Path filePath) throws IOException {
requireNonNull(filePath);
@@ -92,19 +107,21 @@ public static void saveJsonFile(T jsonFile, Path filePath) throws IOExceptio
/**
- * Converts a given string representation of a JSON data to instance of a class
- * @param The generic type to create an instance of
- * @return The instance of T with the specified values in the JSON string
+ * Converts a given string representation of a JSON data to instance of a class.
+ *
+ * @param The generic type to create an instance of.
+ * @return The instance of T with the specified values in the JSON string.
*/
public static T fromJsonString(String json, Class instanceClass) throws IOException {
return objectMapper.readValue(json, instanceClass);
}
/**
- * Converts a given instance of a class into its JSON data string representation
- * @param instance The T object to be converted into the JSON string
- * @param The generic type to create an instance of
- * @return JSON data representation of the given class instance, in string
+ * Converts a given instance of a class into its JSON data string representation.
+ *
+ * @param instance The T object to be converted into the JSON string.
+ * @param The generic type to create an instance of.
+ * @return JSON data representation of the given class instance, in string.
*/
public static String toJsonString(T instance) throws JsonProcessingException {
return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(instance);
@@ -125,10 +142,9 @@ protected Level _deserialize(String value, DeserializationContext ctxt) {
}
/**
- * Gets the logging level that matches loggingLevelString
- *
- * Returns null if there are no matches
+ * Gets the logging level that matches loggingLevelString.
*
+ * @return The logging level and returns null if there are no matches.
*/
private Level getLoggingLevel(String loggingLevelString) {
return Level.parse(loggingLevelString);
@@ -140,4 +156,46 @@ public Class handledType() {
}
}
+ /**
+ * Writes JSON data to a CSV file.
+ *
+ * @param jsonData JSONArray of data.
+ * @param destinationFile File object to write to.
+ */
+ public static void writeJsonToCsv(JSONArray jsonData, File destinationFile) {
+ // If there were no data, we should not even be trying to write anything
+ if (jsonData.length() <= 0) {
+ return;
+ }
+
+ try {
+ String rawJsonDataString = CDL.toString(jsonData);
+
+ // Store unmarked lab scores as 0 instead of -1 for ease of upload to grade book
+ String parsedJsonData = rawJsonDataString.replace("-1", "0");
+ FileUtils.writeStringToFile(destinationFile, parsedJsonData, Charset.defaultCharset());
+ logger.info("The following data was written:\n" + parsedJsonData);
+ } catch (IOException | JSONException e) {
+ logger.severe("Unexpected error: " + e);
+ }
+ }
+
+ /**
+ * Retrieves students' JSON data stored in ProgrammerError.
+ *
+ * @param filePath Path of file to get JSON data from.
+ * @return JSONArray of student's data.
+ * @throws IllegalValueException If the filePath is invalid.
+ */
+ public static JSONArray getJsonData(String filePath) throws IllegalValueException {
+ try {
+ InputStream is = new FileInputStream(filePath);
+ String jsonTxt = IOUtils.toString(is, StandardCharsets.UTF_8);
+ JSONObject json = new JSONObject(jsonTxt);
+ return json.getJSONArray("students");
+ } catch (IOException | JSONException e) {
+ logger.severe("Error with the file!");
+ throw new IllegalValueException("File not found");
+ }
+ }
}
diff --git a/src/main/java/seedu/programmer/commons/util/StringUtil.java b/src/main/java/seedu/programmer/commons/util/StringUtil.java
new file mode 100644
index 00000000000..72f0bc41f55
--- /dev/null
+++ b/src/main/java/seedu/programmer/commons/util/StringUtil.java
@@ -0,0 +1,69 @@
+package seedu.programmer.commons.util;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.programmer.commons.util.AppUtil.checkArgument;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Helper functions for handling strings.
+ */
+public class StringUtil {
+
+ /**
+ * Returns true if the {@code sentence} contains the {@code phrase}.
+ * Ignores case, but a full character sequence match is required.
+ * examples:
+ * containsPhraseIgnoreCase("ABc def", "abc") == true
+ * containsPhraseIgnoreCase("ABc def", "DEF") == true
+ * containsPhraseIgnoreCase("ABc def", "AB") == true
+ * containsPhraseIgnoreCase("ABc def", "ABcdef") == false // not a full char sequence match
+ *
+ *
+ * @param sentence cannot be null.
+ * @param phrase cannot be null, cannot be empty, need not be a single word.
+ * @return true if the {@code phrase} is contained in the {@code sentence}.
+ */
+ public static boolean containsPhraseIgnoreCase(String sentence, String phrase) {
+ requireNonNull(sentence);
+ requireNonNull(phrase);
+
+ String preppedPhrase = phrase.trim();
+ checkArgument(!preppedPhrase.isEmpty(), "Word parameter cannot be empty");
+
+ String preppedSentence = sentence.toLowerCase();
+
+ return preppedSentence.contains(preppedPhrase.toLowerCase());
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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).
+ *
+ * @param s The String to be checked if it is a non-zero unsigned integer.
+ * @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/programmer/logic/Logic.java b/src/main/java/seedu/programmer/logic/Logic.java
new file mode 100644
index 00000000000..0a8d046cfc0
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/Logic.java
@@ -0,0 +1,99 @@
+package seedu.programmer.logic;
+
+import java.nio.file.Path;
+import java.util.List;
+import java.util.function.Predicate;
+
+import javafx.collections.ObservableList;
+import seedu.programmer.commons.core.GuiSettings;
+import seedu.programmer.logic.commands.CommandResult;
+import seedu.programmer.logic.commands.exceptions.CommandException;
+import seedu.programmer.logic.parser.exceptions.ParseException;
+import seedu.programmer.model.Model;
+import seedu.programmer.model.ProgrammerError;
+import seedu.programmer.model.ReadOnlyProgrammerError;
+import seedu.programmer.model.student.DisplayableObject;
+import seedu.programmer.model.student.Student;
+import seedu.programmer.storage.Storage;
+
+/**
+ * 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 ProgrammerError.
+ *
+ * @see seedu.programmer.model.Model#getProgrammerError()
+ */
+ ReadOnlyProgrammerError getProgrammerError();
+
+ /**
+ * Returns an unmodifiable view of the filtered list of students.
+ */
+ ObservableList getFilteredStudentList();
+
+ /**
+ * Returns an unmodifiable view of all students.
+ */
+ ObservableList getAllStudents();
+
+ /**
+ * Returns the selected labs.
+ */
+ ObservableList getSelectedInformation();
+
+ /**
+ * Returns the user prefs' ProgrammerError file path.
+ */
+ Path getProgrammerErrorFilePath();
+
+ /**
+ * Returns the user prefs' GUI settings.
+ */
+ GuiSettings getGuiSettings();
+
+ /**
+ * Sets the user prefs' GUI settings.
+ */
+ void setGuiSettings(GuiSettings guiSettings);
+
+ /**
+ * Returns the Model associated with Logic.
+ */
+ Model getModel();
+
+ /**
+ * Returns the Storage associated with Logic
+ */
+ Storage getStorage();
+
+ /**
+ * Updates ProgrammerError to the specified one.
+ */
+ void updateProgrammerError(ProgrammerError pe);
+
+ /**
+ * Updates FilteredStudents to the specified one.
+ */
+ void updateFilteredStudents(Predicate predicate);
+
+ /**
+ * Saves ProgrammerError to the storage.
+ */
+ void saveProgrammerError(ProgrammerError pe);
+
+ /**
+ * Replaces the existing student list with a new one.
+ */
+ void replaceExistingStudents(List stuList);
+}
diff --git a/src/main/java/seedu/programmer/logic/LogicManager.java b/src/main/java/seedu/programmer/logic/LogicManager.java
new file mode 100644
index 00000000000..573cd3f55af
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/LogicManager.java
@@ -0,0 +1,137 @@
+package seedu.programmer.logic;
+
+import static seedu.programmer.model.Model.PREDICATE_SHOW_ALL_STUDENTS;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.logging.Logger;
+
+import javafx.collections.ObservableList;
+import seedu.programmer.commons.core.GuiSettings;
+import seedu.programmer.commons.core.LogsCenter;
+import seedu.programmer.logic.commands.Command;
+import seedu.programmer.logic.commands.CommandResult;
+import seedu.programmer.logic.commands.exceptions.CommandException;
+import seedu.programmer.logic.parser.ProgrammerErrorParser;
+import seedu.programmer.logic.parser.exceptions.ParseException;
+import seedu.programmer.model.Model;
+import seedu.programmer.model.ProgrammerError;
+import seedu.programmer.model.ReadOnlyProgrammerError;
+import seedu.programmer.model.student.DisplayableObject;
+import seedu.programmer.model.student.Student;
+import seedu.programmer.model.student.exceptions.DuplicateStudentException;
+import seedu.programmer.storage.Storage;
+
+
+/**
+ * The main LogicManager of the app.
+ */
+public class LogicManager implements Logic {
+ public static final String FILE_OPS_ERROR_MESSAGE = "Could not save data to file: ";
+ private final Logger logger = LogsCenter.getLogger(LogicManager.class);
+
+ private final Model model;
+ private final Storage storage;
+ private final ProgrammerErrorParser programmerErrorParser;
+
+ /**
+ * Class constructor for {@code LogicManager} with the given {@code Model} and {@code Storage}.
+ */
+ public LogicManager(Model model, Storage storage) {
+ this.model = model;
+ this.storage = storage;
+ programmerErrorParser = new ProgrammerErrorParser();
+ }
+
+ @Override
+ public CommandResult execute(String commandText) throws CommandException, ParseException {
+ logger.info("----------------[USER COMMAND][" + commandText + "]");
+
+ CommandResult commandResult;
+ Command command = programmerErrorParser.parseCommand(commandText);
+ commandResult = command.execute(model);
+
+ try {
+ storage.saveProgrammerError(model.getProgrammerError());
+ } catch (IOException ioe) {
+ throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe);
+ }
+
+ return commandResult;
+ }
+
+ @Override
+ public Model getModel() {
+ return model;
+ }
+
+ @Override
+ public Storage getStorage() {
+ return storage;
+ }
+
+ @Override
+ public void updateProgrammerError(ProgrammerError pe) {
+ model.setProgrammerError(pe);
+ }
+
+ @Override
+ public void updateFilteredStudents(Predicate predicate) {
+ model.updateFilteredStudentList(predicate);
+ }
+
+ @Override
+ public void saveProgrammerError(ProgrammerError pe) {
+ try {
+ storage.saveProgrammerError(pe);
+ } catch (IOException e) {
+ System.out.println("Unexpected error and ProgrammerError is not saved");
+ }
+ }
+
+ @Override
+ public ReadOnlyProgrammerError getProgrammerError() {
+ return model.getProgrammerError();
+ }
+
+ @Override
+ public ObservableList getFilteredStudentList() {
+ return model.getFilteredStudentList();
+ }
+
+ @Override
+ public ObservableList getAllStudents() {
+ return model.getAllStudents();
+ }
+
+ @Override
+ public ObservableList getSelectedInformation() {
+ return model.getSelectedInformation();
+ }
+
+ @Override
+ public Path getProgrammerErrorFilePath() {
+ return model.getProgrammerErrorFilePath();
+ }
+
+ @Override
+ public GuiSettings getGuiSettings() {
+ return model.getGuiSettings();
+ }
+
+ @Override
+ public void setGuiSettings(GuiSettings guiSettings) {
+ model.setGuiSettings(guiSettings);
+ }
+
+ @Override
+ public void replaceExistingStudents(List stuList) throws DuplicateStudentException {
+ ProgrammerError newPE = new ProgrammerError();
+ newPE.setStudents(stuList);
+ updateProgrammerError(newPE);
+ updateFilteredStudents(PREDICATE_SHOW_ALL_STUDENTS);
+ saveProgrammerError(newPE);
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/AddCommand.java b/src/main/java/seedu/programmer/logic/commands/AddCommand.java
new file mode 100644
index 00000000000..6f31e8e69b4
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/AddCommand.java
@@ -0,0 +1,75 @@
+package seedu.programmer.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_CLASS_ID;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_STUDENT_ID;
+
+import seedu.programmer.logic.commands.exceptions.CommandException;
+import seedu.programmer.model.Model;
+import seedu.programmer.model.student.Student;
+
+/**
+ * Adds a student to ProgrammerError.
+ */
+public class AddCommand extends Command {
+
+ public static final String COMMAND_WORD = "add";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a student to the ProgrammerError.\n"
+ + "Parameters: "
+ + PREFIX_NAME + " "
+ + PREFIX_STUDENT_ID + " "
+ + PREFIX_CLASS_ID + " "
+ + PREFIX_EMAIL + "\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_NAME + "John Doe "
+ + PREFIX_STUDENT_ID + "A0121234H "
+ + PREFIX_CLASS_ID + "B01 "
+ + PREFIX_EMAIL + "e0518441@u.nus.edu";
+
+ public static final String MESSAGE_SUCCESS = "New student added: %1$s";
+ public static final String MESSAGE_DUPLICATE_STUDENT_ID = "This student with the same Student Id "
+ + "already exists in the ProgrammerError";
+ public static final String MESSAGE_DUPLICATE_STUDENT_EMAIL = "This student with the same email "
+ + "already exists in the ProgrammerError";
+ public static final String MESSAGE_DUPLICATE_STUDENT = "This student already exists in the ProgrammerError";
+
+
+ private final Student toAdd;
+
+ /**
+ * Creates an AddCommand to add the specified {@code Student}.
+ */
+ public AddCommand(Student student) {
+ requireNonNull(student);
+ toAdd = student;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ //A duplicate student is a student with an existing student ID and/or email.
+ if (model.hasStudent(toAdd)) {
+ if (model.hasSameStudentId(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_STUDENT_ID);
+ } else if (model.hasSameStudentEmail(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_STUDENT_EMAIL);
+ }
+ }
+
+ model.addStudent(toAdd);
+ model.setSelectedStudent(toAdd);
+ model.setSelectedLabs(toAdd.getLabList());
+ 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/programmer/logic/commands/AddLabCommand.java b/src/main/java/seedu/programmer/logic/commands/AddLabCommand.java
new file mode 100644
index 00000000000..f0eaa8a0982
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/AddLabCommand.java
@@ -0,0 +1,83 @@
+package seedu.programmer.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_LAB_NUM;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_LAB_TOTAL;
+
+import java.util.List;
+
+import seedu.programmer.logic.commands.exceptions.CommandException;
+import seedu.programmer.model.Model;
+import seedu.programmer.model.student.Lab;
+import seedu.programmer.model.student.Student;
+
+/**
+ * Adds a lab with total score and default score for all the students in the list.
+ */
+public class AddLabCommand extends Command {
+
+ public static final String COMMAND_WORD = "addlab";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a lab to all the students in the list.\n"
+ + "Parameters: "
+ + PREFIX_LAB_NUM + " "
+ + PREFIX_LAB_TOTAL + "\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_LAB_NUM + "1 "
+ + PREFIX_LAB_TOTAL + "20";
+
+ public static final String MESSAGE_ADD_LAB_SUCCESS = "Lab Added: %1$s";
+
+ public static final String NO_STUDENT_CONSTRAINTS = "There are no students to add the lab to.";
+
+ private final Lab result;
+
+ /**
+ * Class constructor with a {@code Lab} object.
+ *
+ * @param result the lab result to be added.
+ */
+ public AddLabCommand(Lab result) {
+ requireNonNull(result);
+ this.result = result;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ List studentList = model.getAllStudents();
+
+ if (studentList.isEmpty()) {
+ throw new CommandException(NO_STUDENT_CONSTRAINTS);
+ }
+
+ if (result.getLabTotal().getLabTotalScore() < 0) {
+ throw new CommandException(Lab.MESSAGE_LAB_TOTAL_SCORE_CONSTRAINT);
+ }
+
+ for (Student std: studentList) {
+ Student target = std;
+ Lab newLab = this.result.copy();
+ if (!target.addLab(newLab)) {
+ throw new CommandException(String.format(Lab.MESSAGE_LAB_ALREADY_EXISTS, result));
+ }
+ model.setStudent(target, std);
+ }
+ if (!model.getSelectedInformation().isEmpty()) {
+ Student selectedStudent = model.getSelectedStudent().copy();
+ selectedStudent.addLab(result);
+ model.setSelectedStudent(selectedStudent);
+ model.setSelectedLabs(selectedStudent.getLabList());
+ }
+ return new CommandResult(String.format(MESSAGE_ADD_LAB_SUCCESS, result));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddLabCommand// instanceof handles nulls
+ && result.equals(((AddLabCommand) other).result)); // state check
+ }
+}
+
diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/seedu/programmer/logic/commands/Command.java
similarity index 77%
rename from src/main/java/seedu/address/logic/commands/Command.java
rename to src/main/java/seedu/programmer/logic/commands/Command.java
index 64f18992160..800c93864b5 100644
--- a/src/main/java/seedu/address/logic/commands/Command.java
+++ b/src/main/java/seedu/programmer/logic/commands/Command.java
@@ -1,7 +1,7 @@
-package seedu.address.logic.commands;
+package seedu.programmer.logic.commands;
-import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.Model;
+import seedu.programmer.logic.commands.exceptions.CommandException;
+import seedu.programmer.model.Model;
/**
* Represents a command with hidden internal logic and the ability to be executed.
diff --git a/src/main/java/seedu/programmer/logic/commands/CommandResult.java b/src/main/java/seedu/programmer/logic/commands/CommandResult.java
new file mode 100644
index 00000000000..28de29fb6a5
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/CommandResult.java
@@ -0,0 +1,47 @@
+package seedu.programmer.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Objects;
+
+/**
+ * Represents the result of a command execution.
+ */
+public class CommandResult {
+
+ private final String feedbackToUser;
+
+ /**
+ * Constructs a {@code CommandResult} with the specified feedback to the user.
+ *
+ * @param feedbackToUser The message to be shown to the user.
+ */
+ public CommandResult(String feedbackToUser) {
+ this.feedbackToUser = requireNonNull(feedbackToUser);
+ }
+
+ public String getFeedbackToUser() {
+ return feedbackToUser;
+ }
+
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof CommandResult)) {
+ return false;
+ }
+
+ CommandResult otherCommandResult = (CommandResult) other;
+ return feedbackToUser.equals(otherCommandResult.feedbackToUser);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(feedbackToUser);
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/DashboardCommand.java b/src/main/java/seedu/programmer/logic/commands/DashboardCommand.java
new file mode 100644
index 00000000000..18cd531819d
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/DashboardCommand.java
@@ -0,0 +1,27 @@
+package seedu.programmer.logic.commands;
+
+import seedu.programmer.model.Model;
+
+/**
+ * Shows ProgrammerError's Dashboard for user to see students' statistics.
+ */
+public class DashboardCommand extends Command {
+
+ public static final String COMMAND_WORD = "dashboard";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Displays dashboard of data.\n"
+ + "Example: " + COMMAND_WORD;
+
+ public static final String SHOWING_DASHBOARD_MESSAGE = "Opened dashboard window.";
+
+ /**
+ * Returns a DashboardCommandResult with a message to indicate that the command was executed.
+ *
+ * @param model {@code Model} which the command should operate on.
+ * @return a {@code DashboardCommandResult} with a message.
+ */
+ @Override
+ public DashboardCommandResult execute(Model model) {
+ return new DashboardCommandResult(SHOWING_DASHBOARD_MESSAGE);
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/DashboardCommandResult.java b/src/main/java/seedu/programmer/logic/commands/DashboardCommandResult.java
new file mode 100644
index 00000000000..ed20a01e8fc
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/DashboardCommandResult.java
@@ -0,0 +1,16 @@
+package seedu.programmer.logic.commands;
+
+/**
+ * A CommandResult that requires handling in the UI.
+ */
+public class DashboardCommandResult extends CommandResult {
+
+ /**
+ * Creates a DashboardCommandResult with a message.
+ *
+ * @param feedbackToUser Message to be displayed to the user.
+ */
+ public DashboardCommandResult(String feedbackToUser) {
+ super(feedbackToUser);
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/DeleteCommand.java b/src/main/java/seedu/programmer/logic/commands/DeleteCommand.java
new file mode 100644
index 00000000000..6b7dfe448af
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/DeleteCommand.java
@@ -0,0 +1,54 @@
+package seedu.programmer.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import seedu.programmer.commons.core.Messages;
+import seedu.programmer.commons.core.index.Index;
+import seedu.programmer.logic.commands.exceptions.CommandException;
+import seedu.programmer.model.Model;
+import seedu.programmer.model.student.Student;
+
+/**
+ * Deletes a student identified using it's displayed index from ProgrammerErrors.
+ */
+public class DeleteCommand extends Command {
+
+ public static final String COMMAND_WORD = "delete";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the student identified by the index number used in the displayed student list.\n"
+ + "Parameters: (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ public static final String MESSAGE_DELETE_STUDENT_SUCCESS = "Deleted Student: %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.getFilteredStudentList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX);
+ }
+
+ Student studentToDelete = lastShownList.get(targetIndex.getZeroBased());
+ model.deleteStudent(studentToDelete);
+ model.clearSelectedInformation();
+ return new CommandResult(String.format(MESSAGE_DELETE_STUDENT_SUCCESS, studentToDelete));
+ }
+
+ @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/programmer/logic/commands/DeleteLabCommand.java b/src/main/java/seedu/programmer/logic/commands/DeleteLabCommand.java
new file mode 100644
index 00000000000..c9779472cdd
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/DeleteLabCommand.java
@@ -0,0 +1,75 @@
+package seedu.programmer.logic.commands;
+import static java.util.Objects.requireNonNull;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_LAB_NUM;
+
+import java.util.List;
+
+import seedu.programmer.logic.commands.exceptions.CommandException;
+import seedu.programmer.model.Model;
+import seedu.programmer.model.student.Lab;
+import seedu.programmer.model.student.Student;
+
+/**
+ * Deletes a lab all the students in the list.
+ */
+public class DeleteLabCommand extends Command {
+
+ public static final String COMMAND_WORD = "dellab";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Deletes a lab from all the students in the list.\n"
+ + "Parameters: "
+ + PREFIX_LAB_NUM + "\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_LAB_NUM + "1";
+
+ public static final String MESSAGE_DEL_LAB_SUCCESS = "Deleted %1$s";
+ public static final String MESSAGE_NO_STUDENT = "There are no students whose labs can be deleted";
+
+ private final Lab lab;
+
+ /**
+ * Class constructor for {@code DeleteLabCommand}.
+ *
+ * @param lab The lab to be deleted.
+ */
+ public DeleteLabCommand(Lab lab) {
+ this.lab = lab;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ List studentList = model.getAllStudents();
+
+ if (studentList.isEmpty()) {
+ throw new CommandException(MESSAGE_NO_STUDENT);
+ }
+
+ if (!model.hasLab(lab)) {
+ throw new CommandException(String.format(Lab.MESSAGE_LAB_NOT_EXISTS, lab));
+ }
+
+ for (Student student : studentList) {
+ Student originalStudent = student;
+ originalStudent.deleteLab(lab);
+ model.setStudent(originalStudent, student);
+ }
+
+ if (!model.getSelectedInformation().isEmpty()) {
+ Student selectedStudent = model.getSelectedStudent().copy();
+ selectedStudent.deleteLab(lab);
+ model.setSelectedStudent(selectedStudent);
+ model.setSelectedLabs(selectedStudent.getLabList());
+ }
+
+ return new CommandResult(String.format(MESSAGE_DEL_LAB_SUCCESS, lab));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof DeleteLabCommand// instanceof handles nulls
+ && lab.equals(((DeleteLabCommand) other).lab)); // state check
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/DownloadCommand.java b/src/main/java/seedu/programmer/logic/commands/DownloadCommand.java
new file mode 100644
index 00000000000..4da405beaef
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/DownloadCommand.java
@@ -0,0 +1,26 @@
+package seedu.programmer.logic.commands;
+
+import seedu.programmer.model.Model;
+
+/**
+ * Downloads a csv file of students' data from ProgrammerError's storage.
+ */
+public class DownloadCommand extends Command {
+
+ public static final String COMMAND_WORD = "download";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Downloads student data as CSV.\n"
+ + "Example: " + COMMAND_WORD;
+ public static final String SHOWING_DOWNLOAD_MESSAGE = "Download command executed.";
+
+ /**
+ * Returns a DownloadCommandResult with a message to indicate that the command was executed.
+ *
+ * @param model {@code Model} which the command should operate on.
+ * @return DownloadCommandResult with a message.
+ */
+ @Override
+ public DownloadCommandResult execute(Model model) {
+ return new DownloadCommandResult(SHOWING_DOWNLOAD_MESSAGE);
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/DownloadCommandResult.java b/src/main/java/seedu/programmer/logic/commands/DownloadCommandResult.java
new file mode 100644
index 00000000000..476bcb38e32
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/DownloadCommandResult.java
@@ -0,0 +1,16 @@
+package seedu.programmer.logic.commands;
+
+/**
+ * A CommandResult that requires handling in the UI to download the data in ProgrammerError as a csv file.
+ */
+public class DownloadCommandResult extends CommandResult {
+
+ /**
+ * Creates a DownloadCommandResult.
+ *
+ * @param feedbackToUser Message to show user.
+ */
+ public DownloadCommandResult(String feedbackToUser) {
+ super(feedbackToUser);
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/EditCommand.java b/src/main/java/seedu/programmer/logic/commands/EditCommand.java
new file mode 100644
index 00000000000..76031fc0539
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/EditCommand.java
@@ -0,0 +1,291 @@
+package seedu.programmer.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_CLASS_ID;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_LAB_NUM;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_LAB_RESULT;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_STUDENT_ID;
+
+import java.util.List;
+import java.util.Optional;
+
+import javafx.collections.ObservableList;
+import seedu.programmer.commons.core.Messages;
+import seedu.programmer.commons.core.index.Index;
+import seedu.programmer.commons.util.CollectionUtil;
+import seedu.programmer.logic.commands.exceptions.CommandException;
+import seedu.programmer.model.Model;
+import seedu.programmer.model.student.ClassId;
+import seedu.programmer.model.student.Email;
+import seedu.programmer.model.student.Lab;
+import seedu.programmer.model.student.LabNum;
+import seedu.programmer.model.student.LabResult;
+import seedu.programmer.model.student.LabTotal;
+import seedu.programmer.model.student.Name;
+import seedu.programmer.model.student.Student;
+import seedu.programmer.model.student.StudentId;
+
+/**
+ * Edits the details of an existing student in ProgrammerError.
+ */
+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 student identified "
+ + "by the index number used in the displayed student list. "
+ + "Existing values will be overwritten by the input values.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "[" + PREFIX_NAME + "] "
+ + "[" + PREFIX_STUDENT_ID + "] "
+ + "[" + PREFIX_CLASS_ID + "] "
+ + "[" + PREFIX_EMAIL + "] "
+ + "[" + PREFIX_LAB_NUM + " " + PREFIX_LAB_RESULT + "]\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_STUDENT_ID + "A0121234H "
+ + PREFIX_CLASS_ID + "B01";
+
+ public static final String MESSAGE_EDIT_STUDENT_SUCCESS = "Edited Student: %1$s";
+ public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
+ public static final String MESSAGE_NO_NEW_FIELDS = "There is no fields to be edited. Student's information are "
+ + "already the same as what you have asked to be edited to.";
+ public static final String MESSAGE_DUPLICATE_STUDENT_ID = "This student with the same Student ID "
+ + "already exists in the ProgrammerError";
+ public static final String MESSAGE_DUPLICATE_STUDENT_EMAIL = "This student with the same Email "
+ + "already exists in the ProgrammerError";
+ public static final String MESSAGE_EDIT_LAB_SUCCESS = "Lab %1$s score has been updated!";
+ public static final String MESSAGE_NO_LAB_EDITED = "No lab has been updated.";
+
+ private static LabNum labNum2;
+ private final Index index;
+ private final EditStudentDescriptor editStudentDescriptor;
+
+ /**
+ * Class constructor for EditCommand.
+ *
+ * @param index of the student in the filtered student list to edit.
+ * @param editStudentDescriptor details to edit the student with.
+ */
+ public EditCommand(Index index, EditStudentDescriptor editStudentDescriptor) {
+ requireNonNull(index);
+ requireNonNull(editStudentDescriptor);
+ assert(index.getOneBased() >= 1);
+
+ this.index = index;
+ this.editStudentDescriptor = new EditStudentDescriptor(editStudentDescriptor);
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredStudentList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX);
+ }
+
+ Student studentToEdit = lastShownList.get(index.getZeroBased());
+
+ //Duplicate a copy of the student specified at the index to be edited.
+ //This allows for the original student to remain unchanged, so that comparison of fields can be carried out.
+ Student studentToEditCopy = studentToEdit.copy();
+ Student editedStudent = createEditedStudent(studentToEditCopy, editStudentDescriptor);
+
+ //Check if the user edited any fields.
+ //Throws CommandException if no fields are changed.
+ if (studentToEdit.isIdenticalStudent(editedStudent)) {
+ throw new CommandException(MESSAGE_NO_NEW_FIELDS);
+ }
+
+
+ if (model.hasOtherStudent(studentToEdit, editedStudent)) {
+ if (model.hasOtherSameStudentId(studentToEdit, editedStudent)) {
+ throw new CommandException(MESSAGE_DUPLICATE_STUDENT_ID);
+ } else if (model.hasOtherSameStudentEmail(studentToEdit, editedStudent)) {
+ throw new CommandException(MESSAGE_DUPLICATE_STUDENT_EMAIL);
+ }
+ }
+
+ model.setStudent(studentToEdit, editedStudent);
+ model.setSelectedStudent(editedStudent);
+ model.setSelectedLabs(editedStudent.getLabList());
+ if (labNum2 != null) {
+ return new CommandResult(String.format(MESSAGE_EDIT_STUDENT_SUCCESS, editedStudent)
+ + "\n" + String.format(MESSAGE_EDIT_LAB_SUCCESS, labNum2));
+ }
+
+ return new CommandResult(String.format(MESSAGE_EDIT_STUDENT_SUCCESS, editedStudent)
+ + "\n" + MESSAGE_NO_LAB_EDITED);
+ }
+
+ /**
+ * Creates and returns a {@code Student} with the details of {@code studentToEdit}
+ * edited with {@code editStudentDescriptor}.
+ *
+ * @param studentToEdit Student object to be edited.
+ * @param editStudentDescriptor Contains the corresponding fields of the student to be edited.
+ * @return The {@code Student} with the edited attributes.
+ */
+ private static Student createEditedStudent(Student studentToEdit, EditStudentDescriptor editStudentDescriptor)
+ throws CommandException {
+ assert studentToEdit != null;
+ labNum2 = null;
+
+ Name updatedName = editStudentDescriptor.getName().orElse(studentToEdit.getName());
+ StudentId updateStudentId = editStudentDescriptor.getStudentId().orElse(studentToEdit.getStudentId());
+ ClassId updatedClassId = editStudentDescriptor.getClassId().orElse(studentToEdit.getClassId());
+ Email updatedEmail = editStudentDescriptor.getEmail().orElse(studentToEdit.getEmail());
+ Lab updatedLab = editStudentDescriptor.getLab().orElse(null);
+
+ LabResult updatedResult = null;
+ if (updatedLab != null) {
+ updatedResult = editStudentDescriptor.getResult().orElse(null);
+ LabNum labNum = updatedLab.getLabNum();
+ LabTotal currTotalScore;
+ try {
+ currTotalScore = studentToEdit.getLab(labNum).getLabTotal();
+ } catch (NullPointerException e) { //when getLab does not find anything
+ throw new CommandException(String.format(Lab.MESSAGE_LAB_NOT_EXISTS, updatedLab));
+ }
+ labNum2 = labNum;
+ updatedLab.updateTotal(currTotalScore);
+ }
+
+ if (updatedLab != null && updatedResult != null) {
+ studentToEdit.editLabScore(updatedLab, updatedResult);
+ ObservableList updatedList = studentToEdit.getLabList();
+ return new Student(updatedName, updateStudentId, updatedClassId, updatedEmail, updatedList);
+ } else {
+ return new Student(updatedName, updateStudentId, updatedClassId, updatedEmail,
+ studentToEdit.getLabList());
+ }
+ }
+
+ @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)
+ && editStudentDescriptor.equals(e.editStudentDescriptor);
+ }
+
+ /**
+ * Stores the details to edit the student with. Each non-empty field value will replace the
+ * corresponding field value of the student.
+ */
+ public static class EditStudentDescriptor {
+ private Name name;
+ private StudentId studentId;
+ private ClassId classId;
+ private Email email;
+ private LabResult result;
+ private Lab lab;
+ private ObservableList labList;
+
+ /**
+ * Class constructor.
+ */
+ public EditStudentDescriptor() {}
+
+ /**
+ * Copy constructor.
+ * A defensive copy of {@code tags} is used internally.
+ */
+ public EditStudentDescriptor(EditStudentDescriptor toCopy) {
+ setName(toCopy.name);
+ setStudentId(toCopy.studentId);
+ setClassId(toCopy.classId);
+ setEmail(toCopy.email);
+ setLab(toCopy.lab, toCopy.result);
+ }
+
+ /**
+ * Returns true if at least one field is edited.
+ */
+ public boolean isAnyFieldEdited() {
+ return CollectionUtil.isAnyNonNull(name, studentId, classId, email, lab);
+ }
+
+ public void setName(Name name) {
+ this.name = name;
+ }
+
+ public Optional getName() {
+ return Optional.ofNullable(name);
+ }
+
+ public void setStudentId(StudentId studentId) {
+ this.studentId = studentId;
+ }
+
+ public Optional getStudentId() {
+ return Optional.ofNullable(studentId);
+ }
+
+ public void setClassId(ClassId classId) {
+ this.classId = classId;
+ }
+
+ public Optional getClassId() {
+ return Optional.ofNullable(classId);
+ }
+
+ public void setEmail(Email email) {
+ this.email = email;
+ }
+
+ public Optional getEmail() {
+ return Optional.ofNullable(email);
+ }
+
+ public void setLab(Lab lab, LabResult result) {
+ this.lab = lab;
+ this.result = result;
+ }
+
+ public void setLabList(ObservableList labList) {
+ this.labList = labList;
+ }
+
+ public Optional getLab() {
+ return Optional.ofNullable(lab);
+ }
+
+ public Optional getResult() {
+ return Optional.ofNullable(result);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditStudentDescriptor)) {
+ return false;
+ }
+
+ // state check
+ EditStudentDescriptor e = (EditStudentDescriptor) other;
+
+ return getName().equals(e.getName())
+ && getStudentId().equals(e.getStudentId())
+ && getClassId().equals(e.getClassId())
+ && getEmail().equals(e.getEmail());
+ }
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/EditLabCommand.java b/src/main/java/seedu/programmer/logic/commands/EditLabCommand.java
new file mode 100644
index 00000000000..006188c4d6b
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/EditLabCommand.java
@@ -0,0 +1,137 @@
+package seedu.programmer.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_LAB_NEW_LAB_NUM;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_LAB_NUM;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_LAB_TOTAL;
+
+import java.util.List;
+
+import seedu.programmer.logic.commands.exceptions.CommandException;
+import seedu.programmer.model.Model;
+import seedu.programmer.model.student.Lab;
+import seedu.programmer.model.student.LabNum;
+import seedu.programmer.model.student.LabTotal;
+import seedu.programmer.model.student.Student;
+
+/**
+ * Edits a lab with new lab number and total score for all students.
+ */
+public class EditLabCommand extends Command {
+
+ public static final String COMMAND_WORD = "editlab";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits a lab number and/or total score.\n"
+ + "Parameters: "
+ + PREFIX_LAB_NUM + " "
+ + "[" + PREFIX_LAB_NEW_LAB_NUM + " ] "
+ + "[" + PREFIX_LAB_TOTAL + " ]\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_LAB_NUM + "1 "
+ + PREFIX_LAB_NEW_LAB_NUM + "2 "
+ + PREFIX_LAB_TOTAL + "15";
+
+ public static final String MESSAGE_EDIT_LAB_SUCCESS = "Updated %1$s!";
+ public static final String MESSAGE_ARGUMENT_SHOULD_BE_SPECIFIED =
+ "Kindly specify if you want to edit the lab number and/or the total score.";
+ public static final String MESSAGE_MISSING_LAB_TO_BE_EDITED =
+ "Kindly specify the lab number that you would like to edit using the " + PREFIX_LAB_NUM + "flag.\n%1$s";
+ public static final String MESSAGE_NO_STUDENT = "There are no students whose labs can be edited";
+
+ private final LabNum newLabNum;
+ private final LabTotal total;
+ private final Lab original;
+
+ /**
+ * Class constructor with the original lab, the new lab number and the new total score.
+ *
+ * @param original the lab to be edited.
+ * @param newLabNum the new lab number.
+ * @param total the total score to be added.
+ */
+ public EditLabCommand(Lab original, LabNum newLabNum, LabTotal total) {
+ requireNonNull(original);
+ this.original = original;
+ this.newLabNum = newLabNum;
+ this.total = total;
+ }
+ /**
+ * Class constructor with the original lab and the new total score.
+ *
+ * @param original the lab to be edited.
+ * @param total the total score to be added.
+ */
+ public EditLabCommand(Lab original, LabTotal total) {
+ requireNonNull(original);
+ this.original = original;
+ this.total = total;
+ this.newLabNum = null;
+ }
+
+ /**
+ * Class constructor with the original lab and the new lab number.
+ *
+ * @param original the lab to be edited.
+ * @param newLabNum the new lab number
+ */
+ public EditLabCommand(Lab original, LabNum newLabNum) {
+ requireNonNull(original);
+ this.original = original;
+ this.newLabNum = newLabNum;
+ this.total = original.getLabTotal();
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ List studentList = model.getAllStudents();
+
+ if (studentList.isEmpty()) {
+ throw new CommandException(MESSAGE_NO_STUDENT);
+ }
+
+ if (newLabNum != null) {
+ Lab newLab = new Lab(newLabNum);
+
+ if (studentList.get(0).getLabList().contains(newLab)) {
+ throw new CommandException(String.format(Lab.MESSAGE_LAB_ALREADY_EXISTS, newLab));
+ }
+ }
+
+ Student selectedStudent;
+ if (model.getSelectedInformation().isEmpty()) {
+ selectedStudent = null;
+ } else {
+ selectedStudent = model.getSelectedStudent().copy();
+ }
+
+ for (Student std : studentList) {
+ Student editedStd = std;
+ if (total != null && total.getLabTotalScore() < 0) {
+ throw new CommandException(String.format(Lab.MESSAGE_LAB_TOTAL_SCORE_CONSTRAINT, total));
+ } else if (!std.getLabList().contains(original)) {
+ throw new CommandException(String.format(Lab.MESSAGE_LAB_NOT_EXISTS, original));
+ } else {
+ editedStd.editLabInfo(original, newLabNum, total);
+ if (selectedStudent != null && editedStd.isSameStudent(selectedStudent)) {
+ selectedStudent = editedStd.copy();
+ }
+ model.setStudent(std, editedStd);
+ }
+ }
+ if (!model.getSelectedInformation().isEmpty()) {
+ model.setSelectedStudent(selectedStudent);
+ model.setSelectedLabs(selectedStudent.getLabList());
+ }
+
+ return new CommandResult(String.format(MESSAGE_EDIT_LAB_SUCCESS, original));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof EditLabCommand// instanceof handles nulls
+ && original.equals(((EditLabCommand) other).original)); // state check
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/ExitCommand.java b/src/main/java/seedu/programmer/logic/commands/ExitCommand.java
new file mode 100644
index 00000000000..d39c1045b9c
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/ExitCommand.java
@@ -0,0 +1,19 @@
+package seedu.programmer.logic.commands;
+
+import seedu.programmer.model.Model;
+
+/**
+ * Terminates the program.
+ */
+public class ExitCommand extends Command {
+
+ public static final String COMMAND_WORD = "exit";
+
+ public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting ProgrammerError as requested ...";
+
+ @Override
+ public ExitCommandResult execute(Model model) {
+ return new ExitCommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT);
+ }
+
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/ExitCommandResult.java b/src/main/java/seedu/programmer/logic/commands/ExitCommandResult.java
new file mode 100644
index 00000000000..7600cf39a10
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/ExitCommandResult.java
@@ -0,0 +1,17 @@
+package seedu.programmer.logic.commands;
+
+
+/**
+ * Represents a CommandResult that requires handling in the UI to exit ProgrammerError.
+ */
+public class ExitCommandResult extends CommandResult {
+
+ /**
+ * Class constructor for {@code ExitCommandResult}.
+ *
+ * @param feedbackToUser Message to be displayed to the user.
+ */
+ public ExitCommandResult(String feedbackToUser) {
+ super(feedbackToUser);
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/FillCommand.java b/src/main/java/seedu/programmer/logic/commands/FillCommand.java
new file mode 100644
index 00000000000..b7fd1809ee6
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/FillCommand.java
@@ -0,0 +1,45 @@
+package seedu.programmer.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.programmer.model.Model.PREDICATE_SHOW_ALL_STUDENTS;
+
+import java.util.List;
+
+import seedu.programmer.model.Model;
+import seedu.programmer.model.student.Student;
+import seedu.programmer.model.util.SampleDataUtil;
+
+/**
+ * Fills the model with sample data if there is no data.
+ */
+public class FillCommand extends Command {
+
+ public static final String COMMAND_WORD = "fill";
+ public static final String MESSAGE_SUCCESS = "ProgrammerError has been filled with sample data!";
+ public static final String MESSAGE_FAIL = "There is existing data! Please purge the "
+ + "existing data to import sample data";
+
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ if (isLastShownListEmpty(model)) {
+ model.setProgrammerError(SampleDataUtil.getSampleProgrammerError());
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+ model.updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
+ model.setLabsTracker(model.getFilteredStudentList().get(0).getFreshLabList());
+ return new CommandResult(MESSAGE_FAIL);
+ }
+
+ /**
+ * Parses the ProgrammerError and check if its empty.
+ *
+ * @param model Input the model/data.
+ * @return Whether the list is empty or not.
+ */
+ public boolean isLastShownListEmpty(Model model) {
+ List lastShownList = model.getAllStudents();
+ return lastShownList.size() == 0;
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/FilterCommand.java b/src/main/java/seedu/programmer/logic/commands/FilterCommand.java
new file mode 100644
index 00000000000..984d8ee9378
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/FilterCommand.java
@@ -0,0 +1,54 @@
+package seedu.programmer.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.programmer.commons.core.Messages.MESSAGE_STUDENTS_FILTERED;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_CLASS_ID;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_STUDENT_ID;
+
+import seedu.programmer.model.Model;
+import seedu.programmer.model.student.StudentDetailContainsQueryPredicate;
+
+/**
+ * Finds and lists all students in ProgrammerError whose details contain any of the argument.
+ * Keyword matching is case-insensitive.
+ */
+public class FilterCommand extends Command {
+
+ public static final String COMMAND_WORD = "filter";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all students whose fields contain any of "
+ + "the specified arguments (case-insensitive) and displays them as a list with index numbers.\n"
+ + "Parameters: [" + PREFIX_NAME + "] "
+ + "[" + PREFIX_STUDENT_ID + "] "
+ + "[" + PREFIX_CLASS_ID + "] "
+ + "[" + PREFIX_EMAIL + "]\n"
+ + "Example: " + COMMAND_WORD + " -cid B01";
+
+ private final StudentDetailContainsQueryPredicate predicate;
+
+ /**
+ * Class constructor of {@code FilterCommand} with the {@code predicate} to test which students to be filtered.
+ *
+ * @param predicate that filters the list of students to be displayed.
+ */
+ public FilterCommand(StudentDetailContainsQueryPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredStudentList(predicate);
+ return new CommandResult(
+ String.format(MESSAGE_STUDENTS_FILTERED, model.getFilteredStudentList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof FilterCommand // instanceof handles nulls
+ && predicate.equals(((FilterCommand) other).predicate)); // state check
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/HelpCommand.java b/src/main/java/seedu/programmer/logic/commands/HelpCommand.java
new file mode 100644
index 00000000000..a168e0c23fe
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/HelpCommand.java
@@ -0,0 +1,23 @@
+package seedu.programmer.logic.commands;
+
+import seedu.programmer.model.Model;
+
+/**
+ * Shows full help instructions for every command in UI.
+ */
+public class HelpCommand extends Command {
+
+ public static final String COMMAND_WORD = "help";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Shows program usage instructions.\n"
+ + "Example: "
+ + COMMAND_WORD;
+
+ public static final String SHOWING_HELP_MESSAGE = "Opened help window.";
+
+ @Override
+ public HelpCommandResult execute(Model model) {
+ return new HelpCommandResult(SHOWING_HELP_MESSAGE);
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/HelpCommandResult.java b/src/main/java/seedu/programmer/logic/commands/HelpCommandResult.java
new file mode 100644
index 00000000000..bd03c7e4e26
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/HelpCommandResult.java
@@ -0,0 +1,16 @@
+package seedu.programmer.logic.commands;
+
+/**
+ * Represents a CommandResult that requires handling in the UI to open the HelpWindow.
+ */
+public class HelpCommandResult extends CommandResult {
+
+ /**
+ * Constructor for help command result.
+ *
+ * @param feedbackToUser Message to be displayed to the user.
+ */
+ public HelpCommandResult(String feedbackToUser) {
+ super(feedbackToUser);
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/ListCommand.java b/src/main/java/seedu/programmer/logic/commands/ListCommand.java
new file mode 100644
index 00000000000..ca36b350063
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/ListCommand.java
@@ -0,0 +1,29 @@
+package seedu.programmer.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.programmer.model.Model.PREDICATE_SHOW_ALL_STUDENTS;
+
+import seedu.programmer.model.Model;
+
+/**
+ * Lists all students in ProgrammerError to the user.
+ */
+public class ListCommand extends Command {
+
+ public static final String COMMAND_WORD = "list";
+
+ public static final String MESSAGE_SUCCESS = "Listed all students";
+ public static final String MESSAGE_NO_STUDENTS = "No students to list!";
+
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ if (model.hasNoStudents()) {
+ return new CommandResult(MESSAGE_NO_STUDENTS);
+ }
+
+ model.updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/PurgeCommand.java b/src/main/java/seedu/programmer/logic/commands/PurgeCommand.java
new file mode 100644
index 00000000000..9951bdca86f
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/PurgeCommand.java
@@ -0,0 +1,45 @@
+package seedu.programmer.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.programmer.model.Model.PREDICATE_SHOW_ALL_STUDENTS;
+
+import java.util.List;
+
+import seedu.programmer.model.Model;
+import seedu.programmer.model.ProgrammerError;
+import seedu.programmer.model.student.Student;
+
+/**
+ * Purges ProgrammerError.
+ */
+public class PurgeCommand extends Command {
+
+ public static final String COMMAND_WORD = "purge";
+ public static final String MESSAGE_SUCCESS = "ProgrammerError has been purged of data!";
+ public static final String MESSAGE_FAIL = "There is no data to purge!";
+
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ if (isLastShownListEmpty(model)) {
+ return new CommandResult(MESSAGE_FAIL);
+ }
+ model.setProgrammerError(new ProgrammerError());
+ model.updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
+ model.clearSelectedInformation();
+ model.clearLabsTracker();
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+
+ /**
+ * Parses ProgrammerError and check if its empty.
+ *
+ * @param model Input the model/data.
+ * @return Whether the list is empty or not.
+ */
+ public boolean isLastShownListEmpty(Model model) {
+ List lastShownList = model.getAllStudents();
+ return lastShownList.size() == 0;
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/ShowCommand.java b/src/main/java/seedu/programmer/logic/commands/ShowCommand.java
new file mode 100644
index 00000000000..eb6470e1f00
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/ShowCommand.java
@@ -0,0 +1,60 @@
+package seedu.programmer.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import seedu.programmer.commons.core.Messages;
+import seedu.programmer.commons.core.index.Index;
+import seedu.programmer.logic.commands.exceptions.CommandException;
+import seedu.programmer.model.Model;
+import seedu.programmer.model.student.Student;
+
+/**
+ * Shows the student's particular and lab results at the given index.
+ */
+public class ShowCommand extends Command {
+
+ public static final String COMMAND_WORD = "show";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows the student's particular and lab results "
+ + "at the given index.\n"
+ + "Parameter: (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ public static final String MESSAGE_SHOW_STUDENT_SUCCESS = "Showed %s's lab results on the side panel";
+
+ private final Index targetIndex;
+
+ /**
+ * Class constructor specifying the student at which index to show.
+ *
+ * @param targetIndex The index as displayed on the list (1-indexed) corresponding the student to be shown.
+ */
+ public ShowCommand(Index targetIndex) {
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public ShowCommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredStudentList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX);
+ }
+
+ Student studentToShow = lastShownList.get(targetIndex.getZeroBased());
+ model.setSelectedStudent(studentToShow);
+ model.setSelectedLabs(studentToShow.getLabList());
+ String feedbackToUser = String.format(MESSAGE_SHOW_STUDENT_SUCCESS, studentToShow.getName());
+ return new ShowCommandResult(feedbackToUser, studentToShow);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ShowCommand // instanceof handles nulls
+ && targetIndex.equals(((ShowCommand) other).targetIndex)); // state check
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/ShowCommandResult.java b/src/main/java/seedu/programmer/logic/commands/ShowCommandResult.java
new file mode 100644
index 00000000000..6dcb0fb5ddb
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/ShowCommandResult.java
@@ -0,0 +1,45 @@
+package seedu.programmer.logic.commands;
+
+import java.util.Objects;
+
+import seedu.programmer.model.student.Student;
+
+/**
+ * Represents a CommandResult that requires handling in the UI to show a student's lab results.
+ */
+public class ShowCommandResult extends CommandResult {
+
+ /**
+ * The application should show student's result.
+ */
+ private final Student target;
+
+ /**
+ * Class constructor for a {@code ShowCommandResult} when there is a student to show.
+ */
+ public ShowCommandResult(String feedbackToUser, Student target) {
+ super(feedbackToUser);
+ this.target = target;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof ShowCommandResult)) {
+ return false;
+ }
+
+ ShowCommandResult otherCommandResult = (ShowCommandResult) other;
+ return getFeedbackToUser().equals(otherCommandResult.getFeedbackToUser())
+ && target.equals(otherCommandResult.target);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getFeedbackToUser(), target);
+ }
+
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/UploadCommand.java b/src/main/java/seedu/programmer/logic/commands/UploadCommand.java
new file mode 100644
index 00000000000..cae52f53643
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/UploadCommand.java
@@ -0,0 +1,27 @@
+package seedu.programmer.logic.commands;
+
+import seedu.programmer.model.Model;
+
+/**
+ * Uploads a csv file of students' data to ProgrammerError's storage.
+ */
+public class UploadCommand extends Command {
+
+ public static final String COMMAND_WORD = "upload";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Uploads student data as CSV.\n"
+ + "Example: " + COMMAND_WORD;
+
+ public static final String SHOWING_UPLOAD_MESSAGE = "Upload command executed.";
+
+ /**
+ * Returns an UploadCommandResult with a message to indicate that the command was executed.
+ *
+ * @param model {@code Model} which the command should operate on.
+ * @return UploadCommandResult with a message.
+ */
+ @Override
+ public UploadCommandResult execute(Model model) {
+ return new UploadCommandResult(SHOWING_UPLOAD_MESSAGE);
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/commands/UploadCommandResult.java b/src/main/java/seedu/programmer/logic/commands/UploadCommandResult.java
new file mode 100644
index 00000000000..66965211673
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/commands/UploadCommandResult.java
@@ -0,0 +1,16 @@
+package seedu.programmer.logic.commands;
+
+/**
+ * Represents a CommandResult that requires handling in the UI to upload a csv file to ProgrammerError.
+ */
+public class UploadCommandResult extends CommandResult {
+
+ /**
+ * Class constructor for {@code UploadCommandResult}.
+ *
+ * @param feedbackToUser Message to show user.
+ */
+ public UploadCommandResult(String feedbackToUser) {
+ super(feedbackToUser);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java b/src/main/java/seedu/programmer/logic/commands/exceptions/CommandException.java
similarity index 81%
rename from src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
rename to src/main/java/seedu/programmer/logic/commands/exceptions/CommandException.java
index a16bd14f2cd..f971debe695 100644
--- a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
+++ b/src/main/java/seedu/programmer/logic/commands/exceptions/CommandException.java
@@ -1,4 +1,6 @@
-package seedu.address.logic.commands.exceptions;
+package seedu.programmer.logic.commands.exceptions;
+
+import seedu.programmer.logic.commands.Command;
/**
* Represents an error which occurs during execution of a {@link Command}.
diff --git a/src/main/java/seedu/programmer/logic/parser/AddCommandParser.java b/src/main/java/seedu/programmer/logic/parser/AddCommandParser.java
new file mode 100644
index 00000000000..635cf69d60d
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/parser/AddCommandParser.java
@@ -0,0 +1,62 @@
+package seedu.programmer.logic.parser;
+
+import static seedu.programmer.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.programmer.commons.core.Messages.MESSAGE_MISSING_ARGUMENT;
+import static seedu.programmer.commons.core.Messages.MESSAGE_UNKNOWN_ARGUMENT_FLAG;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_CLASS_ID;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_STUDENT_ID;
+import static seedu.programmer.logic.parser.ParserUtil.arePrefixesPresent;
+
+import seedu.programmer.logic.commands.AddCommand;
+import seedu.programmer.logic.parser.exceptions.InvalidArgFlagsException;
+import seedu.programmer.logic.parser.exceptions.ParseException;
+import seedu.programmer.model.student.ClassId;
+import seedu.programmer.model.student.Email;
+import seedu.programmer.model.student.Name;
+import seedu.programmer.model.student.Student;
+import seedu.programmer.model.student.StudentId;
+
+/**
+ * Parses input arguments and creates a new {@code AddCommand} object.
+ */
+public class AddCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddCommand
+ * and returns an {@code AddCommand} object for execution.
+ *
+ * @param args The String arguments as given by the user.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public AddCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap;
+ try {
+ argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_STUDENT_ID, PREFIX_CLASS_ID, PREFIX_EMAIL);
+ } catch (InvalidArgFlagsException e) {
+ throw new ParseException(
+ String.format(MESSAGE_UNKNOWN_ARGUMENT_FLAG, e.getMessage(), AddCommand.MESSAGE_USAGE));
+ }
+
+ if (!argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
+ }
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_STUDENT_ID, PREFIX_CLASS_ID, PREFIX_EMAIL)) {
+ throw new ParseException(String.format(MESSAGE_MISSING_ARGUMENT, AddCommand.MESSAGE_USAGE));
+ }
+
+ Student student = createStudent(argMultimap);
+ return new AddCommand(student);
+ }
+
+ private Student createStudent(ArgumentMultimap argMultimap) throws ParseException {
+ Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).orElse(null));
+ StudentId studentId = ParserUtil.parseStudentId(argMultimap.getValue(PREFIX_STUDENT_ID).orElse(null));
+ ClassId classId = ParserUtil.parseClassId(argMultimap.getValue(PREFIX_CLASS_ID).orElse(null));
+ Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).orElse(null));
+ return new Student(name, studentId, classId, email);
+ }
+}
diff --git a/src/main/java/seedu/programmer/logic/parser/AddLabCommandParser.java b/src/main/java/seedu/programmer/logic/parser/AddLabCommandParser.java
new file mode 100644
index 00000000000..933e8c83cd1
--- /dev/null
+++ b/src/main/java/seedu/programmer/logic/parser/AddLabCommandParser.java
@@ -0,0 +1,54 @@
+package seedu.programmer.logic.parser;
+
+import static seedu.programmer.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.programmer.commons.core.Messages.MESSAGE_MISSING_ARGUMENT;
+import static seedu.programmer.commons.core.Messages.MESSAGE_UNKNOWN_ARGUMENT_FLAG;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_LAB_NUM;
+import static seedu.programmer.logic.parser.CliSyntax.PREFIX_LAB_TOTAL;
+import static seedu.programmer.logic.parser.ParserUtil.arePrefixesPresent;
+
+import seedu.programmer.logic.commands.AddLabCommand;
+import seedu.programmer.logic.parser.exceptions.InvalidArgFlagsException;
+import seedu.programmer.logic.parser.exceptions.ParseException;
+import seedu.programmer.model.student.Lab;
+import seedu.programmer.model.student.LabNum;
+import seedu.programmer.model.student.LabTotal;
+
+
+/**
+ * Parses input arguments and creates a new AddLabCommand object.
+ */
+public class AddLabCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddLabCommand
+ * and returns an AddLabCommand object for execution.
+ *
+ * @param args The String arguments as given by the user.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public AddLabCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap;
+ try {
+ argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_LAB_NUM, PREFIX_LAB_TOTAL);
+ } catch (InvalidArgFlagsException e) {
+ throw new ParseException(
+ String.format(MESSAGE_UNKNOWN_ARGUMENT_FLAG, e.getMessage(), AddLabCommand.MESSAGE_USAGE));
+ }
+
+ if (!argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddLabCommand.MESSAGE_USAGE));
+ }
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_LAB_NUM, PREFIX_LAB_TOTAL)) {
+ throw new ParseException(String.format(MESSAGE_MISSING_ARGUMENT, AddLabCommand.MESSAGE_USAGE));
+ }
+
+ LabNum labNum = new LabNum(ParserUtil.parseLabNum(
+ argMultimap.getValue(PREFIX_LAB_NUM).orElse(null)));
+ LabTotal total = new LabTotal(ParserUtil.parseTotal(
+ argMultimap.getValue(PREFIX_LAB_TOTAL).orElse(null)));
+ Lab labResult = new Lab(labNum, total);
+ return new AddLabCommand(labResult);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java b/src/main/java/seedu/programmer/logic/parser/ArgumentMultimap.java
similarity index 95%
rename from src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
rename to src/main/java/seedu/programmer/logic/parser/ArgumentMultimap.java
index 954c8e18f8e..7b9493f096f 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
+++ b/src/main/java/seedu/programmer/logic/parser/ArgumentMultimap.java
@@ -1,4 +1,4 @@
-package seedu.address.logic.parser;
+package seedu.programmer.logic.parser;
import java.util.ArrayList;
import java.util.HashMap;
@@ -15,7 +15,9 @@
*/
public class ArgumentMultimap {
- /** Prefixes mapped to their respective arguments**/
+ /**
+ * Prefixes mapped to their respective arguments.
+ */
private final Map