diff --git a/LICENSE b/LICENSE
index 39b3478982c..3ee16000e96 100644
--- a/LICENSE
+++ b/LICENSE
@@ -2,11 +2,11 @@ MIT License
Copyright (c) 2016 Software Engineering Education - FOSS Resources
-Permission is hereby granted, free of charge, to any person obtaining a copy
+Permission is hereby granted, free of charge, to any student obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
+copies of the Software, and to permit students to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
diff --git a/README.md b/README.md
index 13f5c77403f..d6fae19f7f0 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,12 @@
-[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions)
+[![CI Status](https://github.com/AY2122S1-CS2103T-W15-1/tp/actions/workflows/gradle.yml/badge.svg)](https://github.com/AY2122S1-CS2103T-W15-1/tp/actions)
![Ui](docs/images/Ui.png)
-* This is **a sample project for Software Engineering (SE) students**.
+* This is **a student participation tracker for CS2101 instructors**.
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.
+ * to store student contacts and academic information
+ * to assign students to classes and/or groups
+* It inherits from the Addressbook-Level-3 application, created by the [SE-EDU initiative](https://se-education.org).
+* It is named `ClassMATE` because it is meant for a classroom setting.
+* For the detailed documentation of this project, see the **[classMATE Product Website](https://ay2122s1-cs2103t-w15-1.github.io/tp/)**.
+* This project is an effort of team W15-1 of the CS2103T module of AY21/22 Semester 1.
diff --git a/build.gradle b/build.gradle
index be2d2905dde..59edc582595 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,6 +6,10 @@ plugins {
id 'jacoco'
}
+run {
+ enableAssertions = true
+}
+
mainClassName = 'seedu.address.Main'
sourceCompatibility = JavaVersion.VERSION_11
@@ -16,6 +20,10 @@ repositories {
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
+run {
+ enableAssertions = true
+}
+
checkstyle {
toolVersion = '8.29'
}
@@ -66,7 +74,11 @@ dependencies {
}
shadowJar {
- archiveName = 'addressbook.jar'
+ archiveName = 'classmate.jar'
+}
+
+run {
+ enableAssertions = true
}
defaultTasks 'clean', 'test'
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 1c9514e966a..20f5fe72467 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -5,55 +5,57 @@ 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 `vishnu04@comp.nus.edu.sg`
+(temporarily until team email is established)
## Project team
-### John Doe
+### Ngu Yi Yang
-
+
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/nguyiyang)]
+[[portfolio](team/nguyiyang.md)]
-* Role: Project Advisor
+* Role: Team Lead
+* Responsibilities: Integration
-### Jane Doe
+### Rushil Ramesh
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/rushilramesh)]
+[[portfolio](team/rushilramesh.md)]
-* Role: Team Lead
-* Responsibilities: UI
+* Role: Developer
+* Responsibilities: Testing + Model
-### Johnny Doe
+### Gabriel Waikin Loh Matienzo
-
+
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](http://github.com/GabrielWLM)]
+[[portfolio](team/gabrielwlm.md)]
* Role: Developer
-* Responsibilities: Data
+* Responsibilities: Documentation + Data
-### Jean Doe
+### Zhou Yirui
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/zhouyirui)]
+[[portfolio](team/zhouyirui.md)]
* Role: Developer
-* Responsibilities: Dev Ops + Threading
+* Responsibilities: Code Quality
-### James Doe
+### Vishnu Sundaresan
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/juliussneezer04)]
+[[portfolio](team/juliussneezer04.md)]
* Role: Developer
-* Responsibilities: UI
+* Responsibilities: Deliverables + Scheduling & Tracking
diff --git a/docs/DevOps.md b/docs/DevOps.md
index ca59d92f2cb..08a5358bad5 100644
--- a/docs/DevOps.md
+++ b/docs/DevOps.md
@@ -44,7 +44,7 @@ As part of CI, this project uses Codecov to generate coverage reports. Here are
1. Sign up with Codecov using your GitHub account [here](https://codecov.io/signup).
1. Once you are inside Codecov web app, add your fork to CodeCov.
-1. Get the Markdown code for the Codecov badge provided in `Settings > Badges` and update the `docs/index.md` of your repo with it so that the badge [![codecov](https://codecov.io/gh/se-edu/addressbook-level3/branch/master/graph/badge.svg)](https://codecov.io/gh/se-edu/addressbook-level3) in that page reflects the coverage of your project.
+1. Get the Markdown code for the Codecov badge provided in `Settings > Badges` and update the `docs/index.md` of your repo with it so that the badge [![codecov](https://codecov.io/gh/AY2122S1-CS2103T-W15-1/tp/branch/master/graph/badge.svg)](https://codecov.io/gh/AY2122S1-CS2103T-W15-1/tp) in that page reflects the coverage of your project.
### Repository-wide checks
@@ -73,7 +73,7 @@ Any warnings or errors will be printed out to the console.
Here are the steps to create a new release.
-1. Update the version number in [`MainApp.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java).
+1. Update the version number in [`MainApp.java`](https://github.com/AY2122S1-CS2103T-W15-1/tp/tree/master/src/main/java/seedu/address/MainApp.java).
1. Generate a fat JAR file using Gradle (i.e., `gradlew shadowJar`).
1. Tag the repo with the version number. e.g. `v0.1`
1. [Create a new release using GitHub](https://help.github.com/articles/creating-releases/). Upload the JAR file you created.
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 46eae8ee565..3a349032684 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -2,14 +2,17 @@
layout: page
title: Developer Guide
---
+
* Table of Contents
{:toc}
+
+
--------------------------------------------------------------------------------------------------------------------
## **Acknowledgements**
-* {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+* This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
--------------------------------------------------------------------------------------------------------------------
@@ -23,12 +26,13 @@ Refer to the guide [_Setting up and getting started_](SettingUp.md).
-: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-CS2103T-W15-1/tp/tree/master/docs/diagrams/) folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams.
### Architecture
-
+![image](images/ArchitectureDiagram.png)
The ***Architecture Diagram*** given above explains the high-level design of the App.
@@ -36,7 +40,8 @@ Given below is a quick overview of main components and how they interact with ea
**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-CS2103T-W15-1/tp/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/AY2122S1-CS2103T-W15-1/tp/tree/master/src/main/java/seedu/address/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.
@@ -52,101 +57,106 @@ The rest of the App consists of four components.
**How the architecture components interact with each other**
-The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues the command `delete 1`.
+The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues the command `deletestu 1`.
-
+![image](images/ArchitectureSequenceDiagram.png)
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 the (partial) class diagram below.
-
+![image](images\ComponentManagers.png)
The sections below give more details of each component.
### UI component
-The **API** of this component is specified in [`Ui.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/Ui.java)
+The **API** of this component is specified in [`Ui.java`](https://github.com/AY2122S1-CS2103T-W15-1/tp/tree/master/src/main/java/seedu/address/ui/Ui.java)
![Structure of the UI Component](images/UiClassDiagram.png)
-The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI.
+The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `StudentListPanel`, `ClassListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI.
-The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml)
+The `UI` 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/AY2122S1-CS2103T-W15-1/tp/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/AY2122S1-CS2103T-W15-1/tp/tree/master/src/main/resources/view/MainWindow.fxml)
The `UI` component,
* executes user commands using the `Logic` component.
* listens for changes to `Model` data so that the UI can be updated with the modified data.
* keeps a reference to the `Logic` component, because the `UI` relies on the `Logic` to execute commands.
-* depends on some classes in the `Model` component, as it displays `Person` object residing in the `Model`.
+* depends on some classes in the `Model` component, as it displays `Student` and `TutorialClass` objects residing in the `Model`.
### Logic component
-**API** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java)
+**API** : [`Logic.java`](https://github.com/AY2122S1-CS2103T-W15-1/tp/tree/master/src/main/java/seedu/address/logic/Logic.java)
Here's a (partial) class diagram of the `Logic` component:
-
+![image](images/LogicClassDiagram.png)
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. When `Logic` is called upon to execute a command, it uses the `ClassmateParser` class to parse the user command.
1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `AddCommand`) which is executed by the `LogicManager`.
-1. The command can communicate with the `Model` when it is executed (e.g. to add a person).
-1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`.
+1. 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 from `Logic`.
-The Sequence Diagram below illustrates the interactions within the `Logic` component for the `execute("delete 1")` API call.
+The Sequence Diagram below illustrates the interactions within the `Logic` component for the `execute("deletestu 1")` API call.
-![Interactions Inside the Logic Component for the `delete 1` Command](images/DeleteSequenceDiagram.png)
+![Interactions Inside the Logic Component for the `deletestu 1` Command](images/DeleteStudentSequenceDiagram.png)
-
:information_source: **Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+
:information_source: **Note:** The lifeline for `DeleteStudentCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+
Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command:
-
+![image](images/ParserClasses.png)
How the parsing works:
-* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object.
-* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing.
+
+* When called upon to parse a user command, the `ClassmateParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddStudentCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddStudentCommand`) which the `ClassmateParser` returns back as a `Command` object.
+* All `XYZCommandParser` classes (e.g., `AddStudentCommandParser`, `DeleteStudentCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing.
### Model component
-**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java)
-
+**API** : [`Model.java`](https://github.com/AY2122S1-CS2103T-W15-1/tp/tree/master/src/main/java/seedu/address/model/Model.java)
+
+![image](images/ModelClassDiagram.png)
The `Model` component,
-* stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object).
-* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.
+* stores the ClassMATE data i.e., all `Student` objects (which are contained in a `UniqueStudentList` object), and all `TutorialClass` objects (which are contained in a `UniqueTutorialClassList` object).
+* stores the currently 'selected' `Student` and `TutorialClass` objects (e.g., results of a search query) as a separate _filtered_ lists which are exposed to outsiders as an unmodifiable `ObservableList` and `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.
* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects.
* does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components)
-
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
+
:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `ClassMATE`, which `Student` references. This allows `ClassMATE` to only require one `Tag` object per unique tag, instead of each `Student` needing their own `Tag` objects.
-
+![image](images/BetterModelClassDiagram.png)
### Storage component
-**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java)
+**API** : [`Storage.java`](https://github.com/AY2122S1-CS2103T-W15-1/tp/tree/master/src/main/java/seedu/address/storage/Storage.java)
-
+![image](images/StorageClassDiagram.png)
The `Storage` component,
-* can save both address book data and user preference data in json format, and read them back into corresponding objects.
-* inherits from both `AddressBookStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed).
+
+* can save both ClassMATE data and user preference data in json format, and read them back into corresponding objects.
+* inherits from both `ClassmateStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed).
* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`)
### Common classes
-Classes used by multiple components are in the `seedu.addressbook.commons` package.
+Classes used by multiple components are in the `seedu.address.commons` package.
--------------------------------------------------------------------------------------------------------------------
@@ -154,89 +164,440 @@ Classes used by multiple components are in the `seedu.addressbook.commons` packa
This section describes some noteworthy details on how certain features are implemented.
-### \[Proposed\] Undo/redo feature
+### Tutorial Class Management Features
+
+(Contributed by Rushil Ramesh and Vishnu Sundaresan)
+
+ClassMATE allows the user to manage information relevant to the TutorialClass. A User is able to:
+
+1. Add a new tutorial class
+2. Delete an existing tutorial class
+3. List all existing tutorial class
+4. Find tutorial classes by their class codes (more [here](#class-and-tutorial-group-filters-features))
+5. View Class Details
+
+#### Current Implementation
+
+The class `Classmate` facilitates all operations related to tutorial classes. It maintains a `UniqueTutorialClassList`
+of containing all tutorial classes, as well as a `FliteredList` of `TutorialClass` instances reflecting the current
+state of the tutorial class list to be displayed to the user. The `Classmate` contains a summary of all the logic of the
+tutorial class commands (e.g. `AddClassCommand`) executed on the `UniqueTutorialCLassList`.
+
+The following operations are implemented:
+
+* `Classmate#hasTutorialClass(TutorialClass tutorialClass)` - Checks if tutorial class is in ClassMATE
+* `Classmate#addTutorialClass(TutorialClass tutorialClass)` - Adds tutorial Class to ClassMATE
+* `Classmate#removeTutorialClass(TutorialClass tutorialClass)` - Deletes existing tutorial class from ClassMATE
+* `Classmate#getTutorialClassList()` - Displays entire list of tutorial classes.
+* `Model#updateFilteredTutorialClassList(Predicate predicate)` - Searches for tutorial class by keyword and displays filtered list.
+* `Model#updateUnfilteredStudentList(List students)` - Updates list of students when a class is deleted.
+
+These operations are exposed in the `Model` interface as `Model#hasTutorialClass(TutorialClass tutorialClass)`,
+`Model#addTutorialClass(TutorialClass tutorialClass)`, `Model#deleteTutorialClass(TutorialClass tutorialClass)` and
+`Model#getTutorialClass()`respectively.
+
+Given below is an example of how the tutorial class features can be used:
+
+Step 1. The user launches the application for the first time. The `UniqueTutorialClassList` would be derived from the
+initial ClassMATE state, and all tutorial classes stored will be displayed.
+
+Step 2. The user executes an `addc c/G01 s/Tuesday 12:00pm to 2:00pm, Friday 12:00pm to 2:00pm` command. The `addc` command calls `Model#addTutorialClass()`, adding a new tutorial class to ClassMATE. This modifies and saves the
+state of ClassMATE. The updated `UniqueTutorialClassList` will be displayed in the `ClassListPanel`
+to the user.
+
+Step 3. The user executes a `viewc 1` command. The `viewc` command updates the `filteredTutorialClasses` to only display the class at the
+given index, and updates the `filteredStudents` to contain only the students who are in the selected class. The updated filtered list of
+students and tutorial classes will be displayed to the user.
+
+Step 4. The user executes a `deletec 2` command. The `deletec` command calls `Model#deleteTutorialCLass()`, modifying and saving the
+state of ClassMATE by deleting the class stored at the given index in the `FilteredList`. The students from the deleted class are no longer part of the deleted
+class and left with a displayed class code of `No Class`. The tutorial groups that were part of the class will be deleted. This updated list will be displayed to the user.
+
+Step 5. The user executes a `listc` command. The `listc` command calls `Model#updateFilteredTutorialClassList()` modifying and saving the state of the `FilteredList`
+to contain all tutorial classes in ClassMATE. This updated list will be displayed to the user.
+
+Using the example of the `AddClassCommand`,
+when the user enters the `addc` command to add a tutorial class, the user input command undergoes the same command parsing as described in [Logic component](#logic-component).
+During the parsing, a new TutorialClass instance is created. This `TutorialClass` instance will be received by the `AddClassCommand` when it is created.
+The command is then executed, adding the new class to ClassMATE
+
+The *Sequence Diagram* below summarises the aforementioned steps in the execution of the command.
+
+![AddClassSequenceDiagram](images/AddClassSequenceDiagram.png)
+Execution of the `AddClassCommand`
+
+#### Design Considerations
+
+#### Aspect: Student and Tutorial Class lists
+
+* Alternative 1 (current choice): Use two separate lists to store students and tutorial classes
+ * Pros: Faster, simpler command executions for student and tutorial class commands.
+ Easier to maintain overall. Therefore, all students and all tutorial classes can be accessed independent of each other.
+ * Cons: Class specific student commands are slower. For example a user is required to `viewc` in order to filter just the students in the class,
+ increasing the overall time
+* Alternative 2: Nesting of students within Tutorial Class
+ * Pros: Faster in class specific student commands and students are better organised.
+ * Cons: Complexity of tutorial classes is increased and slower to navigate to view other tutorial classes or perform general commands on the students
+
+### Student Management Features
+
+(Contributed by Rushil Ramesh)
+
+ClassMATE allows the user to manage information about Students. The user is able to:
+
+1. Add a student
+1. Edit an existing student
+1. View a student's details
+1. Delete a student
+1. List all students
+1. Find students by name
+
+#### Current Implementation
+
+`Classmate` facilitates all operations related to students. It maintains a `UniqueStudentList` consisting of all students as well as a
+separate `FilteredList` of students in `ModelManager` that reflect the current state of the student list to be displayed to the user. `Classmate` contains the logic related to
+managing students, and summarises the various student related commands.
+
+The following operations are supported by ClassMATE:
+
+* `Classmate#hasStudent(Student student)` - Checks if a student is in ClassMATE
+* `Classmate#addStudent(Student student)` - Adds a student to ClassMATE
+* `Classmate#setStudent(Student student, Student editedStudent)` - Edits a student's details
+* `Classmate#removeStudent(Student student)` - Deletes existing student from ClassMATE
+* `Model#updateFilteredStudentList(Predicate predicate)` - Searches for a student by given keyword and displays filtered list.
+
+These operations are exposed in the `Model` interface, which call methods of `Classmate` and `FilteredList`.
+
+Given below is an example of how the student features could be used by the user:
+
+Step 1. The user launches the application for the first time. The `UniqueStudentList` would be derived from the initial ClassMATE state, and
+all students stored will be displayed with their details.
+
+Step 2. The user creates a tutorial class by using the `addc` command, for example `addc c/G01 s/Tuesday 12:00pm to 2:00pm, Friday 12:00pm to 2:00pm`.
+The newly created tutorial class will be displayed in the `ClassListPanel` to the user. Refer to [Tutorial Class Management Features](#tutorial-class-management-features)
+section for more information on tutorial classes.
+
+Step 3. The user executes a `addstu n/Johnny Tay p/98989898 a/26 Clementi Avenue 6 e/johnnytay@email.com c/G01` command. The `addstu` command executes the
+`AddStudentCommand`, which in turn calls the `Model#addStudent()` command to add a new student to ClassMATE. The student is added to the recently create `G01` class.
+The updated `UniqueStudentList` will be displayed to users on the `StudentListPanel`.
+
+Step 4. The user executes a `findstu Johnny` command. The `findstu` command calls the `Model#updateFilteredStudentList()` method which
+modifies the state of the `FilteredList` of students. The updated filtered list containing the students whose names match the query keywords will
+be displayed to the user. Users will have to type one of the student's names to find a particular student (e.g. `findstu Tay` will also filter our newly added student)
+
+Step 5. The user executes a `viewstu 1` command. The `viewstu` command causes a pop-up window to appear, displaying the details of the selected student, such as the
+groups the student is in and the class participation marks for previous lessons. Any movements to the main screen would result in this window closing.
+
+Step 6. The user executes a `deletestu 2` command. The `deletestu` command calls the `Model#deleteStudent()` function. This executes a `DeleteStudentCommand`,
+which deletes a student currently in the second index of the `FitleredList`. This modifies and saves the state of ClassMATE, displaying the updated list of students
+to the user.
+
+Step 7. the user executes a `liststu` command. The command calls the `Model#updateFilteredStudentList()` function by setting the predicate of the
+`FilteredList` to `true` for all students. The updated list consisting of all students in ClassMATE is then displayed to the user.
+
+The logic flow of executing a student command can be best illustrated using the `FindStudentCommand`. When the enters the `findstu`
+command to find a Student whose name matches the given keyword, the user input undergoes the same command parsing
+as described in the [Logic component](#logic-component) section. During the parsing, a new `NameCOntainsKeywordsPredicate` is created,
+which will be received by the `FindStudentCommand`. The execution of a command sets the`Predicate` of the `FilteredList` of students
+to the parsed predicate, updating the list that is displayed.
+
+The *Sequence Diagram* below summarises the aforementioned steps in the execution of the command.
+
+![FindStudentSequenceDiagram](images/FindStudentSequenceDiagram.png)
+Execution of the `FindStudentCommand`
+
+#### Design Considerations
+
+#### Aspect: Adding Students to ClassMATE
+
+* Alternative 1 (current choice): Add a student with a compulsory `CLASS_CODE` parameter
+ * Pros: This was the most intuitive option, as users only need add students assigned to their classes. Therefore, requiring users
+ to create a class before adding a student prevents the case where students are added without a class
+ * Cons: This increases the command length for the user, increasing the time taken for the user to type the command.
+* Alternative 2: Add a student independent of whether the tutorial class has been created
+ * Pros: Users are able to create a student without having to take the additional step of creating a class, and shorter command
+ length means higher typing speeds for users.
+ * Cons: This would require an additional command to add students to a class, which decreases the efficiency of the program.
+
+#### Aspect: Display of Student Information
+
+* Alternative 1 (current choice): Display a summary of user information in the List and more details upon viewing the student.
+ * Pros: This reduces cluttering in the student display panel and presents the necessary information to the user in the list. User has the option to
+ focus on a particular student and view additional details if they need to.
+ * Cons: This necessitates the creation of an additional `viewc` command for users to be able to view this data.
+
+* Alternative 2: Present all student information in the student list itself.
+ * Pros: All student information can be seen in one place without having to use additional commands to access information.
+ * Cons: This is not visually appealing and provides information in a cluttered manner to the user, reducing the overall
+ quality of the user's experience using the application.
+
+### Student Participation Mark Features
+
+(Contributed by Vishnu Sundaresan)
+
+ClassMATE allows the user to manage information about Class Participation grading relevant to each Student. A User is able to:
+
+1. Add a weekly participation mark
+2. Delete a weekly participation mark
+3. Delete all weekly participation marks
#### Proposed Implementation
-The proposed undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo history, stored internally as an `addressBookStateList` and `currentStatePointer`. Additionally, it implements the following operations:
+Each Student will contain a `List` known as `marks` that will store all participation mark values for the Student. This list is internally stored as an `ArrayList`. Using an `Enumeration` of Student Marks, which contains the following Marks:
-* `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.
+* `POOR` (0 marks)
+* `LOW` (1 mark)
+* `AVG` (2 marks)
+* `GOOD` (3 marks)
+* `HIGH` (4 marks)
+* `EXCELLENT` (5 marks)
-These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively.
+ClassMATE will then support the following command classes:
-Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
+* `AddLastMarkCommand(Index index, StudentMark mark)`
+* `DeleteLastMarkCommand(Index index)`
+* `DeleteAllMarksCommand(Index index)`
-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.
+These commands inherit from the `Command` class, and are named accordingly.
-![UndoRedoState0](images/UndoRedoState0.png)
+Given below is an example of how the student marks features can be used:
-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.
+Step 1. The user launches the application for the first time. The existing `marks` list would be derived from the
+initial ClassMATE state, and all students stored will be displayed along with their currently stored marks below their name
-![UndoRedoState1](images/UndoRedoState1.png)
+Step 2. The user executes an `addm 1 m/low` command. After the Command has been parsed, the `addm` command calls `AddLastMarkCommand#addStudentMark()` and subsequently `Model#setStudent()` and `Model#updateFilteredStudentList()`, adding the mark provided (`LOW` in this case) to Classmate. This modifies and saves the state of ClassMATE. The updated `UniqueStudentList` will be displayed in the `ClassListPanel` to the user.
-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 user executes a `deletelm 1` command. The `deletelm` command calls the `DeleteLastMarkCommand#deleteLastStudentMark()` and subsequently the`Model#setStudent()` and the `Model#updateFilteredStudentList()`, modifying the state of the filtered list of students. The updated filtered list consists the students with the latest mark removed from the 1st student.
-![UndoRedoState2](images/UndoRedoState2.png)
+ **Before `deletelm` command**
-
: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`.
+![StudentMarkState1](images/StudentMarksState1.png)
-
+ **After `deletelm` 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.
+![StudentMarkState2](images/StudentMarksState2.png)
-![UndoRedoState3](images/UndoRedoState3.png)
+Step 4. The user executes a `deleteam 1` command. The `deleteam` command calls `DeleteAllMarkCommand#deleteAllStudentMark()`, then subsequently `Model#setStudent()`and `Model#updateFilteredStudentList()`, modifying and saving the state of ClassMATE by deleting all marks for the 1st student at the given index in the `UniqueStudentList`. This updated list will be displayed to the user.
-
: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.
+Using the example of the `AddMarkCommand`,
+when the user enters the `addm` command to add a tutorial class, the user input command undergoes the same command parsing as described in [“Logic component”](#logic-component).
+During the parsing, a new `Student` instance is created. This `Student` instance will be received by the `AddMarkCommand` when it is created.
-
+The *Sequence Diagram* below summarizes the aforementioned steps.
-The following sequence diagram shows how the undo operation works:
+![AddMarkSequenceDiagram](images/AddMarkSequenceDiagram.png)
-![UndoSequenceDiagram](images/UndoSequenceDiagram.png)
+Execution of the `AddMarkCommand`
-
: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.
+#### Design Considerations
-
+#### Aspect: Rationale for studentMarks size
-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.
+* Alternative 1 (current choice): Keep a list of variable length
+ * Pros: Flexible, allows instructors not to worry about the number of tutorials taken.
+ * Cons: Prone to human error of counting, not tallying within strict 26 tutorial-limit.
+* Alternative 2: Keep a fixed-size list of 26
+ * Pros: Since there are 13 weeks and two tutorials a week, there will be a projected 26 tutorials held. Thus, a fixed size of 26 elements will allow the list to reflect this requirement.
+ * Cons: Instructors are limited to this 26-class limit, and cannot store marks for extra tutorials/make-up sessions.
-
: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.
+#### Aspect: Display of Marks
-
+* Alternative 1: Display as a list under student credentials in each student card
+ * Pros: Simple to implement, easily viewed
+ * Cons: Unable to fit all marks, lack of earlier mark visibility
+* Alternative 2 (current choice): Display in `viewstu` command as separate feature
+ * Pros: Can view all marks at once, clear to understand
+ * Cons: Marks can only be viewed for one student at a time
+
+### ClassCode Features
+
+(Contributed by Zhou Yirui)
+
+ClassMATE allows user to assign a Student or a Tutorial Group to a Tutorial Class using a ClassCode. A user is able to:
+
+1. Add ClassCode to a student
+2. Edit ClassCode of a student
+3. Create Tutorial Group using ClassCode
+4. Create Tutorial Classes using ClassCode
+
+#### Current Implementation
+
+The class `ClassCode` facilitates all operations related to classCode. `ClassCode` is implemented such that a
+Tutorial Class with the corresponding `ClassCode` must exist before the `ClassCode` can be added. Tutorial Class `G00` is a
+default class that do not need to be created and is an empty `ClassCode`. It is assigned to a Student whose Tutorial Class has been deleted.
-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.
+Given below is an example of how `ClassCode` can be used.
-![UndoRedoState4](images/UndoRedoState4.png)
+Step 1: After launching the application for the first time, user executes `addstu n/Abigail p/91199119 e/ab@gmail.com a/Downling Park #15-20 c/G08`.
+The `addstu` command calls `Model#hasTutorialClass()`, and the model component checks if the TutorialClass specified by the
+class code exists. If it exists, the student is added successfully with the classCode parameter `G08`, else, an error message is given.
-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.
+Step 2: The user deletes TutorialClass G08 using the `deletec c/G08` command. The `deletec` command changes the ClassCode of all students
+of TutorialClass `G08` to `G00`. On ClassMATE, the UI reflects the Student to have no Tutorial Class, i.e. `No class`.
-![UndoRedoState5](images/UndoRedoState5.png)
+### Tutorial Group Management Features
-The following activity diagram summarizes what happens when a user executes a new command:
+This feature is split into two parts.
-
+* Adding/removing tutorial group to tutorial class (Contributed by Ngu Yi Yang)
+* Adding/removing student to tutorial group. (Contributed by Zhou Yirui)
-#### Design considerations:
+ClassMATE allows the user to manage information relevant to the TutorialGroup. A User is able to:
-**Aspect: How undo & redo executes:**
+1. Add a new tutorial group to an existing tutorial class
+2. Remove an existing tutorial group from an existing tutorial class
+3. Add a student to an existing tutorial group
+4. Remove a student from tutorial group
-* **Alternative 1 (current choice):** Saves the entire address book.
- * Pros: Easy to implement.
- * Cons: May have performance issues in terms of memory usage.
+#### Current Implementation (Adding/removing tutorial group to tutorial class)
-* **Alternative 2:** Individual command knows how to undo/redo by
- itself.
- * Pros: Will use less memory (e.g. for `delete`, just save the person being deleted).
- * Cons: We must ensure that the implementation of each individual command are correct.
+The class `Classmate` facilitates all operations related to tutorial groups. It maintains a
+`UniqueTutorialClassList` containing all tutorial classes, where each `TutorialClass` maintains a `UniqueTutorialGroupList` containing its tutorial groups.
+`Classmate` contains a summary of all the logic of the interaction between tutorial group and tutorial class such as
+adding tutorial groups to tutorial classes (e.g. `AddGroupCommand`) executed on the `UniqueTutorialGroupList`.
-_{more aspects and alternatives to be added}_
+The following operations are implemented which highlight the interactions between subcomponents within `Model`
+related to adding a tutorial group to a class:
-### \[Proposed\] Data archiving
+* `UniqueTutorialClassList#contains(TutorialClass toCheck)` - Checks if tutorial class exists
+* `UniqueTutorialClassList#contains(TutorialGroup toCheck)` - Checks if tutorial group is in any of the tutorial classes
+* `TutorialClass#isSameTutorialClass(TutorialClass tutorialClass)` - Checks if two tutorial classes are the same. They are the same if their Class codes are the same.
+* `TutorialGroup#isSameTutorialGroup(TutorialClass tutorialGroup)` - Checks if two tutorial groups are the same. They are the same if their Class codes, Group number and Group type are the same.
+* `UniqueTutorialClassList#add(TutorialGroup toAdd)` - Finds the tutorial group list of the tutorial class to add the tutorial group to
+* `UniqueTutorialGroupList#add(TutorialGroup toAdd)` - Adds tutorial group to the tutorial group list of a class
+* `TutorialClass#getTutorialGroups()` - Retrieves the list of tutorial groups within the TutorialClass
+* `TutorialClass#createTestTutorialClass(ClassCode classCode)` - Creates a dummy tutorial class with the class code of the tutorial group for checking
-_{Explain here how the data archiving feature will be implemented}_
+Given below is an example of how the tutorial group features can be used:
+
+Step 1. The user executes an `addcg gn/1 c/G06 type/OP1` command. The `addcg` command calls `Model#hasTutorialClass()`,
+and the model component checks if the tutorial class specified by the class code exists and throws an exception if it does not.
+It then checks whether the tutorial group already exists using `Model#hasTutorialGroup()`and calls `Model#addTutorialGroup()` if it does not.
+
+The checking of whether the tutorial class and tutorial group already exists is implemented as such:
+`Classmate` calls the `contains` method of its `UniqueTutorialClassList`. This method is overloaded to accept
+either a `TutorialClass` or `TutorialGroup`. The difference between the implementation of these two is that for the former,
+it checks through its list of tutorial classes by utilising streams and the `TutorialClass#isSameTutorialClass()` method.
+
+For the latter, it uses `TutorialClass#createTestTutorialClass(ClassCode classCode)`
+to create the tutorial class representing the one that the tutorial group is being added to so that it can then retrieve that tutorial class
+within the `UniqueTutorialClassList`. Since the checking of whether the tutorial class exists is done beforehand,
+the tutorial class is guaranteed to exist and is retrieved. From the tutorial class, its `UniqueTutorialGroupList` is retrieved using the method `TutorialClass#getTutorialGroups()`.
+It then checks whether tutorial group already exists by utilising streams and the `TutorialGroup#isSameTutorialGroup()` method.
+
+Adding of tutorial groups is similar; `UniqueTutorialClassList#add(TutorialGroup toAdd)` retrieves the tutorial class from the `UniqueTutorialClassList` and its `UniqueTutorialGroupList`,
+in order to add the tutorial group using `UniqueTutorialGroupList#add(TutorialGroup toAdd)`.
+
+This modifies and saves the state of ClassMATE.
+
+Step 2. The user executes a `deletecg c/G06 gn/1 type/OP1` command. The `deletecg` command works in the same way as the `addcg`
+command, except it removes that tutorial group from ClassMATE after checking if it exists. It also removes all students
+in that tutorial group.
+
+Using the example of the `AddGroupCommand`,
+when the user enters the `addcg` command to add a tutorial group, the user input command undergoes the same command parsing as described in [“Logic component”](#logic-component).
+During the parsing, a new `TutorialGroup` instance is created. This `TutorialGroup` instance will be received by the `AddGroupCommand` when it is created.
+
+The *Sequence Diagram* below summarizes how tutorial groups are added to a tutorial class.
+
+![AddGroupSequenceDiagram](images/AddGroupSequenceDiagram.png)
+
+The *Sequence Diagram* below shows how `UniqueTutorialClassList` retrieves the
+`UniqueTutorialGroupList` from the specified TutorialClass for checking or adding of a given tutorial group.
+
+![GetTutorialGroupsDiagram](images/GetTutorialGroupsDiagram.png)
+
+
+#### Design Considerations
+
+#### Aspect: Storing Tutorial Groups as lists
+
+* Alternative 1 (current choice): Storing tutorial groups in their respective tutorial classes
+ * Pros: Faster when performing find functions such as finding tutorial groups in a particular class. Tutorials groups are also better organised.
+ * Cons: Splitting groups based on a category makes it harder to extend to support filtering groups with a different category from what is implemented.
+
+* Alternative 2: Use a single list to store all tutorial groups.
+ * Pros: Simpler to implement, easier to add or remove tutorial groups.
+ Storing tutorial groups as arrays in JSON is less complicated.
+ * Cons: Searching or filtering the list of tutorial groups by group types may take a longer time.
+
+#### Current Implementation (Adding/Removing Student from Tutorial Group)
+
+Each Student contains a `Set` of `TutorialGroup` they belong to. Tutorial Groups are stored internally as a `HashSet`. The `HashSet` of
+`TutorialGroup` is implemented such that there are no duplicate `TutorialGroup`, and each Student belongs to at most 1 `TutorialGroup` of
+each Group Type.
+
+ClassMATE will then support the following command classes:
+
+* `AddStudentToGroupCommand(Index index, TutorialGroup tutorialGroup)`
+* `DeleteStudentFromGroupCommand(Index index, TutorialGroup tutorialGroup)`
+
+Given below is an example of how the Add and Delete Student from Tutorial Groups features can be used:
+
+Step 1. The user launches the application for the first time. The existing set of `TutorialGroup` for each Student would be retrieved from the initial
+ClassMATE state, and would be displayed with the details the Student.
+
+Step 2. The user enters `liststu` to list all the existing Students in ClassMATE
+
+Step 3. The user executes `addsg 1 gn/1 c/G06 type/OP1`. After the Command has been parsed, the `addsg` command calls `AddStudentToGroup#addTutorialGroup()`.
+Subsequently, `Model#setStudent` and `Classmate#setStudent` are called consecutively to update the `TutorialGroup` of the Student.
+During the execution of `AddStudentToGroupCommand`, a new `Student` instance with the edited set of `TutorialGroup` is created.
+
+#### Design Considerations
+
+#### Aspect: Student parameters in the Command
+
+* Alternative 1 (current choice): Identifying the Student using Index.
+ * Pros: Easier to implement. Less ambiguity arising from Students with the same names.
+ * Cons: Adding/Deleting a Student from a Tutorial Group takes a longer time. Filtering the Student list may be necessary.
+
+* Alternative 2: Identifying the Student using a Student ID.
+ * Pros: Faster to perform the action of adding/deleting a Student from Tutorial Group.
+ * Cons: Utility of Student ID is low as it is not used by other Commands. Also more difficult to implement.
+
+### Class and Tutorial Group Filters Features
+
+(Contributed by Gabriel Waikin Loh Matienzo)
+
+ClassMATE allows the user to filter students based on tutorial groups and find. A user is able to:
+
+1. View all students in a class
+2. View all students in a group
+
+#### Proposed Implementation
+
+Using the Predicate class `ClassCodeContainsKeywordsPredicate`(implemented by Vishnu), which finds a specific class given a class code as well as implementing a `GroupMember Predicate` that filters for students in a particular tutorial group, `Model#updateFilteredStudentList` is used to display a new list of students from a particular class or tutorial group.
+
+ClassMATE will then support the following command classes:
+
+* `FindClassCommand(ClassCode classCode)`
+* `ViewGroupCommand(ClassCode classCode, GroupNumber groupNumber, GroupType groupType)`
+
+These commands inherit from the `Command` class, and are named accordingly.
+
+Given below is an example of how the class and group filter features can be used:
+
+Step 1. The user has at least one class and at least one group in that class. The user executes a `findc G01` command. During parsing the `findc` command creates a `ClassCodeContainsKeywordsPredicate` that is used to call `Model#updateFilteredClassList()` to filter for `TutorialClass`(s) with the same class code(s) as the one(s) specified. Before this, the `findc` command also checks if there is no such `TutorialClass` and returns an error if there is none. If there are no errors, the state of the filtered list of tutorial classes is updated, and the updated filtered list will display the results of the search query to the user.
+
+Step 2. The user executes a `viewg c/G01 type/OP1 gn/1` command. After parsing the command, the `viewg` command first checks if there exists a `TutorialClass` with the specified class code. the `viewg` command checks if there exists a `TutorialGroup` with the specified class code, group type and group number. After all the checks pass, the `viewg` command calls `Model#updateFilteredStudentList()` to filter for students who belong to the `TutorialGroup` with the specified parameters. This updates the state of the filtered list of students, and the updated filtered list will display the results of the search query to the user.
+
+#### Design Considerations
+
+#### Aspect: Finding Tutorial Classes
+
+* Alternative 1 : Find tutorial classes by filtering for all tutorial classes with class codes containing the given keyword.
+ * Pros: Shorter keywords may increase user typing speed slightly, and user is able to find multiple classes at once.
+ * Cons: The increase in user typing speed may be marginal and negligible, as users may only save time not typing 1 character as the class codes are 3 characters long and all class codes begin with G. Additionally, the search will have lower accuracy as you may see up to 10 classes for a two character search e.g. `G0`.
+* Alternative 2 (current choice): Find tutorial classes by their exact class code
+ * Pros: Higher Accuracy in search, and since class codes are only three characters long, it does not cause users to take significantly more time.
+ * Cons: Keywords used in searches can only match specific classes instead of finding multiple classes at once.
+
+### Recommended workflow for setting up ClassMATE
+
+The *Activity Diagram* below provides an example of how users should set up their tutorial classes, tutorial groups and students
+in ClassMATE.
+
+![SetUpActivityDiagram](images/SetUpActivityDiagram.png)
--------------------------------------------------------------------------------------------------------------------
@@ -257,45 +618,159 @@ _{Explain here how the data archiving feature will be implemented}_
**Target user profile**:
-* has a need to manage a significant number of contacts
+* CS2101 Tutors with multiple tutorial classes
* prefer desktop apps over other types
* can type fast
* prefers typing to mouse interactions
* is reasonably comfortable using CLI apps
-**Value proposition**: manage contacts faster than a typical mouse/GUI driven app
+**Value proposition**: Manage and store student details faster than a typical mouse/GUI driven app. Organise students within classes and groups.
### User stories
Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
-| Priority | As a … | I want to … | So that I can… |
-| -------- | ------------------------------------------ | ------------------------------ | ---------------------------------------------------------------------- |
-| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App |
-| `* * *` | user | add a new person | |
-| `* * *` | user | delete a person | remove entries that I no longer need |
-| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list |
-| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident |
-| `*` | user with many persons in the address book | sort persons by name | locate a person easily |
-
-*{More to be added}*
+| Priority | As a … | I want to … | So that I can… |
+| -------- | ---------------- | --------------------------------------------- | ------------------------------------------------------------ |
+| `* * *` | new user | find help | refer to instructions when I forget how to use the App |
+| `* *` | new user | view sample data | see what the app looks like when in use |
+| `* * *` | user | add a new student | |
+| `* * *` | user | view a student's details | easily check the details and progress of the students |
+| `* * *` | user | add a new class | |
+| `* * ` | user | add a class schedule | plan my week in advance |
+| `* * *` | user | view a class' details | easily check the details of a particular class |
+| `* * *` | user | delete a student | remove students as required |
+| `* * *` | user | delete a class | remove classes I no longer need |
+| `* * *` | user | find a student by name | locate details of students without having to go through the entire list |
+| `* * *` | user | find a class by code | locate details of a class without having to go through the entire list |
+| `* * *` | user | view all classes | see which classes I'm taking |
+| `* * *` | user | view all students in a class | see the students enrolled in a particular class |
+| `* *` | experienced user | add class participation details to a student | track the participation of each student |
+| `*` | user | add different types of marks to students | to mark students for various assessments |
+| `* *` | experienced user | add tutorial groups within tutorial classes | organise my class groups |
+| `* *` | experienced user | add students to specific tutorial groups | to organise students in groups based on examination (e.g. OP1) |
+| `* *` | experienced user | delete students from specific tutorial groups | remove students from tutorial groups as required |
+| `* *` | experienced user | view students from specific tutorial groups | easily see the students in a tutorial group |
+| `* *` | experienced user | delete tutorial groups from tutorial classes | remove tutorial groups I no longer need |
### Use cases
-(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
+(For all use cases below, the **System** is the `ClassMATE` and the **Actor** is the `user`, unless specified otherwise)
+
+**Use case: Delete a student**
+
+**MSS**
+
+1. User requests to list students
+
+2. ClassMATE shows a list of students
+
+3. User requests to delete a specific student in the list
+
+4. ClassMATE deletes the student
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+
+ Use case ends.
+
+* 3a. The given index is invalid.
+
+ * 3a1. ClassMATE shows an error message.
+
+ Use case resumes at step 2.
+
+**Use case: Edit a student**
+
+**MSS**
+
+1. User requests to list students
-**Use case: Delete a person**
+2. ClassMATE shows a list of students
+
+3. User requests to edit a specific student in the list with some parameters
+
+4. ClassMATE edits the student
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+
+ Use case ends.
+
+* 3a. The given index is invalid.
+
+ * 3a1. ClassMATE shows an error message.
+
+ Use case resumes at step 2.
+
+* 3b. The given parameter to edit is a Class Code.
+
+ * 3b1. ClassMATE removes all existing tutorial groups of the student.
+
+ Use case resumes at step 4.
+
+**Use case: List students**
**MSS**
-1. User requests to list persons
-2. AddressBook shows a list of persons
-3. User requests to delete a specific person in the list
-4. AddressBook deletes the person
+1. User requests to list students
+
+2. ClassMATE shows a list of students
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. User decides to specify a class to list students
+
+ * 1a1. ClassMATE shows a list of students in the specified tutorial class
Use case ends.
+
+* 2a. The list is empty.
+
+ Use case ends.
+
+**Use case: Add a tutorial class**
+
+**MSS**
+
+1. User requests to add a tutorial class.
+
+2. ClassMATE adds the tutorial class.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. The tutorial class already exists.
+
+ * 1a1. ClassMATE shows a message informing the user.
+
+ Use case ends.
+
+**Use case: Find and view a tutorial class**
+
+**MSS**
+
+1. User requests to find a tutorial class
+
+2. ClassMATE shows a list of classes with the given keyword
+
+3. User requests to view a specific class in the list
+
+4. ClassMATE shows the class details
+
+ Use case ends.
+
**Extensions**
* 2a. The list is empty.
@@ -304,24 +779,162 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli
* 3a. The given index is invalid.
- * 3a1. AddressBook shows an error message.
+ * 3a1. ClassMATE shows an error message.
- Use case resumes at step 2.
+ Use case resumes at step 2.
-*{More to be added}*
+**Use case: Add a tutorial group**
-### Non-Functional Requirements
+**MSS**
+
+1. User requests to add a tutorial group with the given parameters, Group number, Group type and Class code.
+
+2. ClassMATE adds the tutorial class.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. ClassMATE detects an invalid parameter.
+
+ * 1a1. ClassMATE shows a message informing the user.
+
+ Use case ends.
+
+
+* 1b. The tutorial class that the tutorial group is being added to does not exist.
+
+ * 1b1. ClassMATE shows a message informing the user.
+
+ Use case ends.
+
+
+* 1c. The tutorial group already exists.
+
+ * 1c1. ClassMATE shows a message informing the user.
+
+ Use case ends.
+
+**Use case: Add a Student to a Tutorial Group**
-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.
+**MSS**
+
+1. User lists all the students with `liststu`
+
+2. ClassMATE shows a list of students
+
+3. User requests to add a Student to a Tutorial Group using the parameters INDEX of the Student, Group Number, ClassCode, and Group Type
+
+4. ClassMATE adds the Student to the Tutorial Group
+
+**Extensions**
+
+* 2a. The list is empty.
+
+ Use case ends.
+
+* 3a. The given Index is invalid.
+
+ * 3a1. ClassMATE shows an error message.
+
+ Use case resumes at step 2.
+
+* 3b. Tutorial Group does not exist.
+
+ * 3b1. ClassMATE shows an error message.
+
+ Use case ends.
+
+* 3c. A parameter is invalid.
+
+ * 3c1. ClassMATE shows an error message.
+
+ Use case resumes at step 2.
+
+* 3d. Student already belongs to a group of Group Type (i.e. OP1 or OP2).
+
+ * 3d1. ClassMATE shows an error message.
+
+ Use case resumes at step 2.
+
+**Use case: View Students in a Tutorial Group**
+
+**MSS**
+
+1. User requests to view Students in a Tutorial Group from a Tutorial Class using some parameters that identify the Tutorial Group.
+
+2. ClassMATE shows the filtered list of students that belong to the specified Tutorial Group to the user.
+
+**Extensions**
+
+* 1a. Tutorial Class does not exist.
+
+ * 1a1. ClassMATE shows an error message.
+
+ Use case ends.
-*{More to be added}*
+* 1b. Tutorial Group does not exist.
+
+ * 2b1. ClassMATE shows an error message.
+
+ Use case ends.
+
+**Use case: Delete the Latest Mark from Student**
+
+**MSS**
+
+1. User lists all students with `liststu`
+
+2. ClassMATE shows a list of students
+
+3. User enters command `deletelm x` where 'x' is the index of student to delete marks of
+
+4. ClassMATE deletes the latest mark stored for that student
+
+ Use case ends.
+
+**Extensions**
+
+* 2a. The list is empty.
+
+ Use case ends.
+
+* 3a. The given index is invalid.
+
+ * 3a1. ClassMATE shows an error message.
+
+ Use case resumes at step 2.
+
+* 3b. There are no marks stored for the student.
+
+ * 3b1. ClassMATE shows an error message.
+
+ Use case ends.
+
+### Non-Functional Requirements
+
+1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed.
+2. Should be able to hold at least 1000 students, 400 groups and 99 classes 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.
+4. Readable font, at least size 12.
+5. Should not cause noticeable lag for other applications when running.
+6. Dark Mode.
+7. Able to function in the background.
+8. Able to respond to user actions within three seconds.
+9. A tutorial class should be able to hold up to 20 students.
+10. A group should be able to hold up to 5 students.
+11. Each action should not take more than 3 commands.
### Glossary
-* **Mainstream OS**: Windows, Linux, Unix, OS-X
-* **Private contact detail**: A contact detail that is not meant to be shared with others
+* **Mainstream OS**: Windows, Linux, Unix, (MAC) OS-X
+* **Private student detail**: A student detail that is not meant to be shared with others
+* **Tutorial class**: A CS2101 tutorial class. Each student can only have up to one tutorial class
+* **Student**: An NUS student taking the CS2101(T) module
+* **Tutorial group**: A tutorial group is a subsection of the class and contains a few students for the purpose of small activities or group project.
+* **Group number**: The number of a group in the CS2101 class, which is specified by a number.
+* **Class code**: The name of a typical class in for the CS2101 module. E.g. G06.
+* **Group type**: The type of tutorial group in the CS2101 class, which is either OP1 or OP2.
--------------------------------------------------------------------------------------------------------------------
@@ -332,6 +945,7 @@ Given below are instructions to test the app manually.
:information_source: **Note:** These instructions only provide a starting point for testers to work on;
testers are expected to do more *exploratory* testing.
+
### Launch and shutdown
@@ -347,31 +961,40 @@ testers are expected to do more *exploratory* testing.
1. Resize the window to an optimum size. Move the window to a different location. Close the window.
1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained.
+ Expected: The most recent window size and location is retained.
-1. _{ more test cases … }_
+### Deleting a student
-### Deleting a person
+1. Deleting a student while all students are being shown
-1. Deleting a person while all persons are being shown
+ 1. Prerequisites: List all students using the `liststu` command. Multiple students in the list.
- 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
+ 1. Test case: `deletestu 1`
+ Expected: First student is deleted from the list. Details of the deleted student shown in the status message. Timestamp in the status bar is updated.
- 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.
+ 1. Test case: `deletestu 0`
+ Expected: No student is deleted. Error details shown in the status message. Status bar remains the same.
1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
Expected: Similar to previous.
+1. Deleting a student that at a negative index.
+ 1. Prerequisites: List all students using the `liststu` command. Multiple students in the list.
+ 1. Test case: `deletestu -5`
+ Expected: No student is deleted. Error details shown in the status message. Status bar remains the same.
+ 1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
+ Expected: Similar to previous.
-1. _{ more test cases … }_
### Saving data
1. Dealing with missing/corrupted data files
- 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
+ 1. Prerequisites: None
+
+ 2. Test case: JSON file missing.
+
+ Expected: ClassMATE gives warning about missing storage, and creates a new storage file populated with sample data.
+
+ 3. Test case: JSON file corrupted
-1. _{ more test cases … }_
+ Expected: ClassMATE gives warning about corrupted data, and creates a new storage file populated with sample data.
diff --git a/docs/Documentation.md b/docs/Documentation.md
index 3e68ea364e7..1abb3ceffa8 100644
--- a/docs/Documentation.md
+++ b/docs/Documentation.md
@@ -7,12 +7,10 @@ title: Documentation guide
* We use [**Jekyll**](https://jekyllrb.com/) to manage documentation.
* The `docs/` folder is used for documentation.
-* To learn how set it up and maintain the project website, follow the guide [_[se-edu/guides] **Using Jekyll for project documentation**_](https://se-education.org/guides/tutorials/jekyll.html).
-* Note these points when adapting the documentation to a different project/product:
+* To learn how set it up and maintain the project website, we followed the guide [_[se-edu/guides] **Using Jekyll for project documentation**_](https://se-education.org/guides/tutorials/jekyll.html).
+* we noted these points when adapting the documentation to our project:
* The 'Site-wide settings' section of the page linked above has information on how to update site-wide elements such as the top navigation bar.
- * :bulb: In addition to updating content files, you might have to update the config files `docs\_config.yml` and `docs\_sass\minima\_base.scss` (which contains a reference to `AB-3` that comes into play when converting documentation pages to PDF format).
-* If you are using Intellij for editing documentation files, you can consider enabling 'soft wrapping' for `*.md` files, as explained in [_[se-edu/guides] **Intellij IDEA: Useful settings**_](https://se-education.org/guides/tutorials/intellijUsefulSettings.html#enabling-soft-wrapping)
-
+ * :bulb: In addition to updating content files, we updated the config files `docs\_config.yml` and `docs\_sass\minima\_base.scss`.
**Style guidance:**
diff --git a/docs/SettingUp.md b/docs/SettingUp.md
index 275445bd551..1eca4e6e7e4 100644
--- a/docs/SettingUp.md
+++ b/docs/SettingUp.md
@@ -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 [ClassMATE’s architecture](DeveloperGuide.md#architecture).
1. **Do the tutorials**
These tutorials will help you get acquainted with the codebase.
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 3716f3ca8a4..1248411a208 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,192 +1,655 @@
---
layout: page
-title: User Guide
+title: ClassMATE 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.
+## Introduction
+
+Are you having trouble with administrative work as a CS2101 tutor? Do current tools like Excel sheets or the pen and paper cause a lot of pain when trying to organize and search for students or recording class participation? Could there be a way to streamline this process while providing you a better way to visualise the information? Well, ClassMATE has it all covered!
+
+**ClassMATE** is a **desktop app designed for you to manage student contacts and organize them into their tutorial classes and groups neatly, as well as recording of students' class participation without much hassle. Having both a Command Line Interface** ([CLI](#glossary)) and a **Graphical User Interface** ([GUI](#glossary)), it saves you time on your CS2101 administrative work while providing a pleasant experience at the same time.
+
+This user guide for ClassMATE will teach you how to:
+* Create students, classes and groups
+* Organize groups in their respective classes
+* Add students to a class and their respective oral presentation groups within the class
+* Filter and search students by groups and classes
+* Add class participation marks for students
+
+Check out the first few sections on how to set up ClassMATE and an overview of the symbols and syntax we use in the user guide. You can go through the remaining sections to learn how to use the various efficient features of ClassMATE, comprising the Tutorial Class, Student, Student Marks, and Tutorial Group Commands.
+
+Use the Table of Contents below to navigate to relevant sections to learn the commands for ClassMATE.
+
+Click on a section title to head there now!
* Table of Contents
{:toc}
-
--------------------------------------------------------------------------------------------------------------------
-## Quick start
+## How to use this User Guide
-1. Ensure you have Java `11` or above installed in your Computer.
+This User Guide helps you familiarize yourself with ClassMATE, its features, commands and uses!
-1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases).
+* Use the Quick Start [below](#Quick-Start) :arrow_down_small: to set up ClassMATE on your Computer.
+* You may view the entire list of ClassMATE's Features by clicking [here](#features).
+* Alternatively, you can refer to the Command Summary Table at the bottom, or by clicking [here](#Command-Summary).
+* You can check out a list of frequently-asked questions (FAQs) [here](#FAQ) and the glossary [here](#glossary)
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+Throughout the User Guide,
-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)
+**:information_source: Notes** will be used to give additional points regarding features
-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:
+**:bulb:Tips** will be used to provide quick information bits about features
- * **`list`** : Lists all contacts.
+**:warning:Warning** will be used to provide warnings about 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.
+We hope you find this User Guide helpful when using ClassMATE!
- * **`delete`**`3` : Deletes the 3rd contact shown in the current list.
+------
- * **`clear`** : Deletes all contacts.
+## Quick Start
- * **`exit`** : Exits the app.
+1. Ensure you have Java `11` or above installed in your Computer. (Go to [this website](https://codejava.net/java-se/download-and-install-java-11-openjdk-and-oracle-jdk) and follow the instructions to download and install Oracle JDK 11, which is _basically_ [Java 11](#Glossary).)
+1. Download the latest `classmate.jar` from [here](https://github.com/AY2122S1-CS2103T-W15-1/tp/releases).
+1. Copy the file to the folder you want to use as the _home folder_ for your ClassMATE.
+
+ :information_source: **Note:** Remember which folder is your home folder, as it might be required if you need to make any manual changes!
+
+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 (*Not necessarily the same data*).
+ ![Ui](images/Ui-annotated.png)
+
+1. Type the command in the **Command-Line Input** and press Enter to execute it. e.g. typing **`help`** and pressing Enter will open the help window.
+ Check out some examples in the [Tutorial](#cli-tutorial)
+
1. Refer to the [Features](#features) below for details of each command.
---------------------------------------------------------------------------------------------------------------------
+## CLI Tutorial
-## Features
+In this section, you will familiarize yourself with the use of CLI to facilitate your experience when using ClassMATE.
+All commands have to be typed in the **Command-Line Input** located at the top of the user interface as shown in the image below.
-
+![Command Line Input](images/CommandLineInput.png)
+
+Once you have familiarised yourself with the layout of the application, try out some example commands!
+
+Some example commands you can try:
+* **`liststu`** : Lists all students. All students currently stored in ClassMATE will be displayed in the **Student Panel**.
+* **`addc c/G06 s/Tuesday 2:00pm to 4:00pm, Friday 2:00pm to 4:00pm`**: Adds a tutorial class with the code `G06`.
+
+ The **Tutorial Class Panel** should reflect the updated list of tutorial classes including your new class, `G06`.
+
+* **`addstu n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01 c/G06`**: Adds a student named `John Doe` to ClassMATE.
+
+ The **Student Panel** Should reflect the updated list of students including your new student, `John Doe`.
+
+* **`deletestu 3`**: Deletes the 3rd student shown in the current list.
+
+* **`clear`** : Deletes all data from ClassMATE.
+
+* **`exit`** : Exits the app.
+
+Once you have attempted these commands, you're ready to go!
+
+### Command Format
+
+
**:information_source: Notes about the command format:**
+These are general rules applying to all explanations and command formats listed below!
* 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`.
+ e.g. in `addstu n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`.
* Items in square brackets are optional.
- e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`.
+ e.g. `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`.
* Items with `…` after them can be used multiple times including zero times.
e.g. `[t/TAG]…` can be used as ` ` (i.e. 0 times), `t/friend`, `t/friend t/family` etc.
-* Parameters can be in any order.
- e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable.
+* You can add parameters in any order.
+ e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, you can also type `p/PHONE_NUMBER n/NAME` for the parameters.
-* 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.
+* If a parameter is expected only once in the command, but you specified it multiple times, only the last occurrence of the parameter will be taken.
e.g. if you specify `p/12341234 p/56785678`, only `p/56785678` will be taken.
-* Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be ignored.
+* If you add parameters for commands that do not take in parameters (such as `help`, `liststu`, `exit` and `clear`), they will be ignored.
e.g. if the command specifies `help 123`, it will be interpreted as `help`.
+* `INDEX` items must be positive integers. Negative integers, decimal values, and zero will not be accepted for any command `INDEX`.
+
+ e.g. if the command `viewstu -5` is entered, it will throw an invalid command format error, telling you to enter a positive integer `INDEX` only!
+
-### Viewing help : `help`
+## Features
-Shows a message explaning how to access the help page.
+Here, you can find instructions on how to use ClassMATE's various features. The features are divided into five main subsections, each covering different groups of commands:
+1. [Tutorial Class Commands](#tutorial-class-commands)
+2. [Student Commands](#student-commands)
+3. [Student Marks Commands](#student-marks-commands)
+4. [Tutorial Group Commands](#tutorial-group-commands)
+5. [Other Commands](#other-commands)
-![help message](images/helpMessage.png)
+Each subsection will provide you with an overview, followed by the individual command formats, instructions on how to use them, examples of their usage and the expected outcome of executing these commands.
-Format: `help`
+## Tutorial Class Commands
+This section covers all the commands you can use to manage information pertaining to tutorial classes!
-### Adding a person: `add`
+Features include the ability to:
+1. [Add a tutorial class](#adding-a-tutorial-class--addc)
+1. [List all tutorial classes](#listing-all-classes--listc)
+1. [View all students in a tutorial class](#viewing-a-class-viewc)
+1. [Find a tutorial class by its class code](#finding-classes-by-class-codes-findc)
+1. [Delete a tutorial class](#deleting-a-class-deletec)
-Adds a person to the address book.
+### Adding a tutorial class : `addc`
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
+Adds a tutorial class to ClassMATE.
+
+Entering format: `addc c/CLASS_CODE s/SCHEDULE [t/TAG]…`
+
+**:information_source: Note:**
+
+* Class Code should consist of 'G' followed by two numerical digits (i.e. any value from 'G01' to 'G99').
+
+* Schedule consists of only 2 weekly timeslots. Each time slot should be written in the format `Day H:MM am/pm to H:MM am/pm` (e.g. `Wed 12:00pm to 2:00pm`)
+
+* The `Day` should be start with a capital letter. Short form for days are also accepted (e.g. Tues for Tuesday).
+
+
:warning: **Warning:**
+ Entering wrong/impossible timings is possible and will not be stopped. Enter schedule timings carefully. :warning:
+
+
+Examples:
+
+* `addc c/G06 s/Tuesday 2:00pm to 4:00pm, Friday 2:00 to 4:00pm`
+* `addc c/G01 s/Monday 10:00am to 12:00pm, Thursday 10:00am to 12:00pm`
+
+### Listing all classes : `listc`
+
+Shows a list of all classes in ClassMATE.
+
+Entering format: `listc`
+
+### Viewing a class: `viewc`
+
+![viewing a class](images/viewc.png)
+
+Displays a class and its students in ClassMATE, as shown above.
+
+
:information_source: **Note:**
+`viewc` highlights the class at the given INDEX, and filters out only students in that class!
+
+
+Entering format: `viewc INDEX`
+
+* Views the class details at the specified INDEX.
+* Details of a class includes students in the class and the class schedule.
+* The index refers to the index number shown in the displayed list of classes, **not the Class Code**.
+
+**:information_source: Note:**
+* The index **must** be a positive integer 1, 2, 3, …
:bulb: **Tip:**
-A person can have any number of tags (including 0)
+In order to find a specific class, use the `findc` command to find a particular class before viewing it.
+
+
+Examples:
+
+* `listc` followed by `viewc 2` shows the 2nd class in the displayed class list.
+
+### Finding classes by class codes: `findc`
+
+Finds a class by its class code.
+
+Entering format: `findc CLASS_CODE [MORE_CLASS_CODES]`
+
+**:information_source: Note:**
+* The search is absolute. e.g. `G0` will not match `G06`
+
+Examples:
+
+* `findc G02` returns `G02` if it exists.
+
+### Deleting a class: `deletec`
+
+Deletes a class from ClassMATE.
+
+Entering format: `deletec INDEX`
+
+* Deletes the class at the specified INDEX.
+* The index refers to the index number shown in the displayed list of classes.
+
+**:information_source: Note:**
+* The index **must be a positive integer** 1, 2, 3, …
+* Students formerly belonging to the deleted class would now be assigned to `No Class`. Groups that students were assigned to in the class will no longer exist and students will have no groups.
+
+
:warning: **Warning:**
+This command deletes a class, **ALL** its groups and is irreversible. :warning:
+![deleteClass](images/deletecScreenshot.png)
+
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`
-### Listing all persons : `list`
+* `listc` followed by `deletec 2` deletes the 2nd class in the list of classes.
+* `findc G06` followed by `deletec 1` deletes the 1st class in the results of the `findc` command.
+
+## Student Commands
-Shows a list of all persons in the address book.
+This part of the guide covers all the commands you can use to manage student information!
-Format: `list`
+You can:
+1. [Add a new student](#adding-a-student-addstu)
+1. [Edit an existing student](#editing-a-student--editstu)
+1. [View a student's details](#viewing-a-student--viewstu)
+1. [List all students](#listing-all-students--liststu)
+1. [Find students by name](#finding-students-by-name-findstu)
+1. [Delete a student](#deleting-a-student--deletestu)
-### Editing a person : `edit`
+### Adding a student: `addstu`
-Edits an existing person in the address book.
+Adds a student to ClassMATE.
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
+Entering format: `addstu n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS c/CLASS_CODE [t/TAG]…`
+
+* The Name of a student accommodates special characters such as hyphens, apostrophes and slashes.
+* A student can have any number of tags (including 0)
+
+**:information_source: Note:**
+* The phone number should be at least 3 digits long.
+* The tutorial class with the given Class Code must already exist in classmate.
+
+Examples:
+* If class G06 has not been created, add the class first using `addc`.
+* `addstu n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01 c/G06`
+* `addstu n/Betsy Crowe t/proactive e/betsycrowe@example.com a/10 Kent Dr, #02-02 p/1234567 c/G06 t/teamPlayer`
+
+### Editing a student : `editstu`
+
+Edits an existing student in ClassMATE.
+
+Entering format: `editstu INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [c/CLASS_CODE] [t/TAG]…`
+
+* Edits the student at the specified `INDEX`. The index refers to the index number shown in the displayed student list. The index **must be a positive integer** 1, 2, 3, …
+
+ **:information_source: Note:**
-* 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.
+
+
:warning: **Warning:**
+ An error message will be displayed to provide at least one parameter if no parameters are provided, regardless of whether the INDEX is valid or not. The INDEX will be checked after at least one optional parameter is provided. :warning:
+
+
+* The index must be a positive integer 1, 2, 3, …
+
* Existing values will be updated to the input values.
-* When editing tags, the existing tags of the person will be removed i.e adding of tags is not cumulative.
-* You can remove all the person’s tags by typing `t/` without
- specifying any tags after it.
+
+* When editing tags, the existing tags of the student will be removed i.e. adding of tags is not cumulative.
+
+* You can remove all the student’s tags by typing `t/` without specifying any tags after it.
+
+
:warning: **Warning:**
+When editing a student, the previous information in the parameter being updated will be irreversibly deleted so be careful! :warning:
+
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.
+* `editstu 1 p/91234567 e/johndoe@example.com` Edits the phone number and email address of the 1st student to be `91234567` and `johndoe@example.com` respectively.
+* `editstu 2 n/Betsy Crower t/` Edits the name of the 2nd student to be `Betsy Crower` and clears all existing tags.
+
+### Viewing a student : `viewstu`
+
+![view student](images/viewstu.png)
+
+Views a student's details in ClassMATE, as shown in the picture above.
+
+Format: `viewstu INDEX`
+
+* Views the student's details at specified `INDEX`
+* The index refers to the index number shown in the displayed student list.
+
+**:information_source: Note:**
+* The index must be a positive integer 1, 2, 3, …
+* `viewstu` is the only way to view a student's marks!
+
+Examples:
+
+* `liststu` followed by `viewstu 2` shows second student in the student list.
+* `findstu Betsy` followed by `viewstu 1` shows the 1st student in the results of the find command.
+
+### Listing all students : `liststu`
-### Locating persons by name: `find`
+Shows a list of all students in ClassMATE.
-Finds persons whose names contain any of the given keywords.
+Entering format: `liststu`
-Format: `find KEYWORD [MORE_KEYWORDS]`
+* All students stored are listed.
-* 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`
+### Finding students by name: `findstu`
+
+Finds students whose names contain any of the given keywords.
+
+Entering format: `findstu KEYWORD [MORE_KEYWORDS]`
+
+* The search is case-insensitive. e.g. `hans` will match `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)
+* `findstu John` returns `john` and `John Doe`
+* `findstu alex david` returns `Alex Yeoh`, `David Li`
+
+### Deleting a student : `deletestu`
+
+Deletes the specified student from the student list.
+
+Entering format: `deletestu INDEX`
+
+* Deletes the student at the specified `INDEX`.
+* The index refers to the index number shown in the displayed student list.
+
+**:information_source: Note:**
+* The index **must be a positive integer** 1, 2, 3, …
+
+
:warning: **Warning:**
+This command deletes a student and is irreversible. :warning:
+
+
+Examples:
+* `liststu` followed by `deletestu 2` deletes the 2nd student in the student list.
+* `findstu Betsy` followed by `deletestu 1` deletes the 1st student in the results of the `findstu` command.
-### Deleting a person : `delete`
+## Student Marks Commands
-Deletes the specified person from the address book.
+This section of the guide covers all the commands you can use to manage student marks!
-Format: `delete INDEX`
+You can:
+1. [Add the latest mark](#adding-the-latest-mark-addlm)
+1. [Delete the latest mark](#deleting-latest-mark-deletelm)
+1. [Delete all marks for a student](#deleting-all-marks-deleteam)
-* Deletes the person at the specified `INDEX`.
-* The index refers to the index number shown in the displayed person list.
+There are 6 types of Marks that can be assigned to a student for each session that the student attends. These marks are meant to be a class participation score, but you can use it flexibly. The marks that can be assigned are:
+
+* Poor
+* Low
+* Avg (short for Average)
+* Good
+* High
+* Excellent
+
+### Adding the Latest Mark: `addlm`
+
+Adds a mark to a student for their latest session.
+
+Entering format: `addlm INDEX m/MARK`
+
+* Mark is not case-sensitive.
+* The index refers to the index number shown in the displayed student list.
+
+**:information_source: Note:**
* 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`
+* `liststu` followed by`addlm 2 m/Low` assigns LOW mark to the latest session for 2nd student in the student list.
+* `findstu Betsy` followed by `addlm 1 m/excellent` assigns EXCELLENT mark to the latest session for 1st student in the results of `findstu`.
+
+### Deleting Latest Mark: `deletelm`
+
+Deletes the mark of a student for their latest session.
+
+Entering format: `deletelm INDEX`
+
+* Deletes mark as the mark for latest session.
+* Student has to have some marks assigned previously.
+* The index refers to the index number shown in the displayed student list.
+
+**:information_source: Note:**
+* The index **must be a positive integer** 1, 2, 3, …
+
+Examples:
+
+* `liststu` followed by `addlm 2 m/Low` and `deletelm 2` deletes the LOW mark assigned to the 2nd student in the student list.
+* `findstu Betsy` followed by `deletelm 1` deletes the latest sessions' mark for 1st student in the results of `findstu`.
+
+### Deleting All Marks: `deleteam`
+
+Deletes all marks for a student.
+
+Entering format: `deleteam INDEX`
+
+* Student has to have some marks assigned previously.
+* The index refers to the index number shown in the displayed student list.
+
+**:information_source: Note:**
+* The index **must be a positive integer** 1, 2, 3, …
+
+Examples:
+
+* `liststu` followed by `addlm 2 m/Low` and `deleteam 2` deletes all marks assigned to the 2nd student in the student list.
+* `findstu Betsy` followed by `deleteam 1` deletes all sessions' mark for 1st student in the results of `findstu`.
+
+## Tutorial Group Commands
+
+These are the commands that involve tutorial groups!
+
+The first part covers interactions between groups and classes, while the second part covers interactions between students and groups.
+
+You can:
+1. [Add a new tutorial group](#adding-a-tutorial-group-addcg)
+1. [Views all students in a tutorial group](#viewing-a-tutorial-group-viewg)
+1. [Delete a tutorial group](#deleting-a-tutorial-group-deletecg)
+1. [Add a student to a tutorial group](#adding-students-to-a-tutorial-group-addsg)
+1. [Delete a student from a tutorial group](#deleting-student-from-a-group-deletesg)
+
+### Adding a Tutorial Group: `addcg`
+
+Adds a tutorial group to a particular tutorial class in ClassMATE.
+
+Entering format: `addcg gn/GROUP_NUMBER c/CLASS_CODE type/GROUP_TYPE`
+
+**:information_source: Note:**
+* GROUP_NUMBER should be a single digit
+* GROUP_TYPE refers to the assignment that the group will work for. It should only be OP1 or OP2.
+* The class must have already been added to ClassMATE first. If you are unsure, you can refer to
+ [Adding a Tutorial Class](#adding-a-tutorial-class-:-`addc`)
+* Tutorial groups are identified by GROUP_NUMBER, GROUP_TYPE and CLASS_CODE. This means that
+ any two tutorial groups are identical if all three fields are identical, which is not allowed.
+
+Examples:
+* `addcg gn/1 c/G01 type/OP1` adds Group 1 to class `G01` assigned to the task `OP1`
+
+### Viewing a Tutorial Group: `viewg`
+
+Displays all students in a particular tutorial group in ClassMATE.
+
+Entering format: `viewg c/CLASS_CODE type/GROUP_TYPE gn/GROUP_NUMBER`
+
+**:information_source: Note:**
+* Only `OP1` and `OP2` are accepted as Group Types.
+
+Examples:
+* `viewg c/G06 type/OP2 gn/1` lists the students in `OP2` Group `1` of class `G06`
+
+### Deleting a Tutorial Group: `deletecg`
+
+Deletes a tutorial group from ClassMATE.
+
+Entering Format: `deletecg c/CLASS_CODE type/GROUP_TYPE gn/GROUP_NUMBER`
+
+**:information_source: Note:**
+* GROUP_NUMBER should be a single digit
+
+* GROUP_TYPE refers to the assignment that the group will work for. It should only be OP1 or OP2.
+
+* All students in the deleted group will no longer be in the group.
+
+
:warning: **Warning:**
+This command deletes a group and is irreversible. :warning:
+
+
+Examples:
+* `deletecg c/G06 type/OP2 gn/1` deletes the `OP2` Group `1` of class `G06`
+
+### Adding Students to a Tutorial group: `addsg`
+
+Adds a student to a tutorial group.
+
+Entering format: `addsg INDEX gn/GROUP_NUMBER c/CLASS_CODE type/TYPE`
-Clears all entries from the address book.
+* Adds the student to a group in the class
-Format: `clear`
+**:information_source: Note:**
+* Only `OP1` and `OP2` are accepted as Group Types.
+* A student can only be added to a group if the group has been created under the same class already!
+
+Example:
+* `addsg 1 gn/1 c/G06 type/OP1` adds the student at index 1 to OP1 Group 1 in class G06
+
+### Deleting Student from a group: `deletesg`
+
+Deletes a student from a group.
+
+Entering format: `deletesg INDEX g/GROUP_NUMBER c/CLASS_CODE type/TYPE`
+
+* Deletes the student from a group in the class
+* Type refers to the assignment that the group will work together for
+
+**:information_source: Note:**
+* Only `OP1` and `OP2` are accepted as Group Types.
+
+
+Example:
+* `liststu c/G06`shows that Betsy is a student in class G06 with Index 1.
+ `deletesg 1 gn/1 c/G06 type/OP1` then removes Betsy from OP1 Group 1 in class G06
+
+## Other Features
+
+These are other commands and features you can use in ClassMATE!
+
+### Viewing help : `help`
+
+Shows a message explaining how to access the help page, which directs you to this user guide. So, don't worry about forgetting commands, just refer to this guide!
+
+![help message](images/helpMessage.png)
+
+Entering format: `help`
+
+### Clearing all data : `clear` :warning:
+
+Clears all data from ClassMATE. Below is how it would look like.
+
+![clear](images/clear.png)
+
+
:warning: **Warning:**
+This command deletes **ALL** data and is irreversible :warning:
+
+
+Entering format: `clear`
### Exiting the program : `exit`
Exits the program.
-Format: `exit`
+Entering format: `exit`
### Saving the data
-AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+Saving ClassMATE data is a hassle-free process. Data is 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.
-
-
: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.
+
:bulb: **Tip:**
+Recommended to be done only by advanced users.
-### Archiving data files `[coming in v2.0]`
+In order to find a specific class, use the `findc` command to find a particular class before viewing it.
+
+ClassMATE data are saved as a [JSON](#Glossary) file `[Home Folder/JAR File Location]/data/classmate.json`.
-_Details coming soon ..._
+Advanced users are welcome to update data directly by editing that data file.
+
+
:exclamation: **Caution:**
+If your changes to the data file makes its format invalid, ClassMATE will discard all data and start with an empty data file at the next run.
+
--------------------------------------------------------------------------------------------------------------------
## FAQ
**Q**: How do I transfer my data to another Computer?
-**A**: Install 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.
+**A**: Install the app in the other computer and overwrite the empty data file it creates with the [JSON](#glossary) file that contains the data of your previous ClassMATE home folder.
+
+**Q**: Can I create tutorial groups that are not for Oral Presentation 1 or 2?
+**A**: No, currently ClassMATE only supports the creation of Tutorial Groups for Oral Presentations 1 and 2 only.
+
+**Q**: Can I view students only belonging to a certain Tutorial Class alone?
+**A**: Yes, use the `viewc` command to do so. The `viewc` command is explained [here](#viewing-a-class:-`viewc`)
--------------------------------------------------------------------------------------------------------------------
-## Command summary
+## Command Summary
+
+### Tutorial Class Commands
+
+Action | Format, Examples
+--------|------------------
+**[Add class](#adding-a-tutorial-class--addc)** | `addc c/CLASS_CODE s/SCHEDULE [t/TAG]…` e.g., `addc c/G06 s/Tuesday 2:00pm to 4:00pm, Friday 2:00pm to 4:00pm`
+**[List all classes](#listing-all-classes--listc)** | `listc`
+**[View students in class](#viewing-a-class-viewc)** | `viewc INDEX` e.g., `listc` followed by `viewc 3`
+**[Find class](#finding-classes-by-class-codes-findc)** | `findc CLASS_CODE [MORE_CLASS_CODES]` e.g., `findc G02`
+**[Delete class](#deleting-a-class-deletec)** | `deletec INDEX` e.g., `listc` followed by `deletec 2`
+
+### Student Commands
+
+Action | Format, Examples
+:-------|------------------
+**[Add student](#adding-a-student-addstu)** | `addstu n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS c/CLASS_CODE [t/TAG]…` e.g., `addstu n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 c/G01 t/attentive`
+**[Edit student](#editing-a-student--editstu)** | `editstu INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [c/CLASS_CODE] [t/TAG]…` e.g., `editstu 2 n/James Lee e/jameslee@example.com`
+**[List students](#listing-all-students--liststu)** | `liststu` e.g., `liststu`
+**[View student](#viewing-a-student--viewstu)** | `viewstu INDEX` e.g., `liststu` followed by `viewstu 2`
+**[Find student](#finding-students-by-name-findstu)** | `findstu KEYWORD [MORE_KEYWORDS]` e.g., `findstu John`
+**[Delete student](#deleting-a-student--deletestu)** | `deletestu INDEX` e.g., `liststu` followed by `deletestu 3`
+
+### Student Marks
+
+Action | Format, Examples
+--------|------------------
+**[Add latest mark](#adding-the-latest-mark-addlm)** | `addlm INDEX m/MARK` e.g., `liststu` followed by `addlm 1 m/excellent`
+**[Delete latest mark](#deleting-latest-mark-deletelm)** | `deletelm INDEX` e.g., `liststu` followed by `deletelm 2`
+**[Delete all marks](#deleting-all-marks-deleteam)** | `deleteam INDEX` e.g., `liststu` followed by `deleteam 3`
+
+### Tutorial Groups
+
+Action | Format, Examples
+--------|------------------
+**[Add tutorial group](#adding-a-tutorial-group-addcg)** | `addcg gn/GROUP_NUMBER c/CLASS_CODE type/TYPE` e.g.,`addcg gn/1 c/G11 type/OP1`
+**[View students from group](#viewing-a-tutorial-group-viewg)** | `viewg gn/GROUP_NUMBER c/CLASS_CODE type/GROUP_TYPE` e.g., `viewg gn/1 c/G01 type/OP1`
+**[Delete tutorial group](#deleting-a-tutorial-group-deletecg)** | `deletecg gn/GROUP_NUMBER c/CLASS_CODE type/GROUP_TYPE` e.g., `deletecg gn/1 c/G01 type/OP1`
+**[Add student to group](#adding-students-to-a-tutorial-group-addsg)** | `addsg INDEX gn/GROUP_NUMBER c/CLASS_CODE type/GROUP_TYPE` e.g., `addsg 1 gn/1 c/G01 type/OP1`
+**[Delete student from group](#deleting-student-from-a-group-deletesg)** | `deletesg INDEX gn/GROUP_NUMBER c/CLASS_CODE type/GROUP_TYPE` e.g., `deletesg 1 gn/1 c/G01 type/OP1`
+
+### Other Commands
Action | Format, Examples
--------|------------------
-**Add** | `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…` e.g., `add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/friend t/colleague`
-**Clear** | `clear`
-**Delete** | `delete INDEX` e.g., `delete 3`
-**Edit** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]…` e.g.,`edit 2 n/James Lee e/jameslee@example.com`
-**Find** | `find KEYWORD [MORE_KEYWORDS]` e.g., `find James Jake`
-**List** | `list`
-**Help** | `help`
+**[Help](#viewing-help--help)** | `help`
+**[Clears ClassMATE Data](#clearing-all-data--clear-warning)** | `clear`
+**[Exit ClassMATE](#exiting-the-program--exit)** | `exit`
+
+## Contact Us
+
+For any assistance or difficulties, feel free to drop us an email at [classMateys@gmail.com](mailto:classMateys@gmail.com) !
+
+## Glossary
+
+Term | Definition
+--------|------------------
+**[Java 11](#quick-start)** | Java is a programming language, more on it [here](https://en.wikipedia.org/wiki/Java_(programming_language)).
+**[JSON](#editing-the-data-file)** | a JSON file is an open standard file format, more on it [here](https://en.wikipedia.org/wiki/JSON).
+**[CLI](#cli-tutorial)** | Command Line Interface (CLI) enables users to interact with a program by typing in text commands following visual prompts from the program.
+**[GUI](#quick-start)** | Graphical User Interface (GUI) is a system of interactive visual components that allows users to interact with a program through graphical icons.
+
+[Back to top](#introduction)
diff --git a/docs/_config.yml b/docs/_config.yml
index 6bd245d8f4e..93c32702580 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,5 +1,5 @@
-title: "AB-3"
-theme: minima
+title: "ClassMATE"
+theme: jekyll-theme-slate
header_pages:
- UserGuide.md
@@ -8,7 +8,7 @@ header_pages:
markdown: kramdown
-repository: "se-edu/addressbook-level3"
+repository: "AY2122S1-CS2103T-W15-1/tp"
github_icon: "images/github-icon.png"
plugins:
diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss
index 0d3f6e80ced..b907d03b444 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: "classMATE";
font-size: 32px;
}
}
diff --git a/docs/diagrams/AddClassSequenceDiagram.png b/docs/diagrams/AddClassSequenceDiagram.png
new file mode 100644
index 00000000000..e3fae1c6f5e
Binary files /dev/null and b/docs/diagrams/AddClassSequenceDiagram.png differ
diff --git a/docs/diagrams/AddClassSequenceDiagram.puml b/docs/diagrams/AddClassSequenceDiagram.puml
new file mode 100644
index 00000000000..f58fa42c780
--- /dev/null
+++ b/docs/diagrams/AddClassSequenceDiagram.puml
@@ -0,0 +1,49 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":**AddClassCommand**" as AddClassCommand LOGIC_COLOR
+participant "**r:CommandResult**" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "**m:ModelManager**" as ModelManager MODEL_COLOR
+participant "**c:Classmate**" as Classmate MODEL_COLOR
+end box
+
+[-> AddClassCommand : ""execute(m)""
+activate AddClassCommand
+
+AddClassCommand -> ModelManager : ""addTutorialClass(tc)""
+activate ModelManager
+
+ModelManager -> Classmate : ""addTutorialClass(tc)""
+activate Classmate
+
+
+note right
+""tc"" is the TutorialClass
+that is to be added
+to ClassMate
+end note
+
+Classmate --> ModelManager
+deactivate Classmate
+
+ModelManager --> AddClassCommand
+deactivate
+
+create CommandResult
+AddClassCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> AddClassCommand : ""r""
+deactivate CommandResult
+
+[<-- AddClassCommand : ""r""
+deactivate AddClassCommand
+
+AddClassCommand -[hidden]> CommandResult
+destroy AddClassCommand
+
+@enduml
diff --git a/docs/diagrams/AddGroupSequenceDiagram.png b/docs/diagrams/AddGroupSequenceDiagram.png
new file mode 100644
index 00000000000..793923b50e6
Binary files /dev/null and b/docs/diagrams/AddGroupSequenceDiagram.png differ
diff --git a/docs/diagrams/AddGroupSequenceDiagram.puml b/docs/diagrams/AddGroupSequenceDiagram.puml
new file mode 100644
index 00000000000..7db0be77ccf
--- /dev/null
+++ b/docs/diagrams/AddGroupSequenceDiagram.puml
@@ -0,0 +1,52 @@
+@startuml
+!include style.puml
+
+box Model MODEL_COLOR_T1
+participant "**:UniqueTutorialClassList**" as UniqueTutorialClassList MODEL_COLOR
+participant "<>\n**TutorialClass**" as StaticTutorialClass MODEL_COLOR
+participant ":**TutorialClass**" as TutorialClass MODEL_COLOR
+participant ":**UniqueTutorialGroupList**" as UniqueTutorialGroupList MODEL_COLOR
+end box
+
+
+[-> UniqueTutorialClassList : ""contains(tc)""
+
+note right
+""tc"" is the TutorialClass
+that the TutorialGroup ""tg""
+being added to ClassMATE
+belongs to
+end note
+
+UniqueTutorialClassList -> TutorialClass : ""check for matching tutorial class""
+
+note right
+using streams and
+""isSameTutorialClass"" method
+end note
+
+[-> UniqueTutorialClassList : ""contains(tg)""
+
+ref over UniqueTutorialClassList, StaticTutorialClass, TutorialClass
+get tutorial groups
+end ref
+
+UniqueTutorialClassList -> UniqueTutorialGroupList : ""contains(tg)""
+activate UniqueTutorialGroupList
+
+UniqueTutorialGroupList --> UniqueTutorialClassList
+deactivate UniqueTutorialGroupList
+
+[-> UniqueTutorialClassList : ""add(tg)""
+
+ref over UniqueTutorialClassList, StaticTutorialClass, TutorialClass
+get tutorial groups
+end ref
+
+UniqueTutorialClassList -> UniqueTutorialGroupList : ""add(tg))""
+activate UniqueTutorialGroupList
+
+UniqueTutorialGroupList --> UniqueTutorialClassList
+deactivate UniqueTutorialGroupList
+
+@enduml
diff --git a/docs/diagrams/AddMarkSequenceDiagram.png b/docs/diagrams/AddMarkSequenceDiagram.png
new file mode 100644
index 00000000000..0979c8d5bb1
Binary files /dev/null and b/docs/diagrams/AddMarkSequenceDiagram.png differ
diff --git a/docs/diagrams/AddMarkSequenceDiagram.puml b/docs/diagrams/AddMarkSequenceDiagram.puml
new file mode 100644
index 00000000000..b93db056a6c
--- /dev/null
+++ b/docs/diagrams/AddMarkSequenceDiagram.puml
@@ -0,0 +1,50 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":ClassmateParser" as ClassmateParser LOGIC_COLOR
+participant "a:AddLastMarkCommand" as AddLastMarkCommand LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Student" as Student MODEL_COLOR
+end box
+[-> LogicManager : execute(m)
+activate LogicManager
+
+LogicManager -> ClassmateParser : parseCommand(m)
+activate ClassmateParser
+
+create AddLastMarkCommand
+ClassmateParser -> AddLastMarkCommand
+activate AddLastMarkCommand
+
+AddLastMarkCommand --> ClassmateParser
+deactivate AddLastMarkCommand
+
+ClassmateParser --> LogicManager : a
+deactivate ClassmateParser
+
+LogicManager -> AddLastMarkCommand : execute()
+activate AddLastMarkCommand
+
+create Student
+AddLastMarkCommand -> Student : addStudentMark()
+activate Student
+
+note right
+""sm"" is the StudentMark
+that is to be added
+to Student ""s""
+end note
+
+Student --> AddLastMarkCommand
+deactivate Student
+
+AddLastMarkCommand --> LogicManager : ""r""
+deactivate AddLastMarkCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/ArchitectureDiagram.png b/docs/diagrams/ArchitectureDiagram.png
new file mode 100644
index 00000000000..b99b363f5b6
Binary files /dev/null and b/docs/diagrams/ArchitectureDiagram.png differ
diff --git a/docs/diagrams/ArchitectureSequenceDiagram.png b/docs/diagrams/ArchitectureSequenceDiagram.png
new file mode 100644
index 00000000000..c330bb7ee63
Binary files /dev/null and b/docs/diagrams/ArchitectureSequenceDiagram.png differ
diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml
index ef81d18c337..a45110643f5 100644
--- a/docs/diagrams/ArchitectureSequenceDiagram.puml
+++ b/docs/diagrams/ArchitectureSequenceDiagram.puml
@@ -7,19 +7,19 @@ Participant ":Logic" as logic LOGIC_COLOR
Participant ":Model" as model MODEL_COLOR
Participant ":Storage" as storage STORAGE_COLOR
-user -[USER_COLOR]> ui : "delete 1"
+user -[USER_COLOR]> ui : "deletestu 1"
activate ui UI_COLOR
-ui -[UI_COLOR]> logic : execute("delete 1")
+ui -[UI_COLOR]> logic : execute("deletestu 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 : saveClassmate(classmate)
activate storage STORAGE_COLOR
storage -[STORAGE_COLOR]> storage : Save to file
diff --git a/docs/diagrams/BetterModelClassDiagram.png b/docs/diagrams/BetterModelClassDiagram.png
new file mode 100644
index 00000000000..3de3226136c
Binary files /dev/null and b/docs/diagrams/BetterModelClassDiagram.png differ
diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml
index 5731f9cbaa1..23ac881ad31 100644
--- a/docs/diagrams/BetterModelClassDiagram.puml
+++ b/docs/diagrams/BetterModelClassDiagram.puml
@@ -4,18 +4,33 @@ 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
+Classmate *-right-> "1" UniqueTutorialClassList
+Classmate *-right-> "1" UniqueStudentList
+Classmate *-right-> "1" UniqueTagList
+UniqueTutorialClassList -[hidden]down- UniqueTagList
+UniqueTagList -[hidden]down- UniqueStudentList
+UniqueTagList -[hidden]down- UniqueStudentList
+UniqueTutorialClassList -right-> TutorialClass
UniqueTagList *-right-> "*" Tag
-UniquePersonList -right-> Person
+UniqueStudentList -right-> Student
+UniqueTutorialGroupList -right-> TutorialGroup
-Person -up-> "*" Tag
+TutorialClass *-right-> "1" UniqueTutorialGroupList
+TutorialGroup *-down-> GroupNumber
+TutorialGroup *-down-> ClassCode
+TutorialGroup *-down-> GroupType
+TutorialClass *-down-> ClassCode
+TutorialClass *-down-> "*" Tag
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
+Student *-up-> ClassCode
+Student *-up-> "*" Tag
+Tag -[hidden]right- ClassCode
+
+Student *--> Name
+Student *--> Phone
+Student *--> Email
+Student *--> Address
+Student *--> StudentMark
+TutorialClass *--> Schedule
@enduml
diff --git a/docs/diagrams/CommitActivityDiagram.png b/docs/diagrams/CommitActivityDiagram.png
new file mode 100644
index 00000000000..9869ebfd525
Binary files /dev/null and b/docs/diagrams/CommitActivityDiagram.png differ
diff --git a/docs/diagrams/CommitActivityDiagram.puml b/docs/diagrams/CommitActivityDiagram.puml
index 6a6b23a006f..399661862e2 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 ClassMATE])
:Purge redundant states;
- :Save AddressBook to
- addressBookStateList;
+ :Save ClassMATE to
+ classmateStateList;
else ([else])
endif
stop
diff --git a/docs/diagrams/ComponentManagers.png b/docs/diagrams/ComponentManagers.png
new file mode 100644
index 00000000000..edb5415efe9
Binary files /dev/null and b/docs/diagrams/ComponentManagers.png differ
diff --git a/docs/diagrams/DeleteSequenceDiagram.png b/docs/diagrams/DeleteSequenceDiagram.png
new file mode 100644
index 00000000000..96448c1dbec
Binary files /dev/null and b/docs/diagrams/DeleteSequenceDiagram.png differ
diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml
index 1dc2311b245..83e9ae703b0 100644
--- a/docs/diagrams/DeleteSequenceDiagram.puml
+++ b/docs/diagrams/DeleteSequenceDiagram.puml
@@ -3,9 +3,9 @@
box Logic LOGIC_COLOR_T1
participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
-participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR
-participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR
+participant ":ClassmateParser" as ClassmateParser LOGIC_COLOR
+participant ":DeleteStudentCommandParser" as DeleteStudentCommandParser LOGIC_COLOR
+participant "d:DeleteStudentCommand" as DeleteStudentCommand LOGIC_COLOR
participant ":CommandResult" as CommandResult LOGIC_COLOR
end box
@@ -13,56 +13,56 @@ box Model MODEL_COLOR_T1
participant ":Model" as Model MODEL_COLOR
end box
-[-> LogicManager : execute("delete 1")
+[-> LogicManager : execute("deletestu 1")
activate LogicManager
-LogicManager -> AddressBookParser : parseCommand("delete 1")
-activate AddressBookParser
+LogicManager -> ClassmateParser : parseCommand("deletestu 1")
+activate ClassmateParser
-create DeleteCommandParser
-AddressBookParser -> DeleteCommandParser
-activate DeleteCommandParser
+create DeleteStudentCommandParser
+ClassmateParser -> DeleteStudentCommandParser
+activate DeleteStudentCommandParser
-DeleteCommandParser --> AddressBookParser
-deactivate DeleteCommandParser
+DeleteStudentCommandParser --> ClassmateParser
+deactivate DeleteStudentCommandParser
-AddressBookParser -> DeleteCommandParser : parse("1")
-activate DeleteCommandParser
+ClassmateParser -> DeleteStudentCommandParser : parse("1")
+activate DeleteStudentCommandParser
-create DeleteCommand
-DeleteCommandParser -> DeleteCommand
-activate DeleteCommand
+create DeleteStudentCommand
+DeleteStudentCommandParser -> DeleteStudentCommand
+activate DeleteStudentCommand
-DeleteCommand --> DeleteCommandParser : d
-deactivate DeleteCommand
+DeleteStudentCommand --> DeleteStudentCommandParser : d
+deactivate DeleteStudentCommand
-DeleteCommandParser --> AddressBookParser : d
-deactivate DeleteCommandParser
+DeleteStudentCommandParser --> ClassmateParser : d
+deactivate DeleteStudentCommandParser
'Hidden arrow to position the destroy marker below the end of the activation bar.
-DeleteCommandParser -[hidden]-> AddressBookParser
-destroy DeleteCommandParser
+DeleteStudentCommandParser -[hidden]-> ClassmateParser
+destroy DeleteStudentCommandParser
-AddressBookParser --> LogicManager : d
-deactivate AddressBookParser
+ClassmateParser --> LogicManager : d
+deactivate ClassmateParser
-LogicManager -> DeleteCommand : execute()
-activate DeleteCommand
+LogicManager -> DeleteStudentCommand : execute()
+activate DeleteStudentCommand
-DeleteCommand -> Model : deletePerson(1)
+DeleteStudentCommand -> Model : deleteStudent(1)
activate Model
-Model --> DeleteCommand
+Model --> DeleteStudentCommand
deactivate Model
create CommandResult
-DeleteCommand -> CommandResult
+DeleteStudentCommand -> CommandResult
activate CommandResult
-CommandResult --> DeleteCommand
+CommandResult --> DeleteStudentCommand
deactivate CommandResult
-DeleteCommand --> LogicManager : result
-deactivate DeleteCommand
+DeleteStudentCommand --> LogicManager : result
+deactivate DeleteStudentCommand
[<--LogicManager
deactivate LogicManager
diff --git a/docs/diagrams/FindStudentSequenceDiagram.puml b/docs/diagrams/FindStudentSequenceDiagram.puml
new file mode 100644
index 00000000000..c96c616e824
--- /dev/null
+++ b/docs/diagrams/FindStudentSequenceDiagram.puml
@@ -0,0 +1,50 @@
+@startuml
+!include style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":**FindStudentCommand**" as FindStudentCommand LOGIC_COLOR
+participant "**r:CommandResult**" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "**m:ModelManager**" as ModelManager MODEL_COLOR
+participant "**:FilteredList**" as FilteredList MODEL_COLOR
+end box
+
+[-> FindStudentCommand : ""execute(m)""
+activate FindStudentCommand
+
+FindStudentCommand -> ModelManager : ""updateFilteredStudentList(p)""
+activate ModelManager
+
+note right
+""p"" is the Predicate
+which checks if the
+given ""Student""'s
+name has the
+user input keywords
+end note
+
+ModelManager -> FilteredList : ""setPredicate(p)""
+activate FilteredList
+
+FilteredList --> ModelManager
+deactivate FilteredList
+
+ModelManager --> FindStudentCommand
+deactivate
+
+create CommandResult
+FindStudentCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> FindStudentCommand : ""r""
+deactivate CommandResult
+
+[<-- FindStudentCommand : ""r""
+deactivate FindStudentCommand
+
+FindStudentCommand -[hidden]> CommandResult
+destroy FindStudentCommand
+
+@enduml
diff --git a/docs/diagrams/GetTutorialGroupsDiagram.png b/docs/diagrams/GetTutorialGroupsDiagram.png
new file mode 100644
index 00000000000..9216c8a9778
Binary files /dev/null and b/docs/diagrams/GetTutorialGroupsDiagram.png differ
diff --git a/docs/diagrams/GetTutorialGroupsDiagram.puml b/docs/diagrams/GetTutorialGroupsDiagram.puml
new file mode 100644
index 00000000000..bea5ff25d37
--- /dev/null
+++ b/docs/diagrams/GetTutorialGroupsDiagram.puml
@@ -0,0 +1,31 @@
+@startuml
+!include style.puml
+
+box Model MODEL_COLOR_T1
+participant "**:UniqueTutorialClassList**" as UniqueTutorialClassList MODEL_COLOR
+participant "<>\n**TutorialClass**" as StaticTutorialClass MODEL_COLOR
+participant ":**TutorialClass**" as TutorialClass MODEL_COLOR
+end box
+
+mainframe sd get tutorial groups
+
+UniqueTutorialClassList -> StaticTutorialClass : ""createTestTutorialClass(cc)""
+activate StaticTutorialClass
+StaticTutorialClass --> UniqueTutorialClassList
+deactivate StaticTutorialClass
+
+note right
+""cc"" is the ClassCode
+of the TutorialClass
+that the TutorialGroup is
+being added to
+end note
+
+UniqueTutorialClassList -> TutorialClass : ""check for matching tutorial class""
+activate TutorialClass
+UniqueTutorialClassList -> TutorialClass : ""getTutorialGroups()""
+
+TutorialClass --> UniqueTutorialClassList
+deactivate TutorialClass
+
+@enduml
diff --git a/docs/diagrams/LogicClassDiagram.png b/docs/diagrams/LogicClassDiagram.png
new file mode 100644
index 00000000000..02cd44b7d15
Binary files /dev/null and b/docs/diagrams/LogicClassDiagram.png differ
diff --git a/docs/diagrams/LogicClassDiagram.puml b/docs/diagrams/LogicClassDiagram.puml
index 6d14b17b361..62b10d82653 100644
--- a/docs/diagrams/LogicClassDiagram.puml
+++ b/docs/diagrams/LogicClassDiagram.puml
@@ -6,7 +6,7 @@ skinparam classBackgroundColor LOGIC_COLOR
package Logic {
-Class AddressBookParser
+Class ClassmateParser
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" ClassmateParser
+ClassmateParser ..> XYZCommand : creates >
XYZCommand -up-|> Command
LogicManager .left.> Command : executes >
@@ -38,7 +38,7 @@ LogicManager --> Storage
Storage --[hidden] Model
Command .[hidden]up.> Storage
Command .right.> Model
-note right of XYZCommand: XYZCommand = AddCommand, \nFindCommand, etc
+note right of XYZCommand: XYZCommand = AddStudentCommand, \nFindStudentCommand, etc
Logic ..> CommandResult
LogicManager .down.> CommandResult
diff --git a/docs/diagrams/ModelClassDiagram.png b/docs/diagrams/ModelClassDiagram.png
new file mode 100644
index 00000000000..be01c2e2923
Binary files /dev/null and b/docs/diagrams/ModelClassDiagram.png differ
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 1122257bd9a..fb2ebaa2acd 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -5,50 +5,72 @@ skinparam arrowColor MODEL_COLOR
skinparam classBackgroundColor MODEL_COLOR
Package Model <>{
-Interface ReadOnlyAddressBook <>
+Interface ReadOnlyClassmate <>
Interface ReadOnlyUserPrefs <>
Interface Model <>
-Class AddressBook
-Class ReadOnlyAddressBook
+Class Classmate
+Class ReadOnlyClassmate
Class Model
Class ModelManager
Class UserPrefs
Class ReadOnlyUserPrefs
-Class UniquePersonList
-Class Person
+Class UniqueStudentList
+Class UniqueTutorialClassList
+Class UniqueTutorialGroupList
+Class Student
+Class TutorialClass
+Class TutorialGroup
Class Address
Class Email
+Class StudentMark
Class Name
Class Phone
Class Tag
+Class ClassCode
+Class Schedule
+Class GroupNumber
+Class GroupType
}
Class HiddenOutside #FFFFFF
HiddenOutside ..> Model
-AddressBook .up.|> ReadOnlyAddressBook
+Classmate .up.|> ReadOnlyClassmate
ModelManager .up.|> Model
Model .right.> ReadOnlyUserPrefs
-Model .left.> ReadOnlyAddressBook
-ModelManager -left-> "1" AddressBook
+Model .left.> ReadOnlyClassmate
+ModelManager -left-> "1" Classmate
ModelManager -right-> "1" UserPrefs
UserPrefs .up.|> ReadOnlyUserPrefs
-AddressBook *--> "1" UniquePersonList
-UniquePersonList --> "~* all" Person
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
-Person *--> "*" Tag
+Classmate *--> "1" UniqueStudentList
+Classmate *--> "1" UniqueTutorialClassList
+TutorialClass *--> "1" UniqueTutorialGroupList
+UniqueStudentList *-down-> "~* all" Student
+UniqueTutorialClassList *-down-> "~* all" TutorialClass
+UniqueTutorialGroupList *-down-> "~* " TutorialGroup
+Student *--> Name
+Student *--> Phone
+Student *--> Email
+Student *--> Address
+Student *--> ClassCode
+Student *--> "*" Tag
+Student *--> "*" StudentMark
+TutorialClass *--> ClassCode
+TutorialClass *--> "*" Tag
+TutorialClass *--> Schedule
+TutorialGroup *--> GroupNumber
+TutorialGroup *--> ClassCode
+TutorialGroup *--> GroupType
Name -[hidden]right-> Phone
Phone -[hidden]right-> Address
Address -[hidden]right-> Email
-ModelManager -->"~* filtered" Person
+ModelManager -->"~* filtered" Student
+ModelManager -->"~* filtered" TutorialClass
@enduml
diff --git a/docs/diagrams/ParserClasses.png b/docs/diagrams/ParserClasses.png
new file mode 100644
index 00000000000..80509a7c53b
Binary files /dev/null and b/docs/diagrams/ParserClasses.png differ
diff --git a/docs/diagrams/ParserClasses.puml b/docs/diagrams/ParserClasses.puml
index 6ba585cba01..44db34e87bf 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 ClassmateParser
Class XYZCommandParser
Class CliSyntax
Class ParserUtil
@@ -19,12 +19,12 @@ Class Prefix
}
Class HiddenOutside #FFFFFF
-HiddenOutside ..> AddressBookParser
+HiddenOutside ..> ClassmateParser
-AddressBookParser .down.> XYZCommandParser: creates >
+ClassmateParser .down.> XYZCommandParser: creates >
XYZCommandParser ..> XYZCommand : creates >
-AddressBookParser ..> Command : returns >
+ClassmateParser ..> Command : returns >
XYZCommandParser .up.|> Parser
XYZCommandParser ..> ArgumentMultimap
XYZCommandParser ..> ArgumentTokenizer
diff --git a/docs/diagrams/SetUpActivityDiagram.png b/docs/diagrams/SetUpActivityDiagram.png
new file mode 100644
index 00000000000..8c45fafe26f
Binary files /dev/null and b/docs/diagrams/SetUpActivityDiagram.png differ
diff --git a/docs/diagrams/SetUpActivityDiagram.puml b/docs/diagrams/SetUpActivityDiagram.puml
new file mode 100644
index 00000000000..719638d9b2c
--- /dev/null
+++ b/docs/diagrams/SetUpActivityDiagram.puml
@@ -0,0 +1,9 @@
+@startuml
+start
+:Add tutorial class;
+:Create student and add to tutorial class;
+:Create and add tutorial group to tutorial class;
+:Add student to tutorial group;
+
+stop
+@enduml
diff --git a/docs/diagrams/StorageClassDiagram.png b/docs/diagrams/StorageClassDiagram.png
new file mode 100644
index 00000000000..a54da696b34
Binary files /dev/null and b/docs/diagrams/StorageClassDiagram.png differ
diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml
index 85ac3ea2dee..5be44c13188 100644
--- a/docs/diagrams/StorageClassDiagram.puml
+++ b/docs/diagrams/StorageClassDiagram.puml
@@ -14,11 +14,14 @@ Class JsonUserPrefsStorage
Interface Storage <>
Class StorageManager
-package "AddressBook Storage" #F4F6F6{
-Interface AddressBookStorage <>
-Class JsonAddressBookStorage
-Class JsonSerializableAddressBook
-Class JsonAdaptedPerson
+package "Classmate Storage" #F4F6F6{
+Interface ClassmateStorage <>
+Class JsonClassmateStorage
+Class JsonSerializableStudent
+Class JsonAdaptedStudent
+Class JsonAdaptedTutorialClass
+Class JsonAdaptedTutorialGroup
+Class JsonAdaptedMark
Class JsonAdaptedTag
}
@@ -29,15 +32,20 @@ HiddenOutside ..> Storage
StorageManager .up.|> Storage
StorageManager -up-> "1" UserPrefsStorage
-StorageManager -up-> "1" AddressBookStorage
+StorageManager -up-> "1" ClassmateStorage
Storage -left-|> UserPrefsStorage
-Storage -right-|> AddressBookStorage
+Storage -right-|> ClassmateStorage
JsonUserPrefsStorage .up.|> UserPrefsStorage
-JsonAddressBookStorage .up.|> AddressBookStorage
-JsonAddressBookStorage ..> JsonSerializableAddressBook
-JsonSerializableAddressBook --> "*" JsonAdaptedPerson
-JsonAdaptedPerson --> "*" JsonAdaptedTag
+JsonClassmateStorage .up.|> ClassmateStorage
+JsonClassmateStorage ..> JsonSerializableStudent
+JsonSerializableStudent --> "*" JsonAdaptedStudent
+JsonSerializableStudent --> "*" JsonAdaptedTutorialClass
+JsonAdaptedTutorialClass --> "*" JsonAdaptedTutorialGroup
+JsonAdaptedTutorialClass --> "*" JsonAdaptedTag
+JsonAdaptedStudent --> "*" JsonAdaptedTag
+JsonAdaptedStudent --> "*" JsonAdaptedTutorialGroup
+JsonAdaptedStudent --> "*" JsonAdaptedMark
@enduml
diff --git a/docs/diagrams/UiClassDiagram.png b/docs/diagrams/UiClassDiagram.png
new file mode 100644
index 00000000000..237c45d1f60
Binary files /dev/null and b/docs/diagrams/UiClassDiagram.png differ
diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml
index ecae4876432..921053a2515 100644
--- a/docs/diagrams/UiClassDiagram.puml
+++ b/docs/diagrams/UiClassDiagram.puml
@@ -10,9 +10,12 @@ Class "{abstract}\nUiPart" as UiPart
Class UiManager
Class MainWindow
Class HelpWindow
+Class StudentWindow
Class ResultDisplay
-Class PersonListPanel
-Class PersonCard
+Class StudentListPanel
+Class ClassListPanel
+Class StudentCard
+Class ClassCard
Class StatusBarFooter
Class CommandBox
}
@@ -32,26 +35,33 @@ UiManager .left.|> Ui
UiManager -down-> "1" MainWindow
MainWindow *-down-> "1" CommandBox
MainWindow *-down-> "1" ResultDisplay
-MainWindow *-down-> "1" PersonListPanel
+MainWindow *-down-> "1" StudentListPanel
+MainWindow *-down-> "1" ClassListPanel
MainWindow *-down-> "1" StatusBarFooter
MainWindow --> "0..1" HelpWindow
+MainWindow --> "0..1" StudentWindow
-PersonListPanel -down-> "*" PersonCard
+StudentListPanel -down-> "*" StudentCard
+ClassListPanel -down-> "*" ClassCard
MainWindow -left-|> UiPart
ResultDisplay --|> UiPart
CommandBox --|> UiPart
-PersonListPanel --|> UiPart
-PersonCard --|> UiPart
+StudentListPanel --|> UiPart
+ClassListPanel --|> UiPart
+StudentCard --|> UiPart
+ClassCard --|> UiPart
StatusBarFooter --|> UiPart
HelpWindow --|> UiPart
+StudentWindow --|> UiPart
-PersonCard ..> Model
+ClassCard ..> Model
+StudentCard ..> Model
UiManager -right-> Logic
MainWindow -left-> Logic
-PersonListPanel -[hidden]left- HelpWindow
+StudentListPanel -[hidden]left- HelpWindow
HelpWindow -[hidden]left- CommandBox
CommandBox -[hidden]left- ResultDisplay
ResultDisplay -[hidden]left- StatusBarFooter
diff --git a/docs/diagrams/UndoRedoState0.png b/docs/diagrams/UndoRedoState0.png
new file mode 100644
index 00000000000..e51f6900cdd
Binary files /dev/null and b/docs/diagrams/UndoRedoState0.png differ
diff --git a/docs/diagrams/UndoRedoState0.puml b/docs/diagrams/UndoRedoState0.puml
index 96e30744d24..b77ba1ff93f 100644
--- a/docs/diagrams/UndoRedoState0.puml
+++ b/docs/diagrams/UndoRedoState0.puml
@@ -6,9 +6,9 @@ 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 "__ab0:Classmate__"
+ class State2 as "__ab1:Classmate__"
+ class State3 as "__ab2:Classmate__"
}
State1 -[hidden]right-> State2
State2 -[hidden]right-> State3
diff --git a/docs/diagrams/UndoRedoState1.png b/docs/diagrams/UndoRedoState1.png
new file mode 100644
index 00000000000..771ce969325
Binary files /dev/null and b/docs/diagrams/UndoRedoState1.png differ
diff --git a/docs/diagrams/UndoRedoState1.puml b/docs/diagrams/UndoRedoState1.puml
index 01fcb9b2b96..dfb50e630f0 100644
--- a/docs/diagrams/UndoRedoState1.puml
+++ b/docs/diagrams/UndoRedoState1.puml
@@ -6,9 +6,9 @@ skinparam ClassBorderColor #000000
title After command "delete 5"
package States <> {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab2:AddressBook__"
+ class State1 as "__ab0:Classmate__"
+ class State2 as "__ab1:Classmate__"
+ class State3 as "__ab2:Classmate__"
}
State1 -[hidden]right-> State2
diff --git a/docs/diagrams/UndoRedoState2.png b/docs/diagrams/UndoRedoState2.png
new file mode 100644
index 00000000000..0e066f7bef3
Binary files /dev/null and b/docs/diagrams/UndoRedoState2.png differ
diff --git a/docs/diagrams/UndoRedoState2.puml b/docs/diagrams/UndoRedoState2.puml
index bccc230a5d1..fd4e968b3e1 100644
--- a/docs/diagrams/UndoRedoState2.puml
+++ b/docs/diagrams/UndoRedoState2.puml
@@ -6,9 +6,9 @@ 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__"
+ class State1 as "__ab0:Classmate__"
+ class State2 as "__ab1:Classmate__"
+ class State3 as "__ab2:Classmate__"
}
State1 -[hidden]right-> State2
diff --git a/docs/diagrams/UndoRedoState3.png b/docs/diagrams/UndoRedoState3.png
new file mode 100644
index 00000000000..d863979f51f
Binary files /dev/null and b/docs/diagrams/UndoRedoState3.png differ
diff --git a/docs/diagrams/UndoRedoState3.puml b/docs/diagrams/UndoRedoState3.puml
index ea29c9483e4..ba059df41cc 100644
--- a/docs/diagrams/UndoRedoState3.puml
+++ b/docs/diagrams/UndoRedoState3.puml
@@ -6,9 +6,9 @@ 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 "__ab0:Classmate__"
+ class State2 as "__ab1:Classmate__"
+ class State3 as "__ab2:Classmate__"
}
State1 -[hidden]right-> State2
diff --git a/docs/diagrams/UndoRedoState4.png b/docs/diagrams/UndoRedoState4.png
new file mode 100644
index 00000000000..0fac5ece1fb
Binary files /dev/null and b/docs/diagrams/UndoRedoState4.png differ
diff --git a/docs/diagrams/UndoRedoState4.puml b/docs/diagrams/UndoRedoState4.puml
index 1b784cece80..d485a2fa662 100644
--- a/docs/diagrams/UndoRedoState4.puml
+++ b/docs/diagrams/UndoRedoState4.puml
@@ -6,9 +6,9 @@ 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 "__ab0:Classmate__"
+ class State2 as "__ab1:Classmate__"
+ class State3 as "__ab2:Classmate__"
}
State1 -[hidden]right-> State2
diff --git a/docs/diagrams/UndoRedoState5.png b/docs/diagrams/UndoRedoState5.png
new file mode 100644
index 00000000000..e49a21b7105
Binary files /dev/null and b/docs/diagrams/UndoRedoState5.png differ
diff --git a/docs/diagrams/UndoRedoState5.puml b/docs/diagrams/UndoRedoState5.puml
index 88927be32bc..d219a87ebf6 100644
--- a/docs/diagrams/UndoRedoState5.puml
+++ b/docs/diagrams/UndoRedoState5.puml
@@ -6,9 +6,9 @@ skinparam ClassBorderColor #000000
title After command "clear"
package States <> {
- class State1 as "__ab0:AddressBook__"
- class State2 as "__ab1:AddressBook__"
- class State3 as "__ab3:AddressBook__"
+ class State1 as "__ab0:Classmate__"
+ class State2 as "__ab1:Classmate__"
+ class State3 as "__ab3:Classmate__"
}
State1 -[hidden]right-> State2
diff --git a/docs/diagrams/UndoSequenceDiagram.png b/docs/diagrams/UndoSequenceDiagram.png
new file mode 100644
index 00000000000..ab3b756ba0e
Binary files /dev/null and b/docs/diagrams/UndoSequenceDiagram.png differ
diff --git a/docs/diagrams/UndoSequenceDiagram.puml b/docs/diagrams/UndoSequenceDiagram.puml
index 410aab4e412..a8daae86916 100644
--- a/docs/diagrams/UndoSequenceDiagram.puml
+++ b/docs/diagrams/UndoSequenceDiagram.puml
@@ -3,42 +3,42 @@
box Logic LOGIC_COLOR_T1
participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":ClassmateParser" as ClassmateParser LOGIC_COLOR
participant "u:UndoCommand" as UndoCommand LOGIC_COLOR
end box
box Model MODEL_COLOR_T1
participant ":Model" as Model MODEL_COLOR
-participant ":VersionedAddressBook" as VersionedAddressBook MODEL_COLOR
+participant ":VersionedClassmate" as VersionedClassmate MODEL_COLOR
end box
[-> LogicManager : execute(undo)
activate LogicManager
-LogicManager -> AddressBookParser : parseCommand(undo)
-activate AddressBookParser
+LogicManager -> ClassmateParser : parseCommand(undo)
+activate ClassmateParser
create UndoCommand
-AddressBookParser -> UndoCommand
+ClassmateParser -> UndoCommand
activate UndoCommand
-UndoCommand --> AddressBookParser
+UndoCommand --> ClassmateParser
deactivate UndoCommand
-AddressBookParser --> LogicManager : u
-deactivate AddressBookParser
+ClassmateParser --> LogicManager : u
+deactivate ClassmateParser
LogicManager -> UndoCommand : execute()
activate UndoCommand
-UndoCommand -> Model : undoAddressBook()
+UndoCommand -> Model : undoClassmate()
activate Model
-Model -> VersionedAddressBook : undo()
-activate VersionedAddressBook
+Model -> VersionedClassmate : undo()
+activate VersionedClassmate
-VersionedAddressBook -> VersionedAddressBook :resetData(ReadOnlyAddressBook)
-VersionedAddressBook --> Model :
-deactivate VersionedAddressBook
+VersionedClassmate -> VersionedClassmate :resetData(ReadOnlyClassmate)
+VersionedClassmate --> Model :
+deactivate VersionedClassmate
Model --> UndoCommand
deactivate Model
diff --git a/docs/diagrams/tracing/LogicSequenceDiagram.puml b/docs/diagrams/tracing/LogicSequenceDiagram.puml
index fdcbe1c0ccc..7f08ec5ae6e 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 ":ClassmateParser" as abp LOGIC_COLOR
Participant ":EditCommandParser" as ecp LOGIC_COLOR
Participant "command:EditCommand" as ec LOGIC_COLOR
@@ -13,7 +13,7 @@ create ecp
abp -> ecp
abp -> ecp ++: parse(arguments)
create ec
-ecp -> ec ++: index, editPersonDescriptor
+ecp -> ec ++: index, editStudentDescriptor
ec --> ecp --
ecp --> abp --: command
abp --> logic --: command
diff --git a/docs/images/AddClassSequenceDiagram.png b/docs/images/AddClassSequenceDiagram.png
new file mode 100644
index 00000000000..892af996b2e
Binary files /dev/null and b/docs/images/AddClassSequenceDiagram.png differ
diff --git a/docs/images/AddGroupSequenceDiagram.png b/docs/images/AddGroupSequenceDiagram.png
new file mode 100644
index 00000000000..793923b50e6
Binary files /dev/null and b/docs/images/AddGroupSequenceDiagram.png differ
diff --git a/docs/images/AddMarkSequenceDiagram.png b/docs/images/AddMarkSequenceDiagram.png
new file mode 100644
index 00000000000..0979c8d5bb1
Binary files /dev/null and b/docs/images/AddMarkSequenceDiagram.png differ
diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png
index 2f1346869d0..d2d4571b6e0 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..3de3226136c 100644
Binary files a/docs/images/BetterModelClassDiagram.png and b/docs/images/BetterModelClassDiagram.png differ
diff --git a/docs/images/CommandLineInput.png b/docs/images/CommandLineInput.png
new file mode 100644
index 00000000000..a15b173ad14
Binary files /dev/null and b/docs/images/CommandLineInput.png differ
diff --git a/docs/images/DeleteCommandScreenshot.png b/docs/images/DeleteCommandScreenshot.png
new file mode 100644
index 00000000000..6e584489f98
Binary files /dev/null and b/docs/images/DeleteCommandScreenshot.png differ
diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png
index fa327b39618..28e7a49f6aa 100644
Binary files a/docs/images/DeleteSequenceDiagram.png and b/docs/images/DeleteSequenceDiagram.png differ
diff --git a/docs/images/DeleteStudentSequenceDiagram.png b/docs/images/DeleteStudentSequenceDiagram.png
new file mode 100644
index 00000000000..2cd75de44aa
Binary files /dev/null and b/docs/images/DeleteStudentSequenceDiagram.png differ
diff --git a/docs/images/FindStudentSequenceDiagram.png b/docs/images/FindStudentSequenceDiagram.png
new file mode 100644
index 00000000000..74a11940459
Binary files /dev/null and b/docs/images/FindStudentSequenceDiagram.png differ
diff --git a/docs/images/GetTutorialGroupsDiagram.png b/docs/images/GetTutorialGroupsDiagram.png
new file mode 100644
index 00000000000..9216c8a9778
Binary files /dev/null and b/docs/images/GetTutorialGroupsDiagram.png differ
diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png
index c3028aa1cda..12f87eebe79 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..be01c2e2923 100644
Binary files a/docs/images/ModelClassDiagram.png and b/docs/images/ModelClassDiagram.png differ
diff --git a/docs/images/SetUpActivityDiagram.png b/docs/images/SetUpActivityDiagram.png
new file mode 100644
index 00000000000..8c45fafe26f
Binary files /dev/null and b/docs/images/SetUpActivityDiagram.png differ
diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png
index 82c66f8f16e..a54da696b34 100644
Binary files a/docs/images/StorageClassDiagram.png and b/docs/images/StorageClassDiagram.png differ
diff --git a/docs/images/StudentMarksState1.png b/docs/images/StudentMarksState1.png
new file mode 100644
index 00000000000..fd137b49987
Binary files /dev/null and b/docs/images/StudentMarksState1.png differ
diff --git a/docs/images/StudentMarksState2.png b/docs/images/StudentMarksState2.png
new file mode 100644
index 00000000000..8a4e9133cb0
Binary files /dev/null and b/docs/images/StudentMarksState2.png differ
diff --git a/docs/images/Ui-annotated.png b/docs/images/Ui-annotated.png
new file mode 100644
index 00000000000..f5297cd2676
Binary files /dev/null and b/docs/images/Ui-annotated.png differ
diff --git a/docs/images/Ui.png b/docs/images/Ui.png
index 91488fd1a0f..557ebb0605b 100644
Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ
diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png
index 4bb8b2ce591..a659b9549dd 100644
Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ
diff --git a/docs/images/clear.png b/docs/images/clear.png
new file mode 100644
index 00000000000..32d523fb480
Binary files /dev/null and b/docs/images/clear.png differ
diff --git a/docs/images/deletecScreenshot.png b/docs/images/deletecScreenshot.png
new file mode 100644
index 00000000000..2bb8289cf9a
Binary files /dev/null and b/docs/images/deletecScreenshot.png differ
diff --git a/docs/images/gabrielwlm.png b/docs/images/gabrielwlm.png
new file mode 100644
index 00000000000..de6dc8dc9a2
Binary files /dev/null and b/docs/images/gabrielwlm.png differ
diff --git a/docs/images/helpMessage.png b/docs/images/helpMessage.png
index b1f70470137..64f7971fa8a 100644
Binary files a/docs/images/helpMessage.png and b/docs/images/helpMessage.png differ
diff --git a/docs/images/juliussneezer04.png b/docs/images/juliussneezer04.png
new file mode 100644
index 00000000000..6de7ebaf80a
Binary files /dev/null and b/docs/images/juliussneezer04.png differ
diff --git a/docs/images/nguyiyang.png b/docs/images/nguyiyang.png
new file mode 100644
index 00000000000..650385c7d44
Binary files /dev/null and b/docs/images/nguyiyang.png differ
diff --git a/docs/images/rushilramesh.png b/docs/images/rushilramesh.png
new file mode 100644
index 00000000000..3761b54fb35
Binary files /dev/null and b/docs/images/rushilramesh.png differ
diff --git a/docs/images/viewc.png b/docs/images/viewc.png
new file mode 100644
index 00000000000..71c3ad2f697
Binary files /dev/null and b/docs/images/viewc.png differ
diff --git a/docs/images/viewstu.png b/docs/images/viewstu.png
new file mode 100644
index 00000000000..bcfa308385a
Binary files /dev/null and b/docs/images/viewstu.png differ
diff --git a/docs/images/zhouyirui.png b/docs/images/zhouyirui.png
new file mode 100644
index 00000000000..623fb483432
Binary files /dev/null and b/docs/images/zhouyirui.png differ
diff --git a/docs/img.png b/docs/img.png
new file mode 100644
index 00000000000..a15b173ad14
Binary files /dev/null and b/docs/img.png differ
diff --git a/docs/img_1.png b/docs/img_1.png
new file mode 100644
index 00000000000..82b38f4c90c
Binary files /dev/null and b/docs/img_1.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..3940d5fc7d2 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,17 +1,17 @@
---
layout: page
-title: AddressBook Level-3
+title: ClassMATE
---
-[![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)
+[![CI Status](https://github.com/AY2122S1-CS2103T-W15-1/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2122S1-CS2103T-W15-1/tp/actions)
+[![codecov](https://codecov.io/gh/AY2122S1-CS2103T-W15-1/tp/branch/master/graph/badge.svg)](https://codecov.io/gh/AY2122S1-CS2103T-W15-1/tp)
![Ui](images/Ui.png)
-**AddressBook is a desktop application for managing your contact details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
+**ClassMATE is a desktop application for managing your classes.** 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 classMATE, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
+* If you are interested about developing classMATE, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
**Acknowledgements**
diff --git a/docs/team/diagrams/AddMarkSequenceDiagram.png b/docs/team/diagrams/AddMarkSequenceDiagram.png
new file mode 100644
index 00000000000..0979c8d5bb1
Binary files /dev/null and b/docs/team/diagrams/AddMarkSequenceDiagram.png differ
diff --git a/docs/team/diagrams/StudentMarksState1.png b/docs/team/diagrams/StudentMarksState1.png
new file mode 100644
index 00000000000..fd137b49987
Binary files /dev/null and b/docs/team/diagrams/StudentMarksState1.png differ
diff --git a/docs/team/diagrams/StudentMarksState2.png b/docs/team/diagrams/StudentMarksState2.png
new file mode 100644
index 00000000000..8a4e9133cb0
Binary files /dev/null and b/docs/team/diagrams/StudentMarksState2.png differ
diff --git a/docs/team/gabrielwlm.md b/docs/team/gabrielwlm.md
new file mode 100644
index 00000000000..c0ed4f3cb66
--- /dev/null
+++ b/docs/team/gabrielwlm.md
@@ -0,0 +1,70 @@
+---
+layout: page
+title: Gabriel Waikin Loh Matienzo's Project Portfolio Page
+---
+
+### Project: ClassMATE
+
+ClassMATE is a desktop application designed for instructors of the CS2101 Module in NUS to easily store class and student details. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
+
+Given below are my contributions to the project.
+
+* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/)
+
+* Enhancements implemented:
+ * New feature: Added the ability to find classes:
+ * PR [\#130](), [\#246]()
+ * Allows the user to find a specific tutorial class among all the tutorial classes, so they can use other features of ClassMATE with the desired tutorial class.
+ * This implementation was a bit tough as it was my first feature implementation, which involved configuring several edits to the existing code, including the creation of `FindClassCommand` and `FindClassCommandParser`, which define the find class command. I also modified several files to integrate the `FindClassCommand` into ClassMATE, including `ClassmateParser`.
+ * I also added test cases to catch bugs in the command.
+ * New feature: Added the ability to view students in a group:
+ * PR [\#151](), [\#246]()
+ * Allows the user to only see students who are in a specific tutorial group. The student list is filtered to show only students who are in the desired tutorial group, for easy access to perform other features of ClassMATE with students in the tutorial group.
+ * This implementation was a bit tough as it required an understanding of the `TutorialGroup` feature (contributed by Yirui and Yi Yang) and required the creation of more `Predicate` classes to filter students in the student list, including `GroupMemberPredicate` and `TutorialGroupContainsKeywordPredicate`. It also required an understanding of the syntax in commands in conjunction with the filtering of students.
+ * I also added test cases to catch bugs in the command.
+
+* **Documentation**:
+ * Edited various documents to repurpose AddressBook into ClassMATE [\#78]()
+ * User Guide:
+ * Added documentation for the features `addc`, `deletec` and `viewc` [\#76]()
+ * Rearranged order of the features to improve readability [\#76](), [\#238]()
+ * Updated command summary and improve readability [\#76](), [\#238]()
+ * Added Java 11 download instructions [\#140]()
+ * Made the user guide more personable [\#140]()
+ * Added warnings to commands that involved deletion of data [\#238](), [\#246]()
+ * Fixed spelling and grammatical errors [\#246]()
+ * Added hyperlinks to increase navigability [\#246]()
+ * Added student mark commands in command summary [\#246]()
+ * Developer Guide:
+ * Added glossary terms [\#81]()
+ * Added use cases [\#81](), [\#246]()
+ * Added non-functional requirements [\#81]()
+ * Fixed spelling and grammatical errors [\#130](), [\#246]()
+ * Added the class and group filtering feature section [\#246]()
+
+* **Team-Based tasks**:
+ * Managed documentation for releases `v1.1` - `v1.4` (4 releases) on GitHub
+ * Conducted manual testing of features based on descriptions provided in the User Guide.
+ * **Refactoring**:
+ * Refactored Person to Student
+ * PR [\#93]()
+ * I refactored all mentions and instances of `Person` to `Student` to make ClassMATE more specific to its target users and its purpose, which in short is to keep a record of students.
+ * Refactored AddressBook to Classmate
+ * PR [\#116]()
+ * I refactored all mentions and instances of `AddressBook` to `ClassMATE` to differentiate ClassMATE from AddressBook which we adapted, as it is now a different application.
+ * **Bug Fixes**:
+ * IsSameStudent bug [\#130]()
+ * Findc bug [\#170]()
+ * Viewg bug [\#179]()
+ * Non-existent class/group bug [\#241]()
+ * Documentation bugs [\#170](), [\#220]()
+ * Fixed grammatical errors in PPPs [\#246]()
+
+* **Review Contributions**
+ * PRs Reviewed with comments: [\#77](), [\#131](), [\#135](), [\#138](), [\#142](), [\#207](), [\#240](), [\#243]()
+ * I helped fix grammatical errors and other bugs in the team documents as well as those of my fellow teammates
+
+* **Community Contributions**
+ * Bugs reported in other teams work:
+ * PE-D [1](https://github.com/AY2122S1-CS2103-W14-2/tp/issues/146), [2](https://github.com/AY2122S1-CS2103-W14-2/tp/issues/152), [3](https://github.com/AY2122S1-CS2103-W14-2/tp/issues/162), [4](https://github.com/AY2122S1-CS2103-W14-2/tp/issues/170), [5](https://github.com/AY2122S1-CS2103-W14-2/tp/issues/172), [6](https://github.com/AY2122S1-CS2103-W14-2/tp/issues/181), [7](https://github.com/AY2122S1-CS2103-W14-2/tp/issues/182), [8](https://github.com/AY2122S1-CS2103-W14-2/tp/issues/184), [9](https://github.com/AY2122S1-CS2103-W14-2/tp/issues/185), [10](https://github.com/AY2122S1-CS2103-W14-2/tp/issues/187)
+ * [Smoke Test CATcher](https://github.com/GabrielWLM/ped)
diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md
deleted file mode 100644
index 773a07794e2..00000000000
--- a/docs/team/johndoe.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-layout: page
-title: John Doe's Project Portfolio Page
----
-
-### Project: AddressBook Level 3
-
-AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
-
-Given below are my contributions to the project.
-
-* **New Feature**: Added the ability to undo/redo previous commands.
- * What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command.
- * Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them.
- * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands.
- * Credits: *{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}*
-
-* **New Feature**: Added a history command that allows the user to navigate to previous commands using up/down keys.
-
-* **Code contributed**: [RepoSense link]()
-
-* **Project management**:
- * Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub
-
-* **Enhancements to existing features**:
- * Updated the GUI color scheme (Pull requests [\#33](), [\#34]())
- * Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests [\#36](), [\#38]())
-
-* **Documentation**:
- * User Guide:
- * Added documentation for the features `delete` and `find` [\#72]()
- * Did cosmetic tweaks to existing documentation of features `clear`, `exit`: [\#74]()
- * Developer Guide:
- * Added implementation details of the `delete` feature.
-
-* **Community**:
- * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]()
- * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]())
- * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]())
- * Some parts of the history feature I added was adopted by several other class mates ([1](), [2]())
-
-* **Tools**:
- * Integrated a third party library (Natty) to the project ([\#42]())
- * Integrated a new Github plugin (CircleCI) to the team repo
-
-* _{you can add/remove categories in the list above}_
diff --git a/docs/team/juliussneezer04.md b/docs/team/juliussneezer04.md
new file mode 100644
index 00000000000..3c5317fb9d6
--- /dev/null
+++ b/docs/team/juliussneezer04.md
@@ -0,0 +1,69 @@
+---
+layout: page
+title: Vishnu Sundaresan's Project Portfolio Page
+---
+
+### Project: ClassMATE
+
+ClassMATE is a desktop application designed for instructors of the CS2101 Module in NUS to easily store class and student details. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
+
+Given below are my contributions to the project.
+
+* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/#breakdown=true&search=juliussneezer04)
+* **Enhancements Implemented**:
+ * Allowing TutorialClasses to be stored easily in memory as a JSON list
+ * Creating UniqueTutorialClassList.
+ * Modifying JSON file storage structure to accommodate the list of Tutorial Classes.
+ * Modifying all relevant test cases and test case data accordingly.
+* **New Features Implemented**:
+ * Adding Student Marks functionality
+ * Creating Enumeration of Student Marks.
+ * Adding a special list of student marks to each Student.
+ * Allowing addition at end-of-list, deletion at end-of-list, and deletion of all marks in list operations.
+ * Changed 26 files in the process (adding Test Case Classes for each command).
+ * Displaying marks for each student in decreasing order in `viewstu` window.
+ * Challenge was in increasing `viewstu` window size and decorating the marks in order.
+* **Documentation**:
+ * Contributions to User Guide:
+ * Added documentation for the features `save` and `find` [\#74]([Adding extra pictures and changing names. by juliussneezer04 · Pull Request #74 · AY2122S1-CS2103T-W15-1/tp (github.com)](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/74))
+ * Modifying Quick Start in UG [\#139]([Improving User Guide by juliussneezer04 · Pull Request #139 · AY2122S1-CS2103T-W15-1/tp (github.com)](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/139))
+ * Adding screenshots and explanations of icons to UG [\#144](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/144)
+ * Added documentation for student marks commands in UG [\#153](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/153)
+ * UG Bug Fixes [#253](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/253), [#254](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/254)
+ * Developer Guide:
+ * Documentation regarding Student Marks functionality implementation. [\#127](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/127), [\#146](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/146)
+ * Adding Diagrams for Student Marks functionality. [\#127](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/127), [\#133](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/133) (Sequence Diagram Shown in Appendix A)
+ * Adding Use Cases for Student Marks functionality. [\#132](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/132)
+* **Team-based Tasks**:
+ * Set up the GitHub Team organisation and repo
+ * Added master branch protection.
+ * Created Developers' organisation for team.
+ * Managing scheduling & tracking for upcoming releases `v1.1` - `v1.4` (4 releases) on GitHub
+ * Assigning Issues and Tasks to team members in Repo's Projects
+ * Released v1.2, v1.3 and v1.4 JAR releases.
+ * Set up all Repo Projects for each iteration.
+ * Set up and tracked Milestones 1.1, 1.2, 1.3, 1.4
+ * Recorded Demo Videos for ClassMATE Demos.
+* **Review Contributions**:
+ * PRs reviewed (with non-trivial reviews) [\#155]([Update User Guide by GabrielWLM · Pull Request #155 · AY2122S1-CS2103T-W15-1/tp (github.com)](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/155)), [#245](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/245), [#249](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/249)
+
+
+
+#### Appendix A (Contributions to the Developer Guide)
+
+Sequence Diagram added to Developers' Guide:
+
+![AddMarkSequenceDiagram](diagrams/AddMarkSequenceDiagram.png)
+
+Student Marks State Diagram before/after operation `deletelm`:
+
+*Before* :
+
+![StudentMarksState](diagrams/StudentMarksState1.png)
+
+*After* :
+
+![StudentMarksState2](diagrams/StudentMarksState2.png)
+
+
+
diff --git a/docs/team/nguyiyang.md b/docs/team/nguyiyang.md
new file mode 100644
index 00000000000..bf2e01daf95
--- /dev/null
+++ b/docs/team/nguyiyang.md
@@ -0,0 +1,49 @@
+---
+layout: page
+title: Ngu Yi Yang's Project Portfolio Page
+---
+
+### Project: ClassMATE
+
+ClassMATE is a desktop application designed for instructors of the CS2101 Module in NUS to easily store class and student details. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
+
+Given below are my contributions to the project.
+
+* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/)
+
+* **Enhancements implemented**:
+ * Viewing student functionality
+ * Command for viewing a student
+ * Creating a pop-up window to display student information
+ * Tutorial Group implementation
+ * Creating TutorialGroup and its fields, GroupNumber and GroupType
+ * Saving tutorial groups in JSON file under each tutorial class
+ * Commands for adding and removing tutorial groups
+
+* **Documentation**:
+ * User Guide:
+ * Modifying introduction to include target audience and make it user-centric
+ * Add an overview of main features
+ * Documentation for adding and removing tutorial group from tutorial class commands
+ * Developer Guide:
+ * Documentation for adding and removing tutorial group from tutorial class
+ * Documentation for Non-functional Requirements
+ * Updated class diagram for Model component to include tutorial groups
+ * Created sequence diagram for `AddGroupCommand`
+ * Activity diagram for recommended workflow for ClassMATE
+ * Use cases for adding tutorial group
+
+* **Team-based tasks**:
+ * Updated the link of the GitHub Actions build status badge
+ * Tested features and reported bugs between project iterations [\#123](https://github.com/AY2122S1-CS2103T-W15-1/tp/issues/123)
+ * Bug fixing. Pull Requests: [\#237](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/236), [\#200](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/200)
+ * Tutorial group bugs [\#218](https://github.com/AY2122S1-CS2103T-W15-1/tp/issues/218), [\#224](https://github.com/AY2122S1-CS2103T-W15-1/tp/issues/224), [\#228](https://github.com/AY2122S1-CS2103T-W15-1/tp/issues/228), [\#237](https://github.com/AY2122S1-CS2103T-W15-1/tp/issues/237)
+ * Documentation bugs
+
+* **Review/mentoring contributions**:
+ * PRs reviewed: Suggested an alternative implementation to reduce code repetition [\#198](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/198)
+
+* **Contributions beyond the project team**:
+ * Reporting bugs in other team's products. Some examples include: [1](https://github.com/AY2122S1-CS2103T-T15-4/tp/issues/222), [2](https://github.com/AY2122S1-CS2103T-T15-4/tp/issues/221)
+ * Reviewing the User Guides and Developer Guides of two peer teams
+
diff --git a/docs/team/rushilramesh.md b/docs/team/rushilramesh.md
new file mode 100644
index 00000000000..b46c263e3e1
--- /dev/null
+++ b/docs/team/rushilramesh.md
@@ -0,0 +1,73 @@
+---
+layout: page
+title: Rushil Ramesh's Project Portfolio Page
+---
+
+### Project: ClassMATE
+
+ClassMATE is a desktop application designed for instructors of the CS2101 Module in NUS to easily store class and student details. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
+
+Given below are my contributions to the project.
+
+* **Code contributed**: Check out my contributions [here](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/)
+
+* **Enhancements Implemented**:
+ * New Feature: Added the ability to add tutorial classes:
+ * PR [\#94](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/94), [\#97](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/97)
+ * Allows the user to create a tutorial class with a class code and schedule (and optional tags) so that
+ they can add students to them in the future. This is a basic feature of a CRUD application like ClassMATE.
+ * This implementation was slightly challenging as it was my first feature implemented, which involved making several
+ additions to the existing code, including the creation of `TutorialClass`, `Schedule`, `ClassCode` (contributed by Yirui) and the
+ `EmptyClasscode` which define the tutorial class. I also modified several files involved in the logic behind parsing and executing an
+ `AddClassCommand`. As I implemented the `TutorialClass` feature, I also had to work on the UI, creating a
+ `ClassListPanel` so that users could view classes and students on two separate lists.
+ * New Feature: Added the ability to delete tutorial classes
+ * PR [\#97](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/97), [\#147](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/147)
+ * Allows the user to delete a tutorial class from a specified index in the list of classes. This is a basic CRUD operation
+ that users should be able to perform in the event they no longer require details of a particular class or are assigned to
+ another class.
+ * This implementation required an understanding of the `UniqueList`s and the `ModelManager` as a whole,
+ as deleting a class involved more than simply removing a `TutorialClass` from the list of classes, but involved
+ an update of each student's designated class to an 'empty class', meaning the student has no class. This required
+ adding `Predicate` classes and new methods in `ModelManager`.
+ * New Feature: Implemented the ability to view the students in a class
+ * PR [\#135](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/135)
+ * Allows the user to view a particular class by its index in the list of classes. The student list is filtered to
+ display only students from the particular tutorial class, and the class list only displays the selected class.
+ * This implementation involved the creations of more `Predicate` classes to filter the students out. In addition,
+ I made changes to the UI, including setting the layout of the main page and the UI of the individual students and tutorial classes.
+ I also implemented the list class feature which brings the user back to the original list of classes.
+ * Enhancement to existing feature: Student management features.
+ * PR [\#135](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/135)
+ * Adjusted student functionality, such as preventing students from being added to an empty class and adding a class code.
+ * These features were related to tutorial class, therefore some of my other PRs include updates to student management features.
+
+* **Documentation**:
+ * User Guide:
+ * Added documentation for the features `addstu`, `viewstu` and `deletestu` [\#57](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/57)
+ * Added a write-up for the various sections, including the **Features** section and its various subsections. [\#148](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/148)
+ * Included a CLI Tutorial for users. [\#148](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/148)
+ * Made cosmetic tweaks to various headings, numberings etc. [\#148](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/148)
+ * Updated Command Summary with all new features [\#143](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/143)
+ * Developer Guide:
+ * Added User Stories and Use Cases for CRUD features for students and tutorial classes. [\#65](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/65)
+ * Added and updated Tutorial Class Management features section. [\#124](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/124)
+ * Updated Architecture diagrams to reflect ClassMATE's architecture. [\#124](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/124)
+ * Updated Class Diagrams for UI, Logic and Model [\#124](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/124)
+ * Created Sequence diagram for `AddClassCommand` [\#124](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/124)
+
+* **Team-Based tasks**:
+ * Managed testing for releases `v1.1` - `v1.4` (4 releases) on GitHub
+ * Conducted manual testing of features based on descriptions provided in the User Guide.
+ * **Bug Fixes**:
+ * Empty ClassCode bugs [\#185](https://github.com/AY2122S1-CS2103T-W15-1/tp/issues/185), Schedule Format Bugs [\#162](https://github.com/AY2122S1-CS2103T-W15-1/tp/issues/162), [\#187](https://github.com/AY2122S1-CS2103T-W15-1/tp/issues/187) and UI whitespace bugs [\#173](https://github.com/AY2122S1-CS2103T-W15-1/tp/issues/173)
+ * PR [\#198](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/198) covers bug fixes and implementation of test cases to check these specific cases (if applicable).
+ * Documentation Bugs
+ * Added summary of follow-up action following the PE-D to each issue raised by reviewers.
+
+* **Review Contributions**
+ * PRs Reviewed with comments: [\#120](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/120), [\#139](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/139), [\#155](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/155)
+
+* **Community Contributions**
+ * Bugs reported in other teams work: [1](https://github.com/AY2122S1-CS2103T-F13-2/tp/issues/153), [2](https://github.com/AY2122S1-CS2103T-F13-2/tp/issues/154)
+ * [Smoke Test CATcher](https://github.com/rushilramesh/ped)
diff --git a/docs/team/vishnusundaresan.md b/docs/team/vishnusundaresan.md
new file mode 100644
index 00000000000..3c5317fb9d6
--- /dev/null
+++ b/docs/team/vishnusundaresan.md
@@ -0,0 +1,69 @@
+---
+layout: page
+title: Vishnu Sundaresan's Project Portfolio Page
+---
+
+### Project: ClassMATE
+
+ClassMATE is a desktop application designed for instructors of the CS2101 Module in NUS to easily store class and student details. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
+
+Given below are my contributions to the project.
+
+* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/#breakdown=true&search=juliussneezer04)
+* **Enhancements Implemented**:
+ * Allowing TutorialClasses to be stored easily in memory as a JSON list
+ * Creating UniqueTutorialClassList.
+ * Modifying JSON file storage structure to accommodate the list of Tutorial Classes.
+ * Modifying all relevant test cases and test case data accordingly.
+* **New Features Implemented**:
+ * Adding Student Marks functionality
+ * Creating Enumeration of Student Marks.
+ * Adding a special list of student marks to each Student.
+ * Allowing addition at end-of-list, deletion at end-of-list, and deletion of all marks in list operations.
+ * Changed 26 files in the process (adding Test Case Classes for each command).
+ * Displaying marks for each student in decreasing order in `viewstu` window.
+ * Challenge was in increasing `viewstu` window size and decorating the marks in order.
+* **Documentation**:
+ * Contributions to User Guide:
+ * Added documentation for the features `save` and `find` [\#74]([Adding extra pictures and changing names. by juliussneezer04 · Pull Request #74 · AY2122S1-CS2103T-W15-1/tp (github.com)](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/74))
+ * Modifying Quick Start in UG [\#139]([Improving User Guide by juliussneezer04 · Pull Request #139 · AY2122S1-CS2103T-W15-1/tp (github.com)](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/139))
+ * Adding screenshots and explanations of icons to UG [\#144](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/144)
+ * Added documentation for student marks commands in UG [\#153](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/153)
+ * UG Bug Fixes [#253](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/253), [#254](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/254)
+ * Developer Guide:
+ * Documentation regarding Student Marks functionality implementation. [\#127](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/127), [\#146](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/146)
+ * Adding Diagrams for Student Marks functionality. [\#127](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/127), [\#133](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/133) (Sequence Diagram Shown in Appendix A)
+ * Adding Use Cases for Student Marks functionality. [\#132](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/132)
+* **Team-based Tasks**:
+ * Set up the GitHub Team organisation and repo
+ * Added master branch protection.
+ * Created Developers' organisation for team.
+ * Managing scheduling & tracking for upcoming releases `v1.1` - `v1.4` (4 releases) on GitHub
+ * Assigning Issues and Tasks to team members in Repo's Projects
+ * Released v1.2, v1.3 and v1.4 JAR releases.
+ * Set up all Repo Projects for each iteration.
+ * Set up and tracked Milestones 1.1, 1.2, 1.3, 1.4
+ * Recorded Demo Videos for ClassMATE Demos.
+* **Review Contributions**:
+ * PRs reviewed (with non-trivial reviews) [\#155]([Update User Guide by GabrielWLM · Pull Request #155 · AY2122S1-CS2103T-W15-1/tp (github.com)](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/155)), [#245](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/245), [#249](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/249)
+
+
+
+#### Appendix A (Contributions to the Developer Guide)
+
+Sequence Diagram added to Developers' Guide:
+
+![AddMarkSequenceDiagram](diagrams/AddMarkSequenceDiagram.png)
+
+Student Marks State Diagram before/after operation `deletelm`:
+
+*Before* :
+
+![StudentMarksState](diagrams/StudentMarksState1.png)
+
+*After* :
+
+![StudentMarksState2](diagrams/StudentMarksState2.png)
+
+
+
diff --git a/docs/team/zhouyirui.md b/docs/team/zhouyirui.md
new file mode 100644
index 00000000000..6d2c5efb568
--- /dev/null
+++ b/docs/team/zhouyirui.md
@@ -0,0 +1,49 @@
+---
+layout: page
+title: Zhou Yirui's Project Portfolio Page
+---
+
+### Project: ClassMATE
+
+ClassMATE is a desktop application designed for instructors of the CS2101 Module in NUS to easily store class and student details. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
+
+Given below are my contributions to the project.
+
+* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2122s1.github.io/tp-dashboard/)
+
+* **Enhancements Implemented**
+ * Added a new parameter ClassCode for Students, Tutorial Group and Tutorial Classes
+ * PR [\#113](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/113), PR [\#131](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/131)
+ * This parameter is refers to the ClassCode of the Tutorial Class that a Student belongs to. It contains a default
+ value that when assigned to a Student indicates the Student does not have a class.
+ * Updated more than 25 files in the process of implementing ClassCode. Includes changing every instance of a Student and Tutorial Class (which used ClassCode as a String initially).
+ * Changed the implementation of ClassCode from using INDEX to a parameter when a Student is first added.
+ * Challenge was when I added validation for ClassCode. This resulted in me changing 17 test files in the tedious debugging process,
+ and to correct the previous accepted format of ClassCode in test cases. I also added `TypicalClassmate` to allow verification of ClassCode in tests.
+ * The process of implementing ClassCode required in depth knowledge of the `model`, how data for test cases are created, and used for testing for classes.
+ * Adding Student to Tutorial Group
+ * PR [\#149](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/149)
+ * Allows Student to be assigned to a Tutorial Group within their Tutorial Class
+ * Referenced the implementation of `Tags` when adding `Tutorial Group` as parameter of a Student. One difference in implementation
+ was that `Tutorial Groups` are accumulated by default. I also made changes to UI to allow Tutorial Groups to be shown in a Student's
+ profile card.
+ * Added verification of `Tutorial Groups` to ensure Student is only added to at most 1 Tutorial Group of each Group Type.
+ * Deleting Student from Tutorial Group
+ * PR [\#150](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/150)
+ * Allows Student to be removed from a Tutorial Group within their Tutorial Class
+ * Referenced the implementation of `Tags` when adding `Tutorial Group` as parameter of a Student. One difference in implementation
+ was that `Tutorial Groups` can be deleted selectively.
+
+* **Documentation**:
+ * User Guide:
+ * Added documentations for the features `addsg`,`deleteg` and `viewg` [\#66](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/66)
+ * Added and updated documentations for the features `addsg` and `deletesg` [\#154](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/154)
+ * Added an overview of the structure of User Guide to introduction.
+ * README:
+ * Added a mockup for classMATE [\#70](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/70)
+ * Added details of the project and Continuous Integration badge
+ * Developers Guide:
+ * Added documentations for the features `classCode`. PR: [\#134](https://github.com/AY2122S1-CS2103T-W15-1/tp/pull/134)
+ * Added documentations for the features `addsg` and `deletesg`.
+ * Added Use case for Adding Student to Tutorial Group.
+
diff --git a/docs/tutorials/AddRemark.md b/docs/tutorials/AddRemark.md
index 8919d8eaa17..01e1483b61e 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 ClassMATE application to add optional remarks to people in their ClassMATE and edit it if required. The command should have the following format:
`remark INDEX r/REMARK` (e.g., `remark 2 r/Likes baseball`)
@@ -28,7 +28,7 @@ package seedu.address.logic.commands;
import seedu.address.model.Model;
/**
- * Changes the remark of an existing person in the address book.
+ * Changes the remark of an existing student in the ClassMATE.
*/
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 `ClassmateParser#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"
@@ -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);
@@ -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 `ClassmateParser` to use our new `RemarkCommandParser`!
@@ -225,11 +225,11 @@ 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.address.model.student`. 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 +240,11 @@ 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.address.ui.PersonCard`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-0c6b6abcfac8c205e075294f25e851fe).
+Simply add the following to [`seedu.address.ui.StudentCard`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-0c6b6abcfac8c205e075294f25e851fe).
-**`PersonCard.java`:**
+**`StudentCard.java`:**
``` java
@FXML
@@ -254,9 +254,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 +266,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,13 +289,13 @@ 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`!
+ClassMATE 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.
-:exclamation: You must delete AddressBook’s storage file located at `/data/addressbook.json` before running it! Not doing so will cause AddressBook to default to an empty address book!
+:exclamation: You must delete ClassMATE’s storage file located at `/data/classmate.json` before running it! Not doing so will cause ClassMATE to default to an empty ClassMATE!
@@ -304,16 +304,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 +325,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);
+ throw new CommandException(Messages.MESSAGE_INVALID_STUDENT_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_STUDENTS);
- 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);
}
```
@@ -398,4 +398,4 @@ You should end up with a test that looks something like [this](https://github.co
## Conclusion
-This concludes the tutorial for adding a new `Command` to AddressBook.
+This concludes the tutorial for adding a new `Command` to ClassMATE.
diff --git a/docs/tutorials/RemovingFields.md b/docs/tutorials/RemovingFields.md
index f29169bc924..c5cbf50ff86 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`:**
+**`invalidStudentClassmate.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..8fc9c6097c6 100644
--- a/docs/tutorials/TracingCode.md
+++ b/docs/tutorials/TracingCode.md
@@ -120,14 +120,14 @@ 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 = classmateParser.parseCommand(commandText);
//Executes the Command and stores the result
commandResult = command.execute(model);
try {
//We can deduce that the previous line of code modifies model in some way
// since it's being stored here.
- storage.saveAddressBook(model.getAddressBook());
+ storage.saveClassmate(model.getClassmate());
} catch (IOException ioe) {
throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe);
}
@@ -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 `ClassmateParser#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)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
+ Student studentToEdit = lastShownList.get(index.getZeroBased());
+ Student editedStudent = createEditedStudent(studentToEdit, editStudentDescriptor);
+ if (!studentToEdit.isSameStudent(editedStudent) && model.hasStudent(editedStudent)) {
+ throw new CommandException(MESSAGE_DUPLICATE_STUDENT);
}
- 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_STUDENTS);
+ return new CommandResult(String.format(MESSAGE_EDIT_STUDENT_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)
@@ -217,29 +217,29 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
1. Similar to before, you can step over/into statements in the `LogicManager#execute()` method to examine how the control is transferred to the `Storage` component and what happens inside that component.
-
:bulb: **Intellij Tip:** When trying to step into a statement such as `storage.saveAddressBook(model.getAddressBook())` which contains multiple method calls, Intellij will let you choose (by clicking) which one you want to step into.
+
:bulb: **Intellij Tip:** When trying to step into a statement such as `storage.saveClassmate(model.getClassmate())` which contains multiple method calls, Intellij will let you choose (by clicking) which one you want to step into.
-1. As you step through the code inside the `Storage` component, you will eventually arrive at the `JsonAddressBook#saveAddressBook()` method which calls the `JsonSerializableAddressBook` constructor, to create an object that can be _serialized_ (i.e., stored in storage medium) in JSON format. That constructor is given below (with added line breaks for easier readability):
+1. As you step through the code inside the `Storage` component, you will eventually arrive at the `JsonClassmateStorage#saveClassmate()` method which calls the `JsonSerializableStudent` constructor, to create an object that can be _serialized_ (i.e., stored in storage medium) in JSON format. That constructor is given below (with added line breaks for easier readability):
- **`JsonSerializableAddressBook` constructor:**
+ **`JsonSerializableStudent` constructor:**
``` java
/**
- * Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use.
+ * Converts a given {@code ReadOnlyClassmate} into this class for Jackson use.
*
* @param source future changes to this will not affect the created
- * {@code JsonSerializableAddressBook}.
+ * {@code JsonSerializableStudent}.
*/
- public JsonSerializableAddressBook(ReadOnlyAddressBook source) {
- persons.addAll(
- source.getPersonList()
+ public JsonSerializableStudent(ReadOnlyClassmate source) {
+ 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 `JsonSerializableStudent`.
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.
@@ -292,10 +292,10 @@ Here are some quick questions you can try to answer based on your execution path
2. Allow `delete` to remove more than one index at a time
- 3. Save the address book in the CSV format instead
+ 3. Save the ClassMATE in the CSV format instead
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
+ 6. Add a new entity to the ClassMATE
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java
index 4133aaa0151..9f4cb5da0fe 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/seedu/address/MainApp.java
@@ -15,15 +15,15 @@
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.Classmate;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ReadOnlyClassmate;
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.ClassmateStorage;
+import seedu.address.storage.JsonClassmateStorage;
import seedu.address.storage.JsonUserPrefsStorage;
import seedu.address.storage.Storage;
import seedu.address.storage.StorageManager;
@@ -36,7 +36,7 @@
*/
public class MainApp extends Application {
- public static final Version VERSION = new Version(0, 2, 0, true);
+ public static final Version VERSION = new Version(1, 4, 0, true);
private static final Logger logger = LogsCenter.getLogger(MainApp.class);
@@ -48,7 +48,7 @@ public class MainApp extends Application {
@Override
public void init() throws Exception {
- logger.info("=============================[ Initializing AddressBook ]===========================");
+ logger.info("=============================[ Initializing Classmate ]===========================");
super.init();
AppParameters appParameters = AppParameters.parse(getParameters());
@@ -56,8 +56,8 @@ public void init() throws Exception {
UserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(config.getUserPrefsFilePath());
UserPrefs userPrefs = initPrefs(userPrefsStorage);
- AddressBookStorage addressBookStorage = new JsonAddressBookStorage(userPrefs.getAddressBookFilePath());
- storage = new StorageManager(addressBookStorage, userPrefsStorage);
+ ClassmateStorage classmateStorage = new JsonClassmateStorage(userPrefs.getClassmateFilePath());
+ storage = new StorageManager(classmateStorage, userPrefsStorage);
initLogging(config);
@@ -69,25 +69,25 @@ public void init() throws Exception {
}
/**
- * Returns a {@code ModelManager} with the data from {@code storage}'s address book and {@code userPrefs}.
- * The data from the sample address book will be used instead if {@code storage}'s address book is not found,
- * or an empty address book will be used instead if errors occur when reading {@code storage}'s address book.
+ * Returns a {@code ModelManager} with the data from {@code storage}'s ClassMATE and {@code userPrefs}.
+ * The data from the sample ClassMATE will be used instead if {@code storage}'s ClassMATE is not found,
+ * or an empty ClassMATE will be used instead if errors occur when reading {@code storage}'s ClassMATE.
*/
private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
- Optional addressBookOptional;
- ReadOnlyAddressBook initialData;
+ Optional classmateOptional;
+ ReadOnlyClassmate initialData;
try {
- addressBookOptional = storage.readAddressBook();
- if (!addressBookOptional.isPresent()) {
- logger.info("Data file not found. Will be starting with a sample AddressBook");
+ classmateOptional = storage.readClassmate();
+ if (!classmateOptional.isPresent()) {
+ logger.info("Data file not found. Will be starting with a sample Classmate");
}
- initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook);
+ initialData = classmateOptional.orElseGet(SampleDataUtil::getSampleClassmate);
} 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 Classmate");
+ initialData = new Classmate();
} 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 Classmate");
+ initialData = new Classmate();
}
return new ModelManager(initialData, userPrefs);
@@ -151,7 +151,7 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
+ "Using default user prefs");
initializedPrefs = new UserPrefs();
} catch (IOException e) {
- logger.warning("Problem while reading from the file. Will be starting with an empty AddressBook");
+ logger.warning("Problem while reading from the file. Will be starting with an empty Classmate");
initializedPrefs = new UserPrefs();
}
@@ -167,13 +167,13 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
@Override
public void start(Stage primaryStage) {
- logger.info("Starting AddressBook " + MainApp.VERSION);
+ logger.info("Starting Classmate " + MainApp.VERSION);
ui.start(primaryStage);
}
@Override
public void stop() {
- logger.info("============================ [ Stopping Address Book ] =============================");
+ logger.info("============================ [ Stopping ClassMATE ] =============================");
try {
storage.saveUserPrefs(model.getUserPrefs());
} catch (IOException e) {
diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/seedu/address/commons/core/LogsCenter.java
index 431e7185e76..f6e05a2c477 100644
--- a/src/main/java/seedu/address/commons/core/LogsCenter.java
+++ b/src/main/java/seedu/address/commons/core/LogsCenter.java
@@ -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 = "classmate.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/address/commons/core/Messages.java b/src/main/java/seedu/address/commons/core/Messages.java
index 1deb3a1e469..a06cf433422 100644
--- a/src/main/java/seedu/address/commons/core/Messages.java
+++ b/src/main/java/seedu/address/commons/core/Messages.java
@@ -7,7 +7,14 @@ 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!";
-
+ public static final String MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX =
+ "The student index provided is missing/invalid \n";
+ public static final String MESSAGE_INVALID_CLASS_DISPLAYED_INDEX =
+ "The class index provided is missing/invalid \n";
+ public static final String MESSAGE_STUDENTS_LISTED_OVERVIEW = "%1$d students listed!";
+ public static final String MESSAGE_TUTORIAL_CLASSES_LISTED_OVERVIEW = "%1$d tutorial classes listed!";
+ public static final String MESSAGE_TUTORIAL_GROUP_LISTED_OVERVIEW = "%1$d students from tutorial group listed!";
+ public static final String MESSAGE_CLASS_DOES_NOT_EXIST = "This class code does not exist in ClassMATE";
+ public static final String MESSAGE_GROUP_DOES_NOT_EXIST = "This group does not exist in ClassMATE";
+ public static final String MESSAGE_DUPLICATE_STUDENT = "This student already exists in ClassMATE";
}
diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java
index 92cd8fa605a..0a452664712 100644
--- a/src/main/java/seedu/address/logic/Logic.java
+++ b/src/main/java/seedu/address/logic/Logic.java
@@ -7,8 +7,9 @@
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;
+import seedu.address.model.ReadOnlyClassmate;
+import seedu.address.model.student.Student;
+import seedu.address.model.tutorialclass.TutorialClass;
/**
* API of the Logic component
@@ -24,19 +25,22 @@ public interface Logic {
CommandResult execute(String commandText) throws CommandException, ParseException;
/**
- * Returns the AddressBook.
+ * Returns the Classmate.
*
- * @see seedu.address.model.Model#getAddressBook()
+ * @see seedu.address.model.Model#getClassmate()
*/
- ReadOnlyAddressBook getAddressBook();
+ ReadOnlyClassmate getClassmate();
- /** Returns an unmodifiable view of the filtered list of persons */
- ObservableList getFilteredPersonList();
+ /** Returns an unmodifiable view of the filtered list of students */
+ ObservableList getFilteredStudentList();
+
+ /** Returns an unmodifiable view of the filtered list of Tutprial Classes */
+ ObservableList getFilteredTutorialClassList();
/**
- * Returns the user prefs' address book file path.
+ * Returns the user prefs' ClassMATE file path.
*/
- Path getAddressBookFilePath();
+ Path getClassmateFilePath();
/**
* Returns the user prefs' GUI settings.
diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java
index 9d9c6d15bdc..b9d930fb799 100644
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ b/src/main/java/seedu/address/logic/LogicManager.java
@@ -10,11 +10,12 @@
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.ClassmateParser;
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.model.ReadOnlyClassmate;
+import seedu.address.model.student.Student;
+import seedu.address.model.tutorialclass.TutorialClass;
import seedu.address.storage.Storage;
/**
@@ -26,7 +27,7 @@ public class LogicManager implements Logic {
private final Model model;
private final Storage storage;
- private final AddressBookParser addressBookParser;
+ private final ClassmateParser classmateParser;
/**
* Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}.
@@ -34,7 +35,7 @@ public class LogicManager implements Logic {
public LogicManager(Model model, Storage storage) {
this.model = model;
this.storage = storage;
- addressBookParser = new AddressBookParser();
+ classmateParser = new ClassmateParser();
}
@Override
@@ -42,11 +43,11 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
logger.info("----------------[USER COMMAND][" + commandText + "]");
CommandResult commandResult;
- Command command = addressBookParser.parseCommand(commandText);
+ Command command = classmateParser.parseCommand(commandText);
commandResult = command.execute(model);
try {
- storage.saveAddressBook(model.getAddressBook());
+ storage.saveClassmate(model.getClassmate());
} catch (IOException ioe) {
throw new CommandException(FILE_OPS_ERROR_MESSAGE + ioe, ioe);
}
@@ -55,18 +56,23 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
}
@Override
- public ReadOnlyAddressBook getAddressBook() {
- return model.getAddressBook();
+ public ReadOnlyClassmate getClassmate() {
+ return model.getClassmate();
}
@Override
- public ObservableList getFilteredPersonList() {
- return model.getFilteredPersonList();
+ public ObservableList getFilteredStudentList() {
+ return model.getFilteredStudentList();
}
@Override
- public Path getAddressBookFilePath() {
- return model.getAddressBookFilePath();
+ public ObservableList getFilteredTutorialClassList() {
+ return model.getFilteredTutorialClassList();
+ }
+
+ @Override
+ public Path getClassmateFilePath() {
+ return model.getClassmateFilePath();
}
@Override
diff --git a/src/main/java/seedu/address/logic/commands/AddClassCommand.java b/src/main/java/seedu/address/logic/commands/AddClassCommand.java
new file mode 100644
index 00000000000..3963ce99e6d
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AddClassCommand.java
@@ -0,0 +1,56 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SCHEDULE;
+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.tutorialclass.TutorialClass;
+
+public class AddClassCommand extends Command {
+
+ public static final String COMMAND_WORD = "addc";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a class to Classmate. "
+ + "Parameters: "
+ + PREFIX_CLASSCODE + "CLASSCODE "
+ + PREFIX_SCHEDULE + "SCHEDULE "
+ + "[" + PREFIX_TAG + "TAG]...\n"
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_CLASSCODE + "G06 "
+ + PREFIX_SCHEDULE + "Tuesday 12:00pm to 2:00pm, Friday 12:00pm to 2:00pm "
+ + PREFIX_TAG + "BestClass";
+
+ public static final String MESSAGE_SUCCESS = "New class added: %1$s";
+ public static final String MESSAGE_DUPLICATE_CLASS = "This class already exists in Classmate";
+
+ private final TutorialClass toAdd;
+
+ /**
+ * Creates an AddClassCommand to add the specified {@code Student}
+ */
+ public AddClassCommand(TutorialClass tutorialClass) {
+ requireNonNull(tutorialClass);
+ toAdd = tutorialClass;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ if (model.hasTutorialClass(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_CLASS);
+ }
+
+ model.addTutorialClass(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 AddClassCommand // instanceof handles nulls
+ && toAdd.equals(((AddClassCommand) other).toAdd));
+ }
+}
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/AddGroupCommand.java b/src/main/java/seedu/address/logic/commands/AddGroupCommand.java
new file mode 100644
index 00000000000..3a650209394
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AddGroupCommand.java
@@ -0,0 +1,73 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_CLASS_DOES_NOT_EXIST;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GROUPNUMBER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TYPE;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.tutorialclass.TutorialClass;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Adds a tutorial group to an existing tutorial class in ClassMATE.
+ */
+public class AddGroupCommand extends Command {
+ public static final String COMMAND_WORD = "addcg";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a group to a class to Classmate. "
+ + "Parameters: "
+ + PREFIX_GROUPNUMBER + "GROUPNUMBER "
+ + PREFIX_CLASSCODE + "CLASSCODE "
+ + PREFIX_TYPE + "TYPE "
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_GROUPNUMBER + "1 "
+ + PREFIX_CLASSCODE + "G06 "
+ + PREFIX_TYPE + "OP1 ";
+
+ public static final String MESSAGE_SUCCESS = "New group added: %1$s";
+ public static final String MESSAGE_DUPLICATE_GROUP = "This group already exists in Classmate";
+
+ private final TutorialGroup toAdd;
+ private final TutorialClass toAddTutorialClass;
+
+ /**
+ * Creates an AddGroupCommand to add the specified {@code TutorialGroup}
+ */
+ public AddGroupCommand(TutorialGroup tutorialGroup) {
+ requireNonNull(tutorialGroup);
+ toAdd = tutorialGroup;
+ // new class with the same class code created to check whether it already exists in ClassMATE
+ toAddTutorialClass = TutorialClass.createTestTutorialClass(toAdd.getClassCode());
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ // check if tutorial class already exists in ClassMATE
+ if (!model.hasTutorialClass(toAddTutorialClass)) {
+ throw new CommandException(MESSAGE_CLASS_DOES_NOT_EXIST);
+ }
+
+ // check if tutorial group already exists in ClassMATE
+ if (model.hasTutorialGroup(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_GROUP);
+ }
+
+ model.addTutorialGroup(toAdd);
+
+ // rearrange tutorial groups in order after adding
+ model.sortTutorialGroups();
+ return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof AddGroupCommand // instanceof handles nulls
+ && toAdd.equals(((AddGroupCommand) other).toAdd));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/AddLastMarkCommand.java b/src/main/java/seedu/address/logic/commands/AddLastMarkCommand.java
new file mode 100644
index 00000000000..6a4f44f7167
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AddLastMarkCommand.java
@@ -0,0 +1,103 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_DUPLICATE_STUDENT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_MARK;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_STUDENTS;
+
+import java.util.ArrayList;
+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.student.Student;
+import seedu.address.model.student.StudentMark;
+
+/**
+ * Edits the details of an existing student in the ClassMATE.
+ */
+public class AddLastMarkCommand extends Command {
+
+ public static final String COMMAND_WORD = "addlm";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds Mark to Student's Weekly Marks\n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_MARK + "LOW";
+
+ public static final String MESSAGE_ADD_MARK_STUDENT_SUCCESS = "Added Mark to Student: %1$s";
+ public static final String MESSAGE_NOT_EDITED = "Mark to add must be provided.";
+
+ private final Index index;
+ private final StudentMark mark;
+
+ /**
+ * @param index of the student in the filtered student list to add last mark.
+ * @param studentMark marks to add to Student.
+ */
+ public AddLastMarkCommand(Index index, StudentMark studentMark) {
+ requireNonNull(index);
+ requireNonNull(studentMark);
+
+ this.index = index;
+ this.mark = studentMark;
+ }
+
+ @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());
+ Student editedStudent = addStudentMark(studentToEdit, mark);
+
+ if (!studentToEdit.isSameStudent(editedStudent) && model.hasStudent(editedStudent)) {
+ throw new CommandException(MESSAGE_DUPLICATE_STUDENT);
+ }
+
+ model.setStudent(studentToEdit, editedStudent);
+ model.updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
+ return new CommandResult(String.format(MESSAGE_ADD_MARK_STUDENT_SUCCESS, editedStudent));
+ }
+
+ /**
+ * Creates and returns a {@code Student} with the {@code StudentMark} added.
+ */
+ private static Student addStudentMark(Student studentToEdit, StudentMark mark) {
+ assert studentToEdit != null;
+ List updatedMarks = new ArrayList<>(studentToEdit.getMarks());
+ updatedMarks.add(mark);
+ return new Student(
+ studentToEdit.getName(),
+ studentToEdit.getPhone(),
+ studentToEdit.getEmail(),
+ studentToEdit.getAddress(),
+ studentToEdit.getClassCode(),
+ studentToEdit.getTags(),
+ updatedMarks,
+ studentToEdit.getTutorialGroups());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof AddLastMarkCommand)) {
+ return false;
+ }
+
+ // state check
+ AddLastMarkCommand e = (AddLastMarkCommand) other;
+ return index.equals(e.index)
+ && mark.equals(e.mark);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/AddStudentCommand.java b/src/main/java/seedu/address/logic/commands/AddStudentCommand.java
new file mode 100644
index 00000000000..03029e46098
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AddStudentCommand.java
@@ -0,0 +1,85 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_CLASS_DOES_NOT_EXIST;
+import static seedu.address.commons.core.Messages.MESSAGE_DUPLICATE_STUDENT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
+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.HashSet;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.student.Student;
+import seedu.address.model.tag.Tag;
+import seedu.address.model.tutorialclass.Schedule;
+import seedu.address.model.tutorialclass.TutorialClass;
+
+
+/**
+ * Adds a student to the ClassMATE.
+ */
+public class AddStudentCommand extends Command {
+
+ public static final String COMMAND_WORD = "addstu";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a student to the ClassMATE. "
+ + "Parameters: "
+ + PREFIX_NAME + "NAME "
+ + PREFIX_PHONE + "PHONE "
+ + PREFIX_EMAIL + "EMAIL "
+ + PREFIX_ADDRESS + "ADDRESS "
+ + PREFIX_CLASSCODE + "CLASSCODE "
+ + "[" + 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_CLASSCODE + "G08 "
+ + PREFIX_TAG + "friends "
+ + PREFIX_TAG + "owesMoney";
+
+ public static final String MESSAGE_SUCCESS = "New student added: %1$s";
+
+ private final Student toAdd;
+
+ /**
+ * Creates an AddCommand to add the specified {@code Student}
+ */
+ public AddStudentCommand(Student student) {
+ requireNonNull(student);
+ toAdd = student;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (model.hasStudent(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_STUDENT);
+ }
+
+ // Check tutorial class has been created before the classCode is assigned.
+ TutorialClass toCheckTutorialClass = new TutorialClass(toAdd.getClassCode(),
+ new Schedule("Tues 12:00pm to 2:00pm, Fri 12:00pm to 2:00pm"), new HashSet());
+
+ if (!model.hasTutorialClass(toCheckTutorialClass)) {
+ throw new CommandException(MESSAGE_CLASS_DOES_NOT_EXIST);
+ }
+
+ model.addStudent(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 AddStudentCommand // instanceof handles nulls
+ && toAdd.equals(((AddStudentCommand) other).toAdd));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/AddStudentToGroupCommand.java b/src/main/java/seedu/address/logic/commands/AddStudentToGroupCommand.java
new file mode 100644
index 00000000000..a2f9294ca5b
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AddStudentToGroupCommand.java
@@ -0,0 +1,134 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_CLASS_DOES_NOT_EXIST;
+import static seedu.address.commons.core.Messages.MESSAGE_GROUP_DOES_NOT_EXIST;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GROUPNUMBER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TYPE;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_STUDENTS;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+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.student.Student;
+import seedu.address.model.tutorialclass.TutorialClass;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+
+public class AddStudentToGroupCommand extends Command {
+ public static final String COMMAND_WORD = "addsg";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a student to a group to Classmate "
+ + "by the index number used in the last person listing.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + PREFIX_CLASSCODE + "CLASS_CODE "
+ + PREFIX_TYPE + "GROUP_TYPE "
+ + PREFIX_GROUPNUMBER + "GROUP_NUMBER "
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_GROUPNUMBER + "1 "
+ + PREFIX_CLASSCODE + "G06 "
+ + PREFIX_TYPE + "OP1 ";
+
+ public static final String MESSAGE_SUCCESS = "Index: %1$d added to Group: %2$s";
+ public static final String MESSAGE_DUPLICATE_GROUP = "The student has already been added to an %1$s group";
+ public static final String MESSAGE_NOT_SAME_CLASS = "The student and the tutorial group "
+ + "do not belong to the same tutorial class";
+
+ private final Index index;
+ private final TutorialGroup toAddTutorialGroup;
+
+ /**
+ * Creates an AddClassCommand to add the specified {@code Student}
+ */
+ public AddStudentToGroupCommand(Index index, TutorialGroup tutorialGroup) {
+ requireAllNonNull(index, tutorialGroup);
+ this.index = index;
+ this.toAddTutorialGroup = tutorialGroup;
+ // new class with the same class code created to check whether it already exists in ClassMATE
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredStudentList();
+
+ // Check if index is within range of student list
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX);
+ }
+
+ // check if tutorial class already exists in ClassMATE
+ if (!model.hasTutorialClass(TutorialClass.createTestTutorialClass(toAddTutorialGroup.getClassCode()))) {
+ throw new CommandException(MESSAGE_CLASS_DOES_NOT_EXIST);
+ }
+
+ // check if tutorial group already exists in ClassMATE
+ if (!model.hasTutorialGroup(toAddTutorialGroup)) {
+ throw new CommandException(MESSAGE_GROUP_DOES_NOT_EXIST);
+ }
+
+ Student studentToEdit = lastShownList.get(index.getZeroBased());
+
+ // check if Tutorial Group and Student belong to the same Tutorial Class
+ if (!isSameClass(studentToEdit, toAddTutorialGroup)) {
+ throw new CommandException(MESSAGE_NOT_SAME_CLASS);
+ }
+
+ Student editedStudent = addTutorialGroup(studentToEdit, toAddTutorialGroup);
+
+ model.setStudent(studentToEdit, editedStudent);
+ model.updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
+
+ return new CommandResult(String.format(MESSAGE_SUCCESS, index.getOneBased(), toAddTutorialGroup));
+ }
+
+ public boolean isSameClass(Student student, TutorialGroup tutorialGroup) {
+ return student.getClassCode().equals(tutorialGroup.getClassCode());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof AddStudentToGroupCommand)) {
+ return false;
+ }
+
+ // state check
+ return index.equals(((AddStudentToGroupCommand) other).index)
+ && toAddTutorialGroup.equals(((AddStudentToGroupCommand) other).toAddTutorialGroup);
+ }
+ /**
+ * Creates and returns a {@code Student} with the {@code TutorialGroup} added.
+ */
+ private static Student addTutorialGroup(Student studentToEdit, TutorialGroup group) throws CommandException {
+ assert studentToEdit != null;
+ if (studentToEdit.hasTutorialGroupType(group.getGroupType())) {
+ throw new CommandException(String.format(MESSAGE_DUPLICATE_GROUP, group.getGroupType()));
+ }
+
+ Set updatedTutorialGroups = new HashSet<>(studentToEdit.getTutorialGroups());
+ updatedTutorialGroups.add(group);
+ return new Student(
+ studentToEdit.getName(),
+ studentToEdit.getPhone(),
+ studentToEdit.getEmail(),
+ studentToEdit.getAddress(),
+ studentToEdit.getClassCode(),
+ studentToEdit.getTags(),
+ studentToEdit.getMarks(),
+ updatedTutorialGroups);
+
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java
index 9c86b1fa6e4..0e51dece5fa 100644
--- a/src/main/java/seedu/address/logic/commands/ClearCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ClearCommand.java
@@ -2,22 +2,22 @@
import static java.util.Objects.requireNonNull;
-import seedu.address.model.AddressBook;
+import seedu.address.model.Classmate;
import seedu.address.model.Model;
/**
- * Clears the address book.
+ * Clears the ClassMATE.
*/
public class ClearCommand extends Command {
public static final String COMMAND_WORD = "clear";
- public static final String MESSAGE_SUCCESS = "Address book has been cleared!";
+ public static final String MESSAGE_SUCCESS = "ClassMATE has been cleared!";
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
- model.setAddressBook(new AddressBook());
+ model.setClassmate(new Classmate());
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
index 92f900b7916..5046eff8d85 100644
--- a/src/main/java/seedu/address/logic/commands/CommandResult.java
+++ b/src/main/java/seedu/address/logic/commands/CommandResult.java
@@ -4,6 +4,8 @@
import java.util.Objects;
+import seedu.address.model.student.Student;
+
/**
* Represents the result of a command execution.
*/
@@ -14,16 +16,24 @@ public class CommandResult {
/** Help information should be shown to the user. */
private final boolean showHelp;
+ /** Student information should be shown to the user. */
+ private final boolean showStudent;
+
+ /** Student to be shown to the user. */
+ private final Student student;
+
/** The application should exit. */
private final boolean exit;
/**
* Constructs a {@code CommandResult} with the specified fields.
*/
- public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
+ public CommandResult(String feedbackToUser, boolean showHelp, boolean showStudent, boolean exit, Student student) {
this.feedbackToUser = requireNonNull(feedbackToUser);
this.showHelp = showHelp;
+ this.showStudent = showStudent;
this.exit = exit;
+ this.student = student;
}
/**
@@ -31,7 +41,8 @@ public CommandResult(String feedbackToUser, boolean showHelp, boolean exit) {
* and other fields set to their default value.
*/
public CommandResult(String feedbackToUser) {
- this(feedbackToUser, false, false);
+ this(feedbackToUser, false, false, false,
+ null);
}
public String getFeedbackToUser() {
@@ -42,6 +53,14 @@ public boolean isShowHelp() {
return showHelp;
}
+ public boolean isShowStudent() {
+ return showStudent;
+ }
+
+ public Student getStudent() {
+ return student;
+ }
+
public boolean isExit() {
return exit;
}
@@ -58,14 +77,17 @@ public boolean equals(Object other) {
}
CommandResult otherCommandResult = (CommandResult) other;
+
+ // no need to check for student field, since feedbackToUser contain student details in a string representation
return feedbackToUser.equals(otherCommandResult.feedbackToUser)
&& showHelp == otherCommandResult.showHelp
+ && showStudent == otherCommandResult.showStudent
&& exit == otherCommandResult.exit;
}
@Override
public int hashCode() {
- return Objects.hash(feedbackToUser, showHelp, exit);
+ return Objects.hash(feedbackToUser, showHelp, showStudent, exit, student);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteAllMarkCommand.java b/src/main/java/seedu/address/logic/commands/DeleteAllMarkCommand.java
new file mode 100644
index 00000000000..43c7d56ca80
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteAllMarkCommand.java
@@ -0,0 +1,99 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_DUPLICATE_STUDENT;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_STUDENTS;
+
+import java.util.ArrayList;
+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.student.Student;
+import seedu.address.model.student.StudentMark;
+
+/**
+ * Deletes all marks of an existing student in the ClassMATE.
+ */
+public class DeleteAllMarkCommand extends Command {
+
+ public static final String COMMAND_WORD = "deleteam";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Deletes All of Student's Mark\n"
+ + "Example: " + COMMAND_WORD + " 1 ";
+
+ public static final String MESSAGE_DELETE_ALL_MARK_STUDENT_SUCCESS = "Deleted All Marks of Student: %1$s";
+ public static final String MESSAGE_NO_MARKS = "No Marks to Delete!";
+
+ private final Index index;
+
+ /**
+ * @param index of the student in the filtered student list to delete marks of.
+ */
+ public DeleteAllMarkCommand(Index index) {
+ requireNonNull(index);
+
+ this.index = index;
+ }
+
+ @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());
+ Student editedStudent = deleteAllStudentMark(studentToEdit);
+
+ if (!studentToEdit.isSameStudent(editedStudent) && model.hasStudent(editedStudent)) {
+ throw new CommandException(MESSAGE_DUPLICATE_STUDENT);
+ }
+
+ model.setStudent(studentToEdit, editedStudent);
+ model.updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
+ return new CommandResult(String.format(MESSAGE_DELETE_ALL_MARK_STUDENT_SUCCESS, editedStudent));
+ }
+
+ /**
+ * Creates and returns a {@code Student} with all the marks deleted.
+ */
+ private static Student deleteAllStudentMark(Student studentToEdit) throws CommandException {
+ assert studentToEdit != null;
+ if (studentToEdit.getMarks().isEmpty()) {
+ throw new CommandException(MESSAGE_NO_MARKS);
+ }
+ List updatedMarks = new ArrayList<>();
+ return new Student(
+ studentToEdit.getName(),
+ studentToEdit.getPhone(),
+ studentToEdit.getEmail(),
+ studentToEdit.getAddress(),
+ studentToEdit.getClassCode(),
+ studentToEdit.getTags(),
+ updatedMarks,
+ studentToEdit.getTutorialGroups());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof DeleteAllMarkCommand)) {
+ return false;
+ }
+
+ // state check
+ DeleteAllMarkCommand e = (DeleteAllMarkCommand) other;
+ return index.equals(e.index);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteClassCommand.java b/src/main/java/seedu/address/logic/commands/DeleteClassCommand.java
new file mode 100644
index 00000000000..de5771765d3
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteClassCommand.java
@@ -0,0 +1,94 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+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.student.Address;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.EmptyClassCode;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Phone;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.StudentMark;
+import seedu.address.model.tag.Tag;
+import seedu.address.model.tutorialclass.TutorialClass;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+public class DeleteClassCommand extends Command {
+
+ public static final String COMMAND_WORD = "deletec";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the class identified by the index number used in the displayed class list.\n"
+ + "Parameters: INDEX (must be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ public static final String MESSAGE_DELETE_CLASS_SUCCESS = "Deleted Class: %1$s";
+
+ private final Index targetIndex;
+
+ /**
+ * Constructor for DeleteClassCommand
+ *
+ * @param targetIndex Index to be deleted.
+ */
+ public DeleteClassCommand(Index targetIndex) {
+ requireNonNull(targetIndex);
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredTutorialClassList();
+ List studentList = model.getUnfilteredStudentList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_CLASS_DISPLAYED_INDEX);
+ }
+
+ TutorialClass classToDelete = lastShownList.get(targetIndex.getZeroBased());
+ model.deleteTutorialClass(classToDelete);
+ List newStudentList = studentList.stream()
+ .map(s -> removeStudentFromClass(s, classToDelete.getClassCode()))
+ .collect(Collectors.toList());
+ model.updateUnfilteredStudentList(newStudentList);
+
+ return new CommandResult(String.format(MESSAGE_DELETE_CLASS_SUCCESS, classToDelete));
+ }
+
+ /**
+ * Creates a new {@code Student} with empty class code
+ */
+ public static Student removeStudentFromClass(Student student, ClassCode toDelete) {
+ ClassCode currClass = student.getClassCode();
+ if (currClass.equals(toDelete)) {
+ Name name = student.getName();
+ Phone phone = student.getPhone();
+ Email email = student.getEmail();
+ Address address = student.getAddress();
+ ClassCode classCode = new EmptyClassCode();
+ Set tags = student.getTags();
+ List marks = student.getMarks();
+ Set tutorialGroups = new HashSet<>();
+ return new Student(name, phone, email, address, classCode, tags, marks, tutorialGroups);
+ }
+ return student;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this
+ || (other instanceof DeleteClassCommand
+ && targetIndex.equals(((DeleteClassCommand) other).targetIndex));
+ }
+}
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/DeleteGroupCommand.java b/src/main/java/seedu/address/logic/commands/DeleteGroupCommand.java
new file mode 100644
index 00000000000..1bb888fb0e0
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteGroupCommand.java
@@ -0,0 +1,81 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_CLASS_DOES_NOT_EXIST;
+import static seedu.address.commons.core.Messages.MESSAGE_GROUP_DOES_NOT_EXIST;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GROUPNUMBER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TYPE;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.tutorialclass.TutorialClass;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Deletes a tutorial group from an existing tutorial class in ClassMATE.
+ */
+public class DeleteGroupCommand extends Command {
+
+ public static final String COMMAND_WORD = "deletecg";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the group identified by class code, group number and type used in the displayed class list.\n"
+ + "Parameters: "
+ + PREFIX_CLASSCODE + "CLASS_CODE "
+ + PREFIX_TYPE + "GROUP_TYPE "
+ + PREFIX_GROUPNUMBER + "GROUP_NUMBER "
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_GROUPNUMBER + "1 "
+ + PREFIX_CLASSCODE + "G06 "
+ + PREFIX_TYPE + "OP1 ";
+
+ public static final String MESSAGE_DELETE_GROUP_SUCCESS = "Deleted group: %1$s";
+
+ private final TutorialGroup toDelete;
+ private final TutorialClass toDeleteTutorialClass;
+
+ /**
+ * Constructor for DeleteGroupCommand
+ *
+ * @param tutorialGroup TutorialGroup to be deleted.
+ */
+ public DeleteGroupCommand(TutorialGroup tutorialGroup) {
+ requireNonNull(tutorialGroup);
+ toDelete = tutorialGroup;
+ // new class with the same class code created to check whether it already exists in ClassMATE
+ toDeleteTutorialClass = TutorialClass.createTestTutorialClass(toDelete.getClassCode());
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ // check if tutorial class already exists in ClassMATE
+ if (!model.hasTutorialClass(toDeleteTutorialClass)) {
+ throw new CommandException(MESSAGE_CLASS_DOES_NOT_EXIST);
+ }
+
+ // check if tutorial group already exists in ClassMATE
+ if (!model.hasTutorialGroup(toDelete)) {
+ throw new CommandException(MESSAGE_GROUP_DOES_NOT_EXIST);
+ }
+
+ model.deleteTutorialGroup(toDelete);
+
+ // filters students that belong to that tutorial group and edits them to have the tutorial group deleted
+ model.getUnfilteredStudentList().stream().filter(x -> x.isBelongTutorialGroup(toDelete))
+ .forEach(x -> model.setStudent(x, DeleteStudentFromGroupCommand.deleteTutorialGroup(x, toDelete)));
+
+ // rearrange tutorial groups in order after deleting
+ model.sortTutorialGroups();
+ return new CommandResult(String.format(MESSAGE_DELETE_GROUP_SUCCESS, toDelete));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this
+ || (other instanceof DeleteGroupCommand
+ && toDelete.equals(((DeleteGroupCommand) other).toDelete));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteLastMarkCommand.java b/src/main/java/seedu/address/logic/commands/DeleteLastMarkCommand.java
new file mode 100644
index 00000000000..fa02e6c1d2d
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteLastMarkCommand.java
@@ -0,0 +1,99 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_DUPLICATE_STUDENT;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_STUDENTS;
+
+import java.util.ArrayList;
+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.student.Student;
+import seedu.address.model.student.StudentMark;
+
+/**
+ * Deletes the latest mark of an existing student in the ClassMATE.
+ */
+public class DeleteLastMarkCommand extends Command {
+
+ public static final String COMMAND_WORD = "deletelm";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Deletes Student's Latest Mark\n"
+ + "Example: " + COMMAND_WORD + " 1 ";
+
+ public static final String MESSAGE_DELETE_MARK_STUDENT_SUCCESS = "Deleted Mark from Student: %1$s";
+ public static final String MESSAGE_NO_MARKS = "No Marks to Delete!";
+
+ private final Index index;
+
+ /**
+ * @param index of the student in the filtered student list to delete last mark of.
+ */
+ public DeleteLastMarkCommand(Index index) {
+ requireNonNull(index);
+
+ this.index = index;
+ }
+
+ @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());
+ Student editedStudent = deleteLastStudentMark(studentToEdit);
+
+ if (!studentToEdit.isSameStudent(editedStudent) && model.hasStudent(editedStudent)) {
+ throw new CommandException(MESSAGE_DUPLICATE_STUDENT);
+ }
+
+ model.setStudent(studentToEdit, editedStudent);
+ model.updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
+ return new CommandResult(String.format(MESSAGE_DELETE_MARK_STUDENT_SUCCESS, editedStudent));
+ }
+
+ /**
+ * Creates and returns a {@code Student} with the latest mark deleted.
+ */
+ private static Student deleteLastStudentMark(Student studentToEdit) throws CommandException {
+ assert studentToEdit != null;
+ List updatedMarks = new ArrayList<>(studentToEdit.getMarks());
+ if (updatedMarks.isEmpty()) {
+ throw new CommandException(MESSAGE_NO_MARKS);
+ }
+ updatedMarks.remove(updatedMarks.size() - 1);
+ return new Student(
+ studentToEdit.getName(),
+ studentToEdit.getPhone(),
+ studentToEdit.getEmail(),
+ studentToEdit.getAddress(),
+ studentToEdit.getClassCode(),
+ studentToEdit.getTags(),
+ updatedMarks,
+ studentToEdit.getTutorialGroups());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof DeleteLastMarkCommand)) {
+ return false;
+ }
+
+ // state check
+ DeleteLastMarkCommand e = (DeleteLastMarkCommand) other;
+ return index.equals(e.index);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteStudentCommand.java b/src/main/java/seedu/address/logic/commands/DeleteStudentCommand.java
new file mode 100644
index 00000000000..62082fde6f2
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteStudentCommand.java
@@ -0,0 +1,53 @@
+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.student.Student;
+
+/**
+ * Deletes a student identified using it's displayed index from the ClassMATE.
+ */
+public class DeleteStudentCommand extends Command {
+
+ public static final String COMMAND_WORD = "deletestu";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the student identified by the index number used in the displayed student list.\n"
+ + "Parameters: INDEX (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 DeleteStudentCommand(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);
+ 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 DeleteStudentCommand // instanceof handles nulls
+ && targetIndex.equals(((DeleteStudentCommand) other).targetIndex)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteStudentFromGroupCommand.java b/src/main/java/seedu/address/logic/commands/DeleteStudentFromGroupCommand.java
new file mode 100644
index 00000000000..5ca21d51600
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteStudentFromGroupCommand.java
@@ -0,0 +1,122 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GROUPNUMBER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TYPE;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_STUDENTS;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+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.student.Student;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+
+public class DeleteStudentFromGroupCommand extends Command {
+ public static final String COMMAND_WORD = "deletesg";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Deletes a student from a group in Classmate "
+ + "by the index number used in the last person listing. "
+ + "Parameters: INDEX (must be a positive integer) "
+ + PREFIX_CLASSCODE + "CLASS_CODE "
+ + PREFIX_TYPE + "GROUP_TYPE "
+ + PREFIX_GROUPNUMBER + "GROUP_NUMBER "
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_GROUPNUMBER + "1 "
+ + PREFIX_CLASSCODE + "G06 "
+ + PREFIX_TYPE + "OP1 ";
+
+ public static final String MESSAGE_SUCCESS = "Index: %1$d removed from Group: %2$s";
+ public static final String MESSAGE_GROUP_NOT_EXIST = "The group does not exist in Classmate";
+ public static final String MESSAGE_NOT_BELONG_GROUP = "The student does not being to this Group";
+
+ private final Index index;
+ private final TutorialGroup toDeleteTutorialGroup;
+
+ /**
+ * Creates an DeleteStudentFromGroupCommand to delete the specified {@code TutorialCode}
+ */
+ public DeleteStudentFromGroupCommand(Index index, TutorialGroup tutorialGroup) {
+ requireAllNonNull(index, tutorialGroup);
+ this.index = index;
+ this.toDeleteTutorialGroup = tutorialGroup;
+ // new class with the same class code created to check whether it already exists in ClassMATE
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredStudentList();
+
+ // Check if index is within range of student list
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX);
+ }
+
+ // check if tutorial group already exists in ClassMATE
+ if (!model.hasTutorialGroup(toDeleteTutorialGroup)) {
+ throw new CommandException(MESSAGE_GROUP_NOT_EXIST);
+ }
+
+ Student studentToEdit = lastShownList.get(index.getZeroBased());
+
+ // check if Student belongs to the Tutorial Group
+ if (!isBelongGroup(studentToEdit, toDeleteTutorialGroup)) {
+ throw new CommandException(MESSAGE_NOT_BELONG_GROUP);
+ }
+
+ Student editedStudent = deleteTutorialGroup(studentToEdit, toDeleteTutorialGroup);
+
+ model.setStudent(studentToEdit, editedStudent);
+ model.updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
+
+ return new CommandResult(String.format(MESSAGE_SUCCESS, index.getOneBased(), toDeleteTutorialGroup));
+ }
+
+ public boolean isBelongGroup(Student student, TutorialGroup tutorialGroup) {
+ return student.getTutorialGroups().contains(tutorialGroup);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof DeleteStudentFromGroupCommand)) {
+ return false;
+ }
+
+ // state check
+ return index.equals(((DeleteStudentFromGroupCommand) other).index)
+ && toDeleteTutorialGroup.equals(((DeleteStudentFromGroupCommand) other).toDeleteTutorialGroup);
+ }
+ /**
+ * Creates and returns a {@code Student} with the {@code TutorialGroup} deleted.
+ */
+ public static Student deleteTutorialGroup(Student studentToEdit, TutorialGroup group) {
+ assert studentToEdit != null;
+
+ Set updatedTutorialGroups = new HashSet<>(studentToEdit.getTutorialGroups());
+ updatedTutorialGroups.remove(group);
+ return new Student(
+ studentToEdit.getName(),
+ studentToEdit.getPhone(),
+ studentToEdit.getEmail(),
+ studentToEdit.getAddress(),
+ studentToEdit.getClassCode(),
+ studentToEdit.getTags(),
+ studentToEdit.getMarks(),
+ updatedTutorialGroups);
+
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java
index 7e36114902f..aaa038dd68a 100644
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ b/src/main/java/seedu/address/logic/commands/EditCommand.java
@@ -2,12 +2,14 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
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 static seedu.address.model.Model.PREDICATE_SHOW_ALL_STUDENTS;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -19,87 +21,110 @@
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.student.Address;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Phone;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.StudentMark;
import seedu.address.model.tag.Tag;
+import seedu.address.model.tutorialclass.Schedule;
+import seedu.address.model.tutorialclass.TutorialClass;
+import seedu.address.model.tutorialgroup.TutorialGroup;
/**
- * Edits the details of an existing person in the address book.
+ * Edits the details of an existing student in the ClassMATE.
*/
public class EditCommand extends Command {
- public static final String COMMAND_WORD = "edit";
+ public static final String COMMAND_WORD = "editstu";
- 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. "
+ 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 + "NAME] "
+ "[" + PREFIX_PHONE + "PHONE] "
+ "[" + PREFIX_EMAIL + "EMAIL] "
+ "[" + PREFIX_ADDRESS + "ADDRESS] "
+ + "[" + PREFIX_CLASSCODE + "CLASSCODE] "
+ "[" + 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_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_DUPLICATE_PERSON = "This person already exists in the address book.";
private final Index index;
- private final EditPersonDescriptor editPersonDescriptor;
+ private final EditStudentDescriptor editStudentDescriptor;
/**
- * @param index of the person in the filtered person list to edit
- * @param editPersonDescriptor details to edit the person with
+ * @param index of the student in the filtered student list to edit
+ * @param editStudentDescriptor details to edit the student with
*/
- public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) {
+ public EditCommand(Index index, EditStudentDescriptor editStudentDescriptor) {
requireNonNull(index);
- requireNonNull(editPersonDescriptor);
+ requireNonNull(editStudentDescriptor);
this.index = index;
- this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor);
+ this.editStudentDescriptor = new EditStudentDescriptor(editStudentDescriptor);
}
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
+ List lastShownList = model.getFilteredStudentList();
if (index.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ throw new CommandException(Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX);
}
- Person personToEdit = lastShownList.get(index.getZeroBased());
- Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
+ Student studentToEdit = lastShownList.get(index.getZeroBased());
+ Student editedStudent = createEditedStudent(studentToEdit, editStudentDescriptor);
- if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
+ if (!studentToEdit.isSameStudent(editedStudent) && model.hasStudent(editedStudent)) {
+ throw new CommandException(Messages.MESSAGE_DUPLICATE_STUDENT);
}
- model.setPerson(personToEdit, editedPerson);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson));
+ TutorialClass toCheckTutorialClass = new TutorialClass(editedStudent.getClassCode(),
+ new Schedule("Tues 12:00pm to 2:00pm, Fri 12:00pm to 2:00pm"), new HashSet());
+
+ if (!model.hasTutorialClass(toCheckTutorialClass)) {
+ throw new CommandException(Messages.MESSAGE_CLASS_DOES_NOT_EXIST);
+ }
+
+ model.setStudent(studentToEdit, editedStudent);
+ model.updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
+ return new CommandResult(String.format(MESSAGE_EDIT_STUDENT_SUCCESS, editedStudent));
}
/**
- * Creates and returns a {@code Person} with the details of {@code personToEdit}
- * edited with {@code editPersonDescriptor}.
+ * Creates and returns a {@code Student} with the details of {@code studentToEdit}
+ * edited with {@code editStudentDescriptor}.
*/
- 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);
+ private static Student createEditedStudent(Student studentToEdit, EditStudentDescriptor editStudentDescriptor) {
+ assert studentToEdit != null;
+
+ Name updatedName = editStudentDescriptor.getName().orElse(studentToEdit.getName());
+ Phone updatedPhone = editStudentDescriptor.getPhone().orElse(studentToEdit.getPhone());
+ Email updatedEmail = editStudentDescriptor.getEmail().orElse(studentToEdit.getEmail());
+ Address updatedAddress = editStudentDescriptor.getAddress().orElse(studentToEdit.getAddress());
+ ClassCode updatedClassCode = editStudentDescriptor.getClassCode().orElse(studentToEdit.getClassCode());
+ Set updatedTags = editStudentDescriptor.getTags().orElse(studentToEdit.getTags());
+ Set updatedTutorialGroups = editStudentDescriptor.getTutorialGroups()
+ .orElse(studentToEdit.getTutorialGroups());
+
+ return new Student(
+ updatedName,
+ updatedPhone,
+ updatedEmail,
+ updatedAddress,
+ updatedClassCode,
+ updatedTags,
+ studentToEdit.getMarks(),
+ updatedTutorialGroups);
}
@Override
@@ -117,39 +142,45 @@ public boolean equals(Object other) {
// state check
EditCommand e = (EditCommand) other;
return index.equals(e.index)
- && editPersonDescriptor.equals(e.editPersonDescriptor);
+ && editStudentDescriptor.equals(e.editStudentDescriptor);
}
/**
- * Stores the details to edit the person with. Each non-empty field value will replace the
- * corresponding field value of the person.
+ * 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 EditPersonDescriptor {
+ public static class EditStudentDescriptor {
private Name name;
private Phone phone;
private Email email;
private Address address;
+ private ClassCode classCode;
private Set tags;
+ private List marks;
+ private Set tutorialGroups;
- public EditPersonDescriptor() {}
+ public EditStudentDescriptor() {}
/**
* Copy constructor.
* A defensive copy of {@code tags} is used internally.
*/
- public EditPersonDescriptor(EditPersonDescriptor toCopy) {
+ public EditStudentDescriptor(EditStudentDescriptor toCopy) {
setName(toCopy.name);
setPhone(toCopy.phone);
setEmail(toCopy.email);
setAddress(toCopy.address);
+ setClassCode(toCopy.classCode);
setTags(toCopy.tags);
+ setMarks(toCopy.marks);
+ setTutorialGroups(new HashSet());
}
/**
* Returns true if at least one field is edited.
*/
public boolean isAnyFieldEdited() {
- return CollectionUtil.isAnyNonNull(name, phone, email, address, tags);
+ return CollectionUtil.isAnyNonNull(name, phone, email, address, classCode, tags);
}
public void setName(Name name) {
@@ -184,6 +215,14 @@ public Optional getAddress() {
return Optional.ofNullable(address);
}
+ public void setClassCode(ClassCode classCode) {
+ this.classCode = classCode;
+ }
+
+ public Optional getClassCode() {
+ return Optional.ofNullable(classCode);
+ }
+
/**
* Sets {@code tags} to this object's {@code tags}.
* A defensive copy of {@code tags} is used internally.
@@ -201,6 +240,41 @@ public Optional> getTags() {
return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
}
+ /**
+ * Sets {@code marks} to this object's {@code marks}.
+ * A defensive copy of {@code marks} is used internally.
+ */
+ public void setMarks(List marks) {
+ this.marks = (marks != null) ? new ArrayList<>(marks) : null;
+ }
+
+ /**
+ * Returns an unmodifiable mark list, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ * Returns {@code Optional#empty()} if {@code marks} is null.
+ */
+ public Optional> getMarks() {
+ return (marks != null) ? Optional.of(Collections.unmodifiableList(marks)) : Optional.empty();
+ }
+ /**
+ * Sets {@code tags} to this object's {@code tags}.
+ * A defensive copy of {@code tags} is used internally.
+ */
+ public void setTutorialGroups(Set tutorialGroups) {
+ this.tutorialGroups = (tutorialGroups != null) ? new HashSet<>(tutorialGroups) : 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> getTutorialGroups() {
+ return (tutorialGroups != null)
+ ? Optional.of(Collections.unmodifiableSet(tutorialGroups))
+ : Optional.empty();
+ }
+
@Override
public boolean equals(Object other) {
// short circuit if same object
@@ -209,12 +283,12 @@ public boolean equals(Object other) {
}
// instanceof handles nulls
- if (!(other instanceof EditPersonDescriptor)) {
+ if (!(other instanceof EditStudentDescriptor)) {
return false;
}
// state check
- EditPersonDescriptor e = (EditPersonDescriptor) other;
+ EditStudentDescriptor e = (EditStudentDescriptor) other;
return getName().equals(e.getName())
&& getPhone().equals(e.getPhone())
diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/address/logic/commands/ExitCommand.java
index 3dd85a8ba90..78c7d84640a 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ExitCommand.java
@@ -9,11 +9,11 @@ public class ExitCommand extends Command {
public static final String COMMAND_WORD = "exit";
- public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ...";
+ public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting ClassMATE as requested ...";
@Override
public CommandResult execute(Model model) {
- return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
+ return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, false, true, null);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/FindClassCommand.java b/src/main/java/seedu/address/logic/commands/FindClassCommand.java
new file mode 100644
index 00000000000..8cd722e3b31
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/FindClassCommand.java
@@ -0,0 +1,52 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.core.Messages.MESSAGE_CLASS_DOES_NOT_EXIST;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.tutorialclass.ClassCodeContainsKeywordsPredicate;
+
+/**
+ * Finds and lists all classes in ClassMATE whose class code contains any of the argument keywords.
+ * Keyword matching is case-insensitive.
+ */
+public class FindClassCommand extends Command {
+
+ public static final String COMMAND_WORD = "findc";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all classes with the specified class codes "
+ + "(case-insensitive) and displays them as a list with index numbers.\n"
+ + "Parameters: CLASS_CODE [MORE_CLASS_CODES]...\n"
+ + "Example: " + COMMAND_WORD + " G15 G16 G17";
+
+ private final ClassCodeContainsKeywordsPredicate predicate;
+
+ public FindClassCommand(ClassCodeContainsKeywordsPredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ model.updateFilteredTutorialClassList(predicate);
+
+ // check if tutorial class exists in ClassMATE
+ if (model.getFilteredTutorialClassList().size() == 0) {
+ throw new CommandException(MESSAGE_CLASS_DOES_NOT_EXIST);
+ }
+
+ return new CommandResult(
+ String.format(Messages.MESSAGE_TUTORIAL_CLASSES_LISTED_OVERVIEW,
+ model.getFilteredTutorialClassList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof FindClassCommand // instanceof handles nulls
+ && predicate.equals(((FindClassCommand) other).predicate)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindStudentCommand.java
similarity index 51%
rename from src/main/java/seedu/address/logic/commands/FindCommand.java
rename to src/main/java/seedu/address/logic/commands/FindStudentCommand.java
index d6b19b0a0de..aaaf7e631b4 100644
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ b/src/main/java/seedu/address/logic/commands/FindStudentCommand.java
@@ -4,39 +4,39 @@
import seedu.address.commons.core.Messages;
import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.student.NameContainsKeywordsPredicate;
/**
- * Finds and lists all persons in address book whose name contains any of the argument keywords.
- * Keyword matching is case insensitive.
+ * Finds and lists all students in ClassMATE whose name contains any of the argument keywords.
+ * Keyword matching is case-insensitive.
*/
-public class FindCommand extends Command {
+public class FindStudentCommand extends Command {
- public static final String COMMAND_WORD = "find";
+ public static final String COMMAND_WORD = "findstu";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of "
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all students 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) {
+ public FindStudentCommand(NameContainsKeywordsPredicate predicate) {
this.predicate = predicate;
}
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
- model.updateFilteredPersonList(predicate);
+ model.updateFilteredStudentList(predicate);
return new CommandResult(
- String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ String.format(Messages.MESSAGE_STUDENTS_LISTED_OVERVIEW, model.getFilteredStudentList().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
+ || (other instanceof FindStudentCommand // instanceof handles nulls
+ && predicate.equals(((FindStudentCommand) 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
index bf824f91bd0..cca5cd03ac5 100644
--- a/src/main/java/seedu/address/logic/commands/HelpCommand.java
+++ b/src/main/java/seedu/address/logic/commands/HelpCommand.java
@@ -16,6 +16,6 @@ public class HelpCommand extends Command {
@Override
public CommandResult execute(Model model) {
- return new CommandResult(SHOWING_HELP_MESSAGE, true, false);
+ return new CommandResult(SHOWING_HELP_MESSAGE, true, false, false, null);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/ListClassCommand.java b/src/main/java/seedu/address/logic/commands/ListClassCommand.java
new file mode 100644
index 00000000000..3373ad9e2de
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ListClassCommand.java
@@ -0,0 +1,24 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_CLASSES;
+
+import seedu.address.model.Model;
+
+
+/**
+ * Lists all classes in ClassMate to the user.
+ */
+public class ListClassCommand extends Command {
+
+ public static final String COMMAND_WORD = "listc";
+
+ public static final String MESSAGE_SUCCESS = "Listed all tutorial classes";
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredTutorialClassList(PREDICATE_SHOW_ALL_CLASSES);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
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/commands/ListStudentCommand.java b/src/main/java/seedu/address/logic/commands/ListStudentCommand.java
new file mode 100644
index 00000000000..9421a2c5da3
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ListStudentCommand.java
@@ -0,0 +1,24 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_STUDENTS;
+
+import seedu.address.model.Model;
+
+/**
+ * Lists all students in the ClassMATE to the user.
+ */
+public class ListStudentCommand extends Command {
+
+ public static final String COMMAND_WORD = "liststu";
+
+ public static final String MESSAGE_SUCCESS = "Listed all students";
+
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ViewClassCommand.java b/src/main/java/seedu/address/logic/commands/ViewClassCommand.java
new file mode 100644
index 00000000000..218266180c2
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ViewClassCommand.java
@@ -0,0 +1,71 @@
+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.student.ClassCode;
+import seedu.address.model.student.ClassMemberPredicate;
+import seedu.address.model.tutorialclass.TutorialClass;
+
+
+
+
+
+/**
+ * Views a TutorialClass and its students, identified using it's displayed index from the ClassMATE.
+ */
+public class ViewClassCommand extends Command {
+
+ public static final String COMMAND_WORD = "viewc";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Views the tutorial class identified by the index number in the displayed class list.\n"
+ + "Displays Students in tutorial class in Student List. \n"
+ + "Parmeters: INDEX (must be a positive integer that is a valid index of the list)\n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ public static final String MESSAGE_VIEW_CLASS_SUCCESS = "Viewed class: %1$s";
+
+ private final Index targetIndex;
+
+ /**
+ * Constructor for ViewClassCommand
+ *
+ * @param targetIndex Index to be deleted.
+ */
+ public ViewClassCommand(Index targetIndex) {
+ requireNonNull(targetIndex);
+ this.targetIndex = targetIndex;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredTutorialClassList();
+
+ if (targetIndex.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_CLASS_DISPLAYED_INDEX);
+ }
+
+ // filter List of tutorial classes to show selected class
+ TutorialClass classToShow = lastShownList.get(targetIndex.getZeroBased());
+ model.updateFilteredTutorialClassList(tc -> tc.isSameTutorialClass(classToShow));
+
+ // show only students part of the current class
+ ClassCode targetClassCode = classToShow.getClassCode();
+ model.updateFilteredStudentList(new ClassMemberPredicate(targetClassCode));
+ return new CommandResult(String.format(MESSAGE_VIEW_CLASS_SUCCESS, classToShow));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ViewClassCommand // instanceof handles nulls
+ && targetIndex.equals(((ViewClassCommand) other).targetIndex)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ViewGroupCommand.java b/src/main/java/seedu/address/logic/commands/ViewGroupCommand.java
new file mode 100644
index 00000000000..f30817c429e
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ViewGroupCommand.java
@@ -0,0 +1,74 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GROUPNUMBER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TYPE;
+
+import seedu.address.commons.core.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.student.GroupMemberPredicate;
+import seedu.address.model.tutorialclass.TutorialClass;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Lists all students in a tutorial group in ClassMATE given a class code, tutorial group type and tutorial group name
+ * Keyword matching is case-insensitive.
+ */
+public class ViewGroupCommand extends Command {
+
+ public static final String COMMAND_WORD = "viewg";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all students in a tutorial group given a class "
+ + "code, tutorial group type and tutorial group name (case-insensitive) and displays them as a list"
+ + "with index numbers.\n"
+ + "Parameters: "
+ + PREFIX_CLASSCODE + "CLASS_CODE "
+ + PREFIX_TYPE + "GROUP_TYPE "
+ + PREFIX_GROUPNUMBER + "GROUP_NUMBER "
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_GROUPNUMBER + "3 "
+ + PREFIX_CLASSCODE + "G06 "
+ + PREFIX_TYPE + "OP2 ";
+
+ private final TutorialGroup toView;
+ private final TutorialClass toViewTutorialClass;
+
+ /**
+ * Creates a ViewGroupCommand to show the students in the specified {@code TutorialGroup}
+ */
+ public ViewGroupCommand(TutorialGroup tutorialGroup) {
+ requireNonNull(tutorialGroup);
+ toView = tutorialGroup;
+ // new class with the same class code created to check whether it exists in ClassMATE
+ toViewTutorialClass = TutorialClass.createTestTutorialClass(toView.getClassCode());
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ // check if tutorial class exists in ClassMATE
+ if (!model.hasTutorialClass(toViewTutorialClass)) {
+ throw new CommandException(Messages.MESSAGE_CLASS_DOES_NOT_EXIST);
+ }
+
+ // check if tutorial group exists in ClassMATE
+ if (!model.hasTutorialGroup(toView)) {
+ throw new CommandException(Messages.MESSAGE_GROUP_DOES_NOT_EXIST);
+ }
+
+ model.updateFilteredStudentList(new GroupMemberPredicate(toView));
+ return new CommandResult(
+ String.format(Messages.MESSAGE_TUTORIAL_GROUP_LISTED_OVERVIEW,
+ model.getFilteredStudentList().size()));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ViewGroupCommand // instanceof handles nulls
+ && toView.equals(((ViewGroupCommand) other).toView)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ViewStudentCommand.java b/src/main/java/seedu/address/logic/commands/ViewStudentCommand.java
new file mode 100644
index 00000000000..baeb7efeb8e
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ViewStudentCommand.java
@@ -0,0 +1,54 @@
+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.student.Student;
+
+/**
+ * Views a student identified using it's displayed index from the ClassMATE by showing a popup window.
+ */
+public class ViewStudentCommand extends Command {
+
+ public static final String COMMAND_WORD = "viewstu";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Views the student identified by the index number used in the displayed student list.\n"
+ + "Parameters: INDEX (MUST be a positive integer)\n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ public static final String MESSAGE_VIEW_STUDENT_SUCCESS = "Viewed Student: %1$s";
+
+ private final Index targetIndex;
+
+ public ViewStudentCommand(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 studentToView = lastShownList.get(targetIndex.getZeroBased());
+ return new CommandResult(
+ String.format(MESSAGE_VIEW_STUDENT_SUCCESS, studentToView), false, true,
+ false, studentToView);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ViewStudentCommand // instanceof handles nulls
+ && targetIndex.equals(((ViewStudentCommand) other).targetIndex)); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddClassCommandParser.java b/src/main/java/seedu/address/logic/parser/AddClassCommandParser.java
new file mode 100644
index 00000000000..96072e04c12
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AddClassCommandParser.java
@@ -0,0 +1,47 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SCHEDULE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+
+import java.util.Set;
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.AddClassCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.tag.Tag;
+import seedu.address.model.tutorialclass.Schedule;
+import seedu.address.model.tutorialclass.TutorialClass;
+
+public class AddClassCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddClassCommand
+ * and returns an AddClassCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public AddClassCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_CLASSCODE, PREFIX_SCHEDULE, PREFIX_TAG);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_CLASSCODE, PREFIX_SCHEDULE)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddClassCommand.MESSAGE_USAGE));
+ }
+
+ ClassCode classCode = ParserUtil.parseClassCode(argMultimap.getValue(PREFIX_CLASSCODE).get());
+ Schedule schedule = ParserUtil.parseSchedule(argMultimap.getValue(PREFIX_SCHEDULE).get());
+ Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
+
+ TutorialClass tutorialClass = new TutorialClass(classCode, schedule, tagList);
+
+ return new AddClassCommand(tutorialClass);
+
+ }
+
+ 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/AddGroupCommandParser.java b/src/main/java/seedu/address/logic/parser/AddGroupCommandParser.java
new file mode 100644
index 00000000000..3dae18e89d0
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AddGroupCommandParser.java
@@ -0,0 +1,49 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GROUPNUMBER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TYPE;
+
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.AddGroupCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.tutorialgroup.GroupNumber;
+import seedu.address.model.tutorialgroup.GroupType;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Parses input arguments and creates a new AddGroupCommand object
+ */
+public class AddGroupCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddGroupCommand
+ * and returns an AddGroupCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public AddGroupCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_GROUPNUMBER, PREFIX_CLASSCODE, PREFIX_TYPE);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_GROUPNUMBER, PREFIX_CLASSCODE, PREFIX_TYPE)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddGroupCommand.MESSAGE_USAGE));
+ }
+
+ GroupNumber groupNumber = ParserUtil.parseGroupNumber(argMultimap.getValue(PREFIX_GROUPNUMBER).get());
+ ClassCode classCode = ParserUtil.parseClassCode(argMultimap.getValue(PREFIX_CLASSCODE).get());
+ GroupType groupType = ParserUtil.parseGroupType(argMultimap.getValue(PREFIX_TYPE).get());
+
+ TutorialGroup tutorialGroup = new TutorialGroup(groupNumber, classCode, groupType);
+
+ return new AddGroupCommand(tutorialGroup);
+
+ }
+
+ 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/AddLastMarkCommandParser.java b/src/main/java/seedu/address/logic/parser/AddLastMarkCommandParser.java
new file mode 100644
index 00000000000..caee2caba42
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AddLastMarkCommandParser.java
@@ -0,0 +1,50 @@
+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.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_MARK;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.AddLastMarkCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.student.StudentMark;
+
+/**
+ * Parses input arguments and creates a new AddLastMarkCommand object
+ */
+public class AddLastMarkCommandParser 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 AddLastMarkCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ Index index = null;
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_MARK);
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX + MESSAGE_INVALID_COMMAND_FORMAT,
+ AddLastMarkCommand.MESSAGE_USAGE), pe);
+ }
+
+ StudentMark newMark = null;
+
+ if (argMultimap.getValue(PREFIX_MARK).isPresent()) {
+ newMark = ParserUtil.parseMark(argMultimap.getValue(PREFIX_MARK).get());
+ } else {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddLastMarkCommand.MESSAGE_NOT_EDITED)
+ );
+ }
+
+ return new AddLastMarkCommand(index, newMark);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddStudentCommandParser.java
similarity index 61%
rename from src/main/java/seedu/address/logic/parser/AddCommandParser.java
rename to src/main/java/seedu/address/logic/parser/AddStudentCommandParser.java
index 3b8bfa035e8..fc4d91a88f8 100644
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddStudentCommandParser.java
@@ -2,51 +2,63 @@
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_CLASSCODE;
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.ArrayList;
+import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
-import seedu.address.logic.commands.AddCommand;
+import seedu.address.logic.commands.AddStudentCommand;
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.student.Address;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Phone;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.StudentMark;
import seedu.address.model.tag.Tag;
+import seedu.address.model.tutorialgroup.TutorialGroup;
/**
* Parses input arguments and creates a new AddCommand object
*/
-public class AddCommandParser implements Parser {
+public class AddStudentCommandParser 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 {
+ public AddStudentCommand parse(String args) throws ParseException {
ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS,
+ PREFIX_CLASSCODE, PREFIX_TAG);
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
+ if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_CLASSCODE)
|| !argMultimap.getPreamble().isEmpty()) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddStudentCommand.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());
+ ClassCode classCode = ParserUtil.parseClassCode(argMultimap.getValue(PREFIX_CLASSCODE).orElse("G00"));
Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
+ ArrayList marks = new ArrayList<>();
+ Set tutorialGroups = new HashSet<>();
- Person person = new Person(name, phone, email, address, tagList);
+ Student student = new Student(name, phone, email, address, classCode, tagList, marks, tutorialGroups);
+
+
+ return new AddStudentCommand(student);
- return new AddCommand(person);
}
/**
diff --git a/src/main/java/seedu/address/logic/parser/AddStudentToGroupCommandParser.java b/src/main/java/seedu/address/logic/parser/AddStudentToGroupCommandParser.java
new file mode 100644
index 00000000000..59aff0010ee
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AddStudentToGroupCommandParser.java
@@ -0,0 +1,60 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GROUPNUMBER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TYPE;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.logic.commands.AddGroupCommand;
+import seedu.address.logic.commands.AddStudentToGroupCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.tutorialgroup.GroupNumber;
+import seedu.address.model.tutorialgroup.GroupType;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+
+public class AddStudentToGroupCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddStudentToGroupCommand
+ * and returns an AddStudentToGroupCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public AddStudentToGroupCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_GROUPNUMBER, PREFIX_CLASSCODE, PREFIX_TYPE);
+
+ Index index;
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (IllegalValueException ive) {
+ throw new ParseException(String.format(
+ MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX + MESSAGE_INVALID_COMMAND_FORMAT,
+ AddStudentToGroupCommand.MESSAGE_USAGE), ive);
+ }
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_GROUPNUMBER, PREFIX_CLASSCODE, PREFIX_TYPE)) {
+ throw new ParseException(String.format(
+ MESSAGE_INVALID_COMMAND_FORMAT, AddStudentToGroupCommand.MESSAGE_USAGE));
+ }
+
+ GroupNumber groupNumber = ParserUtil.parseGroupNumber(argMultimap.getValue(PREFIX_GROUPNUMBER).get());
+ ClassCode classCode = ParserUtil.parseClassCode(argMultimap.getValue(PREFIX_CLASSCODE).get());
+ GroupType groupType = ParserUtil.parseGroupType(argMultimap.getValue(PREFIX_TYPE).get());
+
+ TutorialGroup tutorialGroup = new TutorialGroup(groupNumber, classCode, groupType);
+
+ return new AddStudentToGroupCommand(index, tutorialGroup);
+
+ }
+
+ 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/ClassmateParser.java b/src/main/java/seedu/address/logic/parser/ClassmateParser.java
new file mode 100644
index 00000000000..303963d2616
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ClassmateParser.java
@@ -0,0 +1,134 @@
+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.AddClassCommand;
+import seedu.address.logic.commands.AddGroupCommand;
+import seedu.address.logic.commands.AddLastMarkCommand;
+import seedu.address.logic.commands.AddStudentCommand;
+import seedu.address.logic.commands.AddStudentToGroupCommand;
+import seedu.address.logic.commands.ClearCommand;
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.DeleteAllMarkCommand;
+import seedu.address.logic.commands.DeleteClassCommand;
+import seedu.address.logic.commands.DeleteGroupCommand;
+import seedu.address.logic.commands.DeleteLastMarkCommand;
+import seedu.address.logic.commands.DeleteStudentCommand;
+import seedu.address.logic.commands.DeleteStudentFromGroupCommand;
+import seedu.address.logic.commands.EditCommand;
+import seedu.address.logic.commands.ExitCommand;
+import seedu.address.logic.commands.FindClassCommand;
+import seedu.address.logic.commands.FindStudentCommand;
+import seedu.address.logic.commands.HelpCommand;
+import seedu.address.logic.commands.ListClassCommand;
+import seedu.address.logic.commands.ListStudentCommand;
+import seedu.address.logic.commands.ViewClassCommand;
+import seedu.address.logic.commands.ViewGroupCommand;
+import seedu.address.logic.commands.ViewStudentCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses user input.
+ */
+public class ClassmateParser {
+
+ /**
+ * Used for initial separation of command word and args.
+ */
+ private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?(.|\n)*)");
+
+ /**
+ * 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) {
+ //No breaks provided since all cases are return/throw statements
+
+ case AddStudentCommand.COMMAND_WORD:
+ return new AddStudentCommandParser().parse(arguments);
+
+ case AddClassCommand.COMMAND_WORD:
+ return new AddClassCommandParser().parse(arguments);
+
+ case AddGroupCommand.COMMAND_WORD:
+ return new AddGroupCommandParser().parse(arguments);
+
+ case AddStudentToGroupCommand.COMMAND_WORD:
+ return new AddStudentToGroupCommandParser().parse(arguments);
+
+ case AddLastMarkCommand.COMMAND_WORD:
+ return new AddLastMarkCommandParser().parse(arguments);
+
+ case EditCommand.COMMAND_WORD:
+ return new EditCommandParser().parse(arguments);
+
+ case DeleteStudentCommand.COMMAND_WORD:
+ return new DeleteStudentCommandParser().parse(arguments);
+
+ case DeleteGroupCommand.COMMAND_WORD:
+ return new DeleteGroupCommandParser().parse(arguments);
+
+ case DeleteClassCommand.COMMAND_WORD:
+ return new DeleteClassCommandParser().parse(arguments);
+
+ case DeleteStudentFromGroupCommand.COMMAND_WORD:
+ return new DeleteStudentFromGroupCommandParser().parse(arguments);
+
+ case DeleteLastMarkCommand.COMMAND_WORD:
+ return new DeleteLastMarkCommandParser().parse(arguments);
+
+ case DeleteAllMarkCommand.COMMAND_WORD:
+ return new DeleteAllMarkCommandParser().parse(arguments);
+
+ case ViewClassCommand.COMMAND_WORD:
+ return new ViewClassCommandParser().parse(arguments);
+
+ case ViewGroupCommand.COMMAND_WORD:
+ return new ViewGroupCommandParser().parse(arguments);
+
+ case ViewStudentCommand.COMMAND_WORD:
+ return new ViewStudentCommandParser().parse(arguments);
+
+ case ClearCommand.COMMAND_WORD:
+ return new ClearCommand();
+
+ case FindStudentCommand.COMMAND_WORD:
+ return new FindStudentCommandParser().parse(arguments);
+
+ case FindClassCommand.COMMAND_WORD:
+ return new FindClassCommandParser().parse(arguments);
+
+ case ListStudentCommand.COMMAND_WORD:
+ return new ListStudentCommand();
+
+ case ListClassCommand.COMMAND_WORD:
+ return new ListClassCommand();
+
+ 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
index 75b1a9bf119..982dc2cf463 100644
--- a/src/main/java/seedu/address/logic/parser/CliSyntax.java
+++ b/src/main/java/seedu/address/logic/parser/CliSyntax.java
@@ -5,11 +5,19 @@
*/
public class CliSyntax {
- /* Prefix definitions */
+ // Student Prefix definitions
public static final Prefix PREFIX_NAME = new Prefix("n/");
public static final Prefix PREFIX_PHONE = new Prefix("p/");
public static final Prefix PREFIX_EMAIL = new Prefix("e/");
public static final Prefix PREFIX_ADDRESS = new Prefix("a/");
public static final Prefix PREFIX_TAG = new Prefix("t/");
+ public static final Prefix PREFIX_MARK = new Prefix("m/");
+ // TutorialClass Prefix definitions
+ public static final Prefix PREFIX_CLASSCODE = new Prefix("c/");
+ public static final Prefix PREFIX_SCHEDULE = new Prefix("s/");
+
+ // TutorialGroup Prefix definitions
+ public static final Prefix PREFIX_GROUPNUMBER = new Prefix("gn/");
+ public static final Prefix PREFIX_TYPE = new Prefix("type/");
}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteAllMarkCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteAllMarkCommandParser.java
new file mode 100644
index 00000000000..a972aabbd57
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeleteAllMarkCommandParser.java
@@ -0,0 +1,38 @@
+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.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.DeleteAllMarkCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new DeleteLastMarkCommand object
+ */
+public class DeleteAllMarkCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteLastMarkCommand
+ * and returns an DeleteAllMarkCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeleteAllMarkCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ Index index = null;
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args);
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX + MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteAllMarkCommand.MESSAGE_USAGE), pe);
+ }
+
+ return new DeleteAllMarkCommand(index);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteClassCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteClassCommandParser.java
new file mode 100644
index 00000000000..2f1d15f0f99
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeleteClassCommandParser.java
@@ -0,0 +1,28 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_CLASS_DISPLAYED_INDEX;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.DeleteClassCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+
+public class DeleteClassCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteClassCommand
+ * and returns a DeleteClassCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ @Override
+ public DeleteClassCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new DeleteClassCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_CLASS_DISPLAYED_INDEX + MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteClassCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
deleted file mode 100644
index 522b93081cc..00000000000
--- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.DeleteCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
-
-/**
- * Parses input arguments and creates a new DeleteCommand object
- */
-public class DeleteCommandParser implements Parser {
-
- /**
- * Parses the given {@code String} of arguments in the context of the DeleteCommand
- * and returns a DeleteCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
- */
- public DeleteCommand parse(String args) throws ParseException {
- try {
- Index index = ParserUtil.parseIndex(args);
- return new DeleteCommand(index);
- } catch (ParseException pe) {
- throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE), pe);
- }
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteGroupCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteGroupCommandParser.java
new file mode 100644
index 00000000000..c6e198bbf26
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeleteGroupCommandParser.java
@@ -0,0 +1,48 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GROUPNUMBER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TYPE;
+
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.DeleteGroupCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.tutorialgroup.GroupNumber;
+import seedu.address.model.tutorialgroup.GroupType;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Parses input arguments and creates a new DeleteGroupCommand object
+ */
+public class DeleteGroupCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteGroupCommand
+ * and returns an DeleteGroupCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public DeleteGroupCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_GROUPNUMBER, PREFIX_CLASSCODE, PREFIX_TYPE);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_GROUPNUMBER, PREFIX_CLASSCODE, PREFIX_TYPE)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteGroupCommand.MESSAGE_USAGE));
+ }
+
+ GroupNumber groupNumber = ParserUtil.parseGroupNumber(argMultimap.getValue(PREFIX_GROUPNUMBER).get());
+ ClassCode classCode = ParserUtil.parseClassCode(argMultimap.getValue(PREFIX_CLASSCODE).get());
+ GroupType groupType = ParserUtil.parseGroupType(argMultimap.getValue(PREFIX_TYPE).get());
+
+ TutorialGroup tutorialGroup = new TutorialGroup(groupNumber, classCode, groupType);
+
+ return new DeleteGroupCommand(tutorialGroup);
+
+ }
+
+ 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/DeleteLastMarkCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteLastMarkCommandParser.java
new file mode 100644
index 00000000000..01af002330e
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeleteLastMarkCommandParser.java
@@ -0,0 +1,38 @@
+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.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.DeleteLastMarkCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new DeleteLastMarkCommand object
+ */
+public class DeleteLastMarkCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteLastMarkCommand
+ * and returns an DeleteLastMarkCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeleteLastMarkCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ Index index = null;
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args);
+
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX + MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteLastMarkCommand.MESSAGE_USAGE), pe);
+ }
+
+ return new DeleteLastMarkCommand(index);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteStudentCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteStudentCommandParser.java
new file mode 100644
index 00000000000..38a8a867822
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeleteStudentCommandParser.java
@@ -0,0 +1,31 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.DeleteStudentCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new DeleteStudentCommand object
+ */
+public class DeleteStudentCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteStudentCommand
+ * and returns a DeleteStudentCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeleteStudentCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new DeleteStudentCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX + MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteStudentCommand.MESSAGE_USAGE), pe);
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteStudentFromGroupCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteStudentFromGroupCommandParser.java
new file mode 100644
index 00000000000..bed74053710
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeleteStudentFromGroupCommandParser.java
@@ -0,0 +1,59 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GROUPNUMBER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TYPE;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.logic.commands.AddGroupCommand;
+import seedu.address.logic.commands.DeleteStudentFromGroupCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.tutorialgroup.GroupNumber;
+import seedu.address.model.tutorialgroup.GroupType;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+
+public class DeleteStudentFromGroupCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteStudentFromCommand
+ * and returns an DeleteStudentFromGroupCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ public DeleteStudentFromGroupCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_GROUPNUMBER, PREFIX_CLASSCODE, PREFIX_TYPE);
+
+ Index index;
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (IllegalValueException ive) {
+ throw new ParseException(String.format(
+ MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX, DeleteStudentFromGroupCommand.MESSAGE_USAGE), ive);
+ }
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_GROUPNUMBER, PREFIX_CLASSCODE, PREFIX_TYPE)) {
+ throw new ParseException(String.format(
+ MESSAGE_INVALID_COMMAND_FORMAT, DeleteStudentFromGroupCommand.MESSAGE_USAGE));
+ }
+
+ GroupNumber groupNumber = ParserUtil.parseGroupNumber(argMultimap.getValue(PREFIX_GROUPNUMBER).get());
+ ClassCode classCode = ParserUtil.parseClassCode(argMultimap.getValue(PREFIX_CLASSCODE).get());
+ GroupType groupType = ParserUtil.parseGroupType(argMultimap.getValue(PREFIX_TYPE).get());
+
+ TutorialGroup tutorialGroup = new TutorialGroup(groupNumber, classCode, groupType);
+
+ return new DeleteStudentFromGroupCommand(index, tutorialGroup);
+
+ }
+
+ 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/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
index 845644b7dea..178c3fe7016 100644
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
@@ -2,7 +2,9 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
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;
@@ -15,7 +17,7 @@
import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
+import seedu.address.logic.commands.EditCommand.EditStudentDescriptor;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.tag.Tag;
@@ -31,37 +33,49 @@ public class EditCommandParser implements Parser {
*/
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();
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE,
+ PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_CLASSCODE, PREFIX_TAG);
+ Index index = findIndex(argMultimap);
+ EditStudentDescriptor editStudentDescriptor = new EditStudentDescriptor();
if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
- editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
+ editStudentDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
}
if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
- editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
+ editStudentDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
}
if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
- editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
+ editStudentDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
}
if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
- editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
+ editStudentDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
}
- parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
-
- if (!editPersonDescriptor.isAnyFieldEdited()) {
+ if (argMultimap.getValue(PREFIX_CLASSCODE).isPresent()) {
+ editStudentDescriptor.setClassCode(ParserUtil.parseClassCode(argMultimap.getValue(PREFIX_CLASSCODE).get()));
+ }
+ parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editStudentDescriptor::setTags);
+ if (!editStudentDescriptor.isAnyFieldEdited()) {
throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
}
- return new EditCommand(index, editPersonDescriptor);
+ return new EditCommand(index, editStudentDescriptor);
+ }
+
+ /**
+ * Gets index in the Command.
+ *
+ * @param argMultimap Map of Arguments.
+ * @return Input Index.
+ * @throws ParseException if Index is invalid.
+ */
+ private Index findIndex(ArgumentMultimap argMultimap) throws ParseException {
+ try {
+ return ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX + MESSAGE_INVALID_COMMAND_FORMAT,
+ EditCommand.MESSAGE_USAGE),
+ pe);
+ }
}
/**
diff --git a/src/main/java/seedu/address/logic/parser/FindClassCommandParser.java b/src/main/java/seedu/address/logic/parser/FindClassCommandParser.java
new file mode 100644
index 00000000000..3fff11c09bf
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/FindClassCommandParser.java
@@ -0,0 +1,33 @@
+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.FindClassCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.tutorialclass.ClassCodeContainsKeywordsPredicate;
+
+/**
+ * Parses input arguments and creates a new FindClassCommand object
+ */
+public class FindClassCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the FindClassCommand
+ * and returns a FindClassCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public FindClassCommand parse(String args) throws ParseException {
+ String trimmedArgs = args.trim();
+ if (trimmedArgs.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindClassCommand.MESSAGE_USAGE));
+ }
+
+ String[] classCodeKeywords = trimmedArgs.split("\\s+");
+
+ return new FindClassCommand(new ClassCodeContainsKeywordsPredicate(Arrays.asList(classCodeKeywords)));
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindStudentCommandParser.java
similarity index 52%
rename from src/main/java/seedu/address/logic/parser/FindCommandParser.java
rename to src/main/java/seedu/address/logic/parser/FindStudentCommandParser.java
index 4fb71f23103..8d64b519545 100644
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/FindStudentCommandParser.java
@@ -4,30 +4,30 @@
import java.util.Arrays;
-import seedu.address.logic.commands.FindCommand;
+import seedu.address.logic.commands.FindStudentCommand;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.student.NameContainsKeywordsPredicate;
/**
- * Parses input arguments and creates a new FindCommand object
+ * Parses input arguments and creates a new FindStudentCommand object
*/
-public class FindCommandParser implements Parser {
+public class FindStudentCommandParser implements Parser {
/**
- * Parses the given {@code String} of arguments in the context of the FindCommand
- * and returns a FindCommand object for execution.
+ * Parses the given {@code String} of arguments in the context of the FindStudentCommand
+ * and returns a FindStudentCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
- public FindCommand parse(String args) throws ParseException {
+ public FindStudentCommand 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.format(MESSAGE_INVALID_COMMAND_FORMAT, FindStudentCommand.MESSAGE_USAGE));
}
String[] nameKeywords = trimmedArgs.split("\\s+");
- return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
+ return new FindStudentCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
}
}
diff --git a/src/main/java/seedu/address/logic/parser/Parser.java b/src/main/java/seedu/address/logic/parser/Parser.java
index d6551ad8e3f..3a8ffaa4a68 100644
--- a/src/main/java/seedu/address/logic/parser/Parser.java
+++ b/src/main/java/seedu/address/logic/parser/Parser.java
@@ -12,5 +12,5 @@ public interface Parser {
* Parses {@code userInput} into a command and returns it.
* @throws ParseException if {@code userInput} does not conform the expected format
*/
- T parse(String userInput) throws ParseException;
+ Command parse(String userInput) throws ParseException;
}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
index b117acb9c55..ff7a79148a5 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java
@@ -9,11 +9,16 @@
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.student.Address;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Phone;
+import seedu.address.model.student.StudentMark;
import seedu.address.model.tag.Tag;
+import seedu.address.model.tutorialclass.Schedule;
+import seedu.address.model.tutorialgroup.GroupNumber;
+import seedu.address.model.tutorialgroup.GroupType;
/**
* Contains utility methods used for parsing strings in the various *Parser classes.
@@ -65,6 +70,23 @@ public static Phone parsePhone(String phone) throws ParseException {
return new Phone(trimmedPhone);
}
+ /**
+ * Parses a {@code String mark} into a {@code StudentMark}.
+ *
+ * @throws ParseException if the given {@code mark} is invalid.
+ */
+ public static StudentMark parseMark(String mark) throws ParseException {
+ requireNonNull(mark);
+ String trimmedMark = mark.trim().toUpperCase();
+ StudentMark newMark;
+ try {
+ newMark = StudentMark.valueOf(trimmedMark);
+ } catch (IllegalArgumentException e) {
+ throw new ParseException(StudentMark.MESSAGE_CONSTRAINTS);
+ }
+ return newMark;
+ }
+
/**
* Parses a {@code String address} into an {@code Address}.
* Leading and trailing whitespaces will be trimmed.
@@ -95,6 +117,66 @@ public static Email parseEmail(String email) throws ParseException {
return new Email(trimmedEmail);
}
+ /**
+ * Parses a string to return a ClassCode
+ * @param classCode String of classCode
+ * @return ClassCode
+ * @throws ParseException if the given {@code classCode} is invalid.
+ */
+ public static ClassCode parseClassCode(String classCode) throws ParseException {
+ requireNonNull(classCode);
+ String trimmedClassCode = classCode.trim();
+ if (!ClassCode.isValidClassCode(trimmedClassCode)) {
+ throw new ParseException(ClassCode.MESSAGE_CONSTRAINTS);
+ } else if (ClassCode.isDefaultClassCode(classCode)) {
+ throw new ParseException(ClassCode.MESSAGE_EMPTY_CLASS);
+ }
+ return new ClassCode(trimmedClassCode);
+ }
+
+ /**
+ * Parses a {@code String schedule} into an {@code Schedule}.
+ * Leading and trailing whitespaces will be trimmed.
+ * @throws ParseException if the given {@code schedule} is invalid.
+ */
+ public static Schedule parseSchedule(String schedule) throws ParseException {
+ requireNonNull(schedule);
+ String trimmedSchedule = schedule.trim();
+ if (!Schedule.isValidSchedule(trimmedSchedule)) {
+ throw new ParseException(Schedule.MESSAGE_CONSTRAINTS);
+ }
+ return new Schedule(trimmedSchedule);
+ }
+
+ /**
+ * Parses a {@code String groupNumber} into an {@code GroupNumber}.
+ * Leading and trailing whitespaces will be trimmed.
+ * @throws ParseException if the given {@code groupNumber} is invalid.
+ */
+ public static GroupNumber parseGroupNumber(String groupNumber) throws ParseException {
+ requireNonNull(groupNumber);
+ String trimmedGroupNumber = groupNumber.trim();
+ if (!GroupNumber.isValidGroupNumber(trimmedGroupNumber)) {
+ throw new ParseException(GroupNumber.MESSAGE_CONSTRAINTS);
+ }
+ return new GroupNumber(trimmedGroupNumber);
+ }
+
+ /**
+ * Parses a {@code String groupType} into an {@code GrougType}.
+ * Leading and trailing whitespaces will be trimmed.
+ * Letters are set to uppercase.
+ * @throws ParseException if the given {@code groupType} is invalid.
+ */
+ public static GroupType parseGroupType(String groupType) throws ParseException {
+ requireNonNull(groupType);
+ String trimmedGroupType = groupType.trim();
+ if (!GroupType.isValidGroupType(trimmedGroupType)) {
+ throw new ParseException(GroupType.MESSAGE_CONSTRAINTS);
+ }
+ return new GroupType(trimmedGroupType.toUpperCase());
+ }
+
/**
* Parses a {@code String tag} into a {@code Tag}.
* Leading and trailing whitespaces will be trimmed.
diff --git a/src/main/java/seedu/address/logic/parser/ViewClassCommandParser.java b/src/main/java/seedu/address/logic/parser/ViewClassCommandParser.java
new file mode 100644
index 00000000000..576a4a7cee4
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ViewClassCommandParser.java
@@ -0,0 +1,31 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_CLASS_DISPLAYED_INDEX;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.ViewClassCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+
+/**
+ * Parses input arguments and creates a new ViewClassCommand object
+ */
+public class ViewClassCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the ViewClassCommand
+ * and returns a ViewClassCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ @Override
+ public ViewClassCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new ViewClassCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_CLASS_DISPLAYED_INDEX + MESSAGE_INVALID_COMMAND_FORMAT,
+ ViewClassCommand.MESSAGE_USAGE), pe);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ViewGroupCommandParser.java b/src/main/java/seedu/address/logic/parser/ViewGroupCommandParser.java
new file mode 100644
index 00000000000..97f83e48f5c
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ViewGroupCommandParser.java
@@ -0,0 +1,48 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CLASSCODE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_GROUPNUMBER;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TYPE;
+
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.ViewGroupCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.tutorialgroup.GroupNumber;
+import seedu.address.model.tutorialgroup.GroupType;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Parses input arguments and creates a new ViewGroupCommand object
+ */
+public class ViewGroupCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the ViewGroupCommand
+ * and returns a ViewGroupCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public ViewGroupCommand parse(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_CLASSCODE, PREFIX_TYPE, PREFIX_GROUPNUMBER);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_CLASSCODE, PREFIX_TYPE, PREFIX_GROUPNUMBER)
+ || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ViewGroupCommand.MESSAGE_USAGE));
+ }
+
+ GroupNumber groupNumber = ParserUtil.parseGroupNumber(argMultimap.getValue(PREFIX_GROUPNUMBER).get());
+ ClassCode classCode = ParserUtil.parseClassCode(argMultimap.getValue(PREFIX_CLASSCODE).get());
+ GroupType groupType = ParserUtil.parseGroupType(argMultimap.getValue(PREFIX_TYPE).get());
+
+ TutorialGroup tutorialGroup = new TutorialGroup(groupNumber, classCode, groupType);
+
+ return new ViewGroupCommand(tutorialGroup);
+ }
+
+ 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/ViewStudentCommandParser.java b/src/main/java/seedu/address/logic/parser/ViewStudentCommandParser.java
new file mode 100644
index 00000000000..62b38f237ac
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ViewStudentCommandParser.java
@@ -0,0 +1,31 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.commons.core.Messages.MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.ViewStudentCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new ViewCommand object
+ */
+public class ViewStudentCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the ViewCommand
+ * and returns a ViewCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public ViewStudentCommand parse(String args) throws ParseException {
+ try {
+ Index index = ParserUtil.parseIndex(args);
+ return new ViewStudentCommand(index);
+ } catch (ParseException pe) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_STUDENT_DISPLAYED_INDEX + MESSAGE_INVALID_COMMAND_FORMAT,
+ ViewStudentCommand.MESSAGE_USAGE), pe);
+ }
+ }
+
+}
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/Classmate.java b/src/main/java/seedu/address/model/Classmate.java
new file mode 100644
index 00000000000..4a43ce83259
--- /dev/null
+++ b/src/main/java/seedu/address/model/Classmate.java
@@ -0,0 +1,205 @@
+package seedu.address.model;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+
+import javafx.collections.ObservableList;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.UniqueStudentList;
+import seedu.address.model.tutorialclass.TutorialClass;
+import seedu.address.model.tutorialclass.UniqueTutorialClassList;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Wraps all data at the address-book level
+ * Duplicates are not allowed (by .isSameStudent comparison)
+ */
+public class Classmate implements ReadOnlyClassmate {
+
+ public static final ClassCode DEFAULT_CLASSCODE = new ClassCode("G00");
+
+ private final UniqueStudentList students;
+ private final UniqueTutorialClassList tutorialClasses;
+
+ /*
+ * 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.
+ */
+ {
+ students = new UniqueStudentList();
+ tutorialClasses = new UniqueTutorialClassList();
+ }
+
+ public Classmate() {}
+
+ /**
+ * Creates an Classmate using the Students in the {@code toBeCopied}
+ */
+ public Classmate(ReadOnlyClassmate toBeCopied) {
+ this();
+ resetData(toBeCopied);
+ }
+
+ //// list overwrite operations
+
+ /**
+ * Replaces the contents of the student list with {@code students}.
+ * {@code students} must not contain duplicate students.
+ */
+ public void setStudents(List students) {
+ this.students.setStudents(students);
+ }
+
+ /**
+ * Replaces the contents of the tutorial class list with {@code tutorialClasses}.
+ * {@code tutorialClasses} must not contain duplicate students.
+ */
+ public void setTutorialClasses(List tutorialClasses) {
+ this.tutorialClasses.setTutorialClasses(tutorialClasses);
+ }
+
+ /**
+ * Resets the existing data of this {@code Classmate} with {@code newData}.
+ */
+ public void resetData(ReadOnlyClassmate newData) {
+ requireNonNull(newData);
+
+ setStudents(newData.getStudentList());
+ setTutorialClasses(newData.getTutorialClassList());
+ }
+
+ //// student-level operations
+
+ /**
+ * Returns true if a student with the same identity as {@code student} exists in the ClassMATE.
+ */
+ public boolean hasStudent(Student student) {
+ requireNonNull(student);
+ return students.contains(student);
+ }
+
+ /**
+ * Adds a student to the ClassMATE.
+ * The student must not already exist in the ClassMATE.
+ */
+ public void addStudent(Student student) {
+ students.add(student);
+ }
+
+ /**
+ * Replaces the given student {@code target} in the list with {@code editedStudent}.
+ * {@code target} must exist in the ClassMATE.
+ * The student identity of {@code editedStudent} must not be the same as another existing student in ClassMATE.
+ */
+ public void setStudent(Student target, Student editedStudent) {
+ requireNonNull(editedStudent);
+ students.setStudent(target, editedStudent);
+ }
+
+ /**
+ * Removes {@code key} from this {@code Classmate}.
+ * {@code key} must exist in the ClassMATE.
+ */
+ public void removeStudent(Student key) {
+ students.remove(key);
+ }
+
+ //// tutorialclass-level operations
+
+ /**
+ * Returns true if a tutorialClass with the same identity as {@code tutorialClass} exists in the address book.
+ */
+ public boolean hasTutorialClass(TutorialClass tutorialClass) {
+ requireNonNull(tutorialClass);
+ if (tutorialClass.getClassCode().equals(DEFAULT_CLASSCODE)) {
+ return true;
+ }
+ return tutorialClasses.contains(tutorialClass);
+ }
+
+ /**
+ * Adds a tutorialClass to the address book.
+ * The tutorialClass must not already exist in the address book.
+ */
+ public void addTutorialClass(TutorialClass c) {
+ tutorialClasses.add(c);
+ }
+
+
+ /**
+ * Removes {@code key} from this {@code Classmate}.
+ * {@code key} must exist in the ClassMATE.
+ */
+ public void removeTutorialClass(TutorialClass key) {
+ tutorialClasses.remove(key);
+ }
+
+ /**
+ * Removes {@code key} from this {@code Classmate}.
+ * {@code key} must exist in the ClassMATE.
+ */
+ public void removeTutorialGroup(TutorialGroup key) {
+ tutorialClasses.remove(key);
+ }
+
+ /**
+ * Returns true if a tutorialGroup with the same identity as {@code tutorialGroup} exists in the ClassMATE.
+ */
+ public boolean hasTutorialGroup(TutorialGroup tutorialGroup) {
+ requireNonNull(tutorialGroup);
+ return tutorialClasses.contains(tutorialGroup);
+ }
+
+ /**
+ * Adds a tutorialGroup to the ClassMATE.
+ * The tutorial group must not already exist in the ClassMATE.
+ */
+ public void addTutorialGroup(TutorialGroup tutorialGroup) {
+ tutorialClasses.add(tutorialGroup);
+ }
+
+ /**
+ * Sorts the tutorial groups in ClassMATE.
+ */
+ public void sortTutorialGroups() {
+ tutorialClasses.sort();
+ }
+
+
+ //// util methods
+
+ @Override
+ public String toString() {
+ return students.asUnmodifiableObservableList().size() + " students";
+ }
+
+
+
+ @Override
+ public ObservableList getStudentList() {
+ return students.asUnmodifiableObservableList();
+ }
+
+ @Override
+ public ObservableList getTutorialClassList() {
+ return tutorialClasses.asUnmodifiableObservableList();
+ }
+
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Classmate // instanceof handles nulls
+ && students.equals(((Classmate) other).students));
+ }
+
+ @Override
+ public int hashCode() {
+ return students.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java
index d54df471c1f..8c1eef8e743 100644
--- a/src/main/java/seedu/address/model/Model.java
+++ b/src/main/java/seedu/address/model/Model.java
@@ -1,18 +1,24 @@
package seedu.address.model;
import java.nio.file.Path;
+import java.util.List;
import java.util.function.Predicate;
import javafx.collections.ObservableList;
import seedu.address.commons.core.GuiSettings;
-import seedu.address.model.person.Person;
+import seedu.address.model.student.Student;
+import seedu.address.model.tutorialclass.TutorialClass;
+import seedu.address.model.tutorialgroup.TutorialGroup;
/**
* The API of the Model component.
*/
public interface Model {
/** {@code Predicate} that always evaluate to true */
- Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true;
+ Predicate PREDICATE_SHOW_ALL_STUDENTS = unused -> true;
+
+ /** {@code Predicate} that always evaluate to true */
+ Predicate PREDICATE_SHOW_ALL_CLASSES = unused -> true;
/**
* Replaces user prefs data with the data in {@code userPrefs}.
@@ -35,53 +41,103 @@ public interface Model {
void setGuiSettings(GuiSettings guiSettings);
/**
- * Returns the user prefs' address book file path.
+ * Returns the user prefs' ClassMATE file path.
+ */
+ Path getClassmateFilePath();
+
+ /**
+ * Sets the user prefs' ClassMATE file path.
+ */
+ void setClassmateFilePath(Path classmateFilePath);
+
+ /**
+ * Replaces ClassMATE data with the data in {@code classmate}.
+ */
+ void setClassmate(ReadOnlyClassmate classmate);
+
+ /** Returns the Classmate */
+ ReadOnlyClassmate getClassmate();
+
+ /**
+ * Returns true if a student with the same identity as {@code student} exists in the Classmate.
+ */
+ boolean hasStudent(Student student);
+
+ /**
+ * Returns true if a tutorial class with the same identity as {@code tutorialClass} exists in Classmate.
+ */
+ boolean hasTutorialClass(TutorialClass tutorialClass);
+
+ /**
+ * Returns true if a tutorial group with the same identity as {@code tutorialGroup} exists in Classmate.
+ */
+ boolean hasTutorialGroup(TutorialGroup tutorialGroup);
+
+ /**
+ * Deletes the given student.
+ * The student must exist in Classmate.
*/
- Path getAddressBookFilePath();
+ void deleteStudent(Student target);
/**
- * Sets the user prefs' address book file path.
+ * Deletes the given class.
+ * The student must exist in Classmate.
*/
- void setAddressBookFilePath(Path addressBookFilePath);
+ void deleteTutorialClass(TutorialClass target);
/**
- * Replaces address book data with the data in {@code addressBook}.
+ * Deletes the given group.
+ * The TutorialGroup must exist in Classmate.
*/
- void setAddressBook(ReadOnlyAddressBook addressBook);
+ void deleteTutorialGroup(TutorialGroup target);
- /** Returns the AddressBook */
- ReadOnlyAddressBook getAddressBook();
+ /**
+ * Adds the given student.
+ * {@code student} must not already exist in the Classmate.
+ */
+ void addStudent(Student student);
/**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
+ * Adds the given class.
+ * {@code tutorialClass} must not already exist in Classmate.
*/
- boolean hasPerson(Person person);
+ void addTutorialClass(TutorialClass tutorialClass);
/**
- * Deletes the given person.
- * The person must exist in the address book.
+ * Adds the given group.
+ * {@code tutorialGroup} must not already exist in Classmate.
*/
- void deletePerson(Person target);
+ void addTutorialGroup(TutorialGroup tutorialGroup);
/**
- * Adds the given person.
- * {@code person} must not already exist in the address book.
+ * Sorts the tutorial groups.
*/
- void addPerson(Person person);
+ void sortTutorialGroups();
/**
- * 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.
+ * Replaces the given student {@code target} with {@code editedStudent}.
+ * {@code target} must exist in the ClassMATE.
+ * The student identity of {@code editedStudent} must not be the same as another existing student in ClassMATE.
*/
- void setPerson(Person target, Person editedPerson);
+ void setStudent(Student target, Student editedStudent);
+
+ /** Returns an unmodifiable view of the filtered student list */
+ ObservableList getFilteredStudentList();
+
+ /** Returns an unmodifiable view of the unfiltered student list */
+ ObservableList getUnfilteredStudentList();
- /** Returns an unmodifiable view of the filtered person list */
- ObservableList getFilteredPersonList();
+ /** Returns unmodifiable view of filtered Tutorial ClassList */
+ ObservableList getFilteredTutorialClassList();
/**
- * Updates the filter of the filtered person list to filter by the given {@code predicate}.
+ * Updates the filter of the filtered student list to filter by the given {@code predicate}.
* @throws NullPointerException if {@code predicate} is null.
*/
- void updateFilteredPersonList(Predicate predicate);
+ void updateFilteredStudentList(Predicate predicate);
+
+ void updateUnfilteredStudentList(List students);
+
+ void updateFilteredTutorialClassList(Predicate predicate);
+
}
diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java
index 0650c954f5c..069a04ddf67 100644
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ b/src/main/java/seedu/address/model/ModelManager.java
@@ -4,6 +4,7 @@
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
import java.nio.file.Path;
+import java.util.List;
import java.util.function.Predicate;
import java.util.logging.Logger;
@@ -11,34 +12,38 @@
import javafx.collections.transformation.FilteredList;
import seedu.address.commons.core.GuiSettings;
import seedu.address.commons.core.LogsCenter;
-import seedu.address.model.person.Person;
+import seedu.address.model.student.Student;
+import seedu.address.model.tutorialclass.TutorialClass;
+import seedu.address.model.tutorialgroup.TutorialGroup;
/**
- * Represents the in-memory model of the address book data.
+ * Represents the in-memory model of the ClassMATE data.
*/
public class ModelManager implements Model {
private static final Logger logger = LogsCenter.getLogger(ModelManager.class);
- private final AddressBook addressBook;
+ private final Classmate classmate;
private final UserPrefs userPrefs;
- private final FilteredList filteredPersons;
+ private final FilteredList filteredStudents;
+ private final FilteredList filteredTutorialClasses;
/**
- * Initializes a ModelManager with the given addressBook and userPrefs.
+ * Initializes a ModelManager with the given classmate and userPrefs.
*/
- public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) {
+ public ModelManager(ReadOnlyClassmate classmate, ReadOnlyUserPrefs userPrefs) {
super();
- requireAllNonNull(addressBook, userPrefs);
+ requireAllNonNull(classmate, userPrefs);
- logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs);
+ logger.fine("Initializing with ClassMATE: " + classmate + " and user prefs " + userPrefs);
- this.addressBook = new AddressBook(addressBook);
+ this.classmate = new Classmate(classmate);
this.userPrefs = new UserPrefs(userPrefs);
- filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
+ filteredStudents = new FilteredList<>(this.classmate.getStudentList());
+ filteredTutorialClasses = new FilteredList<>(this.classmate.getTutorialClassList());
}
public ModelManager() {
- this(new AddressBook(), new UserPrefs());
+ this(new Classmate(), new UserPrefs());
}
//=========== UserPrefs ==================================================================================
@@ -66,67 +71,125 @@ public void setGuiSettings(GuiSettings guiSettings) {
}
@Override
- public Path getAddressBookFilePath() {
- return userPrefs.getAddressBookFilePath();
+ public Path getClassmateFilePath() {
+ return userPrefs.getClassmateFilePath();
}
@Override
- public void setAddressBookFilePath(Path addressBookFilePath) {
- requireNonNull(addressBookFilePath);
- userPrefs.setAddressBookFilePath(addressBookFilePath);
+ public void setClassmateFilePath(Path classmateFilePath) {
+ requireNonNull(classmateFilePath);
+ userPrefs.setClassmateFilePath(classmateFilePath);
}
- //=========== AddressBook ================================================================================
+ //=========== Classmate ================================================================================
@Override
- public void setAddressBook(ReadOnlyAddressBook addressBook) {
- this.addressBook.resetData(addressBook);
+ public void setClassmate(ReadOnlyClassmate classmate) {
+ this.classmate.resetData(classmate);
}
@Override
- public ReadOnlyAddressBook getAddressBook() {
- return addressBook;
+ public ReadOnlyClassmate getClassmate() {
+ return classmate;
}
@Override
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return addressBook.hasPerson(person);
+ public boolean hasStudent(Student student) {
+ requireNonNull(student);
+ return classmate.hasStudent(student);
}
@Override
- public void deletePerson(Person target) {
- addressBook.removePerson(target);
+ public boolean hasTutorialClass(TutorialClass tutorialClass) {
+ requireAllNonNull(tutorialClass);
+ return classmate.hasTutorialClass(tutorialClass);
}
@Override
- public void addPerson(Person person) {
- addressBook.addPerson(person);
- updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ public boolean hasTutorialGroup(TutorialGroup tutorialGroup) {
+ requireAllNonNull(tutorialGroup);
+ return classmate.hasTutorialGroup(tutorialGroup);
}
@Override
- public void setPerson(Person target, Person editedPerson) {
- requireAllNonNull(target, editedPerson);
+ public void deleteStudent(Student target) {
+ classmate.removeStudent(target);
+ }
+
+ @Override
+ public void deleteTutorialClass(TutorialClass target) {
+ classmate.removeTutorialClass(target);
+ }
+
+ @Override
+ public void deleteTutorialGroup(TutorialGroup target) {
+ classmate.removeTutorialGroup(target);
+ }
+
+ @Override
+ public void addStudent(Student student) {
+ classmate.addStudent(student);
+ updateFilteredStudentList(PREDICATE_SHOW_ALL_STUDENTS);
+ }
+
+ @Override
+ public void addTutorialClass(TutorialClass tutorialClass) {
+ classmate.addTutorialClass(tutorialClass);
+ }
+
+ @Override
+ public void addTutorialGroup(TutorialGroup tutorialGroup) {
+ classmate.addTutorialGroup(tutorialGroup);
+ }
+
+ @Override
+ public void sortTutorialGroups() {
+ classmate.sortTutorialGroups();
+ }
- addressBook.setPerson(target, editedPerson);
+ @Override
+ public void setStudent(Student target, Student editedStudent) {
+ requireAllNonNull(target, editedStudent);
+
+ classmate.setStudent(target, editedStudent);
}
- //=========== Filtered Person List Accessors =============================================================
+ @Override
+ public ObservableList getUnfilteredStudentList() {
+ return classmate.getStudentList();
+ }
+
+ @Override
+ public ObservableList getFilteredTutorialClassList() {
+ return filteredTutorialClasses;
+ }
+
+ @Override
+ public void updateUnfilteredStudentList(List students) {
+ classmate.setStudents(students);
+ }
+
+ //=========== Filtered Student List Accessors =============================================================
/**
- * Returns an unmodifiable view of the list of {@code Person} backed by the internal list of
- * {@code versionedAddressBook}
+ * Returns an unmodifiable view of the list of {@code Student} backed by the internal list of
+ * {@code versionedClassmate}
*/
@Override
- public ObservableList getFilteredPersonList() {
- return filteredPersons;
+ public ObservableList getFilteredStudentList() {
+ return filteredStudents;
+ }
+
+ @Override
+ public void updateFilteredStudentList(Predicate predicate) {
+ requireNonNull(predicate);
+ filteredStudents.setPredicate(predicate);
}
@Override
- public void updateFilteredPersonList(Predicate predicate) {
+ public void updateFilteredTutorialClassList(Predicate predicate) {
requireNonNull(predicate);
- filteredPersons.setPredicate(predicate);
+ filteredTutorialClasses.setPredicate(predicate);
}
@Override
@@ -143,9 +206,9 @@ public boolean equals(Object obj) {
// state check
ModelManager other = (ModelManager) obj;
- return addressBook.equals(other.addressBook)
+ return classmate.equals(other.classmate)
&& userPrefs.equals(other.userPrefs)
- && filteredPersons.equals(other.filteredPersons);
+ && filteredStudents.equals(other.filteredStudents);
}
}
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/ReadOnlyClassmate.java b/src/main/java/seedu/address/model/ReadOnlyClassmate.java
new file mode 100644
index 00000000000..300500e6b6d
--- /dev/null
+++ b/src/main/java/seedu/address/model/ReadOnlyClassmate.java
@@ -0,0 +1,25 @@
+package seedu.address.model;
+
+import javafx.collections.ObservableList;
+import seedu.address.model.student.Student;
+import seedu.address.model.tutorialclass.TutorialClass;
+//import seedu.address.model.tutorialclass.TutorialClass;
+
+/**
+ * Unmodifiable view of an ClassMATE
+ */
+public interface ReadOnlyClassmate {
+
+ /**
+ * Returns an unmodifiable view of the students list.
+ * This list will not contain any duplicate students.
+ */
+ ObservableList getStudentList();
+
+ /**
+ * Returns an unmodifiable view of the tutorial classes list.
+ * This list will not contain any duplicate tutorial classes.
+ */
+ ObservableList getTutorialClassList();
+
+}
diff --git a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java b/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
index befd58a4c73..7a189ed1a81 100644
--- a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
+++ b/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
@@ -11,6 +11,6 @@ public interface ReadOnlyUserPrefs {
GuiSettings getGuiSettings();
- Path getAddressBookFilePath();
+ Path getClassmateFilePath();
}
diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/address/model/UserPrefs.java
index 25a5fd6eab9..22133965d89 100644
--- a/src/main/java/seedu/address/model/UserPrefs.java
+++ b/src/main/java/seedu/address/model/UserPrefs.java
@@ -14,7 +14,7 @@
public class UserPrefs implements ReadOnlyUserPrefs {
private GuiSettings guiSettings = new GuiSettings();
- private Path addressBookFilePath = Paths.get("data" , "addressbook.json");
+ private Path classmateFilePath = Paths.get("data" , "classmate.json");
/**
* Creates a {@code UserPrefs} with default values.
@@ -35,7 +35,7 @@ public UserPrefs(ReadOnlyUserPrefs userPrefs) {
public void resetData(ReadOnlyUserPrefs newUserPrefs) {
requireNonNull(newUserPrefs);
setGuiSettings(newUserPrefs.getGuiSettings());
- setAddressBookFilePath(newUserPrefs.getAddressBookFilePath());
+ setClassmateFilePath(newUserPrefs.getClassmateFilePath());
}
public GuiSettings getGuiSettings() {
@@ -47,13 +47,13 @@ public void setGuiSettings(GuiSettings guiSettings) {
this.guiSettings = guiSettings;
}
- public Path getAddressBookFilePath() {
- return addressBookFilePath;
+ public Path getClassmateFilePath() {
+ return classmateFilePath;
}
- public void setAddressBookFilePath(Path addressBookFilePath) {
- requireNonNull(addressBookFilePath);
- this.addressBookFilePath = addressBookFilePath;
+ public void setClassmateFilePath(Path classmateFilePath) {
+ requireNonNull(classmateFilePath);
+ this.classmateFilePath = classmateFilePath;
}
@Override
@@ -68,19 +68,19 @@ public boolean equals(Object other) {
UserPrefs o = (UserPrefs) other;
return guiSettings.equals(o.guiSettings)
- && addressBookFilePath.equals(o.addressBookFilePath);
+ && classmateFilePath.equals(o.classmateFilePath);
}
@Override
public int hashCode() {
- return Objects.hash(guiSettings, addressBookFilePath);
+ return Objects.hash(guiSettings, classmateFilePath);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Gui Settings : " + guiSettings);
- sb.append("\nLocal data file location : " + addressBookFilePath);
+ sb.append("\nLocal data file location : " + classmateFilePath);
return sb.toString();
}
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java
deleted file mode 100644
index 8ff1d83fe89..00000000000
--- a/src/main/java/seedu/address/model/person/Person.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package seedu.address.model.person;
-
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
-
-import seedu.address.model.tag.Tag;
-
-/**
- * Represents a Person in the address book.
- * Guarantees: details are present and not null, field values are validated, immutable.
- */
-public class Person {
-
- // Identity fields
- private final Name name;
- private final Phone phone;
- private final Email email;
-
- // Data fields
- private final Address address;
- private final Set tags = new HashSet<>();
-
- /**
- * Every field must be present and not null.
- */
- public Person(Name name, Phone phone, Email email, Address address, Set tags) {
- requireAllNonNull(name, phone, email, address, tags);
- this.name = name;
- this.phone = phone;
- this.email = email;
- this.address = address;
- this.tags.addAll(tags);
- }
-
- public Name getName() {
- return name;
- }
-
- public Phone getPhone() {
- return phone;
- }
-
- public Email getEmail() {
- return email;
- }
-
- public Address getAddress() {
- return address;
- }
-
- /**
- * Returns an immutable tag set, which throws {@code UnsupportedOperationException}
- * if modification is attempted.
- */
- public Set getTags() {
- return Collections.unmodifiableSet(tags);
- }
-
- /**
- * Returns true if both persons have the same name.
- * This defines a weaker notion of equality between two persons.
- */
- public boolean isSamePerson(Person otherPerson) {
- if (otherPerson == this) {
- return true;
- }
-
- return otherPerson != null
- && otherPerson.getName().equals(getName());
- }
-
- /**
- * Returns true if both persons have the same identity and data fields.
- * This defines a stronger notion of equality between two persons.
- */
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- if (!(other instanceof Person)) {
- return false;
- }
-
- Person otherPerson = (Person) other;
- return otherPerson.getName().equals(getName())
- && otherPerson.getPhone().equals(getPhone())
- && otherPerson.getEmail().equals(getEmail())
- && otherPerson.getAddress().equals(getAddress())
- && otherPerson.getTags().equals(getTags());
- }
-
- @Override
- public int hashCode() {
- // use this method for custom fields hashing instead of implementing your own
- return Objects.hash(name, phone, email, address, tags);
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append(getName())
- .append("; Phone: ")
- .append(getPhone())
- .append("; Email: ")
- .append(getEmail())
- .append("; Address: ")
- .append(getAddress());
-
- Set tags = getTags();
- if (!tags.isEmpty()) {
- builder.append("; Tags: ");
- tags.forEach(builder::append);
- }
- return builder.toString();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java
deleted file mode 100644
index 0fee4fe57e6..00000000000
--- a/src/main/java/seedu/address/model/person/UniquePersonList.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.util.Iterator;
-import java.util.List;
-
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import seedu.address.model.person.exceptions.DuplicatePersonException;
-import seedu.address.model.person.exceptions.PersonNotFoundException;
-
-/**
- * A list of persons that enforces uniqueness between its elements and does not allow nulls.
- * A person is considered unique by comparing using {@code Person#isSamePerson(Person)}. As such, adding and updating of
- * persons uses Person#isSamePerson(Person) for equality so as to ensure that the person being added or updated is
- * unique in terms of identity in the UniquePersonList. However, the removal of a person uses Person#equals(Object) so
- * as to ensure that the person with exactly the same fields will be removed.
- *
- * Supports a minimal set of list operations.
- *
- * @see Person#isSamePerson(Person)
- */
-public class UniquePersonList implements Iterable {
-
- private final ObservableList internalList = FXCollections.observableArrayList();
- private final ObservableList internalUnmodifiableList =
- FXCollections.unmodifiableObservableList(internalList);
-
- /**
- * Returns true if the list contains an equivalent person as the given argument.
- */
- public boolean contains(Person toCheck) {
- requireNonNull(toCheck);
- return internalList.stream().anyMatch(toCheck::isSamePerson);
- }
-
- /**
- * Adds a person to the list.
- * The person must not already exist in the list.
- */
- public void add(Person toAdd) {
- requireNonNull(toAdd);
- if (contains(toAdd)) {
- throw new DuplicatePersonException();
- }
- internalList.add(toAdd);
- }
-
- /**
- * Replaces the person {@code target} in the list with {@code editedPerson}.
- * {@code target} must exist in the list.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the list.
- */
- public void setPerson(Person target, Person editedPerson) {
- requireAllNonNull(target, editedPerson);
-
- int index = internalList.indexOf(target);
- if (index == -1) {
- throw new PersonNotFoundException();
- }
-
- if (!target.isSamePerson(editedPerson) && contains(editedPerson)) {
- throw new DuplicatePersonException();
- }
-
- internalList.set(index, editedPerson);
- }
-
- /**
- * Removes the equivalent person from the list.
- * The person must exist in the list.
- */
- public void remove(Person toRemove) {
- requireNonNull(toRemove);
- if (!internalList.remove(toRemove)) {
- throw new PersonNotFoundException();
- }
- }
-
- public void setPersons(UniquePersonList replacement) {
- requireNonNull(replacement);
- internalList.setAll(replacement.internalList);
- }
-
- /**
- * Replaces the contents of this list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
- */
- public void setPersons(List persons) {
- requireAllNonNull(persons);
- if (!personsAreUnique(persons)) {
- throw new DuplicatePersonException();
- }
-
- internalList.setAll(persons);
- }
-
- /**
- * Returns the backing list as an unmodifiable {@code ObservableList}.
- */
- public ObservableList asUnmodifiableObservableList() {
- return internalUnmodifiableList;
- }
-
- @Override
- public Iterator iterator() {
- return internalList.iterator();
- }
-
- @Override
- public boolean equals(Object other) {
- return other == this // short circuit if same object
- || (other instanceof UniquePersonList // instanceof handles nulls
- && internalList.equals(((UniquePersonList) other).internalList));
- }
-
- @Override
- public int hashCode() {
- return internalList.hashCode();
- }
-
- /**
- * Returns true if {@code persons} contains only unique persons.
- */
- private boolean personsAreUnique(List persons) {
- for (int i = 0; i < persons.size() - 1; i++) {
- for (int j = i + 1; j < persons.size(); j++) {
- if (persons.get(i).isSamePerson(persons.get(j))) {
- return false;
- }
- }
- }
- return true;
- }
-}
diff --git a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java b/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
deleted file mode 100644
index d7290f59442..00000000000
--- a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package seedu.address.model.person.exceptions;
-
-/**
- * Signals that the operation will result in duplicate Persons (Persons are considered duplicates if they have the same
- * identity).
- */
-public class DuplicatePersonException extends RuntimeException {
- public DuplicatePersonException() {
- super("Operation would result in duplicate persons");
- }
-}
diff --git a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java b/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
deleted file mode 100644
index fa764426ca7..00000000000
--- a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package seedu.address.model.person.exceptions;
-
-/**
- * Signals that the operation is unable to find the specified person.
- */
-public class PersonNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/student/Address.java
similarity index 90%
rename from src/main/java/seedu/address/model/person/Address.java
rename to src/main/java/seedu/address/model/student/Address.java
index 60472ca22a0..bc85ed3a4e0 100644
--- a/src/main/java/seedu/address/model/person/Address.java
+++ b/src/main/java/seedu/address/model/student/Address.java
@@ -1,10 +1,10 @@
-package seedu.address.model.person;
+package seedu.address.model.student;
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's address in the address book.
+ * Represents a Student's address in the ClassMATE.
* Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)}
*/
public class Address {
@@ -31,7 +31,7 @@ public Address(String address) {
}
/**
- * Returns true if a given string is a valid email.
+ * Returns true if a given string is a valid address.
*/
public static boolean isValidAddress(String test) {
return test.matches(VALIDATION_REGEX);
diff --git a/src/main/java/seedu/address/model/student/ClassCode.java b/src/main/java/seedu/address/model/student/ClassCode.java
new file mode 100644
index 00000000000..c2478668f75
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/ClassCode.java
@@ -0,0 +1,68 @@
+package seedu.address.model.student;
+
+import static java.lang.Integer.parseInt;
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+
+/**
+ * Represents a Student's classcode in the ClassMATE.
+ * Guarantees: immutable.
+ */
+
+public class ClassCode implements Comparable {
+
+ public static final String MESSAGE_CONSTRAINTS = "ClassCode must start with G, "
+ + "followed by a 2-digit non-zero number and it should not be blank";
+
+ public static final String MESSAGE_EMPTY_CLASS = "The classcode is invalid. Choose a classcode between G01 and G99";
+
+ public static final String VALIDATION_REGEX = "[G]\\d{2}";
+
+ public final String value;
+
+ /**
+ * Constructs an {@code ClassCode}.
+ *
+ * @param classCode A valid classcode.
+ */
+ public ClassCode (String classCode) {
+ requireNonNull(classCode);
+ checkArgument(isValidClassCode(classCode), MESSAGE_CONSTRAINTS);
+ value = classCode;
+ }
+
+ /**
+ * Returns true if a given string is a valid classCode.
+ */
+ public static boolean isValidClassCode(String test) {
+ boolean value = test.matches(VALIDATION_REGEX);
+ return value;
+ }
+
+ public static boolean isDefaultClassCode(String test) {
+ return test.equals("G00");
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ClassCode // instanceof handles nulls
+ && value.equals(((ClassCode) other).value)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ @Override
+ public int compareTo(ClassCode classCode) {
+ return Integer.compare(parseInt(this.value.substring(1)), parseInt(classCode.value.substring(1)));
+ }
+}
diff --git a/src/main/java/seedu/address/model/student/ClassMemberPredicate.java b/src/main/java/seedu/address/model/student/ClassMemberPredicate.java
new file mode 100644
index 00000000000..6738298f76e
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/ClassMemberPredicate.java
@@ -0,0 +1,30 @@
+package seedu.address.model.student;
+
+import java.util.function.Predicate;
+
+/**
+ * Tests that a {@code Student}'s {@code Classcode} matches the given classcode.
+ */
+public class ClassMemberPredicate implements Predicate {
+ private final ClassCode classCode;
+
+ public ClassMemberPredicate(ClassCode classCode) {
+ this.classCode = classCode;
+ }
+
+ public ClassCode getClassCode() {
+ return classCode;
+ }
+
+ @Override
+ public boolean test(Student student) {
+ return student.getClassCode().equals(classCode);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same instance
+ || other instanceof ClassMemberPredicate // instanceof handles null
+ && classCode.equals(((ClassMemberPredicate) other).getClassCode()); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/seedu/address/model/student/Email.java
similarity index 97%
rename from src/main/java/seedu/address/model/person/Email.java
rename to src/main/java/seedu/address/model/student/Email.java
index f866e7133de..8bdf394723d 100644
--- a/src/main/java/seedu/address/model/person/Email.java
+++ b/src/main/java/seedu/address/model/student/Email.java
@@ -1,10 +1,10 @@
-package seedu.address.model.person;
+package seedu.address.model.student;
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's email in the address book.
+ * Represents a Student's email in the ClassMATE.
* Guarantees: immutable; is valid as declared in {@link #isValidEmail(String)}
*/
public class Email {
diff --git a/src/main/java/seedu/address/model/student/EmptyClassCode.java b/src/main/java/seedu/address/model/student/EmptyClassCode.java
new file mode 100644
index 00000000000..2efd7734785
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/EmptyClassCode.java
@@ -0,0 +1,24 @@
+package seedu.address.model.student;
+
+public class EmptyClassCode extends ClassCode {
+
+ public static final String EMPTY_CLASSCODE = "G00";
+
+ /**
+ * Constructs an {@code EmptyClassCode}.
+ */
+ public EmptyClassCode() {
+ super(EMPTY_CLASSCODE);
+ }
+
+ public static boolean isDefaultClassCode(String test) {
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return this == other
+ || other instanceof EmptyClassCode
+ || ((ClassCode) other).value.equals(this.value);
+ }
+}
diff --git a/src/main/java/seedu/address/model/student/GroupMemberPredicate.java b/src/main/java/seedu/address/model/student/GroupMemberPredicate.java
new file mode 100644
index 00000000000..a802086cee2
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/GroupMemberPredicate.java
@@ -0,0 +1,32 @@
+package seedu.address.model.student;
+
+import java.util.function.Predicate;
+
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Tests that a {@code Student}'s {@code TutorialGroup} matches the given TutorialGroup.
+ */
+public class GroupMemberPredicate implements Predicate {
+ private final TutorialGroup tutorialGroup;
+
+ public GroupMemberPredicate(TutorialGroup tutorialGroup) {
+ this.tutorialGroup = tutorialGroup;
+ }
+
+ public TutorialGroup getTutorialGroup() {
+ return tutorialGroup;
+ }
+
+ @Override
+ public boolean test(Student student) {
+ return student.getTutorialGroups().contains(tutorialGroup);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same instance
+ || other instanceof GroupMemberPredicate // instanceof handles null
+ && tutorialGroup.equals(((GroupMemberPredicate) other).getTutorialGroup()); // state check
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/seedu/address/model/student/Name.java
similarity index 72%
rename from src/main/java/seedu/address/model/person/Name.java
rename to src/main/java/seedu/address/model/student/Name.java
index 79244d71cf7..fdb647531ec 100644
--- a/src/main/java/seedu/address/model/person/Name.java
+++ b/src/main/java/seedu/address/model/student/Name.java
@@ -1,22 +1,23 @@
-package seedu.address.model.person;
+package seedu.address.model.student;
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's name in the address book.
+ * Represents a Student's name in the ClassMATE.
* Guarantees: immutable; is valid as declared in {@link #isValidName(String)}
*/
public class Name {
public static final String MESSAGE_CONSTRAINTS =
- "Names should only contain alphanumeric characters and spaces, and it should not be blank";
+ "Names should only contain alphanumeric characters, accented characters, hyphens, apostrophes and spaces,"
+ + " and it should not be blank";
/*
* The first character of the address must not be a whitespace,
* otherwise " " (a blank string) becomes a valid input.
*/
- public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
+ public static final String VALIDATION_REGEX = "[\\p{Alnum}À-ÿ'\\-][\\p{Alnum}À-ÿ'\\- ]*";
public final String fullName;
@@ -48,7 +49,7 @@ public String toString() {
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof Name // instanceof handles nulls
- && fullName.equals(((Name) other).fullName)); // state check
+ && fullName.toLowerCase().equals(((Name) other).fullName.toLowerCase())); // state check
}
@Override
diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/student/NameContainsKeywordsPredicate.java
similarity index 77%
rename from src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
rename to src/main/java/seedu/address/model/student/NameContainsKeywordsPredicate.java
index c9b5868427c..b036ed35273 100644
--- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
+++ b/src/main/java/seedu/address/model/student/NameContainsKeywordsPredicate.java
@@ -1,4 +1,4 @@
-package seedu.address.model.person;
+package seedu.address.model.student;
import java.util.List;
import java.util.function.Predicate;
@@ -6,9 +6,9 @@
import seedu.address.commons.util.StringUtil;
/**
- * Tests that a {@code Person}'s {@code Name} matches any of the keywords given.
+ * Tests that a {@code Student}'s {@code Name} matches any of the keywords given.
*/
-public class NameContainsKeywordsPredicate implements Predicate {
+public class NameContainsKeywordsPredicate implements Predicate {
private final List keywords;
public NameContainsKeywordsPredicate(List keywords) {
@@ -16,9 +16,9 @@ public NameContainsKeywordsPredicate(List keywords) {
}
@Override
- public boolean test(Person person) {
+ public boolean test(Student student) {
return keywords.stream()
- .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword));
+ .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(student.getName().fullName, keyword));
}
@Override
diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/seedu/address/model/student/Phone.java
similarity index 93%
rename from src/main/java/seedu/address/model/person/Phone.java
rename to src/main/java/seedu/address/model/student/Phone.java
index 872c76b382f..586ed7ae97a 100644
--- a/src/main/java/seedu/address/model/person/Phone.java
+++ b/src/main/java/seedu/address/model/student/Phone.java
@@ -1,10 +1,10 @@
-package seedu.address.model.person;
+package seedu.address.model.student;
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's phone number in the address book.
+ * Represents a Student's phone number in the ClassMATE.
* Guarantees: immutable; is valid as declared in {@link #isValidPhone(String)}
*/
public class Phone {
diff --git a/src/main/java/seedu/address/model/student/Student.java b/src/main/java/seedu/address/model/student/Student.java
new file mode 100644
index 00000000000..73b6f664d6d
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/Student.java
@@ -0,0 +1,197 @@
+package seedu.address.model.student;
+
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import seedu.address.model.tag.Tag;
+import seedu.address.model.tutorialgroup.GroupType;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Represents a Student in the ClassMATE.
+ * Guarantees: details are present and not null, field values are validated, immutable.
+ */
+public class Student {
+
+ // Identity fields
+ private final Name name;
+ private final Phone phone;
+ private final Email email;
+
+ // Data fields
+ private final Address address;
+ private final ClassCode classCode;
+ private final List marks;
+ private final Set tags = new HashSet<>();
+ private final Set tutorialGroups = new HashSet<>();
+
+ /**
+ * Every field must be present and not null.
+ */
+ public Student(Name name, Phone phone, Email email, Address address, ClassCode classCode, Set tags,
+ List marks, Set tutorialGroups) {
+ requireAllNonNull(name, phone, email, address, classCode, tags);
+ this.name = name;
+ this.phone = phone;
+ this.email = email;
+ this.address = address;
+ this.classCode = classCode;
+ this.marks = marks;
+ this.tags.addAll(tags);
+ this.tutorialGroups.addAll(tutorialGroups);
+ }
+
+ public Name getName() {
+ return name;
+ }
+
+ public Phone getPhone() {
+ return phone;
+ }
+
+ public Email getEmail() {
+ return email;
+ }
+
+ public Address getAddress() {
+ return address;
+ }
+
+ public ClassCode getClassCode() {
+ return classCode;
+ }
+
+ /**
+ * Returns an immutable tag set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ */
+ public Set getTags() {
+ return Collections.unmodifiableSet(tags);
+ }
+
+ /**
+ * Returns an immutable tutorial group set, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ */
+ public Set getTutorialGroups() {
+ return Collections.unmodifiableSet(tutorialGroups);
+ }
+
+ /**
+ * Returns an immutable list, which throws {@code UnsupportedOperationException}
+ * if modification is attempted.
+ */
+ public List getMarks() {
+ return Collections.unmodifiableList(marks);
+ }
+
+ /**
+ * Returns true if both students have the same name.
+ * This defines a weaker notion of equality between two students.
+ */
+ public boolean isSameStudent(Student otherStudent) {
+ if (otherStudent == this) {
+ return true;
+ }
+
+ return otherStudent != null
+ && this.equals(otherStudent);
+ }
+
+ /**
+ * Returns true if student is already in a OP group type.
+ * Checks whether student is added to multiple groups of the same type.
+ * @param groupType
+ * @return whether {@code Student} is already in
+ */
+ public boolean hasTutorialGroupType(GroupType groupType) {
+ for (TutorialGroup group : tutorialGroups) {
+ if (group.getGroupType().equals(groupType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if student belongs to the tutorial gorup.
+ *
+ * @param tutorialGroup The given tutorial group to check.
+ * @return whether {@code Student} is already in the tutorial group
+ */
+ public boolean isBelongTutorialGroup(TutorialGroup tutorialGroup) {
+ for (TutorialGroup group : tutorialGroups) {
+ if (group.isSameTutorialGroup(tutorialGroup)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if both students have the same identity and data fields.
+ * This defines a stronger notion of equality between two students.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof Student)) {
+ return false;
+ }
+
+ Student otherStudent = (Student) other;
+ return otherStudent.getName().equals(getName())
+ && otherStudent.getPhone().equals(getPhone())
+ && otherStudent.getEmail().equals(getEmail())
+ && otherStudent.getAddress().equals(getAddress())
+ && otherStudent.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, classCode, 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())
+ .append("; ClassCode: ")
+ .append(getClassCode());
+
+ Set tags = getTags();
+ if (!tags.isEmpty()) {
+ builder.append("; Tags: ");
+ tags.forEach(builder::append);
+ }
+
+ Set tutorialGroups = getTutorialGroups();
+ if (!tutorialGroups.isEmpty()) {
+ builder.append("; TutorialGroups: ");
+ tutorialGroups.forEach(builder::append);
+ }
+
+ List studentMarks = getMarks();
+ if (!studentMarks.isEmpty()) {
+ builder.append("; Marks: ");
+ studentMarks.forEach(mark -> builder.append(mark).append(" "));
+ }
+ return builder.toString();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/student/StudentMark.java b/src/main/java/seedu/address/model/student/StudentMark.java
new file mode 100644
index 00000000000..1fe42c4f58c
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/StudentMark.java
@@ -0,0 +1,20 @@
+package seedu.address.model.student;
+
+public enum StudentMark {
+ POOR(0),
+ LOW(1),
+ AVG(2),
+ GOOD(3),
+ HIGH(4),
+ EXCELLENT(5);
+
+ public static final String MESSAGE_CONSTRAINTS = "Mark can only be within range:\n"
+ + "Poor, Low, Avg, Good, High, Excellent";
+
+ private final int mark;
+
+ StudentMark(int mark) {
+ this.mark = mark;
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/student/UniqueStudentList.java b/src/main/java/seedu/address/model/student/UniqueStudentList.java
new file mode 100644
index 00000000000..ed2aafd3dad
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/UniqueStudentList.java
@@ -0,0 +1,137 @@
+package seedu.address.model.student;
+
+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.student.exceptions.DuplicateStudentException;
+import seedu.address.model.student.exceptions.StudentNotFoundException;
+
+/**
+ * A list of students that enforces uniqueness between its elements and does not allow nulls.
+ * A student is considered unique by comparing using {@code Student#isSameStudent(Student)}. As such, adding and
+ * updating of students uses Student#isSameStudent(Student) for equality to ensure that the student being added or
+ * updated is unique in terms of identity in the UniqueStudentList. However, the removal of a student uses
+ * Student#equals(Object) to ensure that the student with exactly the same fields will be removed.
+ *
+ * Supports a minimal set of list operations.
+ *
+ * @see Student#isSameStudent(Student)
+ */
+public class UniqueStudentList implements Iterable {
+
+ private final ObservableList internalList = FXCollections.observableArrayList();
+ private final ObservableList internalUnmodifiableList =
+ FXCollections.unmodifiableObservableList(internalList);
+
+ /**
+ * Returns true if the list contains an equivalent student as the given argument.
+ */
+ public boolean contains(Student toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::isSameStudent);
+ }
+
+ /**
+ * Adds a student to the list.
+ * The student must not already exist in the list.
+ */
+ public void add(Student toAdd) {
+ requireNonNull(toAdd);
+ if (contains(toAdd)) {
+ throw new DuplicateStudentException();
+ }
+ internalList.add(toAdd);
+ }
+
+ /**
+ * Replaces the student {@code target} in the list with {@code editedStudent}.
+ * {@code target} must exist in the list.
+ * The student identity of {@code editedStudent} must not be the same as another existing student in the list.
+ */
+ public void setStudent(Student target, Student editedStudent) {
+ requireAllNonNull(target, editedStudent);
+
+ int index = internalList.indexOf(target);
+ if (index == -1) {
+ throw new StudentNotFoundException();
+ }
+
+ if (!target.isSameStudent(editedStudent) && contains(editedStudent)) {
+ throw new DuplicateStudentException();
+ }
+
+ internalList.set(index, editedStudent);
+ }
+
+ /**
+ * Removes the equivalent student from the list.
+ * The student must exist in the list.
+ */
+ public void remove(Student toRemove) {
+ requireNonNull(toRemove);
+ if (!internalList.remove(toRemove)) {
+ throw new StudentNotFoundException();
+ }
+ }
+
+ public void setStudents(UniqueStudentList replacement) {
+ requireNonNull(replacement);
+ internalList.setAll(replacement.internalList);
+ }
+
+ /**
+ * Replaces the contents of this list with {@code students}.
+ * {@code students} must not contain duplicate students.
+ */
+ public void setStudents(List students) {
+ requireAllNonNull(students);
+ if (!studentsAreUnique(students)) {
+ throw new DuplicateStudentException();
+ }
+
+ internalList.setAll(students);
+ }
+
+ /**
+ * 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 UniqueStudentList // instanceof handles nulls
+ && internalList.equals(((UniqueStudentList) other).internalList));
+ }
+
+ @Override
+ public int hashCode() {
+ return internalList.hashCode();
+ }
+
+ /**
+ * Returns true if {@code students} contains only unique students.
+ */
+ private boolean studentsAreUnique(List students) {
+ for (int i = 0; i < students.size() - 1; i++) {
+ for (int j = i + 1; j < students.size(); j++) {
+ if (students.get(i).isSameStudent(students.get(j))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/seedu/address/model/student/exceptions/DuplicateStudentException.java b/src/main/java/seedu/address/model/student/exceptions/DuplicateStudentException.java
new file mode 100644
index 00000000000..d1a8f9ce635
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/exceptions/DuplicateStudentException.java
@@ -0,0 +1,11 @@
+package seedu.address.model.student.exceptions;
+
+/**
+ * Signals that the operation will result in duplicate Students (Students are considered duplicates if they have the
+ * same identity).
+ */
+public class DuplicateStudentException extends RuntimeException {
+ public DuplicateStudentException() {
+ super("Operation would result in duplicate students");
+ }
+}
diff --git a/src/main/java/seedu/address/model/student/exceptions/StudentNotFoundException.java b/src/main/java/seedu/address/model/student/exceptions/StudentNotFoundException.java
new file mode 100644
index 00000000000..2b41e9e0296
--- /dev/null
+++ b/src/main/java/seedu/address/model/student/exceptions/StudentNotFoundException.java
@@ -0,0 +1,6 @@
+package seedu.address.model.student.exceptions;
+
+/**
+ * Signals that the operation is unable to find the specified student.
+ */
+public class StudentNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/address/model/tag/Tag.java
index b0ea7e7dad7..8deca2e2ad8 100644
--- a/src/main/java/seedu/address/model/tag/Tag.java
+++ b/src/main/java/seedu/address/model/tag/Tag.java
@@ -4,7 +4,7 @@
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Tag in the address book.
+ * Represents a Tag in the ClassMATE.
* Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String)}
*/
public class Tag {
diff --git a/src/main/java/seedu/address/model/tutorialclass/ClassCodeContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/tutorialclass/ClassCodeContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..e0cbf40c15b
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialclass/ClassCodeContainsKeywordsPredicate.java
@@ -0,0 +1,32 @@
+package seedu.address.model.tutorialclass;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.StringUtil;
+
+/**
+ * Tests that a {@code TutorialClass}'s {@code ClassCode} matches any of the keywords given.
+ */
+public class ClassCodeContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public ClassCodeContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(TutorialClass tutorialClass) {
+ return keywords.stream()
+ .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(
+ tutorialClass.getClassCode().toString(), keyword));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof ClassCodeContainsKeywordsPredicate // instanceof handles nulls
+ && keywords.equals(((ClassCodeContainsKeywordsPredicate) other).keywords)); // state check
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/tutorialclass/Schedule.java b/src/main/java/seedu/address/model/tutorialclass/Schedule.java
new file mode 100644
index 00000000000..3ebcb3bef6d
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialclass/Schedule.java
@@ -0,0 +1,69 @@
+package seedu.address.model.tutorialclass;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+/**
+ *
+ *
+ */
+public class Schedule {
+ public static final String MESSAGE_CONSTRAINTS =
+ "Schedules should follow the format 'day-of-the-week starttime[(hh:mm)am/pm] to endtime[(hh:mm)am/pm]', "
+ + "and different days must be separated by commas. \n"
+ + "Schedule must contain exactly two days\n"
+ + "e.g. Tues 12:00pm to 2:00pm, Friday 12:00pm to 2:00pm";
+
+ private static final String SPLIT_REGEX = "[,\n]";
+ private static final String TIME_REGEX = "((1[0-2]|0?[1-9]):([0-5][0-9]) ?([AaPp][Mm]))";
+ private static final String DAY_OF_THE_WEEK_REGEX = "((Mon|Tues|Wed(nes)?|Thur(s)?|Fri|Sat(ur)?|Sun)(day)?)";
+
+ private static final String VALIDATION_REGEX = DAY_OF_THE_WEEK_REGEX + " " + TIME_REGEX + " to " + TIME_REGEX;
+
+ public final String value;
+
+ /**
+ * Constructor for Schedule class.
+ * @param value String containing class schedule.
+ */
+ public Schedule(String value) {
+ requireNonNull(value);
+ checkArgument(isValidSchedule(value), MESSAGE_CONSTRAINTS);
+ this.value = value;
+ }
+
+ /**
+ * Checks validity of input string.
+ *
+ * @param test Test string.
+ * @return validity of input schedule string.
+ */
+ public static boolean isValidSchedule(String test) {
+ String[] timeslots = test.split(SPLIT_REGEX);
+ if (timeslots.length != 2) {
+ return false;
+ }
+ for (String timeslot : timeslots) {
+ if (!timeslot.trim().matches(VALIDATION_REGEX)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof Schedule // instanceof handles nulls
+ && value.equals(((Schedule) other).value)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return this.value.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/tutorialclass/TutorialClass.java b/src/main/java/seedu/address/model/tutorialclass/TutorialClass.java
new file mode 100644
index 00000000000..4af14610b51
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialclass/TutorialClass.java
@@ -0,0 +1,175 @@
+package seedu.address.model.tutorialclass;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import javafx.collections.ObservableList;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.tag.Tag;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+import seedu.address.model.tutorialgroup.UniqueTutorialGroupList;
+
+/**
+ * Represents a tutorial class in the Classmate.
+ * Guarantees: details are present and not null, fields are validated and immutable.
+ *
+ */
+public class TutorialClass {
+
+ // Class Fields
+ private final ClassCode classCode;
+ private final Schedule schedule;
+ private UniqueTutorialGroupList tutorialGroups;
+ private final Set tags = new HashSet<>();
+
+ /**
+ * @param classCode ClassCode of Tutorial Class.
+ * @param schedule Class Schedule.
+ * @param tags Optional tags.
+ */
+ public TutorialClass(ClassCode classCode, Schedule schedule, Set tags) {
+ this.classCode = classCode;
+ this.schedule = schedule;
+ this.tutorialGroups = new UniqueTutorialGroupList();
+ this.tags.addAll(tags);
+ }
+
+ /**
+ * Constructor that is called when initializing the Tutorial class from storage.
+ *
+ * @param classCode ClassCode of Tutorial Class.
+ * @param schedule Class Schedule.
+ * @param tutorialGroups List of Tutorial Groups
+ * @param tags Optional tags.
+ */
+ public TutorialClass(ClassCode classCode, Schedule schedule, List tutorialGroups, Set tags) {
+ this.classCode = classCode;
+ this.schedule = schedule;
+ this.tutorialGroups = new UniqueTutorialGroupList();
+ for (TutorialGroup tutorialGroup : tutorialGroups) {
+ this.tutorialGroups.add(tutorialGroup);
+ }
+ this.tags.addAll(tags);
+ }
+
+ /**
+ * Creates a tutorial class for checking.
+ * @param classCode ClassCode of TutorialClass for checking.
+ * @return The TutorialClass with a ClassCode.
+ */
+ public static TutorialClass createTestTutorialClass(ClassCode classCode) {
+ return new TutorialClass(classCode, new Schedule("Tuesday 12:00pm to 2:00pm, Friday 12:00pm to 2:00pm"),
+ new HashSet());
+ }
+
+ public ClassCode getClassCode() {
+ return classCode;
+ }
+
+ public Schedule getSchedule() {
+ return schedule;
+ }
+
+ public UniqueTutorialGroupList getTutorialGroups() {
+ return tutorialGroups;
+ }
+
+ /**
+ * Converts the UniqueTutorialGroupList to List to be used for storage
+ *
+ * @return List of tutorial groups
+ */
+ public ObservableList getTutorialGroupsAsList() {
+ return tutorialGroups.asUnmodifiableObservableList();
+ }
+
+ public Set getTags() {
+ return Collections.unmodifiableSet(tags);
+ }
+
+ /**
+ * Returns true if both tutorial classes have the same name.
+ * This defines a weaker notion of equality between two tutorial classes.
+ */
+ public boolean isSameTutorialClass(TutorialClass otherClass) {
+ if (otherClass == this) {
+ return true;
+ }
+
+ return otherClass != null
+ && otherClass.getClassCode().equals(getClassCode());
+
+ }
+
+ /**
+ * Returns true if a student with the same identity as {@code student} exists in the ClassMATE.
+ */
+ public boolean contains(TutorialGroup tutorialGroup) {
+ requireNonNull(tutorialGroup);
+ return tutorialGroups.contains(tutorialGroup);
+ }
+
+ /**
+ * Adds a student to the ClassMATE.
+ * The student must not already exist in the ClassMATE.
+ */
+ public void addTutorialGroup(TutorialGroup tutorialGroup) {
+ tutorialGroups.add(tutorialGroup);
+ }
+
+ /**
+ * Sorts the tutorial groups in ClassMATE.
+ */
+ public void sortTutorialGroups() {
+ tutorialGroups.sort();
+ }
+
+ /**
+ * Removes {@code key} from this {@code Classmate}.
+ * {@code key} must exist in the ClassMATE.
+ */
+ public void removeTutorialGroup(TutorialGroup key) {
+ tutorialGroups.remove(key);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof TutorialClass)) {
+ return false;
+ }
+
+ TutorialClass otherClass = (TutorialClass) other;
+ return otherClass.getSchedule().equals(getSchedule())
+ && otherClass.getClassCode().equals(getClassCode())
+ && otherClass.getTags().equals(getTags());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(classCode, schedule, tags);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(getClassCode())
+ .append("; schedule: ")
+ .append(getSchedule());
+
+ 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/tutorialclass/UniqueTutorialClassList.java b/src/main/java/seedu/address/model/tutorialclass/UniqueTutorialClassList.java
new file mode 100644
index 00000000000..a120e502124
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialclass/UniqueTutorialClassList.java
@@ -0,0 +1,185 @@
+package seedu.address.model.tutorialclass;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import seedu.address.model.tutorialclass.exceptions.DuplicateTutorialClassException;
+import seedu.address.model.tutorialclass.exceptions.TutorialClassNotFoundException;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+import seedu.address.model.tutorialgroup.exceptions.DuplicateTutorialGroupException;
+import seedu.address.model.tutorialgroup.exceptions.TutorialGroupNotFoundException;
+
+/**
+ * A list of tutorial classes that enforces uniqueness between its elements and does not allow nulls.
+ * A tutorial class is considered unique by comparing using {@code TutorialClass#isSameTutorialClass(TutorialClass)}.
+ *
+ * As such, adding and updating of tutorial classes uses TutorialClass#isSameTutorialClass(TutorialClass) for equality
+ * to ensure that the tutorial class being added or updated is unique in terms of identity
+ * in the UniqueTutorialClassList. However, the removal of a tutorial class uses TutorialClass#equals(Object) to
+ * ensure that the TutorialClass with exactly the same fields will be removed.
+ *
+ * Supports a minimal set of list operations.
+ *
+ * @see TutorialClass#isSameTutorialClass(TutorialClass)
+ */
+public class UniqueTutorialClassList implements Iterable {
+
+ private final ObservableList internalList = FXCollections.observableArrayList();
+ private final ObservableList internalUnmodifiableList =
+ FXCollections.unmodifiableObservableList(internalList);
+
+ /**
+ * Returns true if the list contains an equivalent tutorial class as the given argument.
+ */
+ public boolean contains(TutorialClass toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::isSameTutorialClass);
+ }
+
+ /**
+ * Returns true if the list contains the tutorial group.
+ */
+ public boolean contains(TutorialGroup toCheck) {
+ requireNonNull(toCheck);
+
+ // finds the tutorial class that the tutorial group belongs to
+ TutorialClass toCheckTutorialClass = TutorialClass.createTestTutorialClass(toCheck.getClassCode());
+ if (!contains(toCheckTutorialClass)) {
+ return false;
+ }
+ Optional result = internalList.stream()
+ .filter(toCheckTutorialClass::isSameTutorialClass).findFirst();
+ return result.get().getTutorialGroups().contains(toCheck);
+ }
+
+ /**
+ * Adds a tutorial class to the list.
+ * The tutorial class must not already exist in the list.
+ */
+ public void add(TutorialClass toAdd) {
+ requireNonNull(toAdd);
+ if (contains(toAdd)) {
+ throw new DuplicateTutorialClassException();
+ }
+ internalList.add(toAdd);
+ }
+
+ /**
+ * Adds a tutorial group to the tutorial class in the tutorial class list.
+ * The tutorial group must not already exist in the list.
+ */
+ public void add(TutorialGroup toAdd) {
+ requireNonNull(toAdd);
+ if (contains(toAdd)) {
+ throw new DuplicateTutorialGroupException();
+ }
+
+ // finds the tutorial class that the tutorial group belongs to
+ TutorialClass toCheckTutorialClass = TutorialClass.createTestTutorialClass(toAdd.getClassCode());
+ Optional result = internalList.stream()
+ .filter(toCheckTutorialClass::isSameTutorialClass).findFirst();
+
+ // add the tutorial group to the tutorial class found
+ result.get().addTutorialGroup(toAdd);
+ }
+
+ /**
+ * Sorts the tutorial groups within each tutorial class list.
+ */
+ public void sort() {
+ internalList.stream().forEach(x-> x.sortTutorialGroups());
+ }
+
+ /**
+ * Removes the equivalent tutorial class from the list.
+ * The tutorial class must exist in the list.
+ */
+ public void remove(TutorialClass toRemove) {
+ requireNonNull(toRemove);
+ if (!internalList.remove(toRemove)) {
+ throw new TutorialClassNotFoundException();
+ }
+ }
+
+ /**
+ * Removes the equivalent tutorial group from the list.
+ * The tutorial group must exist in the list.
+ */
+ public void remove(TutorialGroup toRemove) {
+ requireNonNull(toRemove);
+
+ if (!this.contains(toRemove)) {
+ throw new TutorialGroupNotFoundException();
+ }
+
+ // finds the tutorial class that the tutorial group belongs to
+ TutorialClass toCheckTutorialClass = TutorialClass.createTestTutorialClass(toRemove.getClassCode());
+ Optional result = internalList.stream()
+ .filter(toCheckTutorialClass::isSameTutorialClass).findFirst();
+
+ // removes the tutorial group from the tutorial class found
+ result.get().removeTutorialGroup(toRemove);
+ }
+
+ public void setTutorialClasses(UniqueTutorialClassList replacement) {
+ requireNonNull(replacement);
+ internalList.setAll(replacement.internalList);
+ }
+
+ /**
+ * Replaces the contents of this list with {@code tutorialClasses}.
+ * {@code tutorialClasses} must not contain duplicate tutorial classes.
+ */
+ public void setTutorialClasses(List tutorialClasses) {
+ requireAllNonNull(tutorialClasses);
+ if (!tutorialClassesAreUnique(tutorialClasses)) {
+ throw new DuplicateTutorialClassException();
+ }
+
+ internalList.setAll(tutorialClasses);
+ }
+
+ /**
+ * 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 UniqueTutorialClassList // instanceof handles nulls
+ && internalList.equals(((UniqueTutorialClassList) other).internalList));
+ }
+
+ @Override
+ public int hashCode() {
+ return internalList.hashCode();
+ }
+
+ /**
+ * Returns true if {@code tutorial classes} contains only unique tutorial classes.
+ */
+ private boolean tutorialClassesAreUnique(List tutorialClasses) {
+ for (int i = 0; i < tutorialClasses.size() - 1; i++) {
+ for (int j = i + 1; j < tutorialClasses.size(); j++) {
+ if (tutorialClasses.get(i).isSameTutorialClass(tutorialClasses.get(j))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/seedu/address/model/tutorialclass/exceptions/ClassNotFoundException.java b/src/main/java/seedu/address/model/tutorialclass/exceptions/ClassNotFoundException.java
new file mode 100644
index 00000000000..d33113dea95
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialclass/exceptions/ClassNotFoundException.java
@@ -0,0 +1,4 @@
+package seedu.address.model.tutorialclass.exceptions;
+
+public class ClassNotFoundException extends RuntimeException {
+}
diff --git a/src/main/java/seedu/address/model/tutorialclass/exceptions/DuplicateClassException.java b/src/main/java/seedu/address/model/tutorialclass/exceptions/DuplicateClassException.java
new file mode 100644
index 00000000000..152eb3e5066
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialclass/exceptions/DuplicateClassException.java
@@ -0,0 +1,7 @@
+package seedu.address.model.tutorialclass.exceptions;
+
+public class DuplicateClassException extends RuntimeException {
+ public DuplicateClassException() {
+ super("Operation would result in duplicate classes");
+ }
+}
diff --git a/src/main/java/seedu/address/model/tutorialclass/exceptions/DuplicateTutorialClassException.java b/src/main/java/seedu/address/model/tutorialclass/exceptions/DuplicateTutorialClassException.java
new file mode 100644
index 00000000000..8f25f20f23f
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialclass/exceptions/DuplicateTutorialClassException.java
@@ -0,0 +1,11 @@
+package seedu.address.model.tutorialclass.exceptions;
+
+/**
+ * Signals that the operation will result in duplicate Students (Students are considered duplicates if they have the
+ * same identity).
+ */
+public class DuplicateTutorialClassException extends RuntimeException {
+ public DuplicateTutorialClassException() {
+ super("Operation would result in duplicate tutorial classes");
+ }
+}
diff --git a/src/main/java/seedu/address/model/tutorialclass/exceptions/TutorialClassNotFoundException.java b/src/main/java/seedu/address/model/tutorialclass/exceptions/TutorialClassNotFoundException.java
new file mode 100644
index 00000000000..a6804c011d7
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialclass/exceptions/TutorialClassNotFoundException.java
@@ -0,0 +1,4 @@
+package seedu.address.model.tutorialclass.exceptions;
+
+public class TutorialClassNotFoundException extends RuntimeException{
+}
diff --git a/src/main/java/seedu/address/model/tutorialgroup/GroupNumber.java b/src/main/java/seedu/address/model/tutorialgroup/GroupNumber.java
new file mode 100644
index 00000000000..c1e86fe5d4e
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialgroup/GroupNumber.java
@@ -0,0 +1,71 @@
+package seedu.address.model.tutorialgroup;
+
+import static java.lang.Integer.parseInt;
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a TutorialGroup's number in the ClassMATE.
+ */
+public class GroupNumber implements Comparable {
+ public static final String MESSAGE_CONSTRAINTS = "Group number must be a single digit between 1 and 4, "
+ + "and it should not be blank";
+
+ private static final String GROUP_NUMBER_REGEX = "[1-4]";
+
+ public final String value;
+
+ /**
+ * Constructs an {@code GroupNumber}.
+ *
+ * @param groupNumber A valid groupNumber.
+ */
+ public GroupNumber(String groupNumber) {
+ requireNonNull(groupNumber);
+ checkArgument(isValidGroupNumber(groupNumber), MESSAGE_CONSTRAINTS);
+ value = groupNumber;
+ }
+
+ /**
+ * Checks validity of input string.
+ *
+ * @param test Test string.
+ * @return Validity of input GroupNumber string.
+ */
+ public static boolean isValidGroupNumber(String test) {
+ return test.matches(GROUP_NUMBER_REGEX);
+ }
+
+ /**
+ * Transforms the group number from a string to its numerical value.
+ *
+ * @return Integer that represents the group.
+ */
+ public Integer parseGroupNumber() {
+ return parseInt(value);
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof GroupNumber // instanceof handles nulls
+ && value.equals(((GroupNumber) other).value)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ @Override
+ public int compareTo(GroupNumber groupNumber) {
+ return parseGroupNumber().compareTo(groupNumber.parseGroupNumber());
+ }
+
+}
+
diff --git a/src/main/java/seedu/address/model/tutorialgroup/GroupType.java b/src/main/java/seedu/address/model/tutorialgroup/GroupType.java
new file mode 100644
index 00000000000..59032814602
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialgroup/GroupType.java
@@ -0,0 +1,66 @@
+package seedu.address.model.tutorialgroup;
+
+import static java.lang.Integer.parseInt;
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a TutorialGroup's type in the ClassMATE.
+ */
+public class GroupType implements Comparable {
+
+ public static final String MESSAGE_CONSTRAINTS = "GroupType can only either be OP1 or OP2";
+ public static final String VALIDATION_REGEX = "[O|o][P|p][1/2]";
+
+ public final String value;
+ /**
+ * Constructs an {@code GroupType}.
+ *
+ * @param groupType A valid groupType.
+ */
+ public GroupType (String groupType) {
+ requireNonNull(groupType);
+ checkArgument(isValidGroupType(groupType), MESSAGE_CONSTRAINTS);
+ value = groupType;
+ }
+
+ /**
+ * Returns true if a given string is a valid groupType.
+ */
+ public static boolean isValidGroupType(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ /**
+ * Gets the group type in terms of its number, 1 or 2.
+ *
+ * @return The group type in terms of its number.
+ */
+ public Integer parseGroupType() {
+ assert value.length() == 3;
+ return parseInt(value.substring(2));
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof GroupType // instanceof handles nulls
+ && value.equals(((GroupType) other).value)); // state check
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ @Override
+ public int compareTo(GroupType groupType) {
+ return parseGroupType().compareTo(groupType.parseGroupType());
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/tutorialgroup/TutorialGroup.java b/src/main/java/seedu/address/model/tutorialgroup/TutorialGroup.java
new file mode 100644
index 00000000000..f87ff4a64c0
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialgroup/TutorialGroup.java
@@ -0,0 +1,99 @@
+package seedu.address.model.tutorialgroup;
+
+import java.util.Objects;
+
+import seedu.address.model.student.ClassCode;
+
+/**
+ * Represents a Tutorial in the ClassMATE.
+ * Guarantees: details are present and not null, field values are validated, immutable.
+ */
+public class TutorialGroup {
+
+ private final GroupNumber groupNumber;
+ private final ClassCode classCode;
+ private final GroupType groupType;
+
+ /**
+ * @param groupNumber GroupNumber of TutorialGroup.
+ * @param classCode ClassCode of TutorialGroup.
+ */
+ public TutorialGroup(GroupNumber groupNumber, ClassCode classCode, GroupType groupType) {
+ this.groupNumber = groupNumber;
+ this.classCode = classCode;
+ this.groupType = groupType;
+
+ }
+
+ public GroupNumber getGroupNumber() {
+ return groupNumber;
+ }
+
+ public ClassCode getClassCode() {
+ return classCode;
+ }
+
+ public GroupType getGroupType() {
+ return groupType;
+ }
+
+ /**
+ * Returns true if both tutorial groups have the same group number, class code and group type.
+ */
+ public boolean isSameTutorialGroup(TutorialGroup otherGroup) {
+ if (otherGroup == this) {
+ return true;
+ }
+
+ return otherGroup != null
+ && otherGroup.getGroupNumber().equals(getGroupNumber())
+ && otherGroup.getClassCode().equals(getClassCode())
+ && otherGroup.getGroupType().equals(getGroupType());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof TutorialGroup)) {
+ return false;
+ }
+
+ TutorialGroup otherGroup = (TutorialGroup) other;
+ return otherGroup.getGroupNumber().equals(getGroupNumber())
+ && otherGroup.getClassCode().equals(getClassCode())
+ && otherGroup.getGroupType().equals(getGroupType());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(groupNumber, classCode, groupType);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("name: ")
+ .append(getGroupNumber())
+ .append("; class: ")
+ .append(getClassCode())
+ .append("; type: ")
+ .append(getGroupType());
+
+ return builder.toString();
+ }
+
+ /**
+ * Returns a short string to be displayed on StudentCard
+ */
+ public String toDisplayString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(getGroupType())
+ .append(" Grp: ")
+ .append(getGroupNumber());
+
+ return builder.toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/tutorialgroup/TutorialGroupContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/tutorialgroup/TutorialGroupContainsKeywordsPredicate.java
new file mode 100644
index 00000000000..7bd414465f1
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialgroup/TutorialGroupContainsKeywordsPredicate.java
@@ -0,0 +1,32 @@
+package seedu.address.model.tutorialgroup;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.StringUtil;
+
+/**
+ * Tests that a {@code TutorialGroup}'s {@code GroupName} matches any of the keywords given.
+ */
+public class TutorialGroupContainsKeywordsPredicate implements Predicate {
+ private final List keywords;
+
+ public TutorialGroupContainsKeywordsPredicate(List keywords) {
+ this.keywords = keywords;
+ }
+
+ @Override
+ public boolean test(TutorialGroup tutorialGroup) {
+ return keywords.stream()
+ .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(
+ tutorialGroup.getClassCode().toString(), keyword));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other == this // short circuit if same object
+ || (other instanceof TutorialGroupContainsKeywordsPredicate // instanceof handles nulls
+ && keywords.equals(((TutorialGroupContainsKeywordsPredicate) other).keywords)); // state check
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/tutorialgroup/UniqueTutorialGroupList.java b/src/main/java/seedu/address/model/tutorialgroup/UniqueTutorialGroupList.java
new file mode 100644
index 00000000000..1206167923b
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialgroup/UniqueTutorialGroupList.java
@@ -0,0 +1,101 @@
+package seedu.address.model.tutorialgroup;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.Comparator;
+import java.util.Iterator;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import seedu.address.model.tutorialgroup.exceptions.DuplicateTutorialGroupException;
+import seedu.address.model.tutorialgroup.exceptions.TutorialGroupNotFoundException;
+
+/**
+ * A list of tutorial groups that enforces uniqueness between its elements and does not allow nulls.
+ * A tutorial group is considered unique by comparing using {@code TutorialGroup#isSameTutorialGroup(TutorialGroup)}.
+ * As such, adding of tutorial groups uses TutorialGroup#isSameTutorialGroup(TutorialGroup) for equality to ensure that
+ * the tutorial group being added is unique in terms of identity in the UniqueTutorialGroupList.
+ * The removal of a tutorial group also uses TutorialGroup#isSameTutorialGroup(TutorialGroup) to ensure that the
+ * tutorial group with all fields identical is removed.
+ *
+ * Supports a minimal set of list operations.
+ *
+ * @see TutorialGroup#isSameTutorialGroup(TutorialGroup)
+ */
+public class UniqueTutorialGroupList implements Iterable {
+
+ private final ObservableList internalList = FXCollections.observableArrayList();
+ private final ObservableList internalUnmodifiableList =
+ FXCollections.unmodifiableObservableList(internalList);
+
+ /**
+ * Returns true if the list contains an equivalent tutorial group as the given argument.
+ */
+ public boolean contains(TutorialGroup toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::isSameTutorialGroup);
+ }
+
+ /**
+ * Adds a tutorial group to the list.
+ * The tutorial group must not already exist in the list.
+ */
+ public void add(TutorialGroup toAdd) {
+ requireNonNull(toAdd);
+ if (contains(toAdd)) {
+ throw new DuplicateTutorialGroupException();
+ }
+ internalList.add(toAdd);
+ }
+
+ /**
+ * Sorts the tutorial group list.
+ * Sorts by ClassCode, followed by GroupType and then GroupName.
+ */
+ public void sort() {
+ Comparator compareByName = Comparator
+ .comparing(TutorialGroup::getClassCode)
+ .thenComparing(TutorialGroup::getGroupType)
+ .thenComparing(TutorialGroup::getGroupNumber);
+ internalList.sort(compareByName);
+ }
+
+ /**
+ * Removes the equivalent tutorial group from the list.
+ * The tutorial group must exist in the list.
+ */
+ public void remove(TutorialGroup toRemove) {
+ requireNonNull(toRemove);
+ if (!internalList.remove(toRemove)) {
+ throw new TutorialGroupNotFoundException();
+ }
+ }
+
+ public ObservableList getInternalList() {
+ return internalList;
+ }
+
+ /**
+ * 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 UniqueTutorialGroupList // instanceof handles nulls
+ && internalList.equals(((UniqueTutorialGroupList) other).internalList));
+ }
+
+ @Override
+ public int hashCode() {
+ return internalList.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/tutorialgroup/exceptions/DuplicateTutorialGroupException.java b/src/main/java/seedu/address/model/tutorialgroup/exceptions/DuplicateTutorialGroupException.java
new file mode 100644
index 00000000000..9cd839154c2
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialgroup/exceptions/DuplicateTutorialGroupException.java
@@ -0,0 +1,11 @@
+package seedu.address.model.tutorialgroup.exceptions;
+
+/**
+ * Signals that the operation will result in duplicate TutorialGroups (TutorialGroups are considered duplicates
+ * if they have the same identity).
+ */
+public class DuplicateTutorialGroupException extends RuntimeException {
+ public DuplicateTutorialGroupException() {
+ super("Operation would result in duplicate tutorial group");
+ }
+}
diff --git a/src/main/java/seedu/address/model/tutorialgroup/exceptions/GroupNotFoundException.java b/src/main/java/seedu/address/model/tutorialgroup/exceptions/GroupNotFoundException.java
new file mode 100644
index 00000000000..65f0c50be97
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialgroup/exceptions/GroupNotFoundException.java
@@ -0,0 +1,4 @@
+package seedu.address.model.tutorialgroup.exceptions;
+
+public class GroupNotFoundException extends RuntimeException {
+}
diff --git a/src/main/java/seedu/address/model/tutorialgroup/exceptions/TutorialGroupNotFoundException.java b/src/main/java/seedu/address/model/tutorialgroup/exceptions/TutorialGroupNotFoundException.java
new file mode 100644
index 00000000000..389dbe9e343
--- /dev/null
+++ b/src/main/java/seedu/address/model/tutorialgroup/exceptions/TutorialGroupNotFoundException.java
@@ -0,0 +1,4 @@
+package seedu.address.model.tutorialgroup.exceptions;
+
+public class TutorialGroupNotFoundException extends RuntimeException{
+}
diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java
index 1806da4facf..8dc6c3ce3ac 100644
--- a/src/main/java/seedu/address/model/util/SampleDataUtil.java
+++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java
@@ -1,49 +1,58 @@
package seedu.address.model.util;
import java.util.Arrays;
+import java.util.List;
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.Classmate;
+import seedu.address.model.ReadOnlyClassmate;
+import seedu.address.model.student.Address;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Phone;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.StudentMark;
import seedu.address.model.tag.Tag;
+import seedu.address.model.tutorialgroup.TutorialGroup;
/**
- * Contains utility methods for populating {@code AddressBook} with sample data.
+ * Contains utility methods for populating {@code Classmate} 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 final ClassCode CLASS_CODE = new ClassCode("G00");
+
+ public static final Set EMPTY_TUTORIAL_GROUP = getTutorialGroupSet();
+
+ public static Student[] getSampleStudents() {
+ return new Student[] {
+ new Student(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"),
+ new Address("Blk 30 Geylang Street 29, #06-40"), CLASS_CODE,
+ getTagSet("friends"), getMarkList("LOW", "EXCELLENT"), EMPTY_TUTORIAL_GROUP),
+ new Student(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"),
+ new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"), CLASS_CODE,
+ getTagSet("colleagues", "friends"), getMarkList("LOW", "HIGH"), EMPTY_TUTORIAL_GROUP),
+ new Student(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"),
+ new Address("Blk 11 Ang Mo Kio Street 74, #11-04"), CLASS_CODE,
+ getTagSet("neighbours"), getMarkList("HIGH", "AVG"), EMPTY_TUTORIAL_GROUP),
+ new Student(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"),
+ new Address("Blk 436 Serangoon Gardens Street 26, #16-43"), CLASS_CODE,
+ getTagSet("family"), getMarkList("LOW", "EXCELLENT"), EMPTY_TUTORIAL_GROUP),
+ new Student(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"),
+ new Address("Blk 47 Tampines Street 20, #17-35"), CLASS_CODE,
+ getTagSet("classmates"), getMarkList("HIGH", "POOR"), EMPTY_TUTORIAL_GROUP),
+ new Student(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"),
+ new Address("Blk 45 Aljunied Street 85, #11-31"), CLASS_CODE,
+ getTagSet("colleagues"), getMarkList("LOW", "POOR"), EMPTY_TUTORIAL_GROUP)
};
}
- public static ReadOnlyAddressBook getSampleAddressBook() {
- AddressBook sampleAb = new AddressBook();
- for (Person samplePerson : getSamplePersons()) {
- sampleAb.addPerson(samplePerson);
+ public static ReadOnlyClassmate getSampleClassmate() {
+ Classmate sampleAb = new Classmate();
+ for (Student sampleStudent : getSampleStudents()) {
+ sampleAb.addStudent(sampleStudent);
}
return sampleAb;
}
@@ -57,4 +66,22 @@ public static Set getTagSet(String... strings) {
.collect(Collectors.toSet());
}
+ /**
+ * Returns a mark list containing the list of strings given.
+ */
+ public static List getMarkList(String... strings) {
+ return Arrays.stream(strings)
+ .map(StudentMark::valueOf)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Returns a tutorial group set containing a default list of tutorial groups.
+ */
+
+ public static Set getTutorialGroupSet(TutorialGroup... tutorialGroups) {
+ return Arrays.stream(tutorialGroups).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/ClassmateStorage.java b/src/main/java/seedu/address/storage/ClassmateStorage.java
new file mode 100644
index 00000000000..b0194b80019
--- /dev/null
+++ b/src/main/java/seedu/address/storage/ClassmateStorage.java
@@ -0,0 +1,46 @@
+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.Classmate;
+import seedu.address.model.ReadOnlyClassmate;
+
+/**
+ * Represents a storage for {@link Classmate}.
+ */
+public interface ClassmateStorage {
+
+ /**
+ * Returns the file path of the data file.
+ */
+ Path getClassmateFilePath();
+
+ /**
+ * Returns Classmate data as a {@link ReadOnlyClassmate}.
+ * 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 readClassmate() throws DataConversionException, IOException;
+
+ /**
+ * @see #getClassmateFilePath()
+ */
+ Optional readClassmate(Path filePath) throws DataConversionException, IOException;
+
+ /**
+ * Saves the given {@link ReadOnlyClassmate} to the storage.
+ * @param classmate cannot be null.
+ * @throws IOException if there was any problem writing to the file.
+ */
+ void saveClassmate(ReadOnlyClassmate classmate) throws IOException;
+
+ /**
+ * @see #saveClassmate(ReadOnlyClassmate)
+ */
+ void saveClassmate(ReadOnlyClassmate classmate, Path filePath) throws IOException;
+
+}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedMark.java b/src/main/java/seedu/address/storage/JsonAdaptedMark.java
new file mode 100644
index 00000000000..e5cee913ae0
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedMark.java
@@ -0,0 +1,51 @@
+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.student.StudentMark;
+
+/**
+ * Jackson-friendly version of {@link StudentMark}.
+ */
+class JsonAdaptedMark {
+
+ private final String mark;
+
+ /**
+ * Constructs a {@code JsonAdapterMark} with the given {@code mark}.
+ */
+ @JsonCreator
+ public JsonAdaptedMark(String mark) {
+ this.mark = mark;
+ }
+
+ /**
+ * Converts a given {@code StudentMark} into this class for Jackson use.
+ */
+ public JsonAdaptedMark(StudentMark source) {
+ mark = source.name();
+ }
+
+ @JsonValue
+ public String getMark() {
+ return mark;
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted mark object into the model's {@code StudentMark} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted tag.
+ */
+ public StudentMark toModelType() throws IllegalValueException {
+ StudentMark newMark;
+ try {
+ newMark = StudentMark.valueOf(mark);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalValueException(StudentMark.MESSAGE_CONSTRAINTS);
+ }
+ return newMark;
+ }
+
+}
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/JsonAdaptedStudent.java b/src/main/java/seedu/address/storage/JsonAdaptedStudent.java
new file mode 100644
index 00000000000..b1550c30cea
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedStudent.java
@@ -0,0 +1,231 @@
+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.student.Address;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.student.Email;
+import seedu.address.model.student.Name;
+import seedu.address.model.student.Phone;
+import seedu.address.model.student.Student;
+import seedu.address.model.student.StudentMark;
+import seedu.address.model.tag.Tag;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Jackson-friendly version of {@link Student}.
+ */
+class JsonAdaptedStudent {
+
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Student's %s field is missing!";
+
+ private final String name;
+ private final String phone;
+ private final String email;
+ private final String address;
+ private final String classCode;
+ private final List tagged = new ArrayList<>();
+ private final List marks = new ArrayList<>();
+ private final List tutorialGroups = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonAdaptedStudent} with the given student details.
+ */
+ @JsonCreator
+ public JsonAdaptedStudent(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
+ @JsonProperty("email") String email, @JsonProperty("address") String address,
+ @JsonProperty("classCode") String classCode,
+ @JsonProperty("tagged") List tagged,
+ @JsonProperty("marks") List marks,
+ @JsonProperty("tutorialGroups") List tutorialGroups) {
+ this.name = name;
+ this.phone = phone;
+ this.email = email;
+ this.address = address;
+ this.classCode = classCode;
+ if (tagged != null) {
+ this.tagged.addAll(tagged);
+ }
+ if (marks != null) {
+ this.marks.addAll(marks);
+ }
+ if (tutorialGroups != null) {
+ this.tutorialGroups.addAll(tutorialGroups);
+ }
+ }
+
+ /**
+ * Converts a given {@code Student} into this class for Jackson use.
+ */
+ public JsonAdaptedStudent(Student source) {
+ name = source.getName().fullName;
+ phone = source.getPhone().value;
+ email = source.getEmail().value;
+ address = source.getAddress().value;
+ classCode = source.getClassCode().value;
+ tagged.addAll(source.getTags().stream()
+ .map(JsonAdaptedTag::new)
+ .collect(Collectors.toList()));
+ marks.addAll(source.getMarks().stream()
+ .map(JsonAdaptedMark::new)
+ .collect(Collectors.toList()));
+ tutorialGroups.addAll(source.getTutorialGroups().stream()
+ .map(JsonAdaptedTutorialGroup::new)
+ .collect(Collectors.toList()));
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted student object into the model's {@code Student} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted student.
+ */
+ public Student toModelType() throws IllegalValueException {
+ final List studentTags = addTags();
+ final List studentMarks = addMarks();
+ final List studentTutorialGroups = addTutorialGroups();
+ final Name modelName = addName();
+ final Phone modelPhone = addPhone();
+ final Email modelEmail = addEmail();
+ final Address modelAddress = addAddress();
+ final ClassCode modelClassCode = addClassCode();
+
+ final Set modelTags = new HashSet<>(studentTags);
+ final List modelMarks = new ArrayList<>(studentMarks);
+ final Set modelTutorialGroups = new HashSet<>(studentTutorialGroups);
+
+ return new Student(modelName, modelPhone, modelEmail, modelAddress,
+ modelClassCode, modelTags, modelMarks, modelTutorialGroups);
+ }
+
+ /**
+ * Abstracted method to create List of tags.
+ *
+ * @return List of tags.
+ * @throws IllegalValueException
+ */
+ private List addTags() throws IllegalValueException {
+ List studentTags = new ArrayList<>();
+ for (JsonAdaptedTag tag : tagged) {
+ studentTags.add(tag.toModelType());
+ }
+ return studentTags;
+ }
+
+ /**
+ * Abstracted method to create List of Student Marks.
+ *
+ * @return List of student marks.
+ * @throws IllegalValueException
+ */
+ private List addMarks() throws IllegalValueException {
+ List studentMarks = new ArrayList<>();
+ for (JsonAdaptedMark mark : marks) {
+ studentMarks.add(mark.toModelType());
+ }
+ return studentMarks;
+ }
+
+ /**
+ * Abstracted method to get list of tutorial groups.
+ *
+ * @return Valid Tutorial Groups.
+ * @throws IllegalValueException
+ */
+ private List addTutorialGroups() throws IllegalValueException {
+ List studentTutorialGroups = new ArrayList<>();
+ for (JsonAdaptedTutorialGroup tutorialGroup : tutorialGroups) {
+ studentTutorialGroups.add(tutorialGroup.toModelType());
+ }
+ return studentTutorialGroups;
+ }
+
+ /**
+ * Abstracted method to add Name.
+ *
+ * @return valid Name.
+ * @throws IllegalValueException
+ */
+ private Name addName() throws IllegalValueException {
+ 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);
+ }
+ return new Name(name);
+ }
+
+ /**
+ * Abstracted method to add Phone.
+ *
+ * @return valid Phone.
+ * @throws IllegalValueException
+ */
+ private Phone addPhone() throws IllegalValueException {
+ 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);
+ }
+ return new Phone(phone);
+ }
+
+ /**
+ * Abstracted method to add Address.
+ *
+ * @return valid Address.
+ * @throws IllegalValueException
+ */
+ private Address addAddress() throws IllegalValueException {
+ 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);
+ }
+ return new Address(address);
+ }
+
+ /**
+ * Abstracted method to add Email.
+ *
+ * @return valid Email.
+ * @throws IllegalValueException
+ */
+ private Email addEmail() throws IllegalValueException {
+ 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);
+ }
+ return new Email(email);
+ }
+
+ /**
+ * Abstracted method to get ClassCode.
+ *
+ * @return Valid ClassCode.
+ * @throws IllegalValueException
+ */
+ private ClassCode addClassCode() throws IllegalValueException {
+ if (classCode == null) {
+ throw new IllegalValueException(
+ String.format(MISSING_FIELD_MESSAGE_FORMAT, ClassCode.class.getSimpleName()));
+ }
+ if (!ClassCode.isValidClassCode(classCode)) {
+ throw new IllegalValueException(ClassCode.MESSAGE_CONSTRAINTS);
+ }
+ return new ClassCode(classCode);
+ }
+
+}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTutorialClass.java b/src/main/java/seedu/address/storage/JsonAdaptedTutorialClass.java
new file mode 100644
index 00000000000..1ebbb7a2b54
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedTutorialClass.java
@@ -0,0 +1,129 @@
+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.student.ClassCode;
+import seedu.address.model.tag.Tag;
+import seedu.address.model.tutorialclass.Schedule;
+import seedu.address.model.tutorialclass.TutorialClass;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+/**
+ * Jackson-friendly version of {@link TutorialClass}.
+ */
+class JsonAdaptedTutorialClass {
+
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Tutorial Class's %s field is missing!";
+
+ private final String classCode;
+ private final String schedule;
+ private final List tutorialGroups = new ArrayList<>();
+ private final List tagged = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonAdaptedTutorialClass} with the given student details.
+ */
+ @JsonCreator
+ public JsonAdaptedTutorialClass(@JsonProperty("classCode") String classCode,
+ @JsonProperty("schedule") String schedule,
+ @JsonProperty("tutorialGroups") List tutorialGroups,
+ @JsonProperty("tagged") List tagged) {
+ this.classCode = classCode;
+ this.schedule = schedule;
+ if (tutorialGroups != null) {
+ this.tutorialGroups.addAll(tutorialGroups);
+ }
+
+ if (tagged != null) {
+ this.tagged.addAll(tagged);
+ }
+ }
+
+ /**
+ * Converts a given {@code TutorialClass} into this class for Jackson use.
+ */
+ public JsonAdaptedTutorialClass(TutorialClass source) {
+ classCode = source.getClassCode().toString();
+ schedule = source.getSchedule().toString();
+ tutorialGroups.addAll(source.getTutorialGroupsAsList().stream()
+ .map(JsonAdaptedTutorialGroup::new)
+ .collect(Collectors.toList()));
+ tagged.addAll(source.getTags().stream()
+ .map(JsonAdaptedTag::new)
+ .collect(Collectors.toList()));
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted student object into the model's {@code Student} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted student.
+ */
+ public TutorialClass toModelType() throws IllegalValueException {
+ final List modelTutorialGroups = new ArrayList<>();
+ for (JsonAdaptedTutorialGroup tutorialGroup : tutorialGroups) {
+ modelTutorialGroups.add(tutorialGroup.toModelType());
+ }
+
+ final List tutorialClassTags = addTags();
+ final ClassCode modelClassCode = addClassCode();
+ final Schedule modelSchedule = addSchedule();
+ final Set modelTags = new HashSet<>(tutorialClassTags);
+ return new TutorialClass(modelClassCode, modelSchedule, modelTutorialGroups, modelTags);
+ }
+
+ /**
+ * Abstracted method to create List of tags.
+ *
+ * @return List of tags.
+ * @throws IllegalValueException
+ */
+ private List addTags() throws IllegalValueException {
+ List tutorialClassTags = new ArrayList<>();
+ for (JsonAdaptedTag tag : tagged) {
+ tutorialClassTags.add(tag.toModelType());
+ }
+ return tutorialClassTags;
+ }
+
+ /**
+ * Abstracted method to get ClassCode.
+ *
+ * @return Valid ClassCode.
+ * @throws IllegalValueException
+ */
+ private ClassCode addClassCode() throws IllegalValueException {
+ if (classCode == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, String.class.getSimpleName()));
+ }
+ if (!ClassCode.isValidClassCode(classCode)) {
+ throw new IllegalValueException(ClassCode.MESSAGE_CONSTRAINTS);
+ }
+ return new ClassCode(classCode);
+ }
+
+ /**
+ * Abstracted method to add Schedule.
+ *
+ * @return valid Schedule.
+ * @throws IllegalValueException
+ */
+ private Schedule addSchedule() throws IllegalValueException {
+ if (schedule == null) {
+ throw new IllegalValueException(
+ String.format(MISSING_FIELD_MESSAGE_FORMAT, Schedule.class.getSimpleName())
+ );
+ }
+ if (!Schedule.isValidSchedule(schedule)) {
+ throw new IllegalValueException(Schedule.MESSAGE_CONSTRAINTS);
+ }
+ return new Schedule(schedule);
+ }
+}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTutorialGroup.java b/src/main/java/seedu/address/storage/JsonAdaptedTutorialGroup.java
new file mode 100644
index 00000000000..79ef11f28ad
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedTutorialGroup.java
@@ -0,0 +1,105 @@
+package seedu.address.storage;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.student.ClassCode;
+import seedu.address.model.tutorialgroup.GroupNumber;
+import seedu.address.model.tutorialgroup.GroupType;
+import seedu.address.model.tutorialgroup.TutorialGroup;
+
+public class JsonAdaptedTutorialGroup {
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Tutorial Group's %s field is missing!";
+
+ private final String groupNumber;
+ private final String classCode;
+ private final String groupType;
+
+ /**
+ * Constructs a {@code JsonAdaptedTutorialGroup} with the given tutorial group details.
+ */
+ @JsonCreator
+ public JsonAdaptedTutorialGroup(@JsonProperty("groupNumber") String groupNumber,
+ @JsonProperty("classCode") String classCode,
+ @JsonProperty("groupType") String groupType) {
+
+ this.groupNumber = groupNumber;
+ this.classCode = classCode;
+ this.groupType = groupType;
+ }
+
+ /**
+ * Converts a given {@code TutorialGroup} into this class for Jackson use.
+ */
+ public JsonAdaptedTutorialGroup(TutorialGroup source) {
+ groupNumber = source.getGroupNumber().toString();
+ classCode = source.getClassCode().toString();
+ groupType = source.getGroupType().toString();
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted tutorial group object into the model's {@code TutorialGroup} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted group.
+ */
+ public TutorialGroup toModelType() throws IllegalValueException {
+ final ClassCode modelClassCode = addClassCode();
+ final GroupNumber modelGroupNumber = addGroupNumber();
+ final GroupType modelGroupType = addGroupType();
+ return new TutorialGroup(modelGroupNumber, modelClassCode, modelGroupType);
+ }
+
+ /**
+ * Abstracted method to get GroupNumber.
+ *
+ * @return Valid GroupNumber.
+ * @throws IllegalValueException
+ */
+ private GroupNumber addGroupNumber() throws IllegalValueException {
+ if (groupNumber == null) {
+ throw new IllegalValueException(
+ String.format(MISSING_FIELD_MESSAGE_FORMAT, GroupNumber.class.getSimpleName())
+ );
+ }
+ if (!GroupNumber.isValidGroupNumber(groupNumber)) {
+ throw new IllegalValueException(GroupNumber.MESSAGE_CONSTRAINTS);
+ }
+ return new GroupNumber(groupNumber);
+ }
+
+ /**
+ * Abstracted method to get ClassCode.
+ *
+ * @return Valid ClassCode.
+ * @throws IllegalValueException
+ */
+ private ClassCode addClassCode() throws IllegalValueException {
+ if (classCode == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ ClassCode.class.getSimpleName()));
+ }
+ if (!ClassCode.isValidClassCode(classCode)) {
+ throw new IllegalValueException(ClassCode.MESSAGE_CONSTRAINTS);
+ }
+ return new ClassCode(classCode);
+ }
+
+ /**
+ * Abstracted method to add GroupType.
+ *
+ * @return valid GroupType.
+ * @throws IllegalValueException
+ */
+ private GroupType addGroupType() throws IllegalValueException {
+ if (groupType == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ GroupType.class.getSimpleName()));
+ }
+ if (!GroupType.isValidGroupType(groupType)) {
+ throw new IllegalValueException(GroupType.MESSAGE_CONSTRAINTS);
+ }
+ return new GroupType(groupType);
+ }
+
+}
diff --git a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java b/src/main/java/seedu/address/storage/JsonClassmateStorage.java
similarity index 50%
rename from src/main/java/seedu/address/storage/JsonAddressBookStorage.java
rename to src/main/java/seedu/address/storage/JsonClassmateStorage.java
index dfab9daaa0d..4a273e61517 100644
--- a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
+++ b/src/main/java/seedu/address/storage/JsonClassmateStorage.java
@@ -12,47 +12,47 @@
import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.commons.util.FileUtil;
import seedu.address.commons.util.JsonUtil;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ReadOnlyClassmate;
/**
- * A class to access AddressBook data stored as a json file on the hard disk.
+ * A class to access Classmate data stored as a json file on the hard disk.
*/
-public class JsonAddressBookStorage implements AddressBookStorage {
+public class JsonClassmateStorage implements ClassmateStorage {
- private static final Logger logger = LogsCenter.getLogger(JsonAddressBookStorage.class);
+ private static final Logger logger = LogsCenter.getLogger(JsonClassmateStorage.class);
private Path filePath;
- public JsonAddressBookStorage(Path filePath) {
+ public JsonClassmateStorage(Path filePath) {
this.filePath = filePath;
}
- public Path getAddressBookFilePath() {
+ public Path getClassmateFilePath() {
return filePath;
}
@Override
- public Optional readAddressBook() throws DataConversionException {
- return readAddressBook(filePath);
+ public Optional readClassmate() throws DataConversionException {
+ return readClassmate(filePath);
}
/**
- * Similar to {@link #readAddressBook()}.
+ * Similar to {@link #readClassmate()}.
*
* @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 {
+ public Optional readClassmate(Path filePath) throws DataConversionException {
requireNonNull(filePath);
- Optional jsonAddressBook = JsonUtil.readJsonFile(
- filePath, JsonSerializableAddressBook.class);
- if (!jsonAddressBook.isPresent()) {
+ Optional jsonClassmate = JsonUtil.readJsonFile(
+ filePath, JsonSerializableStudent.class);
+ if (!jsonClassmate.isPresent()) {
return Optional.empty();
}
try {
- return Optional.of(jsonAddressBook.get().toModelType());
+ return Optional.of(jsonClassmate.get().toModelType());
} catch (IllegalValueException ive) {
logger.info("Illegal values found in " + filePath + ": " + ive.getMessage());
throw new DataConversionException(ive);
@@ -60,21 +60,21 @@ public Optional readAddressBook(Path filePath) throws DataC
}
@Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, filePath);
+ public void saveClassmate(ReadOnlyClassmate classmate) throws IOException {
+ saveClassmate(classmate, filePath);
}
/**
- * Similar to {@link #saveAddressBook(ReadOnlyAddressBook)}.
+ * Similar to {@link #saveClassmate(ReadOnlyClassmate)}.
*
* @param filePath location of the data. Cannot be null.
*/
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
- requireNonNull(addressBook);
+ public void saveClassmate(ReadOnlyClassmate classmate, Path filePath) throws IOException {
+ requireNonNull(classmate);
requireNonNull(filePath);
FileUtil.createIfMissing(filePath);
- JsonUtil.saveJsonFile(new JsonSerializableAddressBook(addressBook), filePath);
+ JsonUtil.saveJsonFile(new JsonSerializableStudent(classmate), 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/JsonSerializableStudent.java b/src/main/java/seedu/address/storage/JsonSerializableStudent.java
new file mode 100644
index 00000000000..5e84b989302
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonSerializableStudent.java
@@ -0,0 +1,78 @@
+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.Classmate;
+import seedu.address.model.ReadOnlyClassmate;
+import seedu.address.model.student.Student;
+import seedu.address.model.tutorialclass.TutorialClass;
+
+/**
+ * An Immutable Classmate that is serializable to JSON format.
+ */
+@JsonRootName(value = "classmate")
+class JsonSerializableStudent {
+
+ public static final String MESSAGE_DUPLICATE_STUDENT = "Students list contains duplicate student(s).";
+ public static final String MESSAGE_DUPLICATE_TUTORIAL_CLASS =
+ "Tutorial Classes list contains duplicate tutorial class(es).";
+
+ private final List